suricata-1.4.7/0000755000000000000000000000000012253546204010310 500000000000000suricata-1.4.7/m4/0000755000000000000000000000000012253546203010627 500000000000000suricata-1.4.7/m4/ltversion.m40000644000000000000000000000126212253546170013042 00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file 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. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) suricata-1.4.7/m4/libtool.m40000644000000000000000000106000712253546170012464 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file 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. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS suricata-1.4.7/m4/lt~obsolete.m40000644000000000000000000001375612253546170013402 00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file 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. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) suricata-1.4.7/m4/ltsugar.m40000644000000000000000000001042412253546170012476 00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file 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. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) suricata-1.4.7/m4/ltoptions.m40000644000000000000000000003007312253546170013052 00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file 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. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) suricata-1.4.7/m4/libprelude.m40000644000000000000000000001760312253546156013156 00000000000000dnl Autoconf macros for libprelude dnl $id$ # Modified for LIBPRELUDE -- Yoann Vandoorselaere # Modified for LIBGNUTLS -- nmav # Configure paths for LIBGCRYPT # Shamelessly stolen from the one of XDELTA by Owen Taylor # Werner Koch 99-12-09 dnl AM_PATH_LIBPRELUDE([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]], THREAD_SUPPORT) dnl Test for libprelude, and define LIBPRELUDE_PREFIX, LIBPRELUDE_CFLAGS, LIBPRELUDE_PTHREAD_CFLAGS, dnl LIBPRELUDE_LDFLAGS, and LIBPRELUDE_LIBS dnl AC_DEFUN([AM_PATH_LIBPRELUDE], [dnl dnl Get the cflags and libraries from the libprelude-config script dnl AC_ARG_WITH(libprelude-prefix, AC_HELP_STRING(--with-libprelude-prefix=PFX, Prefix where libprelude is installed (optional)), libprelude_config_prefix="$withval", libprelude_config_prefix="") if test x$libprelude_config_prefix != x ; then if test x${LIBPRELUDE_CONFIG+set} != xset ; then LIBPRELUDE_CONFIG=$libprelude_config_prefix/bin/libprelude-config fi fi AC_PATH_PROG(LIBPRELUDE_CONFIG, libprelude-config, no) if test "$LIBPRELUDE_CONFIG" != "no"; then if $($LIBPRELUDE_CONFIG --thread > /dev/null 2>&1); then LIBPRELUDE_PTHREAD_CFLAGS=`$LIBPRELUDE_CONFIG --thread --cflags` if test x$4 = xtrue || test x$4 = xyes; then libprelude_config_args="--thread" else libprelude_config_args="--no-thread" fi else LIBPRELUDE_PTHREAD_CFLAGS=`$LIBPRELUDE_CONFIG --pthread-cflags` fi fi min_libprelude_version=ifelse([$1], ,0.1.0,$1) AC_MSG_CHECKING(for libprelude - version >= $min_libprelude_version) no_libprelude="" if test "$LIBPRELUDE_CONFIG" = "no" ; then no_libprelude=yes else LIBPRELUDE_CFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --cflags` LIBPRELUDE_LDFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --ldflags` LIBPRELUDE_LIBS=`$LIBPRELUDE_CONFIG $libprelude_config_args --libs` LIBPRELUDE_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --prefix` LIBPRELUDE_CONFIG_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --config-prefix` libprelude_config_version=`$LIBPRELUDE_CONFIG $libprelude_config_args --version` ac_save_CFLAGS="$CFLAGS" ac_save_LDFLAGS="$LDFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS" LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS" LIBS="$LIBS $LIBPRELUDE_LIBS" dnl dnl Now check if the installed libprelude is sufficiently new. Also sanity dnl checks the results of libprelude-config to some extent dnl rm -f conf.libpreludetest AC_TRY_RUN([ #include #include #include #include int main () { system ("touch conf.libpreludetest"); if( strcmp( prelude_check_version(NULL), "$libprelude_config_version" ) ) { printf("\n*** 'libprelude-config --version' returned %s, but LIBPRELUDE (%s)\n", "$libprelude_config_version", prelude_check_version(NULL) ); printf("*** was found! If libprelude-config was correct, then it is best\n"); printf("*** to remove the old version of LIBPRELUDE. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If libprelude-config was wrong, set the environment variable LIBPRELUDE_CONFIG\n"); printf("*** to point to the correct copy of libprelude-config, and remove the file config.cache\n"); printf("*** before re-running configure\n"); } else if ( strcmp(prelude_check_version(NULL), LIBPRELUDE_VERSION ) ) { printf("\n*** LIBPRELUDE header file (version %s) does not match\n", LIBPRELUDE_VERSION); printf("*** library (version %s)\n", prelude_check_version(NULL) ); } else { if ( prelude_check_version( "$min_libprelude_version" ) ) return 0; else { printf("no\n*** An old version of LIBPRELUDE (%s) was found.\n", prelude_check_version(NULL) ); printf("*** You need a version of LIBPRELUDE newer than %s. The latest version of\n", "$min_libprelude_version" ); printf("*** LIBPRELUDE is always available from http://www.prelude-ids.com/development/download/\n"); printf("*** \n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the libprelude-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of LIBPRELUDE, but you can also set the LIBPRELUDE_CONFIG environment to point to the\n"); printf("*** correct copy of libprelude-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_libprelude=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" LDFLAGS="$ac_save_LDFLAGS" fi if test "x$no_libprelude" = x ; then AC_MSG_RESULT(yes) ifelse([$2], , :, [$2]) else if test -f conf.libpreludetest ; then : else AC_MSG_RESULT(no) fi if test "$LIBPRELUDE_CONFIG" = "no" ; then echo "*** The libprelude-config script installed by LIBPRELUDE could not be found" echo "*** If LIBPRELUDE was installed in PREFIX, make sure PREFIX/bin is in" echo "*** your path, or set the LIBPRELUDE_CONFIG environment variable to the" echo "*** full path to libprelude-config." else if test -f conf.libpreludetest ; then : else echo "*** Could not run libprelude test program, checking why..." CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS" LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS" LIBS="$LIBS $LIBPRELUDE_LIBS" AC_TRY_LINK([ #include #include #include #include ], [ return !!prelude_check_version(NULL); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding LIBPRELUDE or finding the wrong" echo "*** version of LIBPRELUDE. If it is not finding LIBPRELUDE, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" echo "***" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means LIBPRELUDE was incorrectly installed" echo "*** or that you have moved LIBPRELUDE since it was installed. In the latter case, you" echo "*** may want to edit the libprelude-config script: $LIBPRELUDE_CONFIG" ]) CFLAGS="$ac_save_CFLAGS" LDFLAGS="$ac_save_LDFLAGS" LIBS="$ac_save_LIBS" fi fi LIBPRELUDE_CFLAGS="" LIBPRELUDE_LDFLAGS="" LIBPRELUDE_LIBS="" ifelse([$3], , :, [$3]) fi rm -f conf.libpreludetest AC_SUBST(LIBPRELUDE_CFLAGS) AC_SUBST(LIBPRELUDE_PTHREAD_CFLAGS) AC_SUBST(LIBPRELUDE_LDFLAGS) AC_SUBST(LIBPRELUDE_LIBS) AC_SUBST(LIBPRELUDE_PREFIX) AC_SUBST(LIBPRELUDE_CONFIG_PREFIX) m4_ifdef([LT_INIT], [AC_DEFINE([PRELUDE_APPLICATION_USE_LIBTOOL2], [], [Define whether application use libtool >= 2.0])], []) ]) dnl *-*wedit:notab*-* Please keep this as the last line. suricata-1.4.7/reference.config0000644000000000000000000000143012253546156013361 00000000000000# config reference: system URL config reference: bugtraq http://www.securityfocus.com/bid/ config reference: bid http://www.securityfocus.com/bid/ config reference: cve http://cve.mitre.org/cgi-bin/cvename.cgi?name= config reference: secunia http://www.secunia.com/advisories/ #whitehats is unfortunately gone config reference: arachNIDS http://www.whitehats.com/info/IDS config reference: McAfee http://vil.nai.com/vil/content/v_ config reference: nessus http://cgi.nessus.org/plugins/dump.php3?id= config reference: url http:// config reference: et http://doc.emergingthreats.net/ config reference: etpro http://doc.emergingthreatpro.com/ config reference: telus http:// config reference: md5 http://www.threatexpert.com/report.aspx?md5= suricata-1.4.7/aclocal.m40000644000000000000000000014645712253546172012115 00000000000000# generated automatically by aclocal 1.13.3 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file 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. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # 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. # # 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. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file 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. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.13.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.13.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file 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. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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 macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file 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. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file 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. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # --------------------------------------------------------------------------- # Adds support for distributing Python modules and packages. To # install modules, copy them to $(pythondir), using the python_PYTHON # automake variable. To install a package with the same name as the # automake package, install to $(pkgpythondir), or use the # pkgpython_PYTHON automake variable. # # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as # locations to install python extension modules (shared libraries). # Another macro is required to find the appropriate flags to compile # extension modules. # # If your package is configured with a different prefix to python, # users will have to add the install directory to the PYTHONPATH # environment variable, or create a .pth file (see the python # documentation for details). # # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will # cause an error if the version of python installed on the system # doesn't meet the requirement. MINIMUM-VERSION should consist of # numbers and dots only. AC_DEFUN([AM_PATH_PYTHON], [ dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl supported. (2.0 was released on October 16, 2000). m4_define_default([_AM_PYTHON_INTERPRETER_LIST], [python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0]) AC_ARG_VAR([PYTHON], [the Python interpreter]) m4_if([$1],[],[ dnl No version check is needed. # Find any Python interpreter. if test -z "$PYTHON"; then AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) fi am_display_PYTHON=python ], [ dnl A version check is needed. if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. AC_MSG_CHECKING([whether $PYTHON version is >= $1]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_ERROR([Python interpreter is too old])]) am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. AC_CACHE_CHECK([for a Python interpreter with version >= $1], [am_cv_pathless_PYTHON],[ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do test "$am_cv_pathless_PYTHON" = none && break AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) done]) # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) fi am_display_PYTHON=$am_cv_pathless_PYTHON fi ]) if test "$PYTHON" = :; then dnl Run any user-specified action, or abort. m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) # Just factor out some code duplication. am_python_setup_sysconfig="\ import sys # Prefer sysconfig over distutils.sysconfig, for better compatibility # with python 3.x. See automake bug#10227. try: import sysconfig except ImportError: can_use_sysconfig = 0 else: can_use_sysconfig = 1 # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: # try: from platform import python_implementation if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': can_use_sysconfig = 0 except ImportError: pass" dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) dnl Run any user-specified action. $2 fi ]) # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # --------------------------------------------------------------------------- # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. # Run ACTION-IF-FALSE otherwise. # This test uses sys.hexversion instead of the string equivalent (first # word of sys.version), in order to cope with versions such as 2.2c1. # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). AC_DEFUN([AM_PYTHON_CHECK_VERSION], [prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file 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. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file 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. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file 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. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/libprelude.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) suricata-1.4.7/libhtp/0000755000000000000000000000000012253546203011571 500000000000000suricata-1.4.7/libhtp/m4/0000755000000000000000000000000012253546203012111 500000000000000suricata-1.4.7/libhtp/m4/ltversion.m40000644000000000000000000000126212253546165014330 00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file 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. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) suricata-1.4.7/libhtp/m4/libtool.m40000644000000000000000000106000712253546165013752 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file 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. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS suricata-1.4.7/libhtp/m4/lt~obsolete.m40000644000000000000000000001375612253546165014670 00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file 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. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) suricata-1.4.7/libhtp/m4/ltsugar.m40000644000000000000000000001042412253546165013764 00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file 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. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) suricata-1.4.7/libhtp/m4/ltoptions.m40000644000000000000000000003007312253546165014340 00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file 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. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) suricata-1.4.7/libhtp/aclocal.m40000644000000000000000000011206612253546167013370 00000000000000# generated automatically by aclocal 1.13.3 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file 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. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file 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. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.13.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.13.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file 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. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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 macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file 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. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file 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. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file 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. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file 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. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file 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. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) suricata-1.4.7/libhtp/config.guess0000755000000000000000000013036112253546170014040 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-06-10' # This file 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 3 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, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: suricata-1.4.7/libhtp/configure.ac0000644000000000000000000000717312253546156014016 00000000000000 dnl ---------------------- dnl Initialization macros dnl ---------------------- AC_INIT(htp/htp.h) AC_CONFIG_HEADERS([config.h]) dnl ----------------------------------------------- dnl Package name and version number (user defined) dnl ----------------------------------------------- GENERIC_LIBRARY_NAME=htp GENERIC_MAJOR_VERSION=0 GENERIC_MINOR_VERSION=2 GENERIC_MICRO_VERSION=14 # API version (often = GENERIC_MAJOR_VERSION.GENERIC_MINOR_VERSION) GENERIC_API_VERSION=1.0 AC_SUBST(GENERIC_API_VERSION) # Shared library versioning GENERIC_LIBRARY_VERSION=1:2:0 # | | | # +------+ | +---+ # | | | # current:revision:age # | | | # | | +- increment if interfaces have been added # | | set to zero if interfaces have been removed # or changed # | +- increment if source code has changed # | set to zero if current is incremented # +- increment if interfaces have been added, removed or changed dnl -------------------------------- dnl Package name and version number dnl -------------------------------- AC_SUBST(GENERIC_LIBRARY_VERSION) PACKAGE=$GENERIC_LIBRARY_NAME AC_SUBST(GENERIC_LIBRARY_NAME) GENERIC_VERSION=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION.$GENERIC_MICRO_VERSION GENERIC_RELEASE=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION AC_SUBST(GENERIC_RELEASE) AC_SUBST(GENERIC_VERSION) VERSION=$GENERIC_VERSION AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define) AC_CONFIG_MACRO_DIR([m4]) AC_ARG_ENABLE(htp-debug, [ --enable-htp-debug Enable debug output], [ enable_htp_debug=yes ]) if test "$enable_htp_debug" = "yes"; then CFLAGS="${CFLAGS} -DHTP_DEBUG" echo "Debug mode enabled" fi dnl ----------------------------------------------- dnl Checks for programs. dnl ----------------------------------------------- AC_PROG_CC AM_PROG_LIBTOOL AM_SANITY_CHECK dnl ----------------------------------------------- dnl Checks for libs. dnl ----------------------------------------------- AC_CHECK_HEADER(zlib.h,,[AC_ERROR(zlib.h not found ...)]) ZLIB="" AC_CHECK_LIB(z, inflate,, ZLIB="no") if test "$ZLIB" = "no"; then echo echo " ERROR! zlib library not found" echo exit 1 fi dnl ----------------------------------------------- dnl provides a read-only relocation table area in the final ELF dnl ----------------------------------------------- AC_MSG_CHECKING(for -z relro) TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z relro" AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z relro" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) LDFLAGS="${TMPLDFLAGS}" #check for os AC_MSG_CHECKING([host os]) # If no host os was detected, try with uname if test -z "$host" ; then host="`uname`" fi case "$host" in *-*-openbsd*) CFLAGS="${CFLAGS} -fgnu89-inline" ;; esac AC_MSG_RESULT(ok) dnl ----------------------------------------------- dnl forces all relocations to be resolved at run-time dnl ----------------------------------------------- AC_MSG_CHECKING(for -z now) TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z now" AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z now" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) LDFLAGS="${TMPLDFLAGS}" CFLAGS="${CFLAGS} ${SECCFLAGS}" LDFLAGS="${LDFLAGS} ${SECLDFLAGS}" dnl ----------------------------------------------- dnl Generates Makefile's, configuration files and scripts dnl ----------------------------------------------- AC_PREFIX_DEFAULT(/usr/local) AC_OUTPUT(Makefile \ htp.pc \ htp/Makefile \ test/Makefile ) suricata-1.4.7/libhtp/depcomp0000755000000000000000000005601612253546170013101 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 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, see . # 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 . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} 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 # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # 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 cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc 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. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## 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). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - 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 -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # 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. ## 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. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -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 -ne 0; then 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 ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # 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 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, 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. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 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. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # 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 ;; #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 preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | 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) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | 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 preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" 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 preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # 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 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: suricata-1.4.7/libhtp/ChangeLog0000644000000000000000000000000012253546156013260 00000000000000suricata-1.4.7/libhtp/test/0000755000000000000000000000000012253546203012550 500000000000000suricata-1.4.7/libhtp/test/test.h0000644000000000000000000000207112253546156013627 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #ifndef _TEST_H #define _TEST_H #include #include #include #include #include #define UNKNOWN 0 #define CLIENT 1 #define SERVER 2 #ifndef O_BINARY #define O_BINARY 0 #endif typedef struct test_t test_t; struct test_t { char *buf; size_t pos; size_t len; char *chunk; size_t chunk_offset; size_t chunk_len; int chunk_direction; }; int test_run(const char *testsdir, const char *testname, htp_cfg_t *cfg, htp_connp_t **connp); #endif /* _TEST_H */ suricata-1.4.7/libhtp/test/test.c0000644000000000000000000002451612253546156013632 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include #include #include #include #include #include #include #include "../htp/htp.h" #include "test.h" /** * Destroys a test. * * @param test */ static void test_destroy(test_t *test) { if (test->buf != NULL) { free(test->buf); test->buf = NULL; } } /** * Checks if there's a chunk boundary at the given position. * * @param test * @param pos * @return Zero if there is no boundary, SERVER or CLIENT if a boundary * was found, and a negative value on error (e.g., not enough data * to determine if a boundary is present). */ static int test_is_boundary(test_t *test, int pos) { // Check that there's enough room if (pos + 3 >= test->len) return -1; if ((test->buf[pos] == '<') && (test->buf[pos + 1] == '<') && (test->buf[pos + 2] == '<')) { if (test->buf[pos + 3] == '\n') { return SERVER; } if (test->buf[pos + 3] == '\r') { if (pos + 4 >= test->len) return -1; else if (test->buf[pos + 4] == '\n') { return SERVER; } } } if ((test->buf[pos] == '>') && (test->buf[pos + 1] == '>') && (test->buf[pos + 2] == '>')) { if (test->buf[pos + 3] == '\n') { return CLIENT; } if (test->buf[pos + 3] == '\r') { if (pos + 4 >= test->len) return -1; else if (test->buf[pos + 4] == '\n') { return CLIENT; } } } return 0; } /** * Initializes test by loading the entire data file into a memory block. * * @param test * @param filename * @return Non-negative value on success, negative value on error. */ static int test_init(test_t *test, const char *filename) { memset(test, 0, sizeof (test_t)); int fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; struct stat buf; if (fstat(fd, &buf) < 0) { return -1; } test->buf = malloc(buf.st_size); test->len = 0; test->pos = 0; int bytes_read = 0; while ((bytes_read = read(fd, test->buf + test->len, buf.st_size - test->len)) > 0) { test->len += bytes_read; } if (test->len != buf.st_size) { free(test->buf); return -2; } close(fd); return 1; } void test_start(test_t *test) { test->pos = 0; } /** * Finds the next data chunk in the given test. * * @param test * @return One if a chunk is found or zero if there are no more chunks in the test. On * success, test->chunk will point to the beginning of the chunk, while * test->chunk_len will contain its length. */ static int test_next_chunk(test_t *test) { if (test->pos >= test->len) { return 0; } test->chunk = NULL; while (test->pos < test->len) { // Do we need to start another chunk? if (test->chunk == NULL) { // Are we at a boundary test->chunk_direction = test_is_boundary(test, test->pos); if (test->chunk_direction <= 0) { // Error return -1; } // Move over the boundary test->pos += 4; if (test->buf[test->pos] == '\n') test->pos++; // Start new chunk test->chunk = test->buf + test->pos; test->chunk_offset = test->pos; } // Are we at the end of a line? if (test->buf[test->pos] == '\n') { int r = test_is_boundary(test, test->pos + 1); if ((r == CLIENT) || (r == SERVER)) { // We got ourselves a chunk test->chunk_len = test->pos - test->chunk_offset; // Remove one '\r' (in addition to the '\n' that we've already removed), // which belongs to the next boundary if ((test->chunk_len > 0) && (test->chunk[test->chunk_len - 1] == '\r')) { test->chunk_len--; } // Position at the next boundary line test->pos++; return 1; } } test->pos++; } if (test->chunk != NULL) { test->chunk_len = test->pos - test->chunk_offset; return 1; } return 0; } static int parse_filename(const char *filename, char **remote_addr, int *remote_port, char **local_addr, int *local_port) { char *copy = strdup(filename); char *p, *saveptr; char *start = copy; char *q = strrchr(copy, '/'); if (q != NULL) start = q; q = strrchr(start, '\\'); if (q != NULL) start = q; int count = 0; p = strtok_r(start, "_", &saveptr); while (p != NULL) { count++; // printf("%i %s\n", count, p); switch (count) { case 2: *remote_addr = strdup(p); break; case 3: *remote_port = atoi(p); break; case 4: *local_addr = strdup(p); case 5: *local_port = atoi(p); break; } p = strtok_r(NULL, "_", &saveptr); } free(copy); return 0; } /** * Runs a single test. * * @param filename * @param cfg * @return A pointer to the instance of htp_connp_t created during * the test, or NULL if the test failed for some reason. */ int test_run(const char *testsdir, const char *testname, htp_cfg_t *cfg, htp_connp_t **connp) { char filename[1025]; test_t test; struct timeval tv_start, tv_end; int rc; *connp = NULL; strncpy(filename, testsdir, 1024); strncat(filename, "/", 1024 - strlen(filename)); strncat(filename, testname, 1024 - strlen(filename)); printf("Filename: %s\n", filename); // Initinialize test rc = test_init(&test, filename); if (rc < 0) { return rc; } gettimeofday(&tv_start, NULL); test_start(&test); // Create parser *connp = htp_connp_create(cfg); if (*connp == NULL) { fprintf(stderr, "Failed to create connection parser\n"); exit(1); } htp_connp_set_user_data(*connp, (void *) 0x02); // Does the filename contain connection metdata? if (strncmp(testname, "stream", 6) == 0) { // It does; use it char *remote_addr, *local_addr; int remote_port, local_port; parse_filename(testname, &remote_addr, &remote_port, &local_addr, &local_port); htp_connp_open(*connp, (const char *) remote_addr, remote_port, (const char *) local_addr, local_port, tv_start.tv_usec); free(remote_addr); free(local_addr); } else { // No connection metadata; provide some fake information instead htp_connp_open(*connp, (const char *) "127.0.0.1", 10000, (const char *) "127.0.0.1", 80, tv_start.tv_usec); } // Find all chunks and feed them to the parser int in_data_other = 0; char *in_data; size_t in_data_len; size_t in_data_offset; int out_data_other = 0; char *out_data; size_t out_data_len; size_t out_data_offset; for (;;) { if (test_next_chunk(&test) <= 0) { break; } if (test.chunk_direction == CLIENT) { if (in_data_other) { test_destroy(&test); fprintf(stderr, "Unable to buffer more than one inbound chunk.\n"); return -1; } int rc = htp_connp_req_data(*connp, tv_start.tv_usec, test.chunk, test.chunk_len); if (rc == STREAM_STATE_ERROR) { test_destroy(&test); return -101; } if (rc == STREAM_STATE_DATA_OTHER) { // Parser needs to see the outbound stream in order to continue // parsing the inbound stream. in_data_other = 1; in_data = test.chunk; in_data_len = test.chunk_len; in_data_offset = htp_connp_req_data_consumed(*connp); } } else { if (out_data_other) { int rc = htp_connp_res_data(*connp, tv_start.tv_usec, out_data + out_data_offset, out_data_len - out_data_offset); if (rc == STREAM_STATE_ERROR) { test_destroy(&test); return -104; } out_data_other = 0; } int rc = htp_connp_res_data(*connp, tv_start.tv_usec, test.chunk, test.chunk_len); if (rc == STREAM_STATE_ERROR) { test_destroy(&test); return -102; } if (rc == STREAM_STATE_DATA_OTHER) { // Parser needs to see the outbound stream in order to continue // parsing the inbound stream. out_data_other = 1; out_data = test.chunk; out_data_len = test.chunk_len; out_data_offset = htp_connp_res_data_consumed(*connp); // printf("# YYY out offset is %d\n", out_data_offset); } if (in_data_other) { int rc = htp_connp_req_data(*connp, tv_start.tv_usec, in_data + in_data_offset, in_data_len - in_data_offset); if (rc == STREAM_STATE_ERROR) { test_destroy(&test); return -103; } in_data_other = 0; } } } if (out_data_other) { int rc = htp_connp_res_data(*connp, tv_start.tv_usec, out_data + out_data_offset, out_data_len - out_data_offset); if (rc == STREAM_STATE_ERROR) { test_destroy(&test); return -104; } out_data_other = 0; } gettimeofday(&tv_end, NULL); // Close the connection htp_connp_close(*connp, tv_end.tv_usec); // printf("Parsing time: %i\n", tv_end.tv_usec - tv_start.tv_usec); // Clean up test_destroy(&test); return 1; } suricata-1.4.7/libhtp/test/main.c0000644000000000000000000012527612253546156013604 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include #include #include #include #include #include #include "../htp/bstr.h" #include "../htp/htp.h" #include "test.h" char *home = NULL; /** * */ int test_get(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "01-get.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } htp_connp_destroy_all(connp); return 1; } /** * */ int test_post_urlencoded_chunked(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "04-post-urlencoded-chunked.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); bstr *key = NULL; htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); while ((key = table_iterator_next(tx->request_headers, (void **) & h)) != NULL) { char *key = bstr_tocstr(h->name); char *value = bstr_tocstr(h->value); printf("-- HEADER [%s][%s]\n", key, value); free(value); free(key); } bstr *raw = htp_tx_get_request_headers_raw(tx); fprint_raw_data(stdout, "REQUEST HEADERS RAW 2", bstr_ptr(raw), bstr_len(raw)); htp_connp_destroy_all(connp); return 1; } /** * */ int test_post_urlencoded(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "03-post-urlencoded.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } htp_connp_destroy_all(connp); return 1; } /** * */ int test_apache_header_parsing(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "02-header-test-apache2.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (tx == NULL) return -1; int count = 0; bstr *key = NULL; htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); while ((key = table_iterator_next(tx->request_headers, (void **) & h)) != NULL) { char *key = bstr_tocstr(h->name); char *value = bstr_tocstr(h->value); printf("-- HEADER [%s][%s]\n", key, value); free(value); free(key); } // There must be 9 headers if (table_size(tx->request_headers) != 9) { printf("Got %i headers, but expected 9\n", table_size(tx->request_headers)); htp_connp_destroy(connp); return -1; } // Check every header count = 0; key = NULL; h = NULL; table_iterator_reset(tx->request_headers); while ((key = table_iterator_next(tx->request_headers, (void **) & h)) != NULL) { switch (count) { case 0: if (bstr_cmpc(h->name, " Invalid-Folding") != 0) { printf("Header %i incorrect name\n", count + 1); return -1; } if (bstr_cmpc(h->value, "1") != 0) { printf("Header %i incorrect value\n", count + 1); return -1; } break; case 1: if (bstr_cmpc(h->name, "Valid-Folding") != 0) { printf("Header %i incorrect name\n", count + 1); return -1; } if (bstr_cmpc(h->value, "2 2") != 0) { printf("Header %i incorrect value\n", count + 1); return -1; } break; case 2: if (bstr_cmpc(h->name, "Normal-Header") != 0) { printf("Header %i incorrect name\n", count + 1); return -1; } if (bstr_cmpc(h->value, "3") != 0) { printf("Header %i incorrect value\n", count + 1); return -1; } break; case 3: if (bstr_cmpc(h->name, "Invalid Header Name") != 0) { printf("Header %i incorrect name\n", count + 1); return -1; } if (bstr_cmpc(h->value, "4") != 0) { printf("Header %i incorrect value\n", count + 1); return -1; } break; case 4: if (bstr_cmpc(h->name, "Same-Name-Headers") != 0) { printf("Header %i incorrect name\n", count + 1); return -1; } if (bstr_cmpc(h->value, "5, 6") != 0) { printf("Header %i incorrect value\n", count + 1); return -1; } break; case 5: if (bstr_cmpc(h->name, "Empty-Value-Header") != 0) { printf("Header %i incorrect name\n", count + 1); return -1; } if (bstr_cmpc(h->value, "") != 0) { printf("Header %i incorrect value\n", count + 1); return -1; } break; case 6: if (bstr_cmpc(h->name, "") != 0) { printf("Header %i incorrect name\n", count + 1); return -1; } if (bstr_cmpc(h->value, "8, ") != 0) { printf("Header %i incorrect value\n", count + 1); return -1; } break; case 7: if (bstr_cmpc(h->name, "Header-With-LWS-After") != 0) { printf("Header %i incorrect name\n", count + 1); return -1; } if (bstr_cmpc(h->value, "9") != 0) { printf("Header %i incorrect value\n", count + 1); return -1; } break; case 8: { bstr *b = bstr_memdup("BEFORE", 6); if (bstr_cmpc(h->name, "Header-With-NUL") != 0) { printf("Header %i incorrect name\n", count + 1); bstr_free(b); return -1; } if (bstr_cmp(h->value, b) != 0) { printf("Header %i incorrect value\n", count + 1); bstr_free(b); return -1; } bstr_free(b); } break; } count++; } htp_connp_destroy_all(connp); return 1; } /** * */ int test_expect(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "05-expect.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } htp_connp_destroy_all(connp); return 1; } /** * */ int test_uri_normal(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "06-uri-normal.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } htp_connp_destroy_all(connp); return 1; } /** * */ int test_pipelined_connection(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "07-pipelined-connection.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) != 2) { printf("Expected 2 transactions but found %i.", list_size(connp->conn->transactions)); return -1; } if (!(connp->conn->flags & PIPELINED_CONNECTION)) { printf("The pipelined flag not set on a pipelined connection."); return -1; } htp_connp_destroy_all(connp); return 1; } /** * */ int test_not_pipelined_connection(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "08-not-pipelined-connection.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) != 2) { printf("Expected 2 transactions but found %i.", list_size(connp->conn->transactions)); return -1; } if (connp->conn->flags & PIPELINED_CONNECTION) { printf("The pipelined flag set on a connection that is not pipelined."); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (tx->flags & HTP_MULTI_PACKET_HEAD) { printf("The HTP_MULTI_PACKET_HEAD flag set on a single-packet transaction."); return -1; } htp_connp_destroy_all(connp); return 1; } /** * */ int test_multi_packet_request_head(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "09-multi-packet-request-head.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) != 1) { printf("Expected 1 transaction but found %i.", list_size(connp->conn->transactions)); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (!(tx->flags & HTP_MULTI_PACKET_HEAD)) { printf("The HTP_MULTI_PACKET_HEAD flag is not set on a multipacket transaction."); return -1; } htp_connp_destroy_all(connp); return 1; } int test_misc(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "misc.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) == 0) { printf("Expected at least one transaction"); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); printf("Parsed URI: %s\n", bstr_tocstr(tx->parsed_uri_incomplete->path)); htp_connp_destroy_all(connp); return 1; } /** * */ int test_host_in_headers(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "10-host-in-headers.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) != 4) { printf("Expected 4 transactions but found %i.", list_size(connp->conn->transactions)); return -1; } htp_tx_t *tx1 = list_get(connp->conn->transactions, 0); htp_tx_t *tx2 = list_get(connp->conn->transactions, 1); htp_tx_t *tx3 = list_get(connp->conn->transactions, 2); htp_tx_t *tx4 = list_get(connp->conn->transactions, 3); if ((tx1->parsed_uri->hostname == NULL) || (bstr_cmpc(tx1->parsed_uri->hostname, "www.example.com") != 0)) { printf("1) Expected 'www.example.com' as hostname, but got: %s", tx1->parsed_uri->hostname); return -1; } if ((tx2->parsed_uri->hostname == NULL) || (bstr_cmpc(tx2->parsed_uri->hostname, "www.example.com") != 0)) { printf("2) Expected 'www.example.com' as hostname, but got: %s", tx2->parsed_uri->hostname); return -1; } if ((tx3->parsed_uri->hostname == NULL) || (bstr_cmpc(tx3->parsed_uri->hostname, "www.example.com") != 0)) { printf("3) Expected 'www.example.com' as hostname, but got: %s", tx3->parsed_uri->hostname); return -1; } if ((tx4->parsed_uri->hostname == NULL) || (bstr_cmpc(tx4->parsed_uri->hostname, "www.example.com") != 0)) { printf("4) Expected 'www.example.com' as hostname, but got: %s", tx4->parsed_uri->hostname); return -1; } htp_connp_destroy_all(connp); return 1; } int test_response_stream_closure(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "11-response-stream-closure.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) == 0) { printf("Expected at least one transaction"); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (tx->progress != TX_PROGRESS_DONE) { printf("Expected the only transaction to be complete (but got %i).", tx->progress); return -1; } htp_connp_destroy_all(connp); return 1; } int test_connect(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "12-connect-request.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) == 0) { printf("Expected at least one transaction"); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (tx->progress != TX_PROGRESS_DONE) { printf("Expected the only transaction to be complete (but got %i).", tx->progress); return -1; } //printf("Parsed URI: %x\n", tx->parsed_uri); // printf("Server: %s\n", bstr_len(tx->parsed_uri->hostname), bstr_ptr(tx->parsed_uri->hostname)); //printf("Port: %s\n", bstr_ptr(tx->parsed_uri->port)); htp_connp_destroy_all(connp); return 1; } int test_connect_complete(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "15-connect-complete.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) == 0) { printf("Expected at least one transaction"); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (tx->progress != TX_PROGRESS_DONE) { printf("Expected the only transaction to be complete (but got %i).", tx->progress); return -1; } htp_connp_destroy_all(connp); return 1; } int test_connect_extra(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "16-connect-extra.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) == 0) { printf("Expected at least one transaction"); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (tx->progress != TX_PROGRESS_DONE) { printf("Expected the only transaction to be complete (but got %i).", tx->progress); return -1; } htp_connp_destroy_all(connp); return 1; } int test_compressed_response_gzip_ct(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "13-compressed-response-gzip-ct.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) == 0) { printf("Expected at least one transaction"); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (tx->progress != TX_PROGRESS_DONE) { printf("Expected the only transaction to be complete (but got %i).", tx->progress); return -1; } htp_connp_destroy_all(connp); return 1; } int test_compressed_response_gzip_chunked(htp_cfg_t *cfg) { htp_connp_t *connp = NULL; int rc = test_run(home, "14-compressed-response-gzip-chunked.t", cfg, &connp); if (rc < 0) { if (connp != NULL) htp_connp_destroy_all(connp); return -1; } if (list_size(connp->conn->transactions) == 0) { printf("Expected at least one transaction"); return -1; } htp_tx_t *tx = list_get(connp->conn->transactions, 0); if (tx->progress != TX_PROGRESS_DONE) { printf("Expected the only transaction to be complete (but got %i).", tx->progress); return -1; } htp_connp_destroy_all(connp); return 1; } int callback_transaction_start(htp_connp_t *connp) { printf("-- Callback: transaction_start\n"); return HOOK_OK; } int callback_request_line(htp_connp_t *connp) { printf("-- Callback: request_line\n"); return HOOK_OK; } int callback_request_headers(htp_connp_t *connp) { printf("-- Callback: request_headers\n"); return HOOK_OK; } int callback_request_body_data(htp_tx_data_t *d) { printf("-- Callback: request_body_data\n"); fprint_raw_data(stdout, __FUNCTION__, d->data, d->len); return HOOK_OK; } int callback_request_trailer(htp_connp_t *connp) { printf("-- Callback: request_trailer\n"); return HOOK_OK; } int callback_request(htp_connp_t *connp) { printf("-- Callback: request\n"); return HOOK_OK; } int callback_response_line(htp_connp_t *connp) { printf("-- Callback: response_line\n"); return HOOK_OK; } int callback_response_headers(htp_connp_t *connp) { printf("-- Callback: response_headers\n"); return HOOK_OK; } int callback_response_body_data(htp_tx_data_t *d) { printf("-- Callback: response_body_data\n"); fprint_raw_data(stdout, __FUNCTION__, d->data, d->len); return HOOK_OK; } int callback_response_trailer(htp_connp_t *connp) { printf("-- Callback: response_trailer\n"); return HOOK_OK; } int callback_response(htp_connp_t *connp) { printf("-- Callback: response\n"); return HOOK_OK; } int callback_response_destroy(htp_connp_t *connp) { htp_tx_destroy(connp->out_tx); printf("-- Destroyed transaction\n"); return HOOK_OK; } int callback_log(htp_log_t *log) { htp_print_log(stdout, log); return HOOK_OK; } static void print_tx(htp_connp_t *connp, htp_tx_t *tx) { char *request_line = bstr_tocstr(tx->request_line); htp_header_t *h_user_agent = table_getc(tx->request_headers, "user-agent"); htp_header_t *h_referer = table_getc(tx->request_headers, "referer"); char *referer, *user_agent; char buf[256]; time_t t = time(NULL); struct tm *tmp = localtime(&t); strftime(buf, 255, "%d/%b/%Y:%T %z", tmp); if (h_user_agent == NULL) user_agent = strdup("-"); else { user_agent = bstr_tocstr(h_user_agent->value); } if (h_referer == NULL) referer = strdup("-"); else { referer = bstr_tocstr(h_referer->value); } printf("%s - - [%s] \"%s\" %i %i \"%s\" \"%s\"\n", connp->conn->remote_addr, buf, request_line, tx->response_status_number, tx->response_message_len, referer, user_agent); free(referer); free(user_agent); free(request_line); } static int run_directory(char *dirname, htp_cfg_t *cfg) { struct dirent *entry; char buf[1025]; DIR *d = opendir(dirname); htp_connp_t *connp; if (d == NULL) { printf("Failed to open directory: %s\n", dirname); return -1; } while ((entry = readdir(d)) != NULL) { if (strncmp(entry->d_name, "stream", 6) == 0) { int rc = test_run(dirname, entry->d_name, cfg, &connp); if (rc < 0) { if (connp != NULL) { htp_log_t *last_error = htp_connp_get_last_error(connp); if (last_error != NULL) { printf(" -- failed: %s\n", last_error->msg); } else { printf(" -- failed: ERROR NOT AVAILABLE\n"); } return 0; } else { return -1; } } else { printf(" -- %i transaction(s)\n", list_size(connp->conn->transactions)); htp_tx_t *tx = NULL; list_iterator_reset(connp->conn->transactions); while ((tx = list_iterator_next(connp->conn->transactions)) != NULL) { printf(" "); print_tx(connp, tx); } printf("\n"); htp_connp_destroy_all(connp); } } } closedir(d); return 1; } int main_dir(int argc, char** argv) { htp_cfg_t *cfg = htp_config_create(); htp_config_register_log(cfg, callback_log); htp_config_register_response(cfg, callback_response_destroy); run_directory("C:\\http_traces\\run5", cfg); //run_directory("/home/ivanr/work/traces/run3/", cfg); htp_config_destroy(cfg); return (EXIT_SUCCESS); } #define RUN_TEST(X, Y) \ {\ tests++; \ printf("---------------------------------\n"); \ printf("Test: " #X "\n"); \ int rc = X(Y); \ if (rc < 0) { \ printf(" Failed with %i\n", rc); \ failures++; \ } \ printf("\n"); \ } /** * Entry point; runs a bunch of tests and exits. */ int main(int argc, char** argv) { char buf[1025]; int tests = 0, failures = 0; home = NULL; // Try the current working directory first int fd = open("./files/anchor.empty", 0, O_RDONLY); if (fd != -1) { close(fd); home = "./files"; } else { // Try the directory in which the executable resides strncpy(buf, argv[0], 1024); strncat(buf, "/../files/anchor.empty", 1024 - strlen(buf)); fd = open(buf, 0, O_RDONLY); if (fd != -1) { close(fd); strncpy(buf, argv[0], 1024); strncat(buf, "/../files", 1024 - strlen(buf)); home = buf; } else { // Try the directory in which the executable resides strncpy(buf, argv[0], 1024); strncat(buf, "/../../files/anchor.empty", 1024 - strlen(buf)); fd = open(buf, 0, O_RDONLY); if (fd != -1) { close(fd); strncpy(buf, argv[0], 1024); strncat(buf, "/../../files", 1024 - strlen(buf)); home = buf; } } } if (home == NULL) { printf("Failed to find test files."); exit(-1); } htp_cfg_t *cfg = htp_config_create(); //htp_config_set_server_personality(cfg, HTP_SERVER_GENERIC); htp_config_set_server_personality(cfg, HTP_SERVER_APACHE_2_2); // Register hooks htp_config_register_transaction_start(cfg, callback_transaction_start); htp_config_register_request_line(cfg, callback_request_line); htp_config_register_request_headers(cfg, callback_request_headers); htp_config_register_request_body_data(cfg, callback_request_body_data); htp_config_register_request_trailer(cfg, callback_request_trailer); htp_config_register_request(cfg, callback_request); htp_config_register_response_line(cfg, callback_response_line); htp_config_register_response_headers(cfg, callback_response_headers); htp_config_register_response_body_data(cfg, callback_response_body_data); htp_config_register_response_trailer(cfg, callback_response_trailer); htp_config_register_response(cfg, callback_response); htp_config_register_log(cfg, callback_log); htp_config_set_generate_request_uri_normalized(cfg, 1); RUN_TEST(test_get, cfg); //RUN_TEST(test_apache_header_parsing, cfg); //RUN_TEST(test_post_urlencoded, cfg); //RUN_TEST(test_post_urlencoded_chunked, cfg); //RUN_TEST(test_expect, cfg); //RUN_TEST(test_uri_normal, cfg); //RUN_TEST(test_pipelined_connection, cfg); //RUN_TEST(test_not_pipelined_connection, cfg); //RUN_TEST(test_multi_packet_request_head, cfg); //RUN_TEST(test_response_stream_closure, cfg); //RUN_TEST(test_host_in_headers, cfg); //RUN_TEST(test_compressed_response_gzip_ct, cfg); //RUN_TEST(test_compressed_response_gzip_chunked, cfg); //RUN_TEST(test_connect, cfg); //RUN_TEST(test_connect_complete, cfg); //RUN_TEST(test_connect_extra, cfg); //RUN_TEST(test_misc, cfg); //RUN_TEST(test_post_urlencoded_chunked, cfg); printf("Tests: %i\n", tests); printf("Failures: %i\n", failures); htp_config_destroy(cfg); return (EXIT_SUCCESS); } int main_path_decoding_tests(int argc, char** argv) { htp_cfg_t *cfg = htp_config_create(); htp_tx_t *tx = htp_tx_create(cfg, 0, NULL); bstr *path = NULL; // path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); cfg->path_case_insensitive = 1; printf("Before: %s\n", bstr_tocstr(path)); htp_decode_path_inplace(cfg, tx, path); printf("After: %s\n\n", bstr_tocstr(path)); // path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); cfg->path_case_insensitive = 1; cfg->path_compress_separators = 1; printf("Before: %s\n", bstr_tocstr(path)); htp_decode_path_inplace(cfg, tx, path); printf("After: %s\n\n", bstr_tocstr(path)); // path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); cfg->path_case_insensitive = 1; cfg->path_compress_separators = 1; cfg->path_backslash_separators = 1; printf("Before: %s\n", bstr_tocstr(path)); htp_decode_path_inplace(cfg, tx, path); printf("After: %s\n\n", bstr_tocstr(path)); // path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); cfg->path_case_insensitive = 1; cfg->path_compress_separators = 1; cfg->path_backslash_separators = 1; cfg->path_decode_separators = 1; printf("Before: %s\n", bstr_tocstr(path)); htp_decode_path_inplace(cfg, tx, path); printf("After: %s\n\n", bstr_tocstr(path)); // path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); cfg->path_case_insensitive = 1; cfg->path_compress_separators = 1; cfg->path_backslash_separators = 1; cfg->path_decode_separators = 1; cfg->path_invalid_encoding_handling = URL_DECODER_REMOVE_PERCENT; printf("Before: %s\n", bstr_tocstr(path)); htp_decode_path_inplace(cfg, tx, path); printf("After: %s\n\n", bstr_tocstr(path)); // path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven/%u0074"); cfg->path_case_insensitive = 1; cfg->path_compress_separators = 1; cfg->path_backslash_separators = 1; cfg->path_decode_separators = 1; cfg->path_invalid_encoding_handling = URL_DECODER_DECODE_INVALID; printf("Before: %s\n", bstr_tocstr(path)); htp_decode_path_inplace(cfg, tx, path); printf("After: %s\n\n", bstr_tocstr(path)); // path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven/%u0074%u0100"); cfg->path_case_insensitive = 1; cfg->path_compress_separators = 1; cfg->path_backslash_separators = 1; cfg->path_decode_separators = 1; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; cfg->path_decode_u_encoding = 1; printf("Before: %s\n", bstr_tocstr(path)); htp_decode_path_inplace(cfg, tx, path); printf("After: %s\n\n", bstr_tocstr(path)); return (EXIT_SUCCESS); } void encode_utf8_2(uint8_t *data, uint32_t i) { i = i & 0x7ff; data[0] = 0xc0 + (i >> 6); data[1] = 0x80 + (i & 0x3f); } void encode_utf8_3(uint8_t *data, uint32_t i) { i = i & 0xffff; data[0] = 0xe0 + (i >> 12); data[1] = 0x80 + ((i >> 6) & 0x3f); data[2] = 0x80 + (i & 0x3f); } void encode_utf8_4(uint8_t *data, uint32_t i) { i = i & 0x10ffff; data[0] = 0xf0 + (i >> 18); data[1] = 0x80 + ((i >> 12) & 0x3f); data[2] = 0x80 + ((i >> 6) & 0x3f); data[3] = 0x80 + (i & 0x3f); } int main_utf8_decoder_tests(int argc, char** argv) { htp_cfg_t *cfg = htp_config_create(); htp_tx_t *tx = htp_tx_create(cfg, 0, NULL); bstr *path = NULL; path = bstr_cstrdup("//////////"); uint8_t *data = bstr_ptr(path); int i = 0; for (i = 0; i < 0x80; i++) { memset(data, 0x2f, 10); tx->flags = 0; encode_utf8_2(data, i); htp_utf8_validate_path(tx, path); if (tx->flags != HTP_PATH_UTF8_OVERLONG) { printf("#2 i %i data %x %x flags %x\n", i, (uint8_t) data[0], (uint8_t) data[1], tx->flags); } } for (i = 0; i < 0x800; i++) { memset(data, 0x2f, 10); tx->flags = 0; encode_utf8_3(data, i); htp_utf8_validate_path(tx, path); if (tx->flags != HTP_PATH_UTF8_OVERLONG) { printf("#3 i %x data %x %x %x flags %x\n", i, (uint8_t) data[0], (uint8_t) data[1], (uint8_t) data[2], tx->flags); } } for (i = 0; i < 0x10000; i++) { memset(data, 0x2f, 10); tx->flags = 0; encode_utf8_4(data, i); htp_utf8_validate_path(tx, path); if ((i >= 0xff00) && (i <= 0xffff)) { if (tx->flags != (HTP_PATH_UTF8_OVERLONG | HTP_PATH_FULLWIDTH_EVASION)) { printf("#4 i %x data %x %x %x %x flags %x\n", i, (uint8_t) data[0], (uint8_t) data[1], (uint8_t) data[2], (uint8_t) data[3], tx->flags); } } else { if (tx->flags != HTP_PATH_UTF8_OVERLONG) { printf("#4 i %x data %x %x %x %x flags %x\n", i, (uint8_t) data[0], (uint8_t) data[1], (uint8_t) data[2], (uint8_t) data[3], tx->flags); } } } return (EXIT_SUCCESS); } #define PATH_DECODE_TEST_BEFORE(NAME) \ test_name = NAME; \ tests++; \ expected_status = 0; \ expected_flags = -1; \ success = 0; \ cfg = htp_config_create(); \ tx = htp_tx_create(cfg, 0, NULL); #define PATH_DECODE_TEST_AFTER() \ htp_decode_path_inplace(cfg, tx, input); \ htp_utf8_decode_path_inplace(cfg, tx, input); \ if (bstr_cmp(input, expected) == 0) success = 1; \ printf("[%2i] %s: %s\n", tests, (success == 1 ? "SUCCESS" : "FAILURE"), test_name); \ if ((success == 0)||((expected_status != 0)&&(expected_status != tx->response_status_expected_number))) { \ char *s1 = bstr_tocstr(input); \ char *s2 = bstr_tocstr(expected); \ printf(" Output: [%s]\n", s1); \ printf(" Expected: [%s]\n", s2); \ if (expected_status != 0) { \ printf(" Expected status %i; got %i\n", expected_status, tx->response_status_expected_number); \ } \ if (expected_flags != -1) { \ printf(" Expected flags 0x%x; got 0x%x\n", expected_flags, tx->flags); \ } \ free(s2); \ free(s1); \ failures++; \ } \ htp_tx_destroy(tx); \ htp_config_destroy(cfg); \ bstr_free(expected); \ bstr_free(input); int main_path_tests(int argc, char** argv) { htp_cfg_t *cfg = NULL; htp_tx_t *tx = NULL; bstr *input = NULL; bstr *expected = NULL; int success = 0; int tests = 0; int failures = 0; int expected_status = 0; int expected_flags = 0; char *test_name = NULL; PATH_DECODE_TEST_BEFORE("URL-decoding"); input = bstr_cstrdup("/%64est"); expected = bstr_cstrdup("/dest"); PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid URL-encoded, preserve %"); input = bstr_cstrdup("/%xxest"); expected = bstr_cstrdup("/%xxest"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid URL-encoded, remove %"); input = bstr_cstrdup("/%xxest"); expected = bstr_cstrdup("/xxest"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_invalid_encoding_handling = URL_DECODER_REMOVE_PERCENT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid URL-encoded (end of string, test 1), preserve %"); input = bstr_cstrdup("/test/%2"); expected = bstr_cstrdup("/test/%2"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid URL-encoded (end of string, test 2), preserve %"); input = bstr_cstrdup("/test/%"); expected = bstr_cstrdup("/test/%"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid URL-encoded, preserve % and 400"); input = bstr_cstrdup("/%xxest"); expected = bstr_cstrdup("/%xxest"); expected_status = 400; expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("%u decoding (expected not to decode; 400)"); input = bstr_cstrdup("/%u0064"); expected = bstr_cstrdup("/%u0064"); expected_flags = HTP_PATH_INVALID_ENCODING; expected_status = 400; cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("%u decoding (decode; 400)"); input = bstr_cstrdup("/%u0064"); expected = bstr_cstrdup("/d"); expected_status = 400; expected_flags = HTP_PATH_OVERLONG_U; cfg->path_decode_u_encoding = STATUS_400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("%u decoding (also overlong)"); input = bstr_cstrdup("/%u0064"); expected = bstr_cstrdup("/d"); expected_flags = HTP_PATH_OVERLONG_U; cfg->path_decode_u_encoding = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid %u decoding, leave; preserve percent"); input = bstr_cstrdup("/%uXXXX---"); expected = bstr_cstrdup("/%uXXXX---"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_decode_u_encoding = YES; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid %u decoding, decode invalid; preserve percent"); input = bstr_cstrdup("/%uXXXX---"); expected = bstr_cstrdup("/?---"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_decode_u_encoding = YES; cfg->path_invalid_encoding_handling = URL_DECODER_DECODE_INVALID; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid %u decoding, decode invalid; preserve percent; 400"); input = bstr_cstrdup("/%uXXXX---"); expected = bstr_cstrdup("/?---"); expected_flags = HTP_PATH_INVALID_ENCODING; expected_status = 400; cfg->path_decode_u_encoding = YES; cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid %u decoding (not enough data 1), preserve percent"); input = bstr_cstrdup("/%u123"); expected = bstr_cstrdup("/%u123"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_decode_u_encoding = YES; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid %u decoding (not enough data 2), preserve percent"); input = bstr_cstrdup("/%u12"); expected = bstr_cstrdup("/%u12"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_decode_u_encoding = YES; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid %u decoding (not enough data 3), preserve percent"); input = bstr_cstrdup("/%u1"); expected = bstr_cstrdup("/%u1"); expected_flags = HTP_PATH_INVALID_ENCODING; cfg->path_decode_u_encoding = YES; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("%u decoding, best-fit mapping"); input = bstr_cstrdup("/%u0107"); expected = bstr_cstrdup("/c"); cfg->path_decode_u_encoding = YES; cfg->path_unicode_mapping = BESTFIT; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("%u decoding, 404 to UCS-2 characters"); input = bstr_cstrdup("/%u0107"); expected = bstr_cstrdup("/c"); expected_status = 404; cfg->path_decode_u_encoding = YES; cfg->path_unicode_mapping = STATUS_404; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Forward slash (URL-encoded), not expect to decode"); input = bstr_cstrdup("/one%2ftwo"); expected = bstr_cstrdup("/one%2ftwo"); PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Forward slash (URL-encoded), expect to decode"); input = bstr_cstrdup("/one%2ftwo"); expected = bstr_cstrdup("/one/two"); cfg->path_decode_separators = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Forward slash (URL-encoded), expect not do decode and 404"); input = bstr_cstrdup("/one%2ftwo"); expected = bstr_cstrdup("/one%2ftwo"); expected_status = 404; cfg->path_decode_separators = STATUS_404; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Forward slash (%u-encoded), expect to decode"); input = bstr_cstrdup("/one%u002ftwo"); expected = bstr_cstrdup("/one/two"); cfg->path_decode_separators = YES; cfg->path_decode_u_encoding = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Forward slash (%u-encoded, fullwidth), expect to decode"); input = bstr_cstrdup("/one%uff0ftwo"); expected = bstr_cstrdup("/one/two"); cfg->path_decode_separators = YES; cfg->path_decode_u_encoding = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Backslash (URL-encoded), not a separator; expect to decode"); input = bstr_cstrdup("/one%5ctwo"); expected = bstr_cstrdup("/one\\two"); cfg->path_decode_separators = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Backslash (URL-encoded), as path segment separator"); input = bstr_cstrdup("/one%5ctwo"); expected = bstr_cstrdup("/one/two"); cfg->path_decode_separators = YES; cfg->path_backslash_separators = 1; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Backslash (not encoded), as path segment separator"); input = bstr_cstrdup("/one\\two"); expected = bstr_cstrdup("/one/two"); cfg->path_backslash_separators = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Backslash (%u-encoded), as path segment separator"); input = bstr_cstrdup("/one%u005ctwo"); expected = bstr_cstrdup("/one/two"); cfg->path_decode_separators = YES; cfg->path_backslash_separators = YES; cfg->path_decode_u_encoding = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Backslash (%u-encoded, fullwidth), as path segment separator"); input = bstr_cstrdup("/one%uff3ctwo"); expected = bstr_cstrdup("/one/two"); cfg->path_decode_separators = YES; cfg->path_backslash_separators = 1; cfg->path_decode_u_encoding = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid UTF-8 encoding, encoded"); input = bstr_cstrdup("/%f7test"); expected = bstr_cstrdup("/\xf7test"); PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Invalid UTF-8 encoding, encoded (400)"); input = bstr_cstrdup("/%f7test"); expected = bstr_cstrdup("/\xf7test"); expected_status = 400; expected_flags = HTP_PATH_UTF8_INVALID; cfg->path_invalid_utf8_handling = STATUS_400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (raw) in path; leave"); input = bstr_memdup("/test\0text", 10); expected = bstr_memdup("/test\0text", 10); PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (raw) in path; terminate path"); input = bstr_memdup("/test\0text", 10); expected = bstr_cstrdup("/test"); cfg->path_nul_raw_handling = TERMINATE; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (raw) in path; 400"); input = bstr_memdup("/test\0text", 10); expected = bstr_memdup("/test\0text", 10); cfg->path_nul_raw_handling = STATUS_400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (URL-encoded) in path; leave"); input = bstr_cstrdup("/test%00text"); expected = bstr_memdup("/test\0text", 10); PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (URL-encoded) in path; terminate path"); input = bstr_cstrdup("/test%00text"); expected = bstr_cstrdup("/test"); cfg->path_nul_encoded_handling = TERMINATE; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (URL-encoded) in path; 400"); input = bstr_cstrdup("/test%00text"); expected = bstr_memdup("/test\0text", 10); cfg->path_nul_encoded_handling = STATUS_400; expected_status = 400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (URL-encoded) in path; 404"); input = bstr_cstrdup("/test%00text"); expected = bstr_memdup("/test\0text", 10); cfg->path_nul_encoded_handling = STATUS_404; expected_status = 404; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (%u-encoded) in path; terminate path"); input = bstr_cstrdup("/test%00text"); expected = bstr_cstrdup("/test"); cfg->path_nul_encoded_handling = TERMINATE; cfg->path_decode_u_encoding = YES; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (%u-encoded) in path; 400"); input = bstr_cstrdup("/test%00text"); expected = bstr_memdup("/test\0text", 10); cfg->path_nul_encoded_handling = STATUS_400; cfg->path_decode_u_encoding = YES; expected_status = 400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("NUL byte (%u-encoded) in path; 404"); input = bstr_cstrdup("/test%00text"); expected = bstr_memdup("/test\0text", 10); cfg->path_nul_encoded_handling = STATUS_404; cfg->path_decode_u_encoding = YES; expected_status = 404; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Control char in path, encoded (no effect)"); input = bstr_cstrdup("/%01test"); expected = bstr_cstrdup("/\x01test"); cfg->path_control_char_handling = NONE; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Control char in path, raw (no effect)"); input = bstr_cstrdup("/\x01test"); expected = bstr_cstrdup("/\x01test"); cfg->path_control_char_handling = NONE; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Control char in path, encoded (400)"); input = bstr_cstrdup("/%01test"); expected = bstr_cstrdup("/\x01test"); expected_status = 400; cfg->path_control_char_handling = STATUS_400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("Control char in path, raw (400)"); input = bstr_cstrdup("/\x01test"); expected = bstr_cstrdup("/\x01test"); expected_status = 400; cfg->path_control_char_handling = STATUS_400; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("UTF-8; overlong 2-byte sequence"); input = bstr_cstrdup("/%c1%b4est"); expected = bstr_cstrdup("/test"); expected_flags = HTP_PATH_UTF8_OVERLONG; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("UTF-8; overlong 3-byte sequence"); input = bstr_cstrdup("/%e0%81%b4est"); expected = bstr_cstrdup("/test"); expected_flags = HTP_PATH_UTF8_OVERLONG; PATH_DECODE_TEST_AFTER(); PATH_DECODE_TEST_BEFORE("UTF-8; overlong 4-byte sequence"); input = bstr_cstrdup("/%f0%80%81%b4est"); expected = bstr_cstrdup("/test"); expected_flags = HTP_PATH_UTF8_OVERLONG; PATH_DECODE_TEST_AFTER(); printf("\n"); printf("Total tests: %i, %i failure(s).\n", tests, failures); return (EXIT_SUCCESS); } suricata-1.4.7/libhtp/test/Makefile.in0000644000000000000000000004217712253546170014553 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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@ check_PROGRAMS = main$(EXEEXT) subdir = test DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am_main_OBJECTS = main.$(OBJEXT) test.$(OBJEXT) test-tcpick.$(OBJEXT) main_OBJECTS = $(am_main_OBJECTS) main_LDADD = $(LDADD) main_DEPENDENCIES = ../htp/.libs/libhtp.a AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(main_SOURCES) DIST_SOURCES = $(main_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENERIC_API_VERSION = @GENERIC_API_VERSION@ GENERIC_LIBRARY_NAME = @GENERIC_LIBRARY_NAME@ GENERIC_LIBRARY_VERSION = @GENERIC_LIBRARY_VERSION@ GENERIC_RELEASE = @GENERIC_RELEASE@ GENERIC_VERSION = @GENERIC_VERSION@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ main_SOURCES = main.c test.c test.h test-tcpick.c LDADD = ../htp/.libs/libhtp.a -lz AM_CFLAGS = -g -O2 all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list main$(EXEEXT): $(main_OBJECTS) $(main_DEPENDENCIES) $(EXTRA_main_DEPENDENCIES) @rm -f main$(EXEEXT) $(AM_V_CCLD)$(LINK) $(main_OBJECTS) $(main_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-tcpick.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-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 maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am #check: all # ./main # 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: suricata-1.4.7/libhtp/test/Makefile.am0000644000000000000000000000023312253546156014531 00000000000000 check_PROGRAMS = main main_SOURCES = main.c test.c test.h test-tcpick.c LDADD = ../htp/.libs/libhtp.a -lz AM_CFLAGS = -g -O2 #check: all # ./main suricata-1.4.7/libhtp/test/test-tcpick.c0000644000000000000000000002216612253546156015104 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include #include #include #include #include "../htp/htp.h" #define CLIENT 1 #define SERVER 2 static int parse_filename(const char *filename, char **remote_addr, char **local_addr) { char *copy = strdup(filename); char *p, *saveptr; char *start = copy; char *q = strrchr(copy, '/'); if (q != NULL) start = q; q = strrchr(start, '\\'); if (q != NULL) start = q; int count = 0; p = strtok_r(start, "_", &saveptr); while (p != NULL) { count++; // printf("%i %s\n", count, p); switch (count) { case 3: *remote_addr = strdup(p); break; case 4: *local_addr = strdup(p); break; } p = strtok_r(NULL, "_", &saveptr); } free(copy); return 0; } static int parse_chunk_info(char *buf, size_t *response_offset, size_t *response_len) { char *p = buf; size_t lastlen; while ((*p != ']') && (p != '\0')) p++; if (*p == '\0') return -1; p++; while (isspace(*p)) p++; *response_offset = bstr_util_memtoip(p, strlen(p), 10, &lastlen); p += lastlen; while ((*p != '(') && (p != '\0')) p++; if (*p == '\0') return -1; p++; *response_len = bstr_util_memtoip(p, strlen(p), 10, &lastlen); return 1; } static int tcpick_run_file(const char *filename, htp_cfg_t *cfg, htp_connp_t **connp) { struct timeval tv; char buf[1025]; int first = -1, current = -1; char *remote_addr, *local_addr; char *request_last_chunk = NULL; char *response_last_chunk = NULL; size_t request_offset, request_len; size_t request_last_offset = 0, request_last_len = 0; size_t response_offset, response_len; size_t response_last_offset = 0, response_last_len = 0; if (parse_filename(filename, &remote_addr, &local_addr) < 0) { printf("Failed to parse filename: %s\n", filename); return -1; } FILE *f = fopen(filename, "rb"); if (f == NULL) { printf("Unable to open file: %s\n", filename); return -1; } gettimeofday(&tv, NULL); // Create parser *connp = htp_connp_create(cfg); // Find all chunks and feed them to the parser while (fgets(buf, 1024, f) != NULL) { // Ignore empty lines if (buf[0] == LF) { continue; } if (strncmp(buf, "[server", 7) == 0) { current = SERVER; } else { current = CLIENT; } if (first == -1) { first = current; if (first == SERVER) { htp_connp_open(*connp, local_addr, 80, remote_addr, 80, tv.tv_usec); } else { htp_connp_open(*connp, remote_addr, 80, local_addr, 80, tv.tv_usec); } } int len = 0; if (first == current) { if (parse_chunk_info(buf, &request_offset, &request_len) < 0) { printf("Invalid line: %s", buf); fclose(f); htp_connp_destroy_all(*connp); *connp = NULL; return -1; } len = request_len; // printf("# Request offset %i len %i\n", request_offset, request_len); } else { if (parse_chunk_info(buf, &response_offset, &response_len) < 0) { printf("Invalid line: %s", buf); fclose(f); htp_connp_destroy_all(*connp); *connp = NULL; return -1; } len = response_len; // printf("# Response offset %i len %i\n", response_offset, response_len); } // printf("Len: %i\n", len); if (len <= 0) { printf("Invalid length: %i\n", len); fclose(f); htp_connp_destroy_all(*connp); *connp = NULL; return -1; } char *data = malloc(len); if (data == NULL) { printf("Failed to allocate %i bytes\n", len); fclose(f); htp_connp_destroy_all(*connp); *connp = NULL; return -1; } int read = fread(data, 1, len, f); if (read != len) { // printf("Failed to read %i bytes (got %i)\n", len, read); fclose(f); htp_connp_destroy_all(*connp); *connp = NULL; return -1; } if (first == current) { if ((request_last_chunk == NULL) || (request_len != request_last_len) || (memcmp(data, request_last_chunk, request_len) != 0)) { // printf("# Parse request data: %i byte(s)\n", len); if (htp_connp_req_data(*connp, tv.tv_usec, data, len) == HTP_ERROR) { fclose(f); return -1; } } request_last_offset = request_offset; request_last_len = request_len; if (request_last_chunk != NULL) { free(request_last_chunk); } request_last_chunk = data; } else { if ((response_last_chunk == NULL) || (response_len != response_last_len) || (memcmp(data, response_last_chunk, response_len) != 0)) { // printf("# Parse response data: %i byte(s)\n", len); if (htp_connp_res_data(*connp, tv.tv_usec, data, len) == HTP_ERROR) { fclose(f); return -1; } } response_last_offset = response_offset; response_last_len = response_len; if (response_last_chunk != NULL) { free(response_last_chunk); } response_last_chunk = data; } } fclose(f); htp_connp_close(*connp, tv.tv_usec); return 1; } static void print_tx(htp_connp_t *connp, htp_tx_t *tx) { char *request_line = bstr_tocstr(tx->request_line); htp_header_t *h_user_agent = table_getc(tx->request_headers, "user-agent"); htp_header_t *h_referer = table_getc(tx->request_headers, "referer"); char *referer, *user_agent; char buf[256]; time_t t = time(NULL); struct tm *tmp = localtime(&t); strftime(buf, 255, "%d/%b/%Y:%T %z", tmp); if (h_user_agent == NULL) user_agent = strdup("-"); else { user_agent = bstr_tocstr(h_user_agent->value); } if (h_referer == NULL) referer = strdup("-"); else { referer = bstr_tocstr(h_referer->value); } printf("%s - - [%s] \"%s\" %i %i \"%s\" \"%s\"\n", connp->conn->remote_addr, buf, request_line, tx->response_status_number, tx->response_message_len, referer, user_agent); free(referer); free(user_agent); free(request_line); } static int run_file(char *filename, htp_cfg_t *cfg) { htp_connp_t *connp; fprintf(stdout, "Running file %s", filename); int rc = tcpick_run_file(filename, cfg, &connp); if (rc < 0) { if (connp != NULL) { htp_log_t *last_error = htp_connp_get_last_error(connp); if (last_error != NULL) { printf(" -- failed: %s\n", last_error->msg); } else { printf(" -- failed: ERROR NOT AVAILABLE\n"); } return 0; } else { return -1; } } else { printf(" -- %i transaction(s)\n", list_size(connp->conn->transactions)); htp_tx_t *tx = NULL; list_iterator_reset(connp->conn->transactions); while ((tx = list_iterator_next(connp->conn->transactions)) != NULL) { printf(" "); print_tx(connp, tx); } printf("\n"); htp_connp_destroy_all(connp); return 1; } } static int run_directory(char *dirname, htp_cfg_t *cfg) { struct dirent *entry; char buf[1025]; DIR *d = opendir(dirname); if (d == NULL) { printf("Failed to open directory: %s\n", dirname); return -1; } while ((entry = readdir(d)) != NULL) { if (strncmp(entry->d_name, "tcpick", 6) == 0) { strncpy(buf, dirname, 1024); strncat(buf, "/", 1024 - strlen(buf)); strncat(buf, entry->d_name, 1024 - strlen(buf)); // fprintf(stderr, "Filename: %s\n", buf); run_file(buf, cfg); //if (run_file(buf, cfg) <= 0) { // closedir(d); // return 0; //} } } closedir(d); return 1; } int main_xxx(int argc, char** argv) { htp_cfg_t *cfg = htp_config_create(); //run_file("c:/http_traces/run1//tcpick_000015_192.168.1.67_66.249.80.118_www.both.dat", cfg); run_directory("c:/http_traces/run1/", cfg); return 0; } suricata-1.4.7/libhtp/COPYING0000644000000000000000000000101212253546156012545 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */suricata-1.4.7/libhtp/README0000644000000000000000000001037712253546156012410 00000000000000 LibHTP (http://www.libhtp.org) Copyright 2009,2010 Ivan Ristic ====================================================== LibHTP is a security-aware parser for the HTTP protocol and the related bits and pieces. The goals of the project, in the order of importance, are as follows: 1. Completeness of coverage; LibHTP must be able to parse virtually all traffic that is found in practice. 2. Permissive parsing; LibHTP must never fail to parse a stream that would be parsed by some other web server. 3. Awareness of evasion techniques; LibHTP must be able to detect and effectively deal with various evasion techniques, producing, where practical, identical or practically identical results as the web server processing the same traffic stream. 4. Performance; The performance must be adequate for the desired tasks. Completeness and security are often detremental to performance. Our idea of handling the conflicting requirements is to put the library user in control, allowing him to choose the most desired library characteristic. | IMPORTANT LIBHTP IS NOT YET CONSIDERED STABLE. USE AT YOUR OWN RISK. DO NOT | USE IN PRODUCTION. WORK IS CURRENTLY UNDER WAY TO ENSURE THAT | LIBHTP IS SECURE AND THAT IT PERFORMS WELL. | STATUS LIBHTP IS VERY YOUNG AT THIS POINT. IT WILL BE SOME TIME BEFORE | IT CAN BE CONSIDER COMPLETE. AT THE MOMENT, THE FOCUS OF DEVELOPMENT | IS ON ACHIEVING THE FIRST TWO GOALS. LibHTP is an open source product, released under terms of the General Public Licence version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text of the license. In addition, there is a special exception that allows LibHTP to be freely used with any OSI-approved open source licence. Please refer to the file LIBHTP_LICENSING_EXCEPTION for the full text of the exception. INSTALLATION ------------ The installation process should be as simple as: $ ./configure $ make # make install | NOTE If you already have an early 0.2.x version installed, you must | uninstall it before proceeding. Initially /usr was used for the | installation, but /usr/local is used now. If you forgot to uninstall, | clean all traces of LibHTP from /usr/lib/libhtp* and /usr/include/htp/*. If you want to use a repository version of LibHTP, do the following: 1. Use svn export to retrieve the sources of the version you wish to use 2. Run ./update_version, which will update htp.c with the latest Subversion revision used 3. You may wish to also update htp.pc.in and configure.ac with the correct version 4. Run autoconf -i --force, which will prepare the library for installation 5. Run doxygen to generate the API documentation 6. Continue to install as described above DOCUMENTATION ------------- The best documentation at this time is the code itself and the Doxygen output (which should be all right). There's also a quick start guide in the doc/ folder, which should give you enough information to get going. NO WARRANTY ----------- 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. 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. suricata-1.4.7/libhtp/ltmain.sh0000644000000000000000000105204412253546165013346 00000000000000 # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.3ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.2 Debian-2.4.2-1.3ubuntu1" TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 suricata-1.4.7/libhtp/config.h.in0000644000000000000000000000310212253546170013533 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `z' library (-lz). */ #undef HAVE_LIBZ /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* 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 home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS suricata-1.4.7/libhtp/htp/0000755000000000000000000000000012253546203012364 500000000000000suricata-1.4.7/libhtp/htp/hooks.h0000644000000000000000000000237012253546156013611 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #ifndef _HOOKS_H #define _HOOKS_H #include "dslib.h" #ifdef _HTP_H #define HOOK_ERROR HTP_ERROR #define HOOK_OK HTP_OK #define HOOK_DECLINED HTP_DECLINED #else #define HOOK_ERROR -1 #define HOOK_OK 0 #define HOOK_DECLINED 1 #endif typedef struct htp_hook_t htp_hook_t; typedef struct htp_callback_t htp_callback_t; struct htp_hook_t { list_t *callbacks; }; struct htp_callback_t { int (*fn)(); }; int hook_register(htp_hook_t **hook, int (*callback_fn)()); int hook_run_one(htp_hook_t *hook, void *data); int hook_run_all(htp_hook_t *hook, void *data); htp_hook_t *hook_create(); htp_hook_t *hook_copy(htp_hook_t *hook); void hook_destroy(htp_hook_t *hook); #endif /* _HOOKS_H */ suricata-1.4.7/libhtp/htp/htp_request_generic.c0000644000000000000000000002105212253546156016516 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION fo the full text of the exception. * */ #include "htp.h" /** * Extract one request header. A header can span multiple lines, in * which case they will be folded into one before parsing is attempted. * * @param connp * @return HTP_OK or HTP_ERROR */ int htp_process_request_header_generic(htp_connp_t *connp) { bstr *tempstr = NULL; unsigned char *data = NULL; size_t len = 0; // Create new header structure htp_header_t *h = calloc(1, sizeof (htp_header_t)); if (h == NULL) { // TODO return HTP_ERROR; } // Ensure we have the necessary header data in a single buffer if (connp->in_header_line_index + 1 == connp->in_header_line_counter) { // Single line htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, connp->in_header_line_index); if (hl == NULL) { // Internal error // TODO free(h); return HTP_ERROR; } data = (unsigned char *)bstr_ptr(hl->line); if (data == NULL) { free(h); return HTP_ERROR; } len = bstr_len(hl->line); hl->header = h; } else { // Multiple lines (folded) int i = 0; for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); len += bstr_len(hl->line); } tempstr = bstr_alloc(len); if (tempstr == NULL) { // TODO free(h); return HTP_ERROR; } for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); char *data = bstr_ptr(hl->line); size_t len = bstr_len(hl->line); htp_chomp((unsigned char *)data, &len); bstr_add_mem_noex(tempstr, data, len); hl->header = h; } data = (unsigned char *)bstr_ptr(tempstr); } // Now try to oparse the header if (htp_parse_request_header_generic(connp, h, data, len) != HTP_OK) { if (tempstr != NULL) { free(tempstr); } free(h); return HTP_ERROR; } // Do we already have a header with the same name? htp_header_t *h_existing = table_get(connp->in_tx->request_headers, h->name); if (h_existing != NULL) { // TODO Do we want to keep a list of the headers that are // allowed to be combined in this way? // Add to existing header h_existing->value = bstr_expand(h_existing->value, bstr_len(h_existing->value) + 2 + bstr_len(h->value)); bstr_add_mem_noex(h_existing->value, ", ", 2); bstr_add_str_noex(h_existing->value, h->value); // The header is no longer needed free(h->name); free(h->value); free(h); // Keep track of same-name headers h_existing->flags |= HTP_FIELD_REPEATED; } else { // Add as a new header table_add(connp->in_tx->request_headers, h->name, h); } if (tempstr != NULL) { free(tempstr); } return HTP_OK; } /** * Generic request header parser. * * @param connp * @param h * @param data * @param len * @return HTP_OK or HTP_ERROR */ int htp_parse_request_header_generic(htp_connp_t *connp, htp_header_t *h, unsigned char *data, size_t len) { size_t name_start, name_end; size_t value_start, value_end; htp_chomp(data, &len); name_start = 0; // Look for the colon size_t colon_pos = 0; while ((colon_pos < len) && (data[colon_pos] != ':')) colon_pos++; if (colon_pos == len) { // Missing colon h->flags |= HTP_FIELD_UNPARSEABLE; if (!(connp->in_tx->flags & HTP_FIELD_UNPARSEABLE)) { connp->in_tx->flags |= HTP_FIELD_UNPARSEABLE; // Only log once per transaction htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request field invalid: colon missing"); } return HTP_ERROR; } if (colon_pos == 0) { // Empty header name h->flags |= HTP_FIELD_INVALID; if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { connp->in_tx->flags |= HTP_FIELD_INVALID; // Only log once per transaction htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field invalid: empty name"); } } name_end = colon_pos; // Ignore LWS after field-name size_t prev = name_end - 1; while ((prev > name_start) && (htp_is_lws(data[prev]))) { prev--; name_end--; h->flags |= HTP_FIELD_INVALID; if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { connp->in_tx->flags |= HTP_FIELD_INVALID; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field invalid: LWS after name"); } } // Value value_start = colon_pos; // Go over the colon if (value_start < len) { value_start++; } // Ignore LWS before field-content while ((value_start < len) && (htp_is_lws(data[value_start]))) { value_start++; } // Look for the end of field-content value_end = value_start; while (value_end < len) value_end++; // Ignore LWS after field-content prev = value_end - 1; while ((prev > value_start) && (htp_is_lws(data[prev]))) { prev--; value_end--; } // Check that the header name is a token size_t i = name_start; while (i < name_end) { if (!htp_is_token(data[i])) { h->flags |= HTP_FIELD_INVALID; if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { connp->in_tx->flags |= HTP_FIELD_INVALID; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request header name is not a token"); } break; } i++; } // Now extract the name and the value h->name = bstr_memdup((char *)data + name_start, name_end - name_start); if (h->name == NULL) { return HTP_ERROR; } h->value = bstr_memdup((char *)data + value_start, value_end - value_start); if (h->name == NULL) { return HTP_ERROR; } return HTP_OK; } /** * Generic request line parser. * * @param connp * @return HTP_OK or HTP_ERROR */ int htp_parse_request_line_generic(htp_connp_t *connp) { htp_tx_t *tx = connp->in_tx; unsigned char *data = (unsigned char *)bstr_ptr(tx->request_line); size_t len = bstr_len(tx->request_line); size_t pos = 0; // The request method starts at the beginning of the // line and ends with the first whitespace character. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } // No, we don't care if the method is empty. tx->request_method = bstr_memdup((char *)data, pos); if (tx->request_method == NULL) { return HTP_ERROR; } tx->request_method_number = htp_convert_method_to_number(tx->request_method); // Ignore whitespace after request method. The RFC allows // for only one SP, but then suggests any number of SP and HT // should be permitted. while ((pos < len) && (isspace(data[pos]))) { pos++; } size_t start = pos; // The URI ends with the first whitespace. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } tx->request_uri = bstr_memdup((char *)data + start, pos - start); if (tx->request_uri == NULL) { return HTP_ERROR; } // Ignore whitespace after URI while ((pos < len) && (htp_is_space(data[pos]))) { pos++; } // Is there protocol information available? if (pos == len) { // No, this looks like a HTTP/0.9 request. tx->protocol_is_simple = 1; return HTP_OK; } // The protocol information spreads until the end of the line. tx->request_protocol = bstr_memdup((char *)data + pos, len - pos); if (tx->request_protocol == NULL) { return HTP_ERROR; } tx->request_protocol_number = htp_parse_protocol(tx->request_protocol); return HTP_OK; } suricata-1.4.7/libhtp/htp/htp_request_apache_2_2.c0000644000000000000000000002430512253546156016771 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" /** * Extract one request header. A header can span multiple lines, in * which case they will be folded into one before parsing is attempted. * * @param connp * @return HTP_OK or HTP_ERROR */ int htp_process_request_header_apache_2_2(htp_connp_t *connp) { bstr *tempstr = NULL; unsigned char *data = NULL; size_t len = 0; // Create new header structure htp_header_t *h = calloc(1, sizeof (htp_header_t)); if (h == NULL) return HTP_ERROR; // Ensure we have the necessary header data in a single buffer if (connp->in_header_line_index + 1 == connp->in_header_line_counter) { // Single line htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, connp->in_header_line_index); if (hl == NULL) { // Internal error htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process request header (Apache 2.2): Internal error"); free(h); return HTP_ERROR; } data = (unsigned char *) bstr_ptr(hl->line); len = bstr_len(hl->line); hl->header = h; } else { // Multiple lines (folded) int i = 0; for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); if (hl == NULL) { // Internal error htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process request header (Apache 2.2): Internal error"); free(h); return HTP_ERROR; } len += bstr_len(hl->line); } tempstr = bstr_alloc(len); if (tempstr == NULL) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process request header (Apache 2.2): Failed to allocate bstring of %d bytes", len); free(h); return HTP_ERROR; } for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); if (hl == NULL) { // Internal error htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process request header (Apache 2.2): Internal error"); bstr_free(tempstr); free(h); return HTP_ERROR; } char *data = bstr_ptr(hl->line); size_t len = bstr_len(hl->line); htp_chomp((unsigned char *)data, &len); bstr_add_mem_noex(tempstr, data, len); hl->header = h; } data = (unsigned char *) bstr_ptr(tempstr); } // Now try to parse the header if (htp_parse_request_header_apache_2_2(connp, h, data, len) != HTP_OK) { // Note: downstream responsible for error logging if (tempstr != NULL) { free(tempstr); } free(h); return HTP_ERROR; } // Do we already have a header with the same name? htp_header_t *h_existing = table_get(connp->in_tx->request_headers, h->name); if (h_existing != NULL) { // TODO Do we want to keep a list of the headers that are // allowed to be combined in this way? // Add to existing header h_existing->value = bstr_expand(h_existing->value, bstr_len(h_existing->value) + 2 + bstr_len(h->value)); bstr_add_mem_noex(h_existing->value, ", ", 2); bstr_add_str_noex(h_existing->value, h->value); // The header is no longer needed if (h->name != NULL) free(h->name); if (h->value != NULL) free(h->value); free(h); // Keep track of same-name headers h_existing->flags |= HTP_FIELD_REPEATED; } else { // Add as a new header table_add(connp->in_tx->request_headers, h->name, h); } if (tempstr != NULL) { free(tempstr); } return HTP_OK; } /** * Parses a message header line as Apache 2.2 does. * * @param connp * @param h * @param data * @param len * @return HTP_OK or HTP_ERROR */ int htp_parse_request_header_apache_2_2(htp_connp_t *connp, htp_header_t *h, unsigned char *data, size_t len) { size_t name_start, name_end; size_t value_start, value_end; htp_chomp(data, &len); name_start = 0; // Look for the colon size_t colon_pos = 0; while ((colon_pos < len) && (data[colon_pos] != '\0') && (data[colon_pos] != ':')) colon_pos++; if ((colon_pos == len) || (data[colon_pos] == '\0')) { // Missing colon h->flags |= HTP_FIELD_UNPARSEABLE; if (!(connp->in_tx->flags & HTP_FIELD_UNPARSEABLE)) { connp->in_tx->flags |= HTP_FIELD_UNPARSEABLE; // Only log once per transaction htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request field invalid: colon missing"); } return HTP_ERROR; } if (colon_pos == 0) { // Empty header name h->flags |= HTP_FIELD_INVALID; if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { connp->in_tx->flags |= HTP_FIELD_INVALID; // Only log once per transaction htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field invalid: empty name"); } } name_end = colon_pos; // Ignore LWS after field-name size_t prev = name_end - 1; while ((prev > name_start) && (htp_is_lws(data[prev]))) { prev--; name_end--; h->flags |= HTP_FIELD_INVALID; if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { connp->in_tx->flags |= HTP_FIELD_INVALID; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field invalid: LWS after name"); } } // Value value_start = colon_pos; // Go over the colon if (value_start < len) { value_start++; } // Ignore LWS before field-content while ((value_start < len) && (htp_is_lws(data[value_start]))) { value_start++; } // Look for the end of field-content value_end = value_start; while ((value_end < len) && (data[value_end] != '\0')) value_end++; // Ignore LWS after field-content prev = value_end - 1; while ((prev > value_start) && (htp_is_lws(data[prev]))) { prev--; value_end--; } // Check that the header name is a token size_t i = name_start; while (i < name_end) { if (!htp_is_token(data[i])) { h->flags |= HTP_FIELD_INVALID; if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { connp->in_tx->flags |= HTP_FIELD_INVALID; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request header name is not a token"); } break; } i++; } // Now extract the name and the value h->name = bstr_memdup((char *) data + name_start, name_end - name_start); if (h->name == NULL) return HTP_ERROR; h->value = bstr_memdup((char *) data + value_start, value_end - value_start); if (h->value == NULL) { bstr_free(h->name); return HTP_ERROR; } return HTP_OK; } /** * Parse request line as Apache 2.2 does. * * @param connp * @return HTP_OK or HTP_ERROR */ int htp_parse_request_line_apache_2_2(htp_connp_t *connp) { htp_tx_t *tx = connp->in_tx; unsigned char *data = (unsigned char *) bstr_ptr(tx->request_line); size_t len = bstr_len(tx->request_line); size_t pos = 0; // In this implementation we assume the // line ends with the first NUL byte. if (tx->request_line_nul_offset != -1) { len = tx->request_line_nul_offset - 1; } // The request method starts at the beginning of the // line and ends with the first whitespace character. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } // No, we don't care if the method is empty. tx->request_method = bstr_memdup((char *) data, pos); if (tx->request_method == NULL) { return HTP_ERROR; } #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); #endif tx->request_method_number = htp_convert_method_to_number(tx->request_method); // Ignore whitespace after request method. The RFC allows // for only one SP, but then suggests any number of SP and HT // should be permitted. Apache uses isspace(), which is even // more permitting, so that's what we use here. while ((pos < len) && (isspace(data[pos]))) { pos++; } size_t start = pos; // The URI ends with the first whitespace. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } tx->request_uri = bstr_memdup((char *) data + start, pos - start); if (tx->request_uri == NULL) { return HTP_ERROR; } #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); #endif // Ignore whitespace after URI while ((pos < len) && (htp_is_space(data[pos]))) { pos++; } // Is there protocol information available? if (pos == len) { // No, this looks like a HTTP/0.9 request. tx->protocol_is_simple = 1; return HTP_OK; } // The protocol information spreads until the end of the line. tx->request_protocol = bstr_memdup((char *) data + pos, len - pos); if (tx->request_protocol == NULL) return HTP_ERROR; tx->request_protocol_number = htp_parse_protocol(tx->request_protocol); #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); #endif return HTP_OK; } suricata-1.4.7/libhtp/htp/hooks.c0000644000000000000000000001173412253546156013610 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "hooks.h" /** * Creates a new hook. * * @return New htp_hook_t structure on success, NULL on failure */ htp_hook_t *hook_create() { htp_hook_t *hook = calloc(1, sizeof (htp_hook_t)); if (hook == NULL) return NULL; hook->callbacks = list_array_create(4); if (hook->callbacks == NULL) { free(hook); return NULL; } return hook; } /** * Creates a copy of the provided hook. The hook is allowed to be NULL, * in which case this function simply returns a NULL. * * @param hook * @return A copy of the hook, or NULL (if the provided hook was NULL * or, if it wasn't, if there was a memory allocation problem while * constructing a copy). */ htp_hook_t * hook_copy(htp_hook_t *hook) { if (hook == NULL) return NULL; htp_hook_t *copy = hook_create(); if (copy == NULL) return NULL; htp_callback_t *callback = NULL; list_iterator_reset(hook->callbacks); while ((callback = list_iterator_next(hook->callbacks)) != NULL) { if (hook_register(©, callback->fn) < 0) { hook_destroy(copy); return NULL; } } return copy; } /** * Destroys an existing hook. It is all right to send a NULL * to this method because it will simply return straight away. * * @param hook */ void hook_destroy(htp_hook_t *hook) { if (hook == NULL) return; htp_callback_t *callback = NULL; list_iterator_reset(hook->callbacks); while ((callback = list_iterator_next(hook->callbacks)) != NULL) { free(callback); } list_destroy(hook->callbacks); free(hook); } /** * Registers a new callback with the hook. * * @param hook * @param callback_fn * @return 1 on success, -1 on memory allocation error */ int hook_register(htp_hook_t **hook, int (*callback_fn)()) { int hook_created = 0; htp_callback_t *callback = calloc(1, sizeof (htp_callback_t)); if (callback == NULL) return -1; callback->fn = callback_fn; // Create a new hook if one does not exist if (*hook == NULL) { *hook = hook_create(); if (*hook == NULL) { free(callback); return -1; } hook_created = 1; } // Add callback if (list_add((*hook)->callbacks, callback) < 0) { if (hook_created) { free(*hook); } free(callback); return -1; } return 1; } /** * Runs all the callbacks associated with a given hook. Only stops if * one of the callbacks returns an error (HOOK_ERROR). * * @param hook * @param data * @return HOOK_OK or HOOK_ERROR */ int hook_run_all(htp_hook_t *hook, void *data) { if (hook == NULL) { return HOOK_OK; } /* HACK https://redmine.openinfosecfoundation.org/issues/601 */ size_t i = 0; for (i = 0; i < ((list_array_t *)hook->callbacks)->current_size; i++) { void *r = ((list_array_t *)hook->callbacks)->elements[i]; if (r == NULL) continue; htp_callback_t *callback = r; if (callback->fn(data) == HOOK_ERROR) { return HOOK_ERROR; } } #if 0 htp_callback_t *callback = NULL; list_iterator_reset(hook->callbacks); while ((callback = list_iterator_next(hook->callbacks)) != NULL) { if (callback->fn(data) == HOOK_ERROR) { return HOOK_ERROR; } } #endif return HOOK_OK; } /** * Run callbacks until one of them accepts to service the hook. * * @param hook * @param data * @return HOOK_OK on success, HOOK_DECLINED if no callback wanted to run and HOOK_ERROR on error. */ int hook_run_one(htp_hook_t *hook, void *data) { if (hook == NULL) { return HOOK_DECLINED; } /* HACK https://redmine.openinfosecfoundation.org/issues/601 */ size_t i = 0; for (i = 0; i < ((list_array_t *)hook->callbacks)->current_size; i++) { void *r = ((list_array_t *)hook->callbacks)->elements[i]; if (r == NULL) continue; htp_callback_t *callback = r; int status = callback->fn(data); if (status != HOOK_DECLINED) { return status; } } #if 0 htp_callback_t *callback = NULL; list_iterator_reset(hook->callbacks); while ((callback = list_iterator_next(hook->callbacks)) != NULL) { int status = callback->fn(data); // Both HOOK_OK and HOOK_ERROR will stop hook processing if (status != HOOK_DECLINED) { return status; } } #endif return HOOK_DECLINED; } suricata-1.4.7/libhtp/htp/htp.c0000644000000000000000000000124612253546156013255 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include #include "htp.h" /** * Returns the library version. */ const char *htp_get_version() { return HTP_BASE_VERSION_TEXT; } suricata-1.4.7/libhtp/htp/htp_config.c0000644000000000000000000010366112253546156014606 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" /** * This map is used by default for best-fit mapping from the Unicode * values U+0100-FFFF. */ static unsigned char bestfit_1252[] = { 0x01, 0x00, 0x41, 0x01, 0x01, 0x61, 0x01, 0x02, 0x41, 0x01, 0x03, 0x61, 0x01, 0x04, 0x41, 0x01, 0x05, 0x61, 0x01, 0x06, 0x43, 0x01, 0x07, 0x63, 0x01, 0x08, 0x43, 0x01, 0x09, 0x63, 0x01, 0x0a, 0x43, 0x01, 0x0b, 0x63, 0x01, 0x0c, 0x43, 0x01, 0x0d, 0x63, 0x01, 0x0e, 0x44, 0x01, 0x0f, 0x64, 0x01, 0x11, 0x64, 0x01, 0x12, 0x45, 0x01, 0x13, 0x65, 0x01, 0x14, 0x45, 0x01, 0x15, 0x65, 0x01, 0x16, 0x45, 0x01, 0x17, 0x65, 0x01, 0x18, 0x45, 0x01, 0x19, 0x65, 0x01, 0x1a, 0x45, 0x01, 0x1b, 0x65, 0x01, 0x1c, 0x47, 0x01, 0x1d, 0x67, 0x01, 0x1e, 0x47, 0x01, 0x1f, 0x67, 0x01, 0x20, 0x47, 0x01, 0x21, 0x67, 0x01, 0x22, 0x47, 0x01, 0x23, 0x67, 0x01, 0x24, 0x48, 0x01, 0x25, 0x68, 0x01, 0x26, 0x48, 0x01, 0x27, 0x68, 0x01, 0x28, 0x49, 0x01, 0x29, 0x69, 0x01, 0x2a, 0x49, 0x01, 0x2b, 0x69, 0x01, 0x2c, 0x49, 0x01, 0x2d, 0x69, 0x01, 0x2e, 0x49, 0x01, 0x2f, 0x69, 0x01, 0x30, 0x49, 0x01, 0x31, 0x69, 0x01, 0x34, 0x4a, 0x01, 0x35, 0x6a, 0x01, 0x36, 0x4b, 0x01, 0x37, 0x6b, 0x01, 0x39, 0x4c, 0x01, 0x3a, 0x6c, 0x01, 0x3b, 0x4c, 0x01, 0x3c, 0x6c, 0x01, 0x3d, 0x4c, 0x01, 0x3e, 0x6c, 0x01, 0x41, 0x4c, 0x01, 0x42, 0x6c, 0x01, 0x43, 0x4e, 0x01, 0x44, 0x6e, 0x01, 0x45, 0x4e, 0x01, 0x46, 0x6e, 0x01, 0x47, 0x4e, 0x01, 0x48, 0x6e, 0x01, 0x4c, 0x4f, 0x01, 0x4d, 0x6f, 0x01, 0x4e, 0x4f, 0x01, 0x4f, 0x6f, 0x01, 0x50, 0x4f, 0x01, 0x51, 0x6f, 0x01, 0x54, 0x52, 0x01, 0x55, 0x72, 0x01, 0x56, 0x52, 0x01, 0x57, 0x72, 0x01, 0x58, 0x52, 0x01, 0x59, 0x72, 0x01, 0x5a, 0x53, 0x01, 0x5b, 0x73, 0x01, 0x5c, 0x53, 0x01, 0x5d, 0x73, 0x01, 0x5e, 0x53, 0x01, 0x5f, 0x73, 0x01, 0x62, 0x54, 0x01, 0x63, 0x74, 0x01, 0x64, 0x54, 0x01, 0x65, 0x74, 0x01, 0x66, 0x54, 0x01, 0x67, 0x74, 0x01, 0x68, 0x55, 0x01, 0x69, 0x75, 0x01, 0x6a, 0x55, 0x01, 0x6b, 0x75, 0x01, 0x6c, 0x55, 0x01, 0x6d, 0x75, 0x01, 0x6e, 0x55, 0x01, 0x6f, 0x75, 0x01, 0x70, 0x55, 0x01, 0x71, 0x75, 0x01, 0x72, 0x55, 0x01, 0x73, 0x75, 0x01, 0x74, 0x57, 0x01, 0x75, 0x77, 0x01, 0x76, 0x59, 0x01, 0x77, 0x79, 0x01, 0x79, 0x5a, 0x01, 0x7b, 0x5a, 0x01, 0x7c, 0x7a, 0x01, 0x80, 0x62, 0x01, 0x97, 0x49, 0x01, 0x9a, 0x6c, 0x01, 0x9f, 0x4f, 0x01, 0xa0, 0x4f, 0x01, 0xa1, 0x6f, 0x01, 0xab, 0x74, 0x01, 0xae, 0x54, 0x01, 0xaf, 0x55, 0x01, 0xb0, 0x75, 0x01, 0xb6, 0x7a, 0x01, 0xc0, 0x7c, 0x01, 0xc3, 0x21, 0x01, 0xcd, 0x41, 0x01, 0xce, 0x61, 0x01, 0xcf, 0x49, 0x01, 0xd0, 0x69, 0x01, 0xd1, 0x4f, 0x01, 0xd2, 0x6f, 0x01, 0xd3, 0x55, 0x01, 0xd4, 0x75, 0x01, 0xd5, 0x55, 0x01, 0xd6, 0x75, 0x01, 0xd7, 0x55, 0x01, 0xd8, 0x75, 0x01, 0xd9, 0x55, 0x01, 0xda, 0x75, 0x01, 0xdb, 0x55, 0x01, 0xdc, 0x75, 0x01, 0xde, 0x41, 0x01, 0xdf, 0x61, 0x01, 0xe4, 0x47, 0x01, 0xe5, 0x67, 0x01, 0xe6, 0x47, 0x01, 0xe7, 0x67, 0x01, 0xe8, 0x4b, 0x01, 0xe9, 0x6b, 0x01, 0xea, 0x4f, 0x01, 0xeb, 0x6f, 0x01, 0xec, 0x4f, 0x01, 0xed, 0x6f, 0x01, 0xf0, 0x6a, 0x02, 0x61, 0x67, 0x02, 0xb9, 0x27, 0x02, 0xba, 0x22, 0x02, 0xbc, 0x27, 0x02, 0xc4, 0x5e, 0x02, 0xc8, 0x27, 0x02, 0xcb, 0x60, 0x02, 0xcd, 0x5f, 0x03, 0x00, 0x60, 0x03, 0x02, 0x5e, 0x03, 0x03, 0x7e, 0x03, 0x0e, 0x22, 0x03, 0x31, 0x5f, 0x03, 0x32, 0x5f, 0x03, 0x7e, 0x3b, 0x03, 0x93, 0x47, 0x03, 0x98, 0x54, 0x03, 0xa3, 0x53, 0x03, 0xa6, 0x46, 0x03, 0xa9, 0x4f, 0x03, 0xb1, 0x61, 0x03, 0xb4, 0x64, 0x03, 0xb5, 0x65, 0x03, 0xc0, 0x70, 0x03, 0xc3, 0x73, 0x03, 0xc4, 0x74, 0x03, 0xc6, 0x66, 0x04, 0xbb, 0x68, 0x05, 0x89, 0x3a, 0x06, 0x6a, 0x25, 0x20, 0x00, 0x20, 0x20, 0x01, 0x20, 0x20, 0x02, 0x20, 0x20, 0x03, 0x20, 0x20, 0x04, 0x20, 0x20, 0x05, 0x20, 0x20, 0x06, 0x20, 0x20, 0x10, 0x2d, 0x20, 0x11, 0x2d, 0x20, 0x17, 0x3d, 0x20, 0x32, 0x27, 0x20, 0x35, 0x60, 0x20, 0x44, 0x2f, 0x20, 0x74, 0x34, 0x20, 0x75, 0x35, 0x20, 0x76, 0x36, 0x20, 0x77, 0x37, 0x20, 0x78, 0x38, 0x20, 0x7f, 0x6e, 0x20, 0x80, 0x30, 0x20, 0x81, 0x31, 0x20, 0x82, 0x32, 0x20, 0x83, 0x33, 0x20, 0x84, 0x34, 0x20, 0x85, 0x35, 0x20, 0x86, 0x36, 0x20, 0x87, 0x37, 0x20, 0x88, 0x38, 0x20, 0x89, 0x39, 0x20, 0xa7, 0x50, 0x21, 0x02, 0x43, 0x21, 0x07, 0x45, 0x21, 0x0a, 0x67, 0x21, 0x0b, 0x48, 0x21, 0x0c, 0x48, 0x21, 0x0d, 0x48, 0x21, 0x0e, 0x68, 0x21, 0x10, 0x49, 0x21, 0x11, 0x49, 0x21, 0x12, 0x4c, 0x21, 0x13, 0x6c, 0x21, 0x15, 0x4e, 0x21, 0x18, 0x50, 0x21, 0x19, 0x50, 0x21, 0x1a, 0x51, 0x21, 0x1b, 0x52, 0x21, 0x1c, 0x52, 0x21, 0x1d, 0x52, 0x21, 0x24, 0x5a, 0x21, 0x28, 0x5a, 0x21, 0x2a, 0x4b, 0x21, 0x2c, 0x42, 0x21, 0x2d, 0x43, 0x21, 0x2e, 0x65, 0x21, 0x2f, 0x65, 0x21, 0x30, 0x45, 0x21, 0x31, 0x46, 0x21, 0x33, 0x4d, 0x21, 0x34, 0x6f, 0x22, 0x12, 0x2d, 0x22, 0x15, 0x2f, 0x22, 0x16, 0x5c, 0x22, 0x17, 0x2a, 0x22, 0x1a, 0x76, 0x22, 0x1e, 0x38, 0x22, 0x23, 0x7c, 0x22, 0x29, 0x6e, 0x22, 0x36, 0x3a, 0x22, 0x3c, 0x7e, 0x22, 0x61, 0x3d, 0x22, 0x64, 0x3d, 0x22, 0x65, 0x3d, 0x23, 0x03, 0x5e, 0x23, 0x20, 0x28, 0x23, 0x21, 0x29, 0x23, 0x29, 0x3c, 0x23, 0x2a, 0x3e, 0x25, 0x00, 0x2d, 0x25, 0x0c, 0x2b, 0x25, 0x10, 0x2b, 0x25, 0x14, 0x2b, 0x25, 0x18, 0x2b, 0x25, 0x1c, 0x2b, 0x25, 0x2c, 0x2d, 0x25, 0x34, 0x2d, 0x25, 0x3c, 0x2b, 0x25, 0x50, 0x2d, 0x25, 0x52, 0x2b, 0x25, 0x53, 0x2b, 0x25, 0x54, 0x2b, 0x25, 0x55, 0x2b, 0x25, 0x56, 0x2b, 0x25, 0x57, 0x2b, 0x25, 0x58, 0x2b, 0x25, 0x59, 0x2b, 0x25, 0x5a, 0x2b, 0x25, 0x5b, 0x2b, 0x25, 0x5c, 0x2b, 0x25, 0x5d, 0x2b, 0x25, 0x64, 0x2d, 0x25, 0x65, 0x2d, 0x25, 0x66, 0x2d, 0x25, 0x67, 0x2d, 0x25, 0x68, 0x2d, 0x25, 0x69, 0x2d, 0x25, 0x6a, 0x2b, 0x25, 0x6b, 0x2b, 0x25, 0x6c, 0x2b, 0x25, 0x84, 0x5f, 0x27, 0x58, 0x7c, 0x30, 0x00, 0x20, 0x30, 0x08, 0x3c, 0x30, 0x09, 0x3e, 0x30, 0x1a, 0x5b, 0x30, 0x1b, 0x5d, 0xff, 0x01, 0x21, 0xff, 0x02, 0x22, 0xff, 0x03, 0x23, 0xff, 0x04, 0x24, 0xff, 0x05, 0x25, 0xff, 0x06, 0x26, 0xff, 0x07, 0x27, 0xff, 0x08, 0x28, 0xff, 0x09, 0x29, 0xff, 0x0a, 0x2a, 0xff, 0x0b, 0x2b, 0xff, 0x0c, 0x2c, 0xff, 0x0d, 0x2d, 0xff, 0x0e, 0x2e, 0xff, 0x0f, 0x2f, 0xff, 0x10, 0x30, 0xff, 0x11, 0x31, 0xff, 0x12, 0x32, 0xff, 0x13, 0x33, 0xff, 0x14, 0x34, 0xff, 0x15, 0x35, 0xff, 0x16, 0x36, 0xff, 0x17, 0x37, 0xff, 0x18, 0x38, 0xff, 0x19, 0x39, 0xff, 0x1a, 0x3a, 0xff, 0x1b, 0x3b, 0xff, 0x1c, 0x3c, 0xff, 0x1d, 0x3d, 0xff, 0x1e, 0x3e, 0xff, 0x20, 0x40, 0xff, 0x21, 0x41, 0xff, 0x22, 0x42, 0xff, 0x23, 0x43, 0xff, 0x24, 0x44, 0xff, 0x25, 0x45, 0xff, 0x26, 0x46, 0xff, 0x27, 0x47, 0xff, 0x28, 0x48, 0xff, 0x29, 0x49, 0xff, 0x2a, 0x4a, 0xff, 0x2b, 0x4b, 0xff, 0x2c, 0x4c, 0xff, 0x2d, 0x4d, 0xff, 0x2e, 0x4e, 0xff, 0x2f, 0x4f, 0xff, 0x30, 0x50, 0xff, 0x31, 0x51, 0xff, 0x32, 0x52, 0xff, 0x33, 0x53, 0xff, 0x34, 0x54, 0xff, 0x35, 0x55, 0xff, 0x36, 0x56, 0xff, 0x37, 0x57, 0xff, 0x38, 0x58, 0xff, 0x39, 0x59, 0xff, 0x3a, 0x5a, 0xff, 0x3b, 0x5b, 0xff, 0x3c, 0x5c, 0xff, 0x3d, 0x5d, 0xff, 0x3e, 0x5e, 0xff, 0x3f, 0x5f, 0xff, 0x40, 0x60, 0xff, 0x41, 0x61, 0xff, 0x42, 0x62, 0xff, 0x43, 0x63, 0xff, 0x44, 0x64, 0xff, 0x45, 0x65, 0xff, 0x46, 0x66, 0xff, 0x47, 0x67, 0xff, 0x48, 0x68, 0xff, 0x49, 0x69, 0xff, 0x4a, 0x6a, 0xff, 0x4b, 0x6b, 0xff, 0x4c, 0x6c, 0xff, 0x4d, 0x6d, 0xff, 0x4e, 0x6e, 0xff, 0x4f, 0x6f, 0xff, 0x50, 0x70, 0xff, 0x51, 0x71, 0xff, 0x52, 0x72, 0xff, 0x53, 0x73, 0xff, 0x54, 0x74, 0xff, 0x55, 0x75, 0xff, 0x56, 0x76, 0xff, 0x57, 0x77, 0xff, 0x58, 0x78, 0xff, 0x59, 0x79, 0xff, 0x5a, 0x7a, 0xff, 0x5b, 0x7b, 0xff, 0x5c, 0x7c, 0xff, 0x5d, 0x7d, 0xff, 0x5e, 0x7e, 0x00, 0x00, 0x00 }; /** * Creates a new configuration structure. Configuration structures created at * configuration time must not be changed afterwards in order to support lock-less * copying. * * @return New configuration structure. */ htp_cfg_t *htp_config_create() { htp_cfg_t *cfg = calloc(1, sizeof(htp_cfg_t)); if (cfg == NULL) return NULL; cfg->field_limit_hard = HTP_HEADER_LIMIT_HARD; cfg->field_limit_soft = HTP_HEADER_LIMIT_SOFT; cfg->log_level = HTP_LOG_NOTICE; cfg->path_u_bestfit_map = bestfit_1252; cfg->path_replacement_char = '?'; // No need to create hooks here; they will be created on-demand, // during callback registration // Set the default personality before we return htp_config_set_server_personality(cfg, HTP_SERVER_MINIMAL); return cfg; } /** * Creates a copy of the supplied configuration structure. The idea is to create * one or more configuration objects at configuration-time, but to use this * function to create per-connection copies. That way it will be possible to * adjust per-connection configuration as necessary, without affecting the * global configuration. Make sure no other thread changes the configuration * object while this function is operating. * * @param cfg * @return A copy of the configuration structure. */ htp_cfg_t *htp_config_copy(htp_cfg_t *cfg) { htp_cfg_t *copy = malloc(sizeof(htp_cfg_t)); if (copy == NULL) return NULL; *copy = *cfg; // Create copies of the hooks' structures if (cfg->hook_transaction_start != NULL) { copy->hook_transaction_start = hook_copy(cfg->hook_transaction_start); if (copy->hook_transaction_start == NULL) { free(copy); return NULL; } } if (cfg->hook_request_line != NULL) { copy->hook_request_line = hook_copy(cfg->hook_request_line); if (copy->hook_request_line == NULL) { free(copy); return NULL; } } if (cfg->hook_request_uri_normalize != NULL) { copy->hook_request_uri_normalize = hook_copy(cfg->hook_request_uri_normalize); if (copy->hook_request_uri_normalize == NULL) { free(copy); return NULL; } } if (cfg->hook_request_headers != NULL) { copy->hook_request_headers = hook_copy(cfg->hook_request_headers); if (copy->hook_request_headers == NULL) { free(copy); return NULL; } } if (cfg->hook_request_body_data != NULL) { copy->hook_request_body_data = hook_copy(cfg->hook_request_body_data); if (copy->hook_request_body_data == NULL) { free(copy); return NULL; } } if (cfg->hook_request_trailer != NULL) { copy->hook_request_trailer = hook_copy(cfg->hook_request_trailer); if (copy->hook_request_trailer == NULL) { free(copy); return NULL; } } if (cfg->hook_request != NULL) { copy->hook_request = hook_copy(cfg->hook_request); if (copy->hook_request == NULL) { free(copy); return NULL; } } if (cfg->hook_response_line != NULL) { copy->hook_response_line = hook_copy(cfg->hook_response_line); if (copy->hook_response_line == NULL) { free(copy); return NULL; } } if (cfg->hook_response_headers != NULL) { copy->hook_response_headers = hook_copy(cfg->hook_response_headers); if (copy->hook_response_headers == NULL) { free(copy); return NULL; } } if (cfg->hook_response_body_data != NULL) { copy->hook_response_body_data = hook_copy(cfg->hook_response_body_data); if (copy->hook_response_body_data == NULL) { free(copy); return NULL; } } if (cfg->hook_response_trailer != NULL) { copy->hook_response_trailer = hook_copy(cfg->hook_response_trailer); if (copy->hook_response_trailer == NULL) { free(copy); return NULL; } } if (cfg->hook_response != NULL) { copy->hook_response = hook_copy(cfg->hook_response); if (copy->hook_response == NULL) { free(copy); return NULL; } } if (cfg->hook_log != NULL) { copy->hook_log = hook_copy(cfg->hook_log); if (copy->hook_log == NULL) { free(copy); return NULL; } } return copy; } /** * Destroy a configuration structure. * * @param cfg */ void htp_config_destroy(htp_cfg_t *cfg) { // Destroy the hooks hook_destroy(cfg->hook_transaction_start); hook_destroy(cfg->hook_request_line); hook_destroy(cfg->hook_request_uri_normalize); hook_destroy(cfg->hook_request_headers); hook_destroy(cfg->hook_request_body_data); hook_destroy(cfg->hook_request_trailer); hook_destroy(cfg->hook_request); hook_destroy(cfg->hook_response_line); hook_destroy(cfg->hook_response_headers); hook_destroy(cfg->hook_response_body_data); hook_destroy(cfg->hook_response_trailer); hook_destroy(cfg->hook_response); hook_destroy(cfg->hook_log); // Free the structure itself free(cfg); } /** * Registers a transaction_start callback. * * @param cfg * @param callback_fn */ void htp_config_register_transaction_start(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_transaction_start, callback_fn); } /** * Registers a request_line callback. * * @param cfg * @param callback_fn */ void htp_config_register_request_line(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_request_line, callback_fn); } /** * Registers a request_uri_normalize callback. * * @param cfg * @param callback_fn */ void htp_config_register_request_uri_normalize(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_request_uri_normalize, callback_fn); } /** * Registers a request_headers callback. * * @param cfg * @param callback_fn */ void htp_config_register_request_headers(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_request_headers, callback_fn); } /** * Registers a request_trailer callback. * * @param cfg * @param callback_fn */ void htp_config_register_request_trailer(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_request_trailer, callback_fn); } /** * Registers a request_body_data callback. * * @param cfg * @param callback_fn */ void htp_config_register_request_body_data(htp_cfg_t *cfg, int (*callback_fn)(htp_tx_data_t *)) { hook_register(&cfg->hook_request_body_data, callback_fn); } /** * Registers a request callback. * * @param cfg * @param callback_fn */ void htp_config_register_request(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_request, callback_fn); } /** * Registers a request_line callback. * * @param cfg * @param callback_fn */ void htp_config_register_response_line(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_response_line, callback_fn); } /** * Registers a request_headers callback. * * @param cfg * @param callback_fn */ void htp_config_register_response_headers(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_response_headers, callback_fn); } /** * Registers a request_trailer callback. * * @param cfg * @param callback_fn */ void htp_config_register_response_trailer(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_response_trailer, callback_fn); } /** * Registers a request_body_data callback. * * @param cfg * @param callback_fn */ void htp_config_register_response_body_data(htp_cfg_t *cfg, int (*callback_fn)(htp_tx_data_t *)) { hook_register(&cfg->hook_response_body_data, callback_fn); } /** * Registers a request callback. * * @param cfg * @param callback_fn */ void htp_config_register_response(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { hook_register(&cfg->hook_response, callback_fn); } /** * Registers a callback that is invoked every time there is a log message. * * @param cfg * @param callback_fn */ void htp_config_register_log(htp_cfg_t *cfg, int (*callback_fn)(htp_log_t *)) { hook_register(&cfg->hook_log, callback_fn); } /** * Update the best-fit map, which is used to convert UCS-2 characters into * single-byte characters. By default a Windows 1252 best-fit map is used. The map * is an list of triplets, the first 2 bytes being an UCS-2 character to map from, * and the third byte being the single byte to map to. Make sure that your map contains * the mappings to cover the fullwidth form characters (U+FF00-FFEF). * * @param cfg * @param map */ void htp_config_set_bestfit_map(htp_cfg_t *cfg, unsigned char *map) { cfg->path_u_bestfit_map = map; } /** * Whether to generate the request_uri_normalized field. * * @param cfg * @param generate */ void htp_config_set_generate_request_uri_normalized(htp_cfg_t *cfg, int generate) { cfg->generate_request_uri_normalized = generate; } /** * Configures whether backslash characters are treated as path segment separators. They * are not on Unix systems, but are on Windows systems. If this setting is enabled, a path * such as "/one\two/three" will be converted to "/one/two/three". * * @param cfg * @param backslash_separators */ void htp_config_set_path_backslash_separators(htp_cfg_t *cfg, int backslash_separators) { cfg->path_backslash_separators = backslash_separators; } /** * Configures whether backslash characters are treated as query segment separators. They * are not on Unix systems, but are on Windows systems. If this setting is enabled, a query * such as "/one\two/three" will be converted to "/one/two/three". * * @param cfg * @param backslash_separators */ void htp_config_set_query_backslash_separators(htp_cfg_t *cfg, int backslash_separators) { cfg->query_backslash_separators = backslash_separators; } /** * Configures filesystem sensitivity. This setting affects * how URL paths are normalized. There are no path modifications by default, but * on a case-insensitive systems path will be converted to lowercase. * * @param cfg * @param case_insensitive */ void htp_config_set_path_case_insensitive(htp_cfg_t *cfg, int case_insensitive) { cfg->path_case_insensitive = case_insensitive; } /** * Configures filesystem sensitivity. This setting affects * how URL querys are normalized. There are no query modifications by default, but * on a case-insensitive systems query will be converted to lowercase. * * @param cfg * @param case_insensitive */ void htp_config_set_query_case_insensitive(htp_cfg_t *cfg, int case_insensitive) { cfg->query_case_insensitive = case_insensitive; } /** * Configures whether consecutive path segment separators will be compressed. When * enabled, a path such as "/one//two" will be normalized to "/one/two". The backslash_separators * and decode_separators parameters are used before compression takes place. For example, if * backshasl_deparators and decode_separators are both enabled, the path "/one\\/two\/%5cthree/%2f//four" * will be converted to "/one/two/three/four". * * @param cfg * @param compress_separators */ void htp_config_set_path_compress_separators(htp_cfg_t *cfg, int compress_separators) { cfg->path_compress_separators = compress_separators; } /** * Configures whether consecutive query segment separators will be compressed. When * enabled, a query such as "/one//two" will be normalized to "/one/two". The backslash_separators * and decode_separators parameters are used before compression takes place. For example, if * backshasl_deparators and decode_separators are both enabled, the query "/one\\/two\/%5cthree/%2f//four" * will be converted to "/one/two/three/four". * * @param cfg * @param compress_separators */ void htp_config_set_query_compress_separators(htp_cfg_t *cfg, int compress_separators) { cfg->query_compress_separators = compress_separators; } /** * This parameter is used to predict how a server will react when control * characters are present in a request path, but does not affect path * normalization. * * @param cfg * @param control_char_handling Use NONE with servers that ignore control characters in * request path, and STATUS_400 with servers that respond * with 400. */ void htp_config_set_path_control_char_handling(htp_cfg_t *cfg, int control_char_handling) { cfg->path_control_char_handling = control_char_handling; } /** * This parameter is used to predict how a server will react when control * characters are present in a request query, but does not affect query * normalization. * * @param cfg * @param control_char_handling Use NONE with servers that ignore control characters in * request query, and STATUS_400 with servers that respond * with 400. */ void htp_config_set_query_control_char_handling(htp_cfg_t *cfg, int control_char_handling) { cfg->query_control_char_handling = control_char_handling; } /** * Controls the UTF-8 treatment of request paths. One option is to only validate * path as UTF-8. In this case, the UTF-8 flags will be raised as appropriate, and * the path will remain in UTF-8 (if it was UTF-8in the first place). The other option * is to convert a UTF-8 path into a single byte stream using best-fit mapping. * * @param cfg * @param convert_utf8 */ void htp_config_set_path_convert_utf8(htp_cfg_t *cfg, int convert_utf8) { cfg->path_convert_utf8 = convert_utf8; } /** * Configures whether encoded path segment separators will be decoded. Apache does * not do this, but IIS does. If enabled, a path such as "/one%2ftwo" will be normalized * to "/one/two". If the backslash_separators option is also enabled, encoded backslash * characters will be converted too (and subseqently normalized to forward slashes). * * @param cfg * @param decode_separators */ void htp_config_set_path_decode_separators(htp_cfg_t *cfg, int decode_separators) { cfg->path_decode_separators = decode_separators; } /** * Configures whether encoded query segment separators will be decoded. Apache does * not do this, but IIS does. If enabled, a query such as "/one%2ftwo" will be normalized * to "/one/two". If the backslash_separators option is also enabled, encoded backslash * characters will be converted too (and subseqently normalized to forward slashes). * * @param cfg * @param decode_separators */ void htp_config_set_query_decode_separators(htp_cfg_t *cfg, int decode_separators) { cfg->query_decode_separators = decode_separators; } /** * Configures whether %u-encoded sequences in path will be decoded. Such sequences * will be treated as invalid URL encoding if decoding is not desireable. * * @param cfg * @param decode_u_encoding */ void htp_config_set_path_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding) { cfg->path_decode_u_encoding = decode_u_encoding; } /** * Configures whether %u-encoded sequences in query will be decoded. Such sequences * will be treated as invalid URL encoding if decoding is not desireable. * * @param cfg * @param decode_u_encoding */ void htp_config_set_query_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding) { cfg->query_decode_u_encoding = decode_u_encoding; } /** * Configures how server reacts to invalid encoding in path. * * @param cfg * @param invalid_encoding_handling The available options are: URL_DECODER_PRESERVE_PERCENT, * URL_DECODER_REMOVE_PERCENT, URL_DECODER_DECODE_INVALID * and URL_DECODER_STATUS_400. */ void htp_config_set_path_invalid_encoding_handling(htp_cfg_t *cfg, int invalid_encoding_handling) { cfg->path_invalid_encoding_handling = invalid_encoding_handling; } /** * Configures how server reacts to invalid encoding in query. * * @param cfg * @param invalid_encoding_handling The available options are: URL_DECODER_PRESERVE_PERCENT, * URL_DECODER_REMOVE_PERCENT, URL_DECODER_DECODE_INVALID * and URL_DECODER_STATUS_400. */ void htp_config_set_query_invalid_encoding_handling(htp_cfg_t *cfg, int invalid_encoding_handling) { cfg->query_invalid_encoding_handling = invalid_encoding_handling; } /** * Configures how server reacts to invalid UTF-8 characters in path. This setting will * not affect path normalization; it only controls what response status we expect for * a request that contains invalid UTF-8 characters. * * @param cfg * @param invalid_utf8_handling Possible values: NONE or STATUS_400. */ void htp_config_set_path_invalid_utf8_handling(htp_cfg_t *cfg, int invalid_utf8_handling) { cfg->path_invalid_utf8_handling = invalid_utf8_handling; } /** * Configures how server reacts to encoded NUL bytes. Some servers will terminate * path at NUL, while some will respond with 400 or 404. When the termination option * is not used, the NUL byte will remain in the path. * * @param cfg * @param nul_encoded_handling Possible values: TERMINATE, STATUS_400, STATUS_404 */ void htp_config_set_path_nul_encoded_handling(htp_cfg_t *cfg, int nul_encoded_handling) { cfg->path_nul_encoded_handling = nul_encoded_handling; } /** * Configures how server reacts to encoded NUL bytes. Some servers will terminate * query at NUL, while some will respond with 400 or 404. When the termination option * is not used, the NUL byte will remain in the query. * * @param cfg * @param nul_encoded_handling Possible values: TERMINATE, STATUS_400, STATUS_404 */ void htp_config_set_query_nul_encoded_handling(htp_cfg_t *cfg, int nul_encoded_handling) { cfg->query_nul_encoded_handling = nul_encoded_handling; } /** * Configures how server reacts to raw NUL bytes. Some servers will terminate * path at NUL, while some will respond with 400 or 404. When the termination option * is not used, the NUL byte will remain in the path. * * @param cfg * @param nul_raw_handling Possible values: TERMINATE, STATUS_400, STATUS_404 */ void htp_config_set_path_nul_raw_handling(htp_cfg_t *cfg, int nul_raw_handling) { cfg->path_nul_raw_handling = nul_raw_handling; } /** * Configures how server reacts to raw NUL bytes. Some servers will terminate * query at NUL, while some will respond with 400 or 404. When the termination option * is not used, the NUL byte will remain in the query. * * @param cfg * @param nul_raw_handling Possible values: TERMINATE, STATUS_400, STATUS_404 */ void htp_config_set_query_nul_raw_handling(htp_cfg_t *cfg, int nul_raw_handling) { cfg->query_nul_raw_handling = nul_raw_handling; } /** * Sets the replacement characater that will be used to in the lossy best-fit * mapping from Unicode characters into single-byte streams. The question mark * is the default replacement character. * * @param cfg * @param replacement_char */ void htp_config_set_path_replacement_char(htp_cfg_t *cfg, int replacement_char) { cfg->path_replacement_char = replacement_char; } /** * Controls what the library does when it encounters an Unicode character where * only a single-byte would do (e.g., the %u-encoded characters). Conversion always * takes place; this parameter is used to correctly predict the status code used * in response. In the future there will probably be an option to convert such * characters to UCS-2 or UTF-8. * * @param cfg * @param unicode_mapping Possible values: BESTFIT, STATUS_400, STATUS_404. */ void htp_config_set_path_unicode_mapping(htp_cfg_t *cfg, int unicode_mapping) { cfg->path_unicode_mapping = unicode_mapping; } /** * Controls how server reacts to overlong UTF-8 characters. * XXX Not used at the moment. * * @param cfg * @param utf8_overlong_handling */ void htp_config_set_path_utf8_overlong_handling(htp_cfg_t *cfg, int utf8_overlong_handling) { cfg->path_utf8_overlong_handling = utf8_overlong_handling; } /** * Configure desired server personality. * * @param cfg * @param personality * @return HTP_OK if the personality is supported, HTP_ERROR if it isn't. */ int htp_config_set_server_personality(htp_cfg_t *cfg, int personality) { switch (personality) { case HTP_SERVER_MINIMAL: cfg->parse_request_line = htp_parse_request_line_generic; cfg->process_request_header = htp_process_request_header_generic; cfg->parse_response_line = htp_parse_response_line_generic; cfg->process_response_header = htp_process_response_header_generic; break; case HTP_SERVER_GENERIC: cfg->parse_request_line = htp_parse_request_line_generic; cfg->process_request_header = htp_process_request_header_generic; cfg->parse_response_line = htp_parse_response_line_generic; cfg->process_response_header = htp_process_response_header_generic; cfg->path_backslash_separators = YES; cfg->path_decode_separators = YES; cfg->path_compress_separators = YES; // cfg->query_backslash_separators = YES; cfg->query_decode_separators = YES; // cfg->query_compress_separators = YES; break; case HTP_SERVER_IDS: cfg->parse_request_line = htp_parse_request_line_generic; cfg->process_request_header = htp_process_request_header_generic; cfg->parse_response_line = htp_parse_response_line_generic; cfg->process_response_header = htp_process_response_header_generic; cfg->path_backslash_separators = YES; cfg->path_case_insensitive = YES; cfg->path_decode_separators = YES; cfg->path_compress_separators = YES; cfg->path_decode_u_encoding = YES; cfg->path_unicode_mapping = BESTFIT; cfg->path_convert_utf8 = YES; // cfg->query_backslash_separators = YES; cfg->query_case_insensitive = YES; cfg->query_decode_separators = YES; // cfg->query_compress_separators = YES; cfg->query_decode_u_encoding = YES; break; case HTP_SERVER_APACHE : case HTP_SERVER_APACHE_2_2: cfg->parse_request_line = htp_parse_request_line_apache_2_2; cfg->process_request_header = htp_process_request_header_apache_2_2; cfg->parse_response_line = htp_parse_response_line_generic; cfg->process_response_header = htp_process_response_header_generic; cfg->path_backslash_separators = NO; cfg->path_decode_separators = NO; cfg->path_compress_separators = YES; cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; cfg->path_control_char_handling = NONE; // cfg->query_backslash_separators = NO; cfg->query_decode_separators = NO; // cfg->query_compress_separators = YES; cfg->query_invalid_encoding_handling = URL_DECODER_STATUS_400; cfg->query_control_char_handling = NONE; break; case HTP_SERVER_IIS_5_1: cfg->parse_request_line = htp_parse_request_line_generic; cfg->process_request_header = htp_process_request_header_generic; cfg->parse_response_line = htp_parse_response_line_generic; cfg->process_response_header = htp_process_response_header_generic; cfg->path_backslash_separators = YES; cfg->path_decode_separators = NO; cfg->path_compress_separators = YES; cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; cfg->path_decode_u_encoding = YES; cfg->path_unicode_mapping = BESTFIT; cfg->path_control_char_handling = NONE; // cfg->query_backslash_separators = YES; cfg->query_decode_separators = NO; // cfg->query_compress_separators = YES; cfg->query_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; cfg->query_decode_u_encoding = YES; // cfg->query_unicode_mapping = BESTFIT; cfg->query_control_char_handling = NONE; break; case HTP_SERVER_IIS_6_0: cfg->parse_request_line = htp_parse_request_line_generic; cfg->process_request_header = htp_process_request_header_generic; cfg->parse_response_line = htp_parse_response_line_generic; cfg->process_response_header = htp_process_response_header_generic; cfg->path_backslash_separators = YES; cfg->path_decode_separators = YES; cfg->path_compress_separators = YES; cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; cfg->path_decode_u_encoding = YES; cfg->path_unicode_mapping = STATUS_400; cfg->path_control_char_handling = STATUS_400; // cfg->query_backslash_separators = YES; cfg->query_decode_separators = YES; // cfg->query_compress_separators = YES; cfg->query_invalid_encoding_handling = URL_DECODER_STATUS_400; cfg->query_decode_u_encoding = YES; // cfg->query_unicode_mapping = STATUS_400; cfg->query_control_char_handling = STATUS_400; break; case HTP_SERVER_IIS_7_0: case HTP_SERVER_IIS_7_5: cfg->parse_request_line = htp_parse_request_line_generic; cfg->process_request_header = htp_process_request_header_generic; cfg->parse_response_line = htp_parse_response_line_generic; cfg->process_response_header = htp_process_response_header_generic; cfg->path_backslash_separators = YES; cfg->path_decode_separators = YES; cfg->path_compress_separators = YES; cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; cfg->path_control_char_handling = STATUS_400; // cfg->query_backslash_separators = YES; cfg->query_decode_separators = YES; // cfg->query_compress_separators = YES; cfg->query_invalid_encoding_handling = URL_DECODER_STATUS_400; cfg->query_control_char_handling = STATUS_400; break; default: return HTP_ERROR; } // Remember the personality cfg->spersonality = personality; return HTP_OK; } suricata-1.4.7/libhtp/htp/htp_parsers.c0000644000000000000000000000345012253546156015013 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" /** * Determines protocol number from a textual representation (i.e., "HTTP/1.1"). This * function will only understand a properly formatted protocol information. It does * not try to be flexible. * * @param protocol * @return Protocol version or PROTOCOL_UKNOWN. */ int htp_parse_protocol(bstr *protocol) { if (protocol != NULL && bstr_len(protocol) == 8) { char *ptr = bstr_ptr(protocol); if ((ptr[0] == 'H') && (ptr[1] == 'T') && (ptr[2] == 'T') && (ptr[3] == 'P') && (ptr[4] == '/') && (ptr[6] == '.')) { // Check the version numbers if (ptr[5] == '0') { if (ptr[7] == '9') { return HTTP_0_9; } } else if (ptr[5] == '1') { if (ptr[7] == '0') { return HTTP_1_0; } else if (ptr[7] == '1') { return HTTP_1_1; } } } } return PROTOCOL_UNKNOWN; } /** * Determines the numerical value of a response status given as a string. * * @param status * @return Status code on success, or -1 on error. */ int htp_parse_status(bstr *status) { return htp_parse_positive_integer_whitespace((unsigned char *)bstr_ptr(status), bstr_len(status), 10); } suricata-1.4.7/libhtp/htp/htp_connection.c0000644000000000000000000000672612253546156015504 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" /** * Creates a new connection structure. * * @param connp * @return A new htp_connp_t structure on success, NULL on memory allocation failure. */ htp_conn_t *htp_conn_create(htp_connp_t *connp) { htp_conn_t *conn = calloc(1, sizeof (htp_conn_t)); if (conn == NULL) return NULL; conn->connp = connp; conn->transactions = list_array_create(16); if (conn->transactions == NULL) { free(conn); return NULL; } conn->messages = list_array_create(8); if (conn->messages == NULL) { list_destroy(conn->transactions); free(conn); return NULL; } return conn; } /** * Destroys a connection, as well as all the transactions it contains. It is * not possible to destroy a connection structure yet leave any of its * transactions intact. This is because transactions need its connection and * connection structures hold little data anyway. The opposite is true, though * it is possible to delete a transaction but leave its connection alive. * * @param conn */ void htp_conn_destroy(htp_conn_t *conn) { if (conn == NULL) return; // Destroy individual transactions. Do note that iterating // using the iterator does not work here because some of the // list element may be NULL (and with the iterator it is impossible // to distinguish a NULL element from the end of the list). if (conn->transactions != NULL) { size_t i; for (i = 0; i < list_size(conn->transactions); i++) { htp_tx_t *tx = (htp_tx_t *)list_get(conn->transactions, i); if (tx != NULL) { htp_tx_destroy(tx); } } list_destroy(conn->transactions); } // Destroy individual messages if (conn->messages != NULL) { htp_log_t *l = NULL; list_iterator_reset(conn->messages); while ((l = list_iterator_next(conn->messages)) != NULL) { free((void *)l->msg); free(l); } list_destroy(conn->messages); } if (conn->local_addr != NULL) { free(conn->local_addr); } if (conn->remote_addr != NULL) { free(conn->remote_addr); } // Finally, destroy the connection // structure itself. free(conn); } /** * Removes the given transaction structure, which makes it possible to * safely destroy it. It is safe to destroy transactions in this way * because the index of the transactions (in a connection) is preserved. * * @param conn * @param tx * @return 1 if transaction was removed or 0 if it wasn't found */ int htp_conn_remove_tx(htp_conn_t *conn, htp_tx_t *tx) { if ((tx == NULL)||(conn == NULL)||(conn->transactions == NULL)) return 0; unsigned int i = 0; for (i = 0; i < list_size(conn->transactions); i++) { htp_tx_t *etx = list_get(conn->transactions, i); if (tx == etx) { list_replace(conn->transactions, i, NULL); return 1; } } return 0; } suricata-1.4.7/libhtp/htp/htp.h0000644000000000000000000012010712253546156013260 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #ifndef _HTP_H #define _HTP_H typedef struct htp_cfg_t htp_cfg_t; typedef struct htp_conn_t htp_conn_t; typedef struct htp_connp_t htp_connp_t; typedef struct htp_header_t htp_header_t; typedef struct htp_header_line_t htp_header_line_t; typedef struct htp_log_t htp_log_t; typedef struct htp_tx_data_t htp_tx_data_t; typedef struct htp_tx_t htp_tx_t; typedef struct htp_uri_t htp_uri_t; typedef struct htp_urldecoder_t htp_urldecoder_t; #include #include #include #include #include #include #include #include "bstr.h" #include "dslib.h" #include "hooks.h" #include "htp_decompressors.h" // -- Defines ------------------------------------------------------------------------------------- #define HTP_BASE_VERSION_TEXT "0.2.14" #define HTP_ERROR -1 #define HTP_OK 0 #define HTP_DATA 1 #define HTP_DATA_OTHER 2 #define HTP_DECLINED 3 #define PROTOCOL_UNKNOWN -1 #define HTTP_0_9 9 #define HTTP_1_0 100 #define HTTP_1_1 101 #define COMPRESSION_NONE 0 #define COMPRESSION_GZIP 1 #define COMPRESSION_COMPRESS 2 // Not implemented #define COMPRESSION_DEFLATE 3 // Not implemented #define HTP_LOG_MARK __FILE__,__LINE__ #define HTP_LOG_ERROR 1 #define HTP_LOG_WARNING 2 #define HTP_LOG_NOTICE 3 #define HTP_LOG_INFO 4 #define HTP_LOG_DEBUG 5 #define HTP_LOG_DEBUG2 6 #define HTP_HEADER_MISSING_COLON 1 #define HTP_HEADER_INVALID_NAME 2 #define HTP_HEADER_LWS_AFTER_FIELD_NAME 3 #define HTP_LINE_TOO_LONG_HARD 4 #define HTP_LINE_TOO_LONG_SOFT 5 #define HTP_HEADER_LIMIT_HARD 18000 #define HTP_HEADER_LIMIT_SOFT 9000 #define LOG_NO_CODE 0 #define CR '\r' #define LF '\n' #define M_UNKNOWN -1 // The following request method are defined in Apache 2.2.13, in httpd.h. #define M_GET 0 #define M_PUT 1 #define M_POST 2 #define M_DELETE 3 #define M_CONNECT 4 #define M_OPTIONS 5 #define M_TRACE 6 #define M_PATCH 7 #define M_PROPFIND 8 #define M_PROPPATCH 9 #define M_MKCOL 10 #define M_COPY 11 #define M_MOVE 12 #define M_LOCK 13 #define M_UNLOCK 14 #define M_VERSION_CONTROL 15 #define M_CHECKOUT 16 #define M_UNCHECKOUT 17 #define M_CHECKIN 18 #define M_UPDATE 19 #define M_LABEL 20 #define M_REPORT 21 #define M_MKWORKSPACE 22 #define M_MKACTIVITY 23 #define M_BASELINE_CONTROL 24 #define M_MERGE 25 #define M_INVALID 26 // Interestingly, Apache does not define M_HEAD #define M_HEAD 1000 #define HTP_FIELD_UNPARSEABLE 0x000001 #define HTP_FIELD_INVALID 0x000002 #define HTP_FIELD_FOLDED 0x000004 #define HTP_FIELD_REPEATED 0x000008 #define HTP_FIELD_LONG 0x000010 #define HTP_FIELD_NUL_BYTE 0x000020 #define HTP_REQUEST_SMUGGLING 0x000040 #define HTP_INVALID_FOLDING 0x000080 #define HTP_INVALID_CHUNKING 0x000100 #define HTP_MULTI_PACKET_HEAD 0x000200 #define HTP_HOST_MISSING 0x000400 #define HTP_AMBIGUOUS_HOST 0x000800 #define HTP_PATH_ENCODED_NUL 0x001000 #define HTP_PATH_INVALID_ENCODING 0x002000 #define HTP_PATH_INVALID 0x004000 #define HTP_PATH_OVERLONG_U 0x008000 #define HTP_PATH_ENCODED_SEPARATOR 0x010000 #define HTP_PATH_UTF8_VALID 0x020000 /* At least one valid UTF-8 character and no invalid ones */ #define HTP_PATH_UTF8_INVALID 0x040000 #define HTP_PATH_UTF8_OVERLONG 0x080000 #define HTP_PATH_FULLWIDTH_EVASION 0x100000 /* Range U+FF00 - U+FFFF detected */ #define PIPELINED_CONNECTION 1 #define HTP_SERVER_MINIMAL 0 #define HTP_SERVER_GENERIC 1 #define HTP_SERVER_IDS 2 #define HTP_SERVER_IIS_4_0 4 /* Windows NT 4.0 */ #define HTP_SERVER_IIS_5_0 5 /* Windows 2000 */ #define HTP_SERVER_IIS_5_1 6 /* Windows XP Professional */ #define HTP_SERVER_IIS_6_0 7 /* Windows 2003 */ #define HTP_SERVER_IIS_7_0 8 /* Windows 2008 */ #define HTP_SERVER_IIS_7_5 9 /* Windows 7 */ #define HTP_SERVER_TOMCAT_6_0 10 /* Unused */ #define HTP_SERVER_APACHE 11 #define HTP_SERVER_APACHE_2_2 12 #define NONE 0 #define IDENTITY 1 #define CHUNKED 2 #define TX_PROGRESS_NEW 0 #define TX_PROGRESS_REQ_LINE 1 #define TX_PROGRESS_REQ_HEADERS 2 #define TX_PROGRESS_REQ_BODY 3 #define TX_PROGRESS_REQ_TRAILER 4 #define TX_PROGRESS_WAIT 5 #define TX_PROGRESS_RES_LINE 6 #define TX_PROGRESS_RES_HEADERS 7 #define TX_PROGRESS_RES_BODY 8 #define TX_PROGRESS_RES_TRAILER 9 #define TX_PROGRESS_DONE 10 #define STREAM_STATE_NEW 0 #define STREAM_STATE_OPEN 1 #define STREAM_STATE_CLOSED 2 #define STREAM_STATE_ERROR 3 #define STREAM_STATE_TUNNEL 4 #define STREAM_STATE_DATA_OTHER 5 #define STREAM_STATE_DATA 9 #define URL_DECODER_PRESERVE_PERCENT 0 #define URL_DECODER_REMOVE_PERCENT 1 #define URL_DECODER_DECODE_INVALID 2 #define URL_DECODER_STATUS_400 400 #define NONE 0 #define NO 0 #define BESTFIT 0 #define YES 1 #define TERMINATE 1 #define STATUS_400 400 #define STATUS_404 401 #define IN_TEST_NEXT_BYTE_OR_RETURN(X) \ if ((X)->in_current_offset >= (X)->in_current_len) { \ return HTP_DATA; \ } #define IN_NEXT_BYTE(X) \ if ((X)->in_current_offset < (X)->in_current_len) { \ (X)->in_next_byte = (X)->in_current_data[(X)->in_current_offset]; \ (X)->in_current_offset++; \ (X)->in_stream_offset++; \ } else { \ (X)->in_next_byte = -1; \ } #define IN_NEXT_BYTE_OR_RETURN(X) \ if ((X)->in_current_offset < (X)->in_current_len) { \ (X)->in_next_byte = (X)->in_current_data[(X)->in_current_offset]; \ (X)->in_current_offset++; \ (X)->in_stream_offset++; \ } else { \ return HTP_DATA; \ } #define IN_COPY_BYTE_OR_RETURN(X) \ if ((X)->in_current_offset < (X)->in_current_len) { \ (X)->in_next_byte = (X)->in_current_data[(X)->in_current_offset]; \ (X)->in_current_offset++; \ (X)->in_stream_offset++; \ } else { \ return HTP_DATA; \ } \ \ if ((X)->in_line_len < (X)->in_line_size) { \ (X)->in_line[(X)->in_line_len] = (X)->in_next_byte; \ (X)->in_line_len++; \ if (((X)->in_line_len == HTP_HEADER_LIMIT_SOFT)&&(!((X)->in_tx->flags & HTP_FIELD_LONG))) { \ (X)->in_tx->flags |= HTP_FIELD_LONG; \ htp_log((X), HTP_LOG_MARK, HTP_LOG_ERROR, HTP_LINE_TOO_LONG_SOFT, "Request field over soft limit"); \ } \ } else { \ htp_log((X), HTP_LOG_MARK, HTP_LOG_ERROR, HTP_LINE_TOO_LONG_HARD, "Request field over hard limit"); \ return HTP_ERROR; \ } #define OUT_TEST_NEXT_BYTE_OR_RETURN(X) \ if ((X)->out_current_offset >= (X)->out_current_len) { \ return HTP_DATA; \ } #define OUT_NEXT_BYTE(X) \ if ((X)->out_current_offset < (X)->out_current_len) { \ (X)->out_next_byte = (X)->out_current_data[(X)->out_current_offset]; \ (X)->out_current_offset++; \ (X)->out_stream_offset++; \ } else { \ (X)->out_next_byte = -1; \ } #define OUT_NEXT_BYTE_OR_RETURN(X) \ if ((X)->out_current_offset < (X)->out_current_len) { \ (X)->out_next_byte = (X)->out_current_data[(X)->out_current_offset]; \ (X)->out_current_offset++; \ (X)->out_stream_offset++; \ } else { \ return HTP_DATA; \ } #define OUT_COPY_BYTE_OR_RETURN(X) \ if ((X)->out_current_offset < (X)->out_current_len) { \ (X)->out_next_byte = (X)->out_current_data[(X)->out_current_offset]; \ (X)->out_current_offset++; \ (X)->out_stream_offset++; \ } else { \ return HTP_DATA; \ } \ \ if ((X)->out_line_len < (X)->out_line_size) { \ (X)->out_line[(X)->out_line_len] = (X)->out_next_byte; \ (X)->out_line_len++; \ if (((X)->out_line_len == HTP_HEADER_LIMIT_SOFT)&&(!((X)->out_tx->flags & HTP_FIELD_LONG))) { \ (X)->out_tx->flags |= HTP_FIELD_LONG; \ htp_log((X), HTP_LOG_MARK, HTP_LOG_ERROR, HTP_LINE_TOO_LONG_SOFT, "Response field over soft limit"); \ } \ } else { \ htp_log((X), HTP_LOG_MARK, HTP_LOG_ERROR, HTP_LINE_TOO_LONG_HARD, "Response field over hard limit"); \ return HTP_ERROR; \ } typedef uint32_t htp_time_t; // -- Data structures ----------------------------------------------------------------------------- struct htp_cfg_t { /** Hard field limit length. If the parser encounters a line that's longer * than this value it will give up parsing. Do note that the line limit * is not the same thing as header length limit. Because of header folding, * a header can end up being longer than the line limit. */ size_t field_limit_hard; /** Soft field limit length. If this limit is reached the parser will issue * a warning but continue to run. */ size_t field_limit_soft; /** Log level, which will be used when deciding whether to store or * ignore the messages issued by the parser. */ int log_level; /** * Server personality ID. */ int spersonality; /** The function used for request line parsing. Depends on the personality. */ int (*parse_request_line)(htp_connp_t *connp); /** The function used for response line parsing. Depends on the personality. */ int (*parse_response_line)(htp_connp_t *connp); /** The function used for request header parsing. Depends on the personality. */ int (*process_request_header)(htp_connp_t *connp); /** The function used for response header parsing. Depends on the personality. */ int (*process_response_header)(htp_connp_t *connp); // Path handling /** Should we treat backslash characters as path segment separators? */ int path_backslash_separators; int query_backslash_separators; /** Should we treat paths as case insensitive? */ int path_case_insensitive; int query_case_insensitive; /** Should we compress multiple path segment separators into one? */ int path_compress_separators; int query_compress_separators; /** This parameter is used to predict how a server will react when control * characters are present in a request path, but does not affect path * normalization. */ int path_control_char_handling; int query_control_char_handling; /** Should the parser convert UTF-8 into a single-byte stream, using * best-fit? */ int path_convert_utf8; /** Should we URL-decode encoded path segment separators? */ int path_decode_separators; int query_decode_separators; /** Should we decode %u-encoded characters? */ int path_decode_u_encoding; int query_decode_u_encoding; /** How do handle invalid encodings: URL_DECODER_LEAVE_PERCENT, * URL_DECODER_REMOVE_PERCENT or URL_DECODER_DECODE_INVALID. */ int path_invalid_encoding_handling; int query_invalid_encoding_handling; /** Controls how invalid UTF-8 characters are handled. */ int path_invalid_utf8_handling; /** Controls how encoded NUL bytes are handled. */ int path_nul_encoded_handling; int query_nul_encoded_handling; /** Controls how raw NUL bytes are handled. */ int path_nul_raw_handling; int query_nul_raw_handling; /** The replacement character used when there is no best-fit mapping. */ unsigned char path_replacement_char; /** How will the server handle UCS-2 characters? */ int path_unicode_mapping; /** XXX Unused */ int path_utf8_overlong_handling; /** The best-fit map to use to decode %u-encoded characters. */ unsigned char *path_u_bestfit_map; /** Whether to generate the request_uri_normalized field. */ int generate_request_uri_normalized; // Hooks /** Transaction start hook, invoked when the parser receives the first * byte of a new transaction. */ htp_hook_t *hook_transaction_start; /** Request line hook, invoked after a request line has been parsed. */ htp_hook_t *hook_request_line; /** Request URI normalization hook, for overriding default normalization of URI. */ htp_hook_t *hook_request_uri_normalize; /** Request headers hook, invoked after all request headers are seen. */ htp_hook_t *hook_request_headers; /** Request body data hook, invoked every time body data is available. Chunked data * will be dechunked and compressed data will be decompressed (not implemented at present) * before the data is passed to this hook. */ htp_hook_t *hook_request_body_data; /** Request trailer hook, invoked after all trailer headers are seen, * and if they are seen (not invoked otherwise). */ htp_hook_t *hook_request_trailer; /** Request hook, invoked after a complete request is seen. */ htp_hook_t *hook_request; /** Response line hook, invoked after a response line has been parsed. */ htp_hook_t *hook_response_line; /** Response headers book, invoked after all response headers have been seen. */ htp_hook_t *hook_response_headers; /** Response body data hook, invoked whenever a chunk of response data is available. Chunked * data will be dechunked and compressed data will be decompressed (not implemented * at present) before the data is passed to this hook.*/ htp_hook_t *hook_response_body_data; /** Response trailer hook, invoked after all trailer headers have been processed, * and only if the trailer exists. */ htp_hook_t *hook_response_trailer; /** Response hook, invoked after a response has been seen. There isn't a separate * transaction hook, use this hook to do something whenever a transaction is * complete. */ htp_hook_t *hook_response; /** * Log hook, invoked every time the library wants to log. */ htp_hook_t *hook_log; /** Opaque user data associated with this configuration structure. */ void *user_data; }; struct htp_conn_t { /** Connection parser associated with this connection. */ htp_connp_t *connp; /** Remote IP address. */ char *remote_addr; /** Remote port. */ int remote_port; /** Local IP address. */ char *local_addr; /** Local port. */ int local_port; /** Transactions carried out on this connection. The list may contain * NULL elements when some of the transactions are deleted (and then * removed from a connection by calling htp_conn_remove_tx(). */ list_t *transactions; /** Log messages associated with this connection. */ list_t *messages; /** Parsing flags: PIPELINED_CONNECTION. */ unsigned int flags; /** When was this connection opened? */ htp_time_t open_timestamp; /** When was this connection closed? */ htp_time_t close_timestamp; /** Inbound data counter. */ size_t in_data_counter; /** Outbound data counter. */ size_t out_data_counter; /** Inbound packet counter. */ size_t in_packet_counter; /** Outbound packet counter. */ size_t out_packet_counter; }; struct htp_connp_t { // General fields /** Current parser configuration structure. */ htp_cfg_t *cfg; /** Is the configuration structure only used with this connection * parser? If it is, then it can be changed as parsing goes on, * and destroyed along with the parser in the end. */ int is_cfg_private; /** The connection structure associated with this parser. */ htp_conn_t *conn; /** Opaque user data associated with this parser. */ void *user_data; /** On parser failure, this field will contain the error information. Do note, however, * that the value in this field will only be valid immediately after an error condition, * but it is not guaranteed to remain valid if the parser is invoked again. */ htp_log_t *last_error; // Request parser fields /** Parser inbound status. Starts as HTP_OK, but may turn into HTP_ERROR. */ unsigned int in_status; /** Parser output status. Starts as HTP_OK, but may turn into HTP_ERROR. */ unsigned int out_status; /** The time when the last request data chunk was received. */ htp_time_t in_timestamp; /** Pointer to the current request data chunk. */ unsigned char *in_current_data; /** The length of the current request data chunk. */ int64_t in_current_len; /** The offset of the next byte in the request data chunk to consume. */ int64_t in_current_offset; /** How many data chunks does the inbound connection stream consist of? */ size_t in_chunk_count; /** The index of the first chunk used in the current request. */ size_t in_chunk_request_index; /** The offset, in the entire connection stream, of the next request byte. */ int64_t in_stream_offset; /** The value of the request byte currently being processed. */ int in_next_byte; /** Pointer to the request line buffer. */ unsigned char *in_line; /** Size of the request line buffer. */ size_t in_line_size; /** Lenght of the current request line. */ size_t in_line_len; /** Ongoing inbound transaction. */ htp_tx_t *in_tx; /** The request header line currently being processed. */ htp_header_line_t *in_header_line; /** The index, in the structure holding all request header lines, of the * line with which the current header begins. The header lines are * kept in the transaction structure. */ int in_header_line_index; /** How many lines are there in the current request header? */ int in_header_line_counter; /** * The request body length declared in a valid request headers. The key here * is "valid". This field will not be populated if a request contains both * a Transfer-Encoding header and a Content-Lenght header. */ int64_t in_content_length; /** Holds the remaining request body length that we expect to read. This * field will be available only when the length of a request body is known * in advance, i.e. when request headers contain a Content-Length header. */ int64_t in_body_data_left; /** Holds the amount of data that needs to be read from the * current data chunk. Only used with chunked request bodies. */ int in_chunked_length; /** Current request parser state. */ int (*in_state)(htp_connp_t *); // Response parser fields /** Response counter, incremented with every new response. This field is * used to match responses to requests. The expectation is that for every * response there will already be a transaction (request) waiting. */ size_t out_next_tx_index; /** The time when the last response data chunk was received. */ htp_time_t out_timestamp; /** Pointer to the current response data chunk. */ unsigned char *out_current_data; /** The length of the current response data chunk. */ int64_t out_current_len; /** The offset of the next byte in the response data chunk to consume. */ int64_t out_current_offset; /** The offset, in the entire connection stream, of the next response byte. */ int64_t out_stream_offset; /** The value of the response byte currently being processed. */ int out_next_byte; /** Pointer to the response line buffer. */ unsigned char *out_line; /** Size of the response line buffer. */ size_t out_line_size; /** Lenght of the current response line. */ size_t out_line_len; /** Ongoing outbound transaction */ htp_tx_t *out_tx; /** The response header line currently being processed. */ htp_header_line_t *out_header_line; /** The index, in the structure holding all response header lines, of the * line with which the current header begins. The header lines are * kept in the transaction structure. */ int out_header_line_index; /** How many lines are there in the current response header? */ int out_header_line_counter; /** * The length of the current response body as presented in the * Content-Length response header. */ int64_t out_content_length; /** The remaining length of the current response body, if known. */ int64_t out_body_data_left; /** Holds the amount of data that needs to be read from the * current response data chunk. Only used with chunked response bodies. */ int out_chunked_length; /** Current response parser state. */ int (*out_state)(htp_connp_t *); /** Response decompressor used to decompress response body data. */ htp_decompressor_t *out_decompressor; }; struct htp_log_t { /** The connection parser associated with this log message. */ htp_connp_t *connp; /** The transaction associated with this log message, if any. */ htp_tx_t *tx; /** Log message. */ const char *msg; /** Message level. */ int level; /** Message code. */ int code; /** File in which the code that emitted the message resides. */ const char *file; /** Line number on which the code that emitted the message resides. */ unsigned int line; }; struct htp_header_line_t { /** Header line data. */ bstr *line; /** Offset at which header name begins, if applicable. */ size_t name_offset; /** Header name length, if applicable. */ size_t name_len; /** Offset at which header value begins, if applicable. */ size_t value_offset; /** Value length, if applicable. */ size_t value_len; /** How many NUL bytes are there on this header line? */ unsigned int has_nulls; /** The offset of the first NUL byte, or -1. */ int first_nul_offset; /** Parsing flags: HTP_FIELD_INVALID_NOT_FATAL, HTP_FIELD_INVALID_FATAL, HTP_FIELD_LONG */ unsigned int flags; /** terminator characters, if NULL assume RFC compliant 0d 0a */ bstr *terminators; /** Header that uses this line. */ htp_header_t *header; }; struct htp_header_t { /** Header name. */ bstr *name; /** Header value. */ bstr *value; /** Parsing flags: HTP_FIELD_INVALID_NOT_FATAL, HTP_FIELD_FOLDED, HTP_FIELD_REPEATED */ unsigned int flags; }; struct htp_tx_t { /** The connection parsed associated with this transaction. */ htp_connp_t *connp; /** The connection to which this transaction belongs. */ htp_conn_t *conn; /** The configuration structure associated with this transaction. */ htp_cfg_t *cfg; /** Is the configuration structure shared with other transactions or connections? As * a rule of thumb transactions will initially share their configuration structure, but * copy-on-write may be used when an attempt to modify configuration is detected. */ int is_cfg_shared; /** The user data associated with this transaction. */ void *user_data; // Request unsigned int request_ignored_lines; /** The first line of this request. */ bstr *request_line; /** How many NUL bytes are there in the request line? */ int request_line_nul; /** The offset of the first NUL byte. */ int request_line_nul_offset; /** Request method. */ bstr *request_method; /** Request method, as number. Available only if we were able to recognize the request method. */ int request_method_number; /** Request URI, raw, as given to us on the request line. */ bstr *request_uri; /** * Normalized request URI as a single string. The availability of this * field depends on configuration. Use htp_config_set_generate_request_uri_normalized() * to ask for the field to be generated. */ bstr *request_uri_normalized; /** Request protocol, as text. */ bstr *request_protocol; /** Protocol version as a number: -1 means unknown, 9 (HTTP_0_9) means 0.9, * 100 (HTTP_1_0) means 1.0 and 101 (HTTP_1_1) means 1.1. */ int request_protocol_number; /** Is this request using a short-style HTTP/0.9 request? */ int protocol_is_simple; /** This structure holds a parsed request_uri, with the missing information * added (e.g., adding port number from the TCP information) and the fields * normalized. This structure should be used to make decisions about a request. * To inspect raw data, either use request_uri, or parsed_uri_incomplete. */ htp_uri_t *parsed_uri; /** This structure holds the individual components parsed out of the request URI. No * attempt is made to normalize the contents or replace the missing pieces with * defaults. The purpose of this field is to allow you to look at the data as it * was supplied. Use parsed_uri when you need to act on data. Note that this field * will never have the port as a number. */ htp_uri_t *parsed_uri_incomplete; /** The actual message length (the length _after_ transformations * have been applied). This field will change as a request body is being * received, with the final value available once the entire body has * been received. */ size_t request_message_len; /** The actual entity length (the length _before_ transformations * have been applied). This field will change as a request body is being * received, with the final value available once the entire body has * been received. */ size_t request_entity_len; /** TODO The length of the data transmitted in a request body, minus the length * of the files (if any). At worst, this field will be equal to the entity * length if the entity encoding is not recognized. If we recognise the encoding * (e.g., if it is application/x-www-form-urlencoded or multipart/form-data), the * decoder may be able to separate the data from everything else, in which case * the value in this field will be lower. */ size_t request_nonfiledata_len; /** TODO The length of the files uploaded using multipart/form-data, or in a * request that uses PUT (in which case this field will be equal to the * entity length field). This field will be zero in all other cases. */ size_t request_filedata_len; /** Original request header lines. This list stores instances of htp_header_line_t. */ list_t *request_header_lines; /** Parsed request headers. */ table_t *request_headers; /** Contains raw request headers. This field is generated on demand, use * htp_tx_get_request_headers_raw() to get it. */ bstr *request_headers_raw; /** How many request header lines have been included in the raw * buffer (above). */ size_t request_headers_raw_lines; /** Request transfer coding: IDENTITY or CHUNKED. Only available on requests that have bodies. */ int request_transfer_coding; /** Compression; currently COMPRESSION_NONE or COMPRESSION_GZIP. */ int request_content_encoding; // Response /** How many empty lines did we ignore before reaching the status line? */ unsigned int response_ignored_lines; /** Response line. */ bstr *response_line; /** Response protocol, as text. */ bstr *response_protocol; /** Response protocol as number. Only available if we were * able to parse the protocol version. */ int response_protocol_number; /** Response status code, as text. */ bstr *response_status; /** Reponse status code, available only if we were able to parse it. */ int response_status_number; /** This field is set by the protocol decoder with it thinks that the * backend server will reject a request with a particular status code. */ int response_status_expected_number; /** The message associated with the response status code. */ bstr *response_message; /** Have we seen the server respond with a 100 response? */ int seen_100continue; /** Original response header lines. */ list_t *response_header_lines; /** Parsed response headers. */ table_t *response_headers; /** Contains raw response headers. This field is generated on demand, use * htp_tx_get_response_headers_raw() to get it. */ bstr *response_headers_raw; /** How many response header lines have been included in the raw * buffer (above). */ size_t response_headers_raw_lines; /** The actual message length (the length _after_ transformations * have been applied). This field will change as a request body is being * received, with the final value available once the entire body has * been received. */ size_t response_message_len; /** The actual entity length (the length _before_ transformations * have been applied). This field will change as a request body is being * received, with the final value available once the entire body has * been received. */ size_t response_entity_len; /** Response transfer coding: IDENTITY or CHUNKED. Only available on responses that have bodies. */ int response_transfer_coding; /** Compression; currently COMPRESSION_NONE or COMPRESSION_GZIP. */ int response_content_encoding; // Common /** Parsing flags: HTP_INVALID_CHUNKING, HTP_INVALID_FOLDING, * HTP_REQUEST_SMUGGLING, HTP_MULTI_PACKET_HEAD. */ unsigned int flags; /** Transaction progress. Look for the TX_PROGRESS_* constants for more information. */ unsigned int progress; }; /** This structure is used to pass transaction data to callbacks. */ struct htp_tx_data_t { /** Transaction pointer. */ htp_tx_t *tx; /** Pointer to the data buffer. */ unsigned char *data; /** Buffer length. */ size_t len; }; /** URI structure. Each of the fields provides access to a single * URI element. A typical URI will look like this: * http://username:password@hostname.com:8080/path?query#fragment. */ struct htp_uri_t { /** Scheme */ bstr *scheme; /** Username */ bstr *username; /** Password */ bstr *password; /** Hostname */ bstr *hostname; /** Port, as string */ bstr *port; /** Port, as number, but only if the port is valid. */ int port_number; /** The path part of this URI */ bstr *path; /** Query string */ bstr *query; /** Fragment identifier */ bstr *fragment; }; // -- Functions ----------------------------------------------------------------------------------- const char *htp_get_version(); htp_cfg_t *htp_config_copy(htp_cfg_t *cfg); htp_cfg_t *htp_config_create(); void htp_config_destroy(htp_cfg_t *cfg); void htp_config_register_transaction_start(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_request_line(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_request_uri_normalize(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_request_headers(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_request_body_data(htp_cfg_t *cfg, int (*callback_fn)(htp_tx_data_t *)); void htp_config_register_request_trailer(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_request(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_response_line(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_response_headers(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_response_body_data(htp_cfg_t *cfg, int (*callback_fn)(htp_tx_data_t *)); void htp_config_register_response_trailer(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_response(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); void htp_config_register_log(htp_cfg_t *cfg, int (*callback_fn)(htp_log_t *)); int htp_config_set_server_personality(htp_cfg_t *cfg, int personality); void htp_config_set_bestfit_map(htp_cfg_t *cfg, unsigned char *map); void htp_config_set_path_backslash_separators(htp_cfg_t *cfg, int backslash_separators); void htp_config_set_query_backslash_separators(htp_cfg_t *cfg, int backslash_separators); void htp_config_set_path_case_insensitive(htp_cfg_t *cfg, int path_case_insensitive); void htp_config_set_query_case_insensitive(htp_cfg_t *cfg, int case_insensitive); void htp_config_set_path_compress_separators(htp_cfg_t *cfg, int compress_separators); void htp_config_set_query_compress_separators(htp_cfg_t *cfg, int compress_separators); void htp_config_set_path_control_char_handling(htp_cfg_t *cfg, int control_char_handling); void htp_config_set_query_control_char_handling(htp_cfg_t *cfg, int control_char_handling); void htp_config_set_path_convert_utf8(htp_cfg_t *cfg, int convert_utf8); void htp_config_set_path_decode_separators(htp_cfg_t *cfg, int backslash_separators); void htp_config_set_query_decode_separators(htp_cfg_t *cfg, int decode_separators); void htp_config_set_path_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding); void htp_config_set_query_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding); void htp_config_set_path_invalid_encoding_handling(htp_cfg_t *cfg, int invalid_encoding_handling); void htp_config_set_query_invalid_encoding_handling(htp_cfg_t *cfg, int invalid_encoding_handling); void htp_config_set_path_invalid_utf8_handling(htp_cfg_t *cfg, int invalid_utf8_handling); void htp_config_set_path_nul_encoded_handling(htp_cfg_t *cfg, int nul_encoded_handling); void htp_config_set_query_nul_encoded_handling(htp_cfg_t *cfg, int nul_encoded_handling); void htp_config_set_path_nul_raw_handling(htp_cfg_t *cfg, int nul_raw_handling); void htp_config_set_query_nul_raw_handling(htp_cfg_t *cfg, int nul_raw_handling); void htp_config_set_path_replacement_char(htp_cfg_t *cfg, int replacement_char); void htp_config_set_path_unicode_mapping(htp_cfg_t *cfg, int unicode_mapping); void htp_config_set_generate_request_uri_normalized(htp_cfg_t *cfg, int generate); htp_connp_t *htp_connp_create(htp_cfg_t *cfg); htp_connp_t *htp_connp_create_copycfg(htp_cfg_t *cfg); void htp_connp_open(htp_connp_t *connp, const char *remote_addr, int remote_port, const char *local_addr, int local_port, htp_time_t timestamp); void htp_connp_close(htp_connp_t *connp, htp_time_t timestamp); void htp_connp_destroy(htp_connp_t *connp); void htp_connp_destroy_all(htp_connp_t *connp); void htp_connp_set_user_data(htp_connp_t *connp, void *user_data); void *htp_connp_get_user_data(htp_connp_t *connp); htp_conn_t *htp_conn_create(htp_connp_t *connp); void htp_conn_destroy(htp_conn_t *conn); int htp_conn_remove_tx(htp_conn_t *conn, htp_tx_t *tx); int htp_connp_req_data(htp_connp_t *connp, htp_time_t timestamp, unsigned char *data, size_t len); size_t htp_connp_req_data_consumed(htp_connp_t *connp); int htp_connp_res_data(htp_connp_t *connp, htp_time_t timestamp, unsigned char *data, size_t len); size_t htp_connp_res_data_consumed(htp_connp_t *connp); void htp_connp_clear_error(htp_connp_t *connp); htp_log_t *htp_connp_get_last_error(htp_connp_t *connp); htp_header_t *htp_connp_header_parse(htp_connp_t *, unsigned char *, size_t); #define CFG_NOT_SHARED 0 #define CFG_SHARED 1 htp_tx_t *htp_tx_create(htp_cfg_t *cfg, int is_cfg_shared, htp_conn_t *conn); void htp_tx_destroy(htp_tx_t *tx); void htp_tx_set_config(htp_tx_t *tx, htp_cfg_t *cfg, int is_cfg_shared); void htp_tx_set_user_data(htp_tx_t *tx, void *user_data); void *htp_tx_get_user_data(htp_tx_t *tx); bstr *htp_tx_get_request_uri_normalized(htp_tx_t *tx); // Parsing functions int htp_parse_request_line_generic(htp_connp_t *connp); int htp_parse_request_header_generic(htp_connp_t *connp, htp_header_t *h, unsigned char *data, size_t len); int htp_process_request_header_generic(htp_connp_t *); int htp_parse_request_header_apache_2_2(htp_connp_t *connp, htp_header_t *h, unsigned char *data, size_t len); int htp_parse_request_line_apache_2_2(htp_connp_t *connp); int htp_process_request_header_apache_2_2(htp_connp_t *); int htp_parse_response_line_generic(htp_connp_t *connp); int htp_process_response_header_generic(htp_connp_t *connp); // Parser states int htp_connp_REQ_IDLE(htp_connp_t *connp); int htp_connp_REQ_LINE(htp_connp_t *connp); int htp_connp_REQ_PROTOCOL(htp_connp_t *connp); int htp_connp_REQ_HEADERS(htp_connp_t *connp); int htp_connp_REQ_BODY_DETERMINE(htp_connp_t *connp); int htp_connp_REQ_BODY_IDENTITY(htp_connp_t *connp); int htp_connp_REQ_BODY_CHUNKED_LENGTH(htp_connp_t *connp); int htp_connp_REQ_BODY_CHUNKED_DATA(htp_connp_t *connp); int htp_connp_REQ_BODY_CHUNKED_DATA_END(htp_connp_t *connp); int htp_connp_REQ_CONNECT_CHECK(htp_connp_t *connp); int htp_connp_REQ_CONNECT_WAIT_RESPONSE(htp_connp_t *connp); int htp_connp_RES_IDLE(htp_connp_t *connp); int htp_connp_RES_LINE(htp_connp_t *connp); int htp_connp_RES_HEADERS(htp_connp_t *connp); int htp_connp_RES_BODY_DETERMINE(htp_connp_t *connp); int htp_connp_RES_BODY_IDENTITY(htp_connp_t *connp); int htp_connp_RES_BODY_CHUNKED_LENGTH(htp_connp_t *connp); int htp_connp_RES_BODY_CHUNKED_DATA(htp_connp_t *connp); int htp_connp_RES_BODY_CHUNKED_DATA_END(htp_connp_t *connp); // Utility functions int htp_convert_method_to_number(bstr *); int htp_is_lws(int c); int htp_is_separator(int c); int htp_is_text(int c); int htp_is_token(int c); int htp_chomp(unsigned char *data, size_t *len); int htp_is_space(int c); int htp_parse_protocol(bstr *protocol); int htp_is_line_empty(unsigned char *data, size_t len); int htp_is_line_whitespace(unsigned char *data, size_t len); int htp_connp_is_line_folded(unsigned char *data, size_t len); int htp_connp_is_line_terminator(htp_connp_t *connp, unsigned char *data, size_t len); int htp_connp_is_line_ignorable(htp_connp_t *connp, unsigned char *data, size_t len); int htp_parse_uri(bstr *input, htp_uri_t **uri); int htp_parse_authority(htp_connp_t *connp, bstr *input, htp_uri_t **uri); int htp_normalize_parsed_uri(htp_connp_t *connp, htp_uri_t *parsed_uri_incomplete, htp_uri_t *parsed_uri); bstr *htp_normalize_hostname_inplace(bstr *input); void htp_replace_hostname(htp_connp_t *connp, htp_uri_t *parsed_uri, bstr *hostname); int htp_decode_path_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path); int htp_decode_query_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path); void htp_uriencoding_normalize_inplace(bstr *s); int htp_prenormalize_uri_path_inplace(bstr *s, int *flags, int case_insensitive, int backslash, int decode_separators, int remove_consecutive); void htp_normalize_uri_path_inplace(bstr *s); void htp_utf8_decode_path_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path); void htp_utf8_validate_path(htp_tx_t *tx, bstr *path); int htp_parse_content_length(bstr *b); int htp_parse_chunked_length(unsigned char *data, size_t len); int htp_parse_positive_integer_whitespace(unsigned char *data, size_t len, int base); int htp_parse_status(bstr *status); void htp_log(htp_connp_t *connp, const char *file, int line, int level, int code, const char *fmt, ...); void htp_print_log(FILE *stream, htp_log_t *log); void fprint_raw_data(FILE *stream, const char *name, unsigned char *data, size_t len); char *htp_connp_in_state_as_string(htp_connp_t *connp); char *htp_connp_out_state_as_string(htp_connp_t *connp); char *htp_tx_progress_as_string(htp_tx_t *tx); bstr *htp_unparse_uri_noencode(htp_uri_t *uri); bstr *htp_tx_get_request_headers_raw(htp_tx_t *tx); bstr *htp_tx_get_response_headers_raw(htp_tx_t *tx); #endif /* _HTP_H */ suricata-1.4.7/libhtp/htp/bstr.c0000644000000000000000000003466412253546156013446 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "bstr.h" #include /** * Allocate a zero-length bstring, but reserving space for at least len bytes. * * @param len * @return New string */ bstr *bstr_alloc(size_t len) { unsigned char *s = malloc(sizeof (bstr_t) + len); if (s == NULL) return NULL; bstr_t *b = (bstr_t *) s; b->len = 0; b->size = len; b->ptr = NULL; return (bstr *) s; } /** * Deallocate a bstring. Allows a NULL bstring on input. * * @param b */ void bstr_free(bstr *b) { if (b == NULL) return; free(b); } /** * Append source bstring to destination bstring, growing * destination if necessary. * * @param destination * @param source * @return destination, at a potentially different memory location */ bstr *bstr_add_str(bstr *destination, bstr *source) { return bstr_add_mem(destination, bstr_ptr(source), bstr_len(source)); } /** * Append a NUL-terminated source to destination, growing * destination if necessary. * * @param destination * @param source * @return destination, at a potentially different memory location */ bstr *bstr_add_cstr(bstr *destination, char *source) { return bstr_add_mem(destination, source, strlen(source)); } /** * Append a memory region to destination, growing destination * if necessary. * * @param destination * @param data * @param len * @return destination, at a potentially different memory location */ bstr *bstr_add_mem(bstr *destination, char *data, size_t len) { if (bstr_size(destination) < bstr_len(destination) + len) { destination = bstr_expand(destination, bstr_len(destination) + len); if (destination == NULL) return NULL; } bstr_t *b = (bstr_t *) destination; memcpy(bstr_ptr(destination) + b->len, data, len); b->len = b->len + len; return destination; } /** * Append source bstring to destination bstring, growing * destination if necessary. * * @param destination * @param source * @return destination, at a potentially different memory location */ bstr *bstr_add_str_noex(bstr *destination, bstr *source) { return bstr_add_mem_noex(destination, bstr_ptr(source), bstr_len(source)); } /** * Append a NUL-terminated source to destination, growing * destination if necessary. * * @param destination * @param source * @return destination, at a potentially different memory location */ bstr *bstr_add_cstr_noex(bstr *destination, char *source) { return bstr_add_mem_noex(destination, source, strlen(source)); } /** * Append a memory region to destination, growing destination * if necessary. * * @param destination * @param data * @param len * @return destination, at a potentially different memory location */ bstr *bstr_add_mem_noex(bstr *destination, char *data, size_t len) { size_t copylen = len; if (bstr_size(destination) < bstr_len(destination) + copylen) { copylen = bstr_size(destination) - bstr_len(destination); if (copylen <= 0) return destination; } bstr_t *b = (bstr_t *) destination; memcpy(bstr_ptr(destination) + b->len, data, copylen); b->len = b->len + copylen; return destination; } /** * Expand a string to support at least newsize bytes. The input bstring * is not changed if it is big enough to accommodate the desired size. If * the input bstring is smaller, however, it is expanded. The pointer to * the bstring may change. If the expansion fails, the original bstring * is left untouched (it is not freed). * * @param s * @param newsize * @return new bstring, or NULL if memory allocation failed */ bstr *bstr_expand(bstr *s, size_t newsize) { if (((bstr_t *) s)->ptr != NULL) { void * newblock = realloc(((bstr_t *) s)->ptr, newsize); if (newblock == NULL) { return NULL; } else { ((bstr_t *) s)->ptr = newblock; } } else { void *newblock = realloc(s, sizeof (bstr_t) + newsize); if (newblock == NULL) { return NULL; } else { s = newblock; } } ((bstr_t *) s)->size = newsize; return s; } /** * Create a new bstring by copying the provided NUL-terminated string. * * @param data * @return new bstring */ bstr *bstr_cstrdup(char *data) { return bstr_memdup(data, strlen(data)); } /** * Create a new bstring by copying the provided memory region. * * @param data * @param len * @return new bstring */ bstr *bstr_memdup(char *data, size_t len) { bstr *b = bstr_alloc(len); if (b == NULL) return NULL; memcpy(bstr_ptr(b), data, len); ((bstr_t *) b)->len = len; return b; } /** * Create a new bstring by copying the provided bstring. * * @param b * @return new bstring */ bstr *bstr_strdup(bstr *b) { return bstr_strdup_ex(b, 0, bstr_len(b)); } /** * Create a new bstring by copying a part of the provided * bstring. * * @param b * @param offset * @param len * @return new bstring */ bstr *bstr_strdup_ex(bstr *b, size_t offset, size_t len) { bstr *bnew = bstr_alloc(len); if (bnew == NULL) return NULL; memcpy(bstr_ptr(bnew), bstr_ptr(b) + offset, len); ((bstr_t *) bnew)->len = len; return bnew; } /** * Take the provided memory region and construct a NUL-terminated * string, replacing NUL bytes with "\0". * * @param data * @param len * @return new NUL-terminated string */ char *bstr_memtocstr(char *data, size_t len) { // Count how many NUL bytes we have in the string. size_t i, nulls = 0; for (i = 0; i < len; i++) { if (data[i] == '\0') { nulls++; } } // Now copy the string into a NUL-terminated buffer. char *r, *t; r = t = malloc(len + nulls + 1); if (t == NULL) return NULL; while (len--) { // Escape NUL bytes, but just copy everything else. if (*data == '\0') { data++; *t++ = '\\'; *t++ = '0'; } else { *t++ = *data++; } } // Terminate string. *t = '\0'; return r; } /** * Create a new NUL-terminated string out of the provided bstring. * * @param b * @return new NUL-terminated string */ char *bstr_tocstr(bstr *b) { if (b == NULL) return NULL; return bstr_memtocstr(bstr_ptr(b), bstr_len(b)); } /** * Return the first position of the provided character (byte). * * @param b * @param c * @return the first position of the character, or -1 if it could not be found */ int bstr_chr(bstr *b, int c) { char *data = bstr_ptr(b); size_t len = bstr_len(b); size_t i = 0; while (i < len) { if (data[i] == c) { return i; } i++; } return -1; } /** * Return the last position of a character (byte). * * @param b * @param c * @return the last position of the character, or -1 if it could not be found */ int bstr_rchr(bstr *b, int c) { char *data = bstr_ptr(b); size_t len = bstr_len(b); int i = len; while (i >= 0) { if (data[i] == c) { return i; } i--; } return -1; } /** * Compare two memory regions. * * @param s1 * @param l1 * @param s2 * @param l2 * @return 0 if the memory regions are identical, -1 or +1 if they're not */ int bstr_cmp_ex(char *s1, size_t l1, char *s2, size_t l2) { size_t p1 = 0, p2 = 0; while ((p1 < l1) && (p2 < l2)) { if (s1[p1] != s2[p2]) { // Difference return (s1[p1] < s2[p2]) ? -1 : 1; } p1++; p2++; } if ((p1 == l2) && (p2 == l1)) { // They're identical return 0; } else { // One string is shorter if (p1 == l1) return -1; else return 1; } } /** * Case-insensitive comparison of two memory regions. * * @param s1 * @param l1 * @param s2 * @param l2 * @return 0 if the memory regions are identical, -1 or +1 if they're not */ int bstr_cmp_nocase_ex(char *s1, size_t l1, char *s2, size_t l2) { size_t p1 = 0, p2 = 0; while ((p1 < l1) && (p2 < l2)) { if (tolower((int)s1[p1]) != tolower((int)s2[p2])) { // Difference return (tolower((int)s1[p1]) < tolower((int)s2[p2])) ? -1 : 1; } p1++; p2++; } if ((p1 == l2) && (p2 == l1)) { // They're identical return 0; } else { // One string is shorter if (p1 == l1) return -1; else return 1; } } /** * Compare a bstring with a NUL-terminated string. * * @param b * @param c * @return 0, -1 or +1 */ int bstr_cmpc(bstr *b, char *c) { return bstr_cmp_ex(bstr_ptr(b), bstr_len(b), c, strlen(c)); } /** * Compare two bstrings. * * @param b1 * @param b2 * @return 0, -1 or +1 */ int bstr_cmp(bstr *b1, bstr *b2) { return bstr_cmp_ex(bstr_ptr(b1), bstr_len(b1), bstr_ptr(b2), bstr_len(b2)); } /** * Case-insensitive comparison two bstrings. * * @param b1 * @param b2 * @return 0, -1 or +1 */ int bstr_cmp_nocase(bstr *b1, bstr *b2) { return bstr_cmp_nocase_ex(bstr_ptr(b1), bstr_len(b1), bstr_ptr(b2), bstr_len(b2)); } /** * Convert bstring to lowercase. * * @param b * @return b */ bstr *bstr_tolowercase(bstr *b) { if (b == NULL) return NULL; unsigned char *data = (unsigned char *)bstr_ptr(b); size_t len = bstr_len(b); size_t i = 0; while (i < len) { data[i] = tolower(data[i]); i++; } return b; } /** * Create a copy of the provided bstring, then convert it to lowercase. * * @param b * @return bstring copy */ bstr *bstr_dup_lower(bstr *b) { return bstr_tolowercase(bstr_strdup(b)); } /** * */ int bstr_util_memtoip(char *data, size_t len, int base, size_t *lastlen) { int rval = 0, tval = 0, tflag = 0; size_t i = *lastlen = 0; for (i = 0; i < len; i++) { int d = data[i]; *lastlen = i; // Convert character to digit. if ((d >= '0') && (d <= '9')) { d -= '0'; } else if ((d >= 'a') && (d <= 'z')) { d -= 'a' - 10; } else if ((d >= 'A') && (d <= 'Z')) { d -= 'A' - 10; } else { d = -1; } // Check that the digit makes sense with the base // we are using. if ((d == -1) || (d >= base)) { if (tflag) { // Return what we have so far; lastlen points // to the first non-digit position. return rval; } else { // We didn't see a single digit. return -1; } } if (tflag) { rval *= base; if (tval > rval) { // Overflow return -2; } rval += d; if (tval > rval) { // Overflow return -2; } tval = rval; } else { tval = rval = d; tflag = 1; } } *lastlen = i + 1; return rval; } /** * Find needle in a haystack. * * @param haystack * @param needle * @return */ int bstr_indexof(bstr *haystack, bstr *needle) { return bstr_indexofmem(haystack, bstr_ptr(needle), bstr_len(needle)); } /** * Find index in the haystack, with the needle being a NUL-terminated string. * * @param haystack * @param needle * @return */ int bstr_indexofc(bstr *haystack, char *needle) { return bstr_indexofmem(haystack, needle, strlen(needle)); } /** * Find index in the haystack. Ignore case differences. * * @param haystack * @param needle * @return */ int bstr_indexof_nocase(bstr *haystack, bstr *needle) { return bstr_indexofmem_nocase(haystack, bstr_ptr(needle), bstr_len(needle)); } /** * Find index in the haystack, with the needle being a NUL-terminated string. * Ignore case differences. * * @param haystack * @param needle * @return */ int bstr_indexofc_nocase(bstr *haystack, char *needle) { return bstr_indexofmem_nocase(haystack, needle, strlen(needle)); } /** * Find index in the haystack, with the needle being a memory region. * * @param haystack * @param data2 * @param len2 * @return */ int bstr_indexofmem(bstr *haystack, char *data2, size_t len2) { unsigned char *data = (unsigned char *)bstr_ptr(haystack); size_t len = bstr_len(haystack); size_t i, j; // TODO Is an optimisation here justified? // http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm for (i = 0; i < len; i++) { size_t k = i; for (j = 0; ((j < len2) && (k < len)); j++) { if (data[k++] != data2[j]) break; } if ((k - i) == len2) { return i; } } return -1; } /** * Find index in the haystack, with the needle being a memory region. * Ignore case differences. * * @param haystack * @param data2 * @param len2 * @return */ int bstr_indexofmem_nocase(bstr *haystack, char *data2, size_t len2) { unsigned char *data = (unsigned char *)bstr_ptr(haystack); size_t len = bstr_len(haystack); size_t i, j; // TODO No need to inspect the last len2 - 1 bytes for (i = 0; i < len; i++) { size_t k = i; for (j = 0; ((j < len2) && (k < len)); j++) { if (toupper(data[k++]) != toupper((unsigned char)data2[j])) break; } if ((k - i) == len2) { return i; } } return -1; } /** * Remove one byte from the end of the string. * * @param s */ void bstr_chop(bstr *s) { bstr_t *b = (bstr_t *) s; if (b->len > 0) { b->len--; } } /** * Adjust bstring length. You will need to use this method whenever * you work directly with the string contents, and you end up changing * its length. * * @param s * @param newlen */ void bstr_len_adjust(bstr *s, size_t newlen) { bstr_t *b = (bstr_t *) s; b->len = newlen; } /** * Return the character (byte) at the given position. * * @param s * @param pos * @return the character, or -1 if the bstring is too short */ char bstr_char_at(bstr *s, size_t pos) { unsigned char *data = (unsigned char *)bstr_ptr(s); size_t len = bstr_len(s); if (pos > len) return -1; return data[pos]; } suricata-1.4.7/libhtp/htp/bstr.h0000644000000000000000000000603612253546156013443 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #ifndef _BSTR_H #define _BSTR_H #include #include #include // IMPORTANT This binary string library is used internally by the parser and you should // not rely on it in your code. The implementation may change. // // TODO // - Add a function that wraps an existing data // - Support Unicode bstrings typedef void * bstr; bstr *bstr_alloc(size_t newsize); void bstr_free(bstr *s); bstr *bstr_expand(bstr *s, size_t newsize); bstr *bstr_cstrdup(char *); bstr *bstr_memdup(char *data, size_t len); bstr *bstr_strdup(bstr *b); bstr *bstr_strdup_ex(bstr *b, size_t offset, size_t len); char *bstr_tocstr(bstr *); int bstr_chr(bstr *, int); int bstr_rchr(bstr *, int); int bstr_cmpc(bstr *, char *); int bstr_cmp(bstr *, bstr *); int bstr_cmp_nocase(bstr *, bstr *); bstr *bstr_dup_lower(bstr *); bstr *bstr_tolowercase(bstr *); bstr *bstr_add_mem(bstr *, char *, size_t); bstr *bstr_add_str(bstr *, bstr *); bstr *bstr_add_cstr(bstr *, char *); bstr *bstr_add_mem_noex(bstr *, char *, size_t); bstr *bstr_add_str_noex(bstr *, bstr *); bstr *bstr_add_cstr_noex(bstr *, char *); int bstr_util_memtoip(char *data, size_t len, int base, size_t *lastlen); char *bstr_memtocstr(char *data, size_t len); int bstr_indexof(bstr *haystack, bstr *needle); int bstr_indexofc(bstr *haystack, char *needle); int bstr_indexof_nocase(bstr *haystack, bstr *needle); int bstr_indexofc_nocase(bstr *haystack, char *needle); int bstr_indexofmem(bstr *haystack, char *data, size_t len); int bstr_indexofmem_nocase(bstr *haystack, char *data, size_t len); void bstr_chop(bstr *b); void bstr_len_adjust(bstr *s, size_t newlen); char bstr_char_at(bstr *s, size_t pos); typedef struct bstr_t bstr_t; struct bstr_t { /** The length of the string stored in the buffer. */ size_t len; /** The current size of the buffer. If the buffer is bigger than the * string then it will be able to expand without having to reallocate. */ size_t size; /** Optional buffer pointer. If this pointer is NUL (as it currently is * in virtually all cases, the string buffer will immediatelly follow * this structure. If the pointer is not NUL, it points to the actual * buffer used, and there's no data following this structure. */ char *ptr; }; #define bstr_len(X) ((*(bstr_t *)(X)).len) #define bstr_size(X) ((*(bstr_t *)(X)).size) #define bstr_ptr(X) ( ((*(bstr_t *)(X)).ptr == NULL) ? (char *)((char *)(X) + sizeof(bstr_t)) : (char *)(*(bstr_t *)(X)).ptr ) #endif /* _BSTR_H */ suricata-1.4.7/libhtp/htp/htp_request.c0000644000000000000000000010142612253546156015026 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include #include "htp.h" /** * Performs check for a CONNECT transaction to decide whether inbound * parsing needs to be suspended. * * @param connp * @return HTP_OK if the request does not use CONNECT, HTP_DATA_OTHER if * inbound parsing needs to be suspended until we hear from the * other side */ int htp_connp_REQ_CONNECT_CHECK(htp_connp_t *connp) { // If the request uses the CONNECT method, then there will // not be a request body, but first we need to wait to see the // response in order to determine if the tunneling request // was a success. if (connp->in_tx->request_method_number == M_CONNECT) { connp->in_state = htp_connp_REQ_CONNECT_WAIT_RESPONSE; connp->in_status = STREAM_STATE_DATA_OTHER; connp->in_tx->progress = TX_PROGRESS_WAIT; return HTP_DATA_OTHER; } // Continue to the next step to determine the presence // of the request body connp->in_state = htp_connp_REQ_BODY_DETERMINE; return HTP_OK; } /** * Determines whether inbound parsing, which was suspended after * encountering a CONNECT transaction, can proceed (after receiving * the response). * * @param connp * @return HTP_OK if the parser can resume parsing, HTP_DATA_OTHER if * it needs to continue waiting. */ int htp_connp_REQ_CONNECT_WAIT_RESPONSE(htp_connp_t *connp) { // Check that we saw the response line of the current // inbound transaction. if (connp->in_tx->progress <= TX_PROGRESS_RES_LINE) { return HTP_DATA_OTHER; } // A 2xx response means a tunnel was established. Anything // else means we continue to follow the HTTP stream. if ((connp->in_tx->response_status_number >= 200) && (connp->in_tx->response_status_number <= 299)) { // TODO Check that the server did not accept a connection // to itself. // The requested tunnel was established: we are going // to ignore the remaining data on this stream connp->in_status = STREAM_STATE_TUNNEL; connp->in_state = htp_connp_REQ_IDLE; } else { // No tunnel; continue to the next transaction connp->in_state = htp_connp_REQ_IDLE; } return HTP_OK; } /** * Consumes bytes until the end of the current line. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_BODY_CHUNKED_DATA_END(htp_connp_t *connp) { // TODO We shouldn't really see anything apart from CR and LF, // so we should warn about anything else. for (;;) { IN_NEXT_BYTE_OR_RETURN(connp); connp->in_tx->request_message_len++; if (connp->in_next_byte == LF) { connp->in_state = htp_connp_REQ_BODY_CHUNKED_LENGTH; return HTP_OK; } } return HTP_ERROR; } /** * Processes a chunk of data. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_BODY_CHUNKED_DATA(htp_connp_t *connp) { htp_tx_data_t d; d.tx = connp->in_tx; d.data = &connp->in_current_data[connp->in_current_offset]; d.len = 0; for (;;) { IN_NEXT_BYTE(connp); if (connp->in_next_byte == -1) { // Send data to callbacks int rc = hook_run_all(connp->cfg->hook_request_body_data, &d); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request body data callback returned error (%d)", rc); return HTP_ERROR; } // Ask for more data return HTP_DATA; } else { connp->in_tx->request_message_len++; connp->in_tx->request_entity_len++; connp->in_chunked_length--; d.len++; if (connp->in_chunked_length == 0) { // End of data chunk // Send data to callbacks int rc = hook_run_all(connp->cfg->hook_request_body_data, &d); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request body data callback returned error (%d)", rc); return HTP_ERROR; } connp->in_state = htp_connp_REQ_BODY_CHUNKED_DATA_END; return HTP_OK; } } } return HTP_ERROR; } /** * Extracts chunk length. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_BODY_CHUNKED_LENGTH(htp_connp_t *connp) { for (;;) { IN_COPY_BYTE_OR_RETURN(connp); connp->in_tx->request_message_len++; // Have we reached the end of the line? if (connp->in_next_byte == LF) { htp_chomp(connp->in_line, &connp->in_line_len); // Extract chunk length connp->in_chunked_length = htp_parse_chunked_length(connp->in_line, connp->in_line_len); // Cleanup for the next line connp->in_line_len = 0; // Handle chunk length if (connp->in_chunked_length > 0) { // More data available // TODO Add a check for chunk length connp->in_state = htp_connp_REQ_BODY_CHUNKED_DATA; } else if (connp->in_chunked_length == 0) { // End of data connp->in_state = htp_connp_REQ_HEADERS; connp->in_tx->progress = TX_PROGRESS_REQ_TRAILER; } else { // Invalid chunk length htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request chunk encoding: Invalid chunk length"); return HTP_ERROR; } return HTP_OK; } } return HTP_ERROR; } /** * Processes identity request body. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_BODY_IDENTITY(htp_connp_t *connp) { htp_tx_data_t d; d.tx = connp->in_tx; d.data = &connp->in_current_data[connp->in_current_offset]; d.len = 0; for (;;) { IN_NEXT_BYTE(connp); if (connp->in_next_byte == -1) { // End of chunk if (d.len != 0) { int rc = hook_run_all(connp->cfg->hook_request_body_data, &d); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request body data callback returned error (%d)", rc); return HTP_ERROR; } } // Ask for more data return HTP_DATA; } else { connp->in_tx->request_message_len++; connp->in_tx->request_entity_len++; connp->in_body_data_left--; d.len++; if (connp->in_body_data_left == 0) { // End of body if (d.len != 0) { int rc = hook_run_all(connp->cfg->hook_request_body_data, &d); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request body data callback returned error (%d)", rc); return HTP_ERROR; } } // Done connp->in_state = htp_connp_REQ_IDLE; connp->in_tx->progress = TX_PROGRESS_WAIT; return HTP_OK; } } } return HTP_ERROR; } /** * Determines presence (and encoding) of a request body. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_BODY_DETERMINE(htp_connp_t *connp) { htp_header_t *cl = table_getc(connp->in_tx->request_headers, "content-length"); htp_header_t *te = table_getc(connp->in_tx->request_headers, "transfer-encoding"); // Check for the Transfer-Encoding header, which // would indicate a chunked request body if (te != NULL && te->value != NULL) { // Make sure it contains "chunked" only if (bstr_cmpc(te->value, "chunked") != 0) { // Invalid T-E header value htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid T-E value in request"); } // Chunked encoding is a HTTP/1.1 feature. Check // that some other protocol is not used. The flag will // also be set if the protocol could not be parsed. // // TODO IIS 7.0, for example, would ignore the T-E header when it // it is used with a protocol below HTTP 1.1. if (connp->in_tx->request_protocol_number < HTTP_1_1) { connp->in_tx->flags |= HTP_INVALID_CHUNKING; // TODO Log } // If the T-E header is present we are going to use it. connp->in_tx->request_transfer_coding = CHUNKED; // We are still going to check for the presence of C-L if (cl != NULL) { // This is a violation of the RFC connp->in_tx->flags |= HTP_REQUEST_SMUGGLING; // TODO Log } connp->in_state = htp_connp_REQ_BODY_CHUNKED_LENGTH; connp->in_tx->progress = TX_PROGRESS_REQ_BODY; } else // Next check for the presence of the Content-Length header if (cl != NULL && cl->value != NULL) { // It seems that we have a request body. connp->in_tx->request_transfer_coding = IDENTITY; // Check for a folded C-L header if (cl->flags & HTP_FIELD_FOLDED) { connp->in_tx->flags |= HTP_REQUEST_SMUGGLING; // TODO Log } // Check for multiple C-L headers if (cl->flags & HTP_FIELD_REPEATED) { connp->in_tx->flags |= HTP_REQUEST_SMUGGLING; // TODO Log } // Get body length int i = htp_parse_content_length(cl->value); if (i < 0) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid C-L field in request"); return HTP_ERROR; } else { connp->in_content_length = i; connp->in_body_data_left = connp->in_content_length; if (connp->in_content_length != 0) { connp->in_state = htp_connp_REQ_BODY_IDENTITY; connp->in_tx->progress = TX_PROGRESS_REQ_BODY; } else { connp->in_state = htp_connp_REQ_IDLE; connp->in_tx->progress = TX_PROGRESS_WAIT; } } } else { // This request does not have a body, which // means that we're done with it connp->in_state = htp_connp_REQ_IDLE; connp->in_tx->progress = TX_PROGRESS_WAIT; } // Host resolution htp_header_t *h = table_getc(connp->in_tx->request_headers, "host"); if (h == NULL) { // No host information in the headers // HTTP/1.1 requires host information in the headers if (connp->in_tx->request_protocol_number >= HTTP_1_1) { connp->in_tx->flags |= HTP_HOST_MISSING; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Host information in request headers required by HTTP/1.1"); } } else { // Host information available in the headers // Is there host information in the URI? if (connp->in_tx->parsed_uri->hostname == NULL) { // There is no host information in the URI. Place the // hostname from the headers into the parsed_uri structure. htp_replace_hostname(connp, connp->in_tx->parsed_uri, h->value); } else if (bstr_cmp_nocase(h->value, connp->in_tx->parsed_uri->hostname) != 0) { // The host information is different in the // headers and the URI. The HTTP RFC states that // we should ignore the headers copy. connp->in_tx->flags |= HTP_AMBIGUOUS_HOST; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Host information ambiguous"); } } // Run hook REQUEST_HEADERS int rc = hook_run_all(connp->cfg->hook_request_headers, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request headers callback returned error (%d)", rc); return HTP_ERROR; } return HTP_OK; } /** * Parses request headers. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_HEADERS(htp_connp_t *connp) { for (;;) { IN_COPY_BYTE_OR_RETURN(connp); if (connp->in_header_line == NULL) { connp->in_header_line = calloc(1, sizeof (htp_header_line_t)); if (connp->in_header_line == NULL) return HTP_ERROR; connp->in_header_line->first_nul_offset = -1; } // Keep track of NUL bytes if (connp->in_next_byte == 0) { // Store the offset of the first NUL if (connp->in_header_line->has_nulls == 0) { connp->in_header_line->first_nul_offset = connp->in_line_len; } // Remember how many NULs there were connp->in_header_line->flags |= HTP_FIELD_NUL_BYTE; connp->in_header_line->has_nulls++; } // Have we reached the end of the line? if (connp->in_next_byte == LF) { #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, connp->in_line, connp->in_line_len); #endif // Should we terminate headers? if (htp_connp_is_line_terminator(connp, connp->in_line, connp->in_line_len)) { // Terminator line // Parse previous header, if any if (connp->in_header_line_index != -1) { if (connp->cfg->process_request_header(connp) != HTP_OK) { // Note: downstream responsible for error logging return HTP_ERROR; } // Reset index connp->in_header_line_index = -1; } // Cleanup free(connp->in_header_line); connp->in_line_len = 0; connp->in_header_line = NULL; // We've seen all request headers if (connp->in_chunk_count != connp->in_chunk_request_index) { connp->in_tx->flags |= HTP_MULTI_PACKET_HEAD; } // Move onto the next processing phase if (connp->in_tx->progress == TX_PROGRESS_REQ_HEADERS) { // Determine if this request has a body //connp->in_state = htp_connp_REQ_BODY_DETERMINE; connp->in_state = htp_connp_REQ_CONNECT_CHECK; } else { // Run hook REQUEST_TRAILER int rc = hook_run_all(connp->cfg->hook_request_trailer, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request trailer callback returned error (%d)", rc); return HTP_ERROR; } // We've completed parsing this request connp->in_state = htp_connp_REQ_IDLE; connp->in_tx->progress = TX_PROGRESS_WAIT; } return HTP_OK; } // Prepare line for consumption size_t raw_in_line_len = connp->in_line_len; htp_chomp(connp->in_line, &connp->in_line_len); // Check for header folding if (htp_connp_is_line_folded(connp->in_line, connp->in_line_len) == 0) { // New header line // Parse previous header, if any if (connp->in_header_line_index != -1) { if (connp->cfg->process_request_header(connp) != HTP_OK) { // Note: downstream responsible for error logging return HTP_ERROR; } // Reset index connp->in_header_line_index = -1; } // Remember the index of the fist header line connp->in_header_line_index = connp->in_header_line_counter; } else { // Folding; check that there's a previous header line to add to if (connp->in_header_line_index == -1) { if (!(connp->in_tx->flags & HTP_INVALID_FOLDING)) { connp->in_tx->flags |= HTP_INVALID_FOLDING; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid request field folding"); } } } // Add the raw header line to the list if (raw_in_line_len > connp->in_line_len) { if (raw_in_line_len - connp->in_line_len == 2 && connp->in_line[connp->in_line_len] == 0x0d && connp->in_line[connp->in_line_len + 1] == 0x0a) { connp->in_header_line->terminators = NULL; } else { connp->in_header_line->terminators = bstr_memdup((char *) connp->in_line + connp->in_line_len, raw_in_line_len - connp->in_line_len); if (connp->in_header_line->terminators == NULL) { return HTP_ERROR; } } } else { connp->in_header_line->terminators = NULL; } connp->in_header_line->line = bstr_memdup((char *) connp->in_line, connp->in_line_len); if (connp->in_header_line->line == NULL) { return HTP_ERROR; } list_add(connp->in_tx->request_header_lines, connp->in_header_line); connp->in_header_line = NULL; // Cleanup for the next line connp->in_line_len = 0; if (connp->in_header_line_index == -1) { connp->in_header_line_index = connp->in_header_line_counter; } connp->in_header_line_counter++; } } return HTP_ERROR; } /** * Determines request protocol. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_PROTOCOL(htp_connp_t *connp) { // Is this a short-style HTTP/0.9 request? If it is, // we will not want to parse request headers. if (connp->in_tx->protocol_is_simple == 0) { // Switch to request header parsing. connp->in_state = htp_connp_REQ_HEADERS; connp->in_tx->progress = TX_PROGRESS_REQ_HEADERS; } else { // We're done with this request. connp->in_state = htp_connp_REQ_IDLE; connp->in_tx->progress = TX_PROGRESS_WAIT; } return HTP_OK; } /** * Parses request line. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_LINE(htp_connp_t *connp) { for (;;) { // Get one byte IN_COPY_BYTE_OR_RETURN(connp); // Keep track of NUL bytes if (connp->in_next_byte == 0) { // Remember how many NULs there were connp->in_tx->request_line_nul++; // Store the offset of the first NUL byte if (connp->in_tx->request_line_nul_offset == -1) { connp->in_tx->request_line_nul_offset = connp->in_line_len; } } // Have we reached the end of the line? if (connp->in_next_byte == LF) { #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, connp->in_line, connp->in_line_len); #endif // Is this a line that should be ignored? if (htp_connp_is_line_ignorable(connp, connp->in_line, connp->in_line_len)) { // We have an empty/whitespace line, which we'll note, ignore and move on connp->in_tx->request_ignored_lines++; // TODO How many empty lines are we willing to accept? // Start again connp->in_line_len = 0; return HTP_OK; } // Process request line htp_chomp(connp->in_line, &connp->in_line_len); connp->in_tx->request_line = bstr_memdup((char *) connp->in_line, connp->in_line_len); if (connp->in_tx->request_line == NULL) { return HTP_ERROR; } // Parse request line if (connp->cfg->parse_request_line(connp) != HTP_OK) { // Note: downstream responsible for error logging return HTP_ERROR; } if (connp->in_tx->request_method_number == M_CONNECT) { // Parse authority if (htp_parse_authority(connp, connp->in_tx->request_uri, &(connp->in_tx->parsed_uri_incomplete)) != HTP_OK) { // Note: downstream responsible for error logging return HTP_ERROR; } } else { // Parse the request URI if (htp_parse_uri(connp->in_tx->request_uri, &(connp->in_tx->parsed_uri_incomplete)) != HTP_OK) { // Note: downstream responsible for error logging return HTP_ERROR; } // Keep the original URI components, but // create a copy which we can normalize and use internally if (htp_normalize_parsed_uri(connp, connp->in_tx->parsed_uri_incomplete, connp->in_tx->parsed_uri)) { // Note: downstream responsible for error logging return HTP_ERROR; } // Run hook REQUEST_URI_NORMALIZE int rc = hook_run_all(connp->cfg->hook_request_uri_normalize, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request URI normalize callback returned error (%d)", rc); return HTP_ERROR; } // Now is a good time to generate request_uri_normalized, before we finalize // parsed_uri (and lose the information which parts were provided in the request and // which parts we added). if (connp->cfg->generate_request_uri_normalized) { connp->in_tx->request_uri_normalized = htp_unparse_uri_noencode(connp->in_tx->parsed_uri); if (connp->in_tx->request_uri_normalized == NULL) { // There's no sense in logging anything on a memory allocation failure return HTP_ERROR; } #ifdef HTP_DEBUG fprint_raw_data(stderr, "request_uri_normalized", (unsigned char *) bstr_ptr(connp->in_tx->request_uri_normalized), bstr_len(connp->in_tx->request_uri_normalized)); #endif } // Finalize parsed_uri // Scheme if (connp->in_tx->parsed_uri->scheme != NULL) { if (bstr_cmpc(connp->in_tx->parsed_uri->scheme, "http") != 0) { // TODO Invalid scheme } } else { connp->in_tx->parsed_uri->scheme = bstr_cstrdup("http"); if (connp->in_tx->parsed_uri->scheme == NULL) { return HTP_ERROR; } } // Port if (connp->in_tx->parsed_uri->port != NULL) { if (connp->in_tx->parsed_uri->port_number != -1) { // Check that the port in the URI is the same // as the port on which the client is talking // to the server if (connp->in_tx->parsed_uri->port_number != connp->conn->local_port) { // Incorrect port; use the real port instead connp->in_tx->parsed_uri->port_number = connp->conn->local_port; // TODO Log } } else { // Invalid port; use the real port instead connp->in_tx->parsed_uri->port_number = connp->conn->local_port; // TODO Log } } else { connp->in_tx->parsed_uri->port_number = connp->conn->local_port; } // Path if (connp->in_tx->parsed_uri->path == NULL) { connp->in_tx->parsed_uri->path = bstr_cstrdup("/"); if (connp->in_tx->parsed_uri->path == NULL) { return HTP_ERROR; } } } // Run hook REQUEST_LINE int rc = hook_run_all(connp->cfg->hook_request_line, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request line callback returned error (%d)", rc); return HTP_ERROR; } // Clean up. connp->in_line_len = 0; // Move on to the next phase. connp->in_state = htp_connp_REQ_PROTOCOL; return HTP_OK; } } return HTP_ERROR; } /** * The idle state is invoked before and after every transaction. Consequently, * it will start a new transaction when data is available and finalise a transaction * which has been processed. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_REQ_IDLE(htp_connp_t * connp) { // If we're here and a transaction object exists that // means we've just completed parsing a request. We need // to run the final hook and start over. if (connp->in_tx != NULL) { // Run hook REQUEST int rc = hook_run_all(connp->cfg->hook_request, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request callback returned error (%d)", rc); return HTP_ERROR; } // Start afresh connp->in_tx = NULL; } // We want to start parsing the next request (and change // the state from IDLE) only if there's at least one // byte of data available. Otherwise we could be creating // new structures even if there's no more data on the // connection. IN_TEST_NEXT_BYTE_OR_RETURN(connp); // Detect pipelining if (list_size(connp->conn->transactions) > connp->out_next_tx_index) { connp->conn->flags |= PIPELINED_CONNECTION; } // Parsing a new request connp->in_tx = htp_tx_create(connp->cfg, CFG_SHARED, connp->conn); if (connp->in_tx == NULL) return HTP_ERROR; connp->in_tx->connp = connp; list_add(connp->conn->transactions, connp->in_tx); connp->in_content_length = -1; connp->in_body_data_left = -1; connp->in_header_line_index = -1; connp->in_header_line_counter = 0; connp->in_chunk_request_index = connp->in_chunk_count; // Run hook TRANSACTION_START int rc = hook_run_all(connp->cfg->hook_transaction_start, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Transaction start callback returned error (%d)", rc); return HTP_ERROR; } // Change state into request line parsing connp->in_state = htp_connp_REQ_LINE; connp->in_tx->progress = TX_PROGRESS_REQ_LINE; return HTP_OK; } size_t htp_connp_req_data_consumed(htp_connp_t *connp) { return connp->in_current_offset; } /** * Process a chunk of inbound (client or request) data. * * @param connp * @param timestamp * @param data * @param len * @return HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_req_data(htp_connp_t *connp, htp_time_t timestamp, unsigned char *data, size_t len) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data(connp->in_status %x)\n", connp->in_status); fprint_raw_data(stderr, __FUNCTION__, data, len); #endif // Return if the connection has had a fatal error if (connp->in_status == STREAM_STATE_ERROR) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Inbound parser is in STREAM_STATE_ERROR"); #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (previous error)\n"); #endif return STREAM_STATE_ERROR; } // If the length of the supplied data chunk is zero, proceed // only if the stream has been closed. We do not allow zero-sized // chunks in the API, but we use it internally to force the parsers // to finalize parsing. if ((len == 0) && (connp->in_status != STREAM_STATE_CLOSED)) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Zero-length data chunks are not allowed"); #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (zero-length chunk)\n"); #endif return STREAM_STATE_ERROR; } // Store the current chunk information connp->in_timestamp = timestamp; connp->in_current_data = data; connp->in_current_len = len; connp->in_current_offset = 0; connp->in_chunk_count++; connp->conn->in_data_counter += len; connp->conn->in_packet_counter++; // Return without processing any data if the stream is in tunneling // mode (which it would be after an initial CONNECT transaction). if (connp->in_status == STREAM_STATE_TUNNEL) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_TUNNEL\n"); #endif return STREAM_STATE_TUNNEL; } // Invoke a processor, in a loop, until an error // occurs or until we run out of data. Many processors // will process a request, each pointing to the next // processor that needs to run. for (;;) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: in state=%s, progress=%s\n", htp_connp_in_state_as_string(connp), htp_tx_progress_as_string(connp->in_tx)); #endif // Return if there's been an error // or if we've run out of data. We are relying // on processors to add error messages, so we'll // keep quiet here. int rc = connp->in_state(connp); if (rc == HTP_OK) { if (connp->in_status == STREAM_STATE_TUNNEL) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_TUNNEL\n"); #endif return STREAM_STATE_TUNNEL; } } else { // Do we need more data? if (rc == HTP_DATA) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA\n"); #endif return STREAM_STATE_DATA; } // Check for suspended parsing if (rc == HTP_DATA_OTHER) { // We might have actually consumed the entire data chunk? if (connp->in_current_offset >= connp->in_current_len) { // Do not send STREAM_DATE_DATA_OTHER if we've // consumed the entire chunk #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (suspended parsing)\n"); #endif return STREAM_STATE_DATA; } else { // Partial chunk consumption #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA_OTHER\n"); #endif return STREAM_STATE_DATA_OTHER; } } // Remember that we've had an error. Errors are // (at least at present) not possible to recover from. connp->in_status = STREAM_STATE_ERROR; #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_ERROR (state response)\n"); #endif return STREAM_STATE_ERROR; } } return HTP_ERROR; } suricata-1.4.7/libhtp/htp/htp_decompressors.h0000644000000000000000000000253512253546156016234 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #ifndef _HTP_DECOMPRESSORS_H #define _HTP_DECOMPRESSORS_H typedef struct htp_decompressor_gzip_t htp_decompressor_gzip_t; typedef struct htp_decompressor_t htp_decompressor_t; #include "zlib.h" #define GZIP_BUF_SIZE 8192 #define GZIP_WINDOW_SIZE -15 #define DEFLATE_MAGIC_1 0x1f #define DEFLATE_MAGIC_2 0x8b struct htp_decompressor_t { int (*decompress)(htp_decompressor_t *, htp_tx_data_t *); int (*callback)(htp_tx_data_t *); void (*destroy)(htp_decompressor_t *); }; struct htp_decompressor_gzip_t { htp_decompressor_t super; int initialized; int zlib_initialized; uint8_t header[10]; uint8_t header_len; z_stream stream; unsigned char *buffer; unsigned long crc; }; htp_decompressor_t * htp_gzip_decompressor_create(htp_connp_t *connp); #endif /* _HTP_DECOMPRESSORS_H */ suricata-1.4.7/libhtp/htp/dslib.h0000644000000000000000000000571712253546156013573 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #ifndef _DSLIB_H #define _DSLIB_H #include "bstr.h" // IMPORTANT This library is used internally by the parser and you should // not rely on it in your code. The implementation may change at // some point in the future. // What we have here is two implementations of a list structure (array- and link-list-based), // and one implementation of a table (case-insensitive keys; multiple key values are allowed). // The lists can be used as a stack. // // TODO The table element retrieval if very inefficient at the moment. #define list_push(L, E) (L)->push(L, E) #define list_pop(L) (L)->pop(L) #define list_empty(L) (L)->empty(L) #define list_get(L, N) (L)->get((list_t *)L, N) #define list_replace(L, N, E) (L)->replace((list_t *)L, N, E) #define list_add(L, N) (L)->push(L, N) #define list_size(L) (L)->size(L) #define list_iterator_reset(L) (L)->iterator_reset(L) #define list_iterator_next(L) (L)->iterator_next(L) #define list_destroy(L) (L)->destroy(L) #define LIST_COMMON \ int (*push)(list_t *, void *); \ void *(*pop)(list_t *); \ int (*empty)(list_t *); \ void *(*get)(list_t *, size_t index); \ int (*replace)(list_t *, size_t index, void *); \ size_t (*size)(list_t *); \ void (*iterator_reset)(list_t *); \ void *(*iterator_next)(list_t *); \ void (*destroy)(list_t *) typedef struct list_t list_t; typedef struct list_array_t list_array_t; typedef struct list_linked_element_t list_linked_element_t; typedef struct list_linked_t list_linked_t; typedef struct table_t table_t; struct list_t { LIST_COMMON; }; struct list_linked_element_t { void *data; list_linked_element_t *next; }; struct list_linked_t { LIST_COMMON; list_linked_element_t *first; list_linked_element_t *last; }; struct list_array_t { LIST_COMMON; size_t first; size_t last; size_t max_size; size_t current_size; void **elements; size_t iterator_index; }; list_t *list_linked_create(void); list_t *list_array_create(size_t size); struct table_t { list_t *list; }; table_t *table_create(size_t size); int table_add(table_t *, bstr *, void *); void table_set(table_t *, bstr *, void *); void *table_get(table_t *, bstr *); void *table_getc(table_t *, char *); void table_iterator_reset(table_t *); bstr *table_iterator_next(table_t *, void **); size_t table_size(table_t *t); void table_destroy(table_t *); void table_clear(table_t *); #endif /* _DSLIB_H */ suricata-1.4.7/libhtp/htp/dslib.c0000644000000000000000000003016712253546156013563 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include #include #include "dslib.h" // -- Queue List -- /** * Add element to list. * * @param list * @param element * @return 1 on success, -1 on error (memory allocation failure) */ static int list_linked_push(list_t *_q, void *element) { list_linked_t *q = (list_linked_t *) _q; list_linked_element_t *qe = calloc(1, sizeof (list_linked_element_t)); if (qe == NULL) return -1; // Rememeber the element qe->data = element; // If the queue is empty, make this element first if (!q->first) { q->first = qe; } if (q->last) { q->last->next = qe; } q->last = qe; return 1; } /** * Remove one element from the beginning of the list. * * @param list * @return a pointer to the removed element, or NULL if the list is empty. */ static void *list_linked_pop(list_t *_q) { list_linked_t *q = (list_linked_t *) _q; void *r = NULL; if (!q->first) { return NULL; } list_linked_element_t *qe = q->first; q->first = qe->next; r = qe->data; if (!q->first) { q->last = NULL; } free(qe); return r; } /** * Is the list empty? * * @param list * @return 1 if the list is empty, 0 if it is not */ static int list_linked_empty(list_t *_q) { list_linked_t *q = (list_linked_t *) _q; if (!q->first) { return 1; } else { return 0; } } /** * Destroy list. This function will not destroy any of the * data stored in it. You'll have to do that manually beforehand. * * @param l */ void list_linked_destroy(list_linked_t *l) { // Free the list structures list_linked_element_t *temp = l->first; list_linked_element_t *prev = NULL; while (temp != NULL) { free(temp->data); prev = temp; temp = temp->next; free(prev); } // Free the list itself free(l); } /** * Create a new linked list. * * @return a pointer to the newly creted list (list_t), or NULL on memory allocation failure */ list_t *list_linked_create(void) { list_linked_t *q = calloc(1, sizeof (list_linked_t)); if (q == NULL) return NULL; q->push = list_linked_push; q->pop = list_linked_pop; q->empty = list_linked_empty; q->destroy = (void (*)(list_t *))list_linked_destroy; return (list_t *) q; } // -- Queue Array -- /** * Add new element to the end of the list, expanding the list * as necessary. * * @param list * @param element * * @return 1 on success or -1 on failure (memory allocation) */ static int list_array_push(list_t *_q, void *element) { list_array_t *q = (list_array_t *) _q; // Check if we're full if (q->current_size >= q->max_size) { int new_size = q->max_size * 2; void *newblock = NULL; if (q->first == 0) { // The simple case of expansion is when the first // element in the list resides in the first slot. In // that case we just add some new space to the end, // adjust the max_size and that's that. newblock = realloc(q->elements, new_size * sizeof (void *)); if (newblock == NULL) return -1; } else { // When the first element is not in the first // memory slot, we need to rearrange the order // of the elements in order to expand the storage area. newblock = malloc(new_size * sizeof (void *)); if (newblock == NULL) return -1; // Copy the beginning of the list to the beginning of the new memory block memcpy(newblock, (char *)q->elements + q->first * sizeof (void *), (q->max_size - q->first) * sizeof (void *)); // Append the second part of the list to the end memcpy((char *)newblock + (q->max_size - q->first) * sizeof (void *), q->elements, q->first * sizeof (void *)); free(q->elements); } q->first = 0; q->last = q->current_size; q->max_size = new_size; q->elements = newblock; } q->elements[q->last] = element; q->current_size++; q->last++; if (q->last == q->max_size) { q->last = 0; } return 1; } /** * Remove one element from the beginning of the list. * * @param list * @return the removed element, or NULL if the list is empty */ static void *list_array_pop(list_t *_q) { list_array_t *q = (list_array_t *) _q; void *r = NULL; if (q->current_size == 0) { return NULL; } r = q->elements[q->first]; q->first++; if (q->first == q->max_size) { q->first = 0; } q->current_size--; return r; } /** * Returns the size of the list. * * @param list */ static size_t list_array_size(list_t *_l) { return ((list_array_t *) _l)->current_size; } /** * Return the element at the given index. * * @param list * @param index * @return the desired element, or NULL if the list is too small, or * if the element at that position carries a NULL */ static void *list_array_get(list_t *_l, size_t idx) { list_array_t *l = (list_array_t *) _l; void *r = NULL; if (idx + 1 > l->current_size) return NULL; size_t i = l->first; r = l->elements[l->first]; while (idx--) { if (++i == l->max_size) { i = 0; } r = l->elements[i]; } return r; } /** * Replace the element at the given index with the provided element. * * @param list * @param index * @param element * * @return 1 if the element was replaced, or 0 if the list is too small */ static int list_array_replace(list_t *_l, size_t idx, void *element) { list_array_t *l = (list_array_t *) _l; if (idx + 1 > l->current_size) return 0; size_t i = l->first; while (idx--) { if (++i == l->max_size) { i = 0; } } l->elements[i] = element; return 1; } /** * Reset the list iterator. * * @param l */ void list_array_iterator_reset(list_array_t *l) { l->iterator_index = 0; } /** * Advance to the next list value. * * @param l * @return the next list value, or NULL if there aren't more elements * left to iterate over or if the element itself is NULL */ void *list_array_iterator_next(list_array_t *l) { void *r = NULL; if (l->iterator_index < l->current_size) { r = list_get(l, l->iterator_index); l->iterator_index++; } return r; } /** * Free the memory occupied by this list. This function assumes * the data elements were freed beforehand. * * @param l */ void list_array_destroy(list_array_t *l) { free(l->elements); free(l); } /** * Create new array-based list. * * @param size * @return newly allocated list (list_t) */ list_t *list_array_create(size_t size) { // Allocate the list structure list_array_t *q = calloc(1, sizeof (list_array_t)); if (q == NULL) return NULL; // Allocate the initial batch of elements q->elements = malloc(size * sizeof (void *)); if (q->elements == NULL) { free(q); return NULL; } // Initialise structure q->first = 0; q->last = 0; q->max_size = size; q->push = list_array_push; q->pop = list_array_pop; q->get = list_array_get; q->replace = list_array_replace; q->size = list_array_size; q->iterator_reset = (void (*)(list_t *))list_array_iterator_reset; q->iterator_next = (void *(*)(list_t *))list_array_iterator_next; q->destroy = (void (*)(list_t *))list_array_destroy; return (list_t *) q; } // -- Table -- /** * Create a new table structure. * * @param size * @return newly created table_t */ table_t *table_create(size_t size) { table_t *t = calloc(1, sizeof (table_t)); if (t == NULL) return NULL; // Use a list behind the scenes t->list = list_array_create(size * 2); if (t->list == NULL) { free(t); return NULL; } return t; } /** * Destroy a table. * * @param table */ void table_destroy(table_t * table) { // Free keys only int counter = 0; void *data = NULL; list_iterator_reset(table->list); while ((data = list_iterator_next(table->list)) != NULL) { // Free key if ((counter % 2) == 0) { free(data); } counter++; } list_destroy(table->list); free(table); } /** * Add a new table element. This function currently makes a copy of * the key, which is inefficient. * * @param table * @param key * @param element */ int table_add(table_t *table, bstr *key, void *element) { // Lowercase key bstr *lkey = bstr_dup_lower(key); if (lkey == NULL) { return -1; } // Add key if (list_add(table->list, lkey) != 1) { free(lkey); return -1; } // Add element if (list_add(table->list, element) != 1) { list_pop(table->list); free(lkey); return -1; } return 1; } /** * @param table * @param key */ static void *table_get_internal(table_t *table, bstr *key) { // Iterate through the list, comparing // keys with the parameter, return data if found. bstr *ts = NULL; list_iterator_reset(table->list); while ((ts = list_iterator_next(table->list)) != NULL) { void *data = list_iterator_next(table->list); if (bstr_cmp(ts, key) == 0) { return data; } } return NULL; } /** * Retrieve the first element in the table with the given * key (as a NUL-terminated string). * * @param table * @param cstr * @return table element, or NULL if not found */ void *table_getc(table_t *table, char *cstr) { if (table == NULL||cstr == NULL) return NULL; // TODO This is very inefficient bstr *key = bstr_cstrdup(cstr); if (key == NULL) return NULL; bstr_tolowercase(key); void *data = table_get_internal(table, key); free(key); return data; } /** * Retrieve the first element in the table with the given key. * * @param table * @param key * @return table element, or NULL if not found */ void *table_get(table_t *table, bstr *key) { if (table == NULL||key == NULL) return NULL; // TODO This is very inefficient bstr *lkey = bstr_dup_lower(key); if (lkey == NULL) return NULL; void *data = table_get_internal(table, lkey); free(lkey); return data; } /** * Reset the table iterator. * * @param table */ void table_iterator_reset(table_t *table) { list_iterator_reset(table->list); } /** * Advance to the next table element. * * @param t * @param data * @return pointer to the key and the element if there is a next element, NULL otherwise */ bstr *table_iterator_next(table_t *t, void **data) { bstr *s = list_iterator_next(t->list); if (s != NULL) { *data = list_iterator_next(t->list); } return s; } /** * Returns the size of the table. * * @param table * @return table size */ size_t table_size(table_t *table) { return list_size(table->list) / 2; } /** * Remove all elements from the table. * * @param table */ void table_clear(table_t *table) { // TODO Clear table by removing the existing elements if (table == NULL) return; size_t size = list_size(table->list); list_destroy(table->list); // Use a list behind the scenes table->list = list_array_create(size == 0 ? 10 : size); if (table->list == NULL) { free(table); } } #if 0 int main(int argc, char **argv) { list_t *q = list_linked_create(); list_push(q, "1"); list_push(q, "2"); list_push(q, "3"); list_push(q, "4"); char *s = NULL; while ((s = (char *) list_pop(q)) != NULL) { printf("Got: %s\n", s); } free(q); } #endif suricata-1.4.7/libhtp/htp/htp_decompressors.c0000644000000000000000000001560412253546156016230 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" #include "htp_decompressors.h" /** * Decompress a chunk of gzip-compressed data. * * @param drec * @param d */ static int htp_gzip_decompressor_decompress(htp_decompressor_gzip_t *drec, htp_tx_data_t *d) { size_t consumed = 0; // Return if we've previously had an error if (drec->initialized < 0) { return drec->initialized; } // Do we need to initialize? if (drec->initialized == 0) { // Check the header if ((drec->header_len == 0) && (d->len >= 10)) { // We have received enough data initialize; use the input buffer directly if ((d->data[0] != DEFLATE_MAGIC_1) || (d->data[1] != DEFLATE_MAGIC_2)) { htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "GZip decompressor: Magic bytes mismatch"); drec->initialized = -1; return -1; } if (d->data[3] == 0) { drec->initialized = 1; consumed = 10; } else if ((d->data[3] & (1 << 3)) || (d->data[3] & (1 << 4))) { /* skip past * - FNAME extension, which is a name ended in a NUL terminator * or * - FCOMMENT extension, which is a commend ended in a NULL terminator */ size_t len; for (len = 10; len < d->len && d->data[len] != '\0'; len++); drec->initialized = 1; consumed = len + 1; } else { htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "GZip decompressor: Unable to handle flags: %d", d->data[3]); drec->initialized = -1; return -1; } } else { // We do not (or did not) have enough bytes, so we have // to copy some data into our internal header buffer. // How many bytes do we need? size_t copylen = 10 - drec->header_len; // Is there enough in input? if (copylen > d->len) copylen = d->len; // Copy the bytes memcpy(drec->header + drec->header_len, d->data, copylen); drec->header_len += copylen; consumed = copylen; // Do we have enough now? if (drec->header_len == 10) { // We do! if ((drec->header[0] != DEFLATE_MAGIC_1) || (drec->header[1] != DEFLATE_MAGIC_2)) { htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "GZip decompressor: Magic bytes mismatch"); drec->initialized = -1; return -1; } if (drec->header[3] != 0) { htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "GZip decompressor: Unable to handle flags: %d", d->data[3]); drec->initialized = -1; return -1; } drec->initialized = 1; } else { // Need more data return 1; } } } // Decompress data int rc = 0; drec->stream.next_in = d->data + consumed; drec->stream.avail_in = d->len - consumed; while (drec->stream.avail_in != 0) { // If there's no more data left in the // buffer, send that information out if (drec->stream.avail_out == 0) { drec->crc = crc32(drec->crc, drec->buffer, GZIP_BUF_SIZE); // Prepare data for callback htp_tx_data_t d2; d2.tx = d->tx; d2.data = drec->buffer; d2.len = GZIP_BUF_SIZE; // Send decompressed data to callback if (drec->super.callback(&d2) < 0) { inflateEnd(&drec->stream); drec->zlib_initialized = 0; return -1; } drec->stream.next_out = drec->buffer; drec->stream.avail_out = GZIP_BUF_SIZE; } rc = inflate(&drec->stream, Z_NO_FLUSH); if (rc == Z_STREAM_END) { // How many bytes do we have? size_t len = GZIP_BUF_SIZE - drec->stream.avail_out; // Update CRC drec->crc = crc32(drec->crc, drec->buffer, len); // Prepare data for callback htp_tx_data_t d2; d2.tx = d->tx; d2.data = drec->buffer; d2.len = len; // Send decompressed data to callback if (drec->super.callback(&d2) < 0) { inflateEnd(&drec->stream); drec->zlib_initialized = 0; return -1; } // TODO Handle trailer return 1; } if (rc != Z_OK) { htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "GZip decompressor: inflate failed with %d", rc); inflateEnd(&drec->stream); drec->zlib_initialized = 0; return -1; } } return 1; } /** * Shut down gzip decompressor. * * @param drec */ static void htp_gzip_decompressor_destroy(htp_decompressor_gzip_t * drec) { if (drec == NULL) return; if (drec->zlib_initialized) { inflateEnd(&drec->stream); drec->zlib_initialized = 0; } free(drec->buffer); free(drec); } /** * Initialize gzip decompressor. * * @param connp */ htp_decompressor_t * htp_gzip_decompressor_create(htp_connp_t *connp) { htp_decompressor_gzip_t *drec = calloc(1, sizeof (htp_decompressor_gzip_t)); if (drec == NULL) return NULL; drec->super.decompress = (int (*)(htp_decompressor_t *, htp_tx_data_t *)) htp_gzip_decompressor_decompress; drec->super.destroy = (void (*)(htp_decompressor_t *))htp_gzip_decompressor_destroy; drec->buffer = malloc(GZIP_BUF_SIZE); if (drec->buffer == NULL) { free(drec); return NULL; } int rc = inflateInit2(&drec->stream, GZIP_WINDOW_SIZE); if (rc != Z_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "GZip decompressor: inflateInit2 failed with code %d", rc); inflateEnd(&drec->stream); free(drec->buffer); free(drec); return NULL; } drec->zlib_initialized = 1; drec->stream.avail_out = GZIP_BUF_SIZE; drec->stream.next_out = drec->buffer; return (htp_decompressor_t *) drec; } suricata-1.4.7/libhtp/htp/utf8_decoder.h0000644000000000000000000000430612253546156015042 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #ifndef _UTF8_DECODER_H #define _UTF8_DECODER_H /* HTP changes: * * - Changed the name of the function from "decode" to "utf8_decode" * - Created a separate header file * - Copied the licence from the web page * - Created a copy of the data and function "utf8_decode_allow_overlong", which * does not treat overlong characters as invalid. */ /* Copyright (c) 2008-2009 Bjoern Hoehrmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #define UTF8_ACCEPT 0 #define UTF8_REJECT 1 uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte); uint32_t utf8_decode_allow_overlong(uint32_t* state, uint32_t* codep, uint32_t byte); #endif /* _UTF8_DECODER_H */ suricata-1.4.7/libhtp/htp/Makefile.in0000644000000000000000000005562612253546170014372 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = htp DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(library_include_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" \ "$(DESTDIR)$(library_includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) libhtp_la_LIBADD = am__objects_1 = am__objects_2 = bstr.lo hooks.lo htp_config.lo \ htp_connection_parser.lo htp_request_apache_2_2.lo \ htp_request_generic.lo htp_request_parsers.lo \ htp_response_generic.lo htp_util.lo dslib.lo htp.lo \ htp_connection.lo htp_parsers.lo htp_request.lo \ htp_response.lo htp_transaction.lo utf8_decoder.lo \ htp_decompressors.lo am_libhtp_la_OBJECTS = $(am__objects_1) $(am__objects_2) libhtp_la_OBJECTS = $(am_libhtp_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libhtp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libhtp_la_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libhtp_la_SOURCES) DIST_SOURCES = $(libhtp_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(library_include_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENERIC_API_VERSION = @GENERIC_API_VERSION@ GENERIC_LIBRARY_NAME = @GENERIC_LIBRARY_NAME@ GENERIC_LIBRARY_VERSION = @GENERIC_LIBRARY_VERSION@ GENERIC_RELEASE = @GENERIC_RELEASE@ GENERIC_VERSION = @GENERIC_VERSION@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ h_sources = bstr.h dslib.h hooks.h htp.h utf8_decoder.h htp_decompressors.h c_sources = bstr.c hooks.c htp_config.c htp_connection_parser.c htp_request_apache_2_2.c htp_request_generic.c htp_request_parsers.c htp_response_generic.c htp_util.c dslib.c htp.c htp_connection.c htp_parsers.c htp_request.c htp_response.c htp_transaction.c utf8_decoder.c htp_decompressors.c library_includedir = $(includedir)/$(GENERIC_LIBRARY_NAME) library_include_HEADERS = $(h_sources) INCLUDES = -I$(top_srcdir) AM_CFLAGS = -D_GNU_SOURCE -g -O2 -Wall -Wextra -std=gnu99 -pedantic lib_LTLIBRARIES = libhtp.la libhtp_la_SOURCES = $(h_sources) $(c_sources) libhtp_la_LDFLAGS = -version-info $(GENERIC_LIBRARY_VERSION) -release $(GENERIC_RELEASE) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu htp/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu htp/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libhtp.la: $(libhtp_la_OBJECTS) $(libhtp_la_DEPENDENCIES) $(EXTRA_libhtp_la_DEPENDENCIES) $(AM_V_CCLD)$(libhtp_la_LINK) -rpath $(libdir) $(libhtp_la_OBJECTS) $(libhtp_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bstr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dslib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hooks.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_config.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_connection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_connection_parser.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_decompressors.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_parsers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_request.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_request_apache_2_2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_request_generic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_request_parsers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_response.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_response_generic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_transaction.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htp_util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8_decoder.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-library_includeHEADERS: $(library_include_HEADERS) @$(NORMAL_INSTALL) @list='$(library_include_HEADERS)'; test -n "$(library_includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(library_includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(library_includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(library_includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(library_includedir)" || exit $$?; \ done uninstall-library_includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(library_include_HEADERS)'; test -n "$(library_includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(library_includedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(library_includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-library_includeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES \ uninstall-library_includeHEADERS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES \ install-library_includeHEADERS install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES \ uninstall-library_includeHEADERS # 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: suricata-1.4.7/libhtp/htp/htp_transaction.c0000644000000000000000000001311512253546156015660 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" /** * Creates a new transaction structure. * * @param cfg * @param is_cfg_shared * @param conn * @return The newly created transaction, or NULL on memory allocation failure. */ htp_tx_t *htp_tx_create(htp_cfg_t *cfg, int is_cfg_shared, htp_conn_t *conn) { htp_tx_t *tx = calloc(1, sizeof (htp_tx_t)); if (tx == NULL) return NULL; tx->conn = conn; tx->cfg = cfg; tx->is_cfg_shared = is_cfg_shared; tx->conn = conn; tx->request_header_lines = list_array_create(32); tx->request_headers = table_create(32); tx->request_line_nul_offset = -1; tx->parsed_uri = calloc(1, sizeof (htp_uri_t)); tx->parsed_uri_incomplete = calloc(1, sizeof (htp_uri_t)); tx->response_header_lines = list_array_create(32); tx->response_headers = table_create(32); tx->request_protocol_number = -1; return tx; } /** * Destroys the supplied transaction. * * @param tx */ void htp_tx_destroy(htp_tx_t *tx) { bstr_free(tx->request_line); bstr_free(tx->request_method); bstr_free(tx->request_uri); bstr_free(tx->request_uri_normalized); bstr_free(tx->request_protocol); if (tx->parsed_uri != NULL) { bstr_free(tx->parsed_uri->scheme); bstr_free(tx->parsed_uri->username); bstr_free(tx->parsed_uri->password); bstr_free(tx->parsed_uri->hostname); bstr_free(tx->parsed_uri->port); bstr_free(tx->parsed_uri->path); bstr_free(tx->parsed_uri->query); bstr_free(tx->parsed_uri->fragment); free(tx->parsed_uri); } if (tx->parsed_uri_incomplete != NULL) { bstr_free(tx->parsed_uri_incomplete->scheme); bstr_free(tx->parsed_uri_incomplete->username); bstr_free(tx->parsed_uri_incomplete->password); bstr_free(tx->parsed_uri_incomplete->hostname); bstr_free(tx->parsed_uri_incomplete->port); bstr_free(tx->parsed_uri_incomplete->path); bstr_free(tx->parsed_uri_incomplete->query); bstr_free(tx->parsed_uri_incomplete->fragment); free(tx->parsed_uri_incomplete); } // Destroy request_header_lines htp_header_line_t *hl = NULL; if (tx->request_header_lines != NULL) { list_iterator_reset(tx->request_header_lines); while ((hl = list_iterator_next(tx->request_header_lines)) != NULL) { bstr_free(hl->line); bstr_free(hl->terminators); // No need to destroy hl->header because // htp_header_line_t does not own it. free(hl); } list_destroy(tx->request_header_lines); } // Destroy request_headers htp_header_t *h = NULL; if (tx->request_headers != NULL) { table_iterator_reset(tx->request_headers); while (table_iterator_next(tx->request_headers, (void **) & h) != NULL) { bstr_free(h->name); bstr_free(h->value); free(h); } table_destroy(tx->request_headers); } if (tx->request_headers_raw != NULL) { bstr_free(tx->request_headers_raw); } bstr_free(tx->response_line); bstr_free(tx->response_protocol); bstr_free(tx->response_status); bstr_free(tx->response_message); // Destroy response_header_lines hl = NULL; if (tx->response_header_lines != NULL) { list_iterator_reset(tx->response_header_lines); while ((hl = list_iterator_next(tx->response_header_lines)) != NULL) { bstr_free(hl->line); bstr_free(hl->terminators); // No need to destroy hl->header because // htp_header_line_t does not own it. free(hl); } list_destroy(tx->response_header_lines); } // Destroy response headers h = NULL; if (tx->response_headers) { table_iterator_reset(tx->response_headers); while (table_iterator_next(tx->response_headers, (void **) & h) != NULL) { bstr_free(h->name); bstr_free(h->value); free(h); } table_destroy(tx->response_headers); } // Tell the connection to remove this transaction // from the list htp_conn_remove_tx(tx->conn, tx); // Invalidate the pointer to this transactions held // by the connection parser. This is to allow a transaction // to be destroyed from within the final response callback. if (tx->connp != NULL) { if (tx->connp->out_tx == tx) { tx->connp->out_tx = NULL; } } free(tx); } /** * Returns the user data associated with this transaction. * * @param tx * @return A pointer to user data or NULL */ void *htp_tx_get_user_data(htp_tx_t *tx) { return tx->user_data; } /** * Sets the configuration that is to be used for this transaction. * * @param tx * @param cfg * @param is_cfg_shared */ void htp_tx_set_config(htp_tx_t *tx, htp_cfg_t *cfg, int is_cfg_shared) { tx->cfg = cfg; tx->is_cfg_shared = is_cfg_shared; } /** * Associates user data with this transaction. * * @param tx * @param user_data */ void htp_tx_set_user_data(htp_tx_t *tx, void *user_data) { tx->user_data = user_data; } suricata-1.4.7/libhtp/htp/htp_request_parsers.c0000644000000000000000000000535612253546156016572 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" #if 0 /** * */ int htp_header_parse_internal_strict(unsigned char *data, size_t len, htp_header_t *h) { size_t name_start, name_end; size_t value_start, value_end; // Deal with the name first name_start = name_end = 0; // Find where the header name ends while (name_end < len) { if (htp_is_lws(data[name_end]) || data[name_end] == ':') break; name_end++; } if (name_end == 0) { // Empty header name return -1; } if (name_end == len) { // TODO return -1; } // Is there any LWS before colon? size_t pos = name_end; while (pos < len) { if (!htp_is_lws(data[pos])) break; pos++; // TODO // return -1; } if (pos == len) { // TODO return -1; } // The next character must be a colon if (data[pos] != ':') { // TODO return -1; } // Move over the colon pos++; // Again, ignore any LWS while (pos < len) { if (!htp_is_lws(data[pos])) break; pos++; } if (pos == len) { // TODO return -1; } value_start = value_end = pos; while (value_end < len) { if (htp_is_lws(data[value_end])) break; value_end++; } h->name_offset = name_start; h->name_len = name_end - name_start; h->value_offset = value_start; h->value_len = value_end - value_start; return 1; } */ /** * */ htp_header_t *htp_connp_header_parse(htp_connp_t *reqp, unsigned char *data, size_t len) { htp_header_t *h = calloc(1, sizeof (htp_header_t)); if (h == NULL) return NULL; // Parse the header line if (reqp->impl_header_parse(data, len, h) < 0) { // Invalid header line h->is_parsed = 0; h->name = bstr_memdup(data, len); return h; } // Now extract the name and the value h->name = bstr_memdup(data + h->name_offset, h->name_len); h->value = bstr_memdup(data + h->value_offset, h->value_len); h->is_parsed = 1; // Because header names are case-insensitive, we will convert // the name to lowercase to use it as a lookup key. h->name_lowercase = bstr_tolowercase(h->name); return h; } #endif suricata-1.4.7/libhtp/htp/htp_response.c0000644000000000000000000007636012253546156015204 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include #include "htp.h" /** * Invoked whenever decompressed response body data becomes available. * * @param d * @return HTP_OK on state change, HTP_ERROR on error. */ static int htp_connp_RES_BODY_DECOMPRESSOR_CALLBACK(htp_tx_data_t *d) { // Invoke all callbacks int rc = hook_run_all(d->tx->connp->cfg->hook_response_body_data, d); if (rc != HTP_OK) { htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response body data callback returned error (%d)", rc); return HTP_ERROR; } return HTP_OK; } /** * Consumes bytes until the end of the current line. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_BODY_CHUNKED_DATA_END(htp_connp_t *connp) { // TODO We shouldn't really see anything apart from CR and LF, // so we should warn about anything else. for (;;) { OUT_NEXT_BYTE_OR_RETURN(connp); connp->out_tx->request_message_len++; if (connp->out_next_byte == LF) { connp->out_state = htp_connp_RES_BODY_CHUNKED_LENGTH; return HTP_OK; } } return HTP_ERROR; } /** * Processes a chunk of data. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_BODY_CHUNKED_DATA(htp_connp_t *connp) { htp_tx_data_t d; d.tx = connp->out_tx; d.data = &connp->out_current_data[connp->out_current_offset]; d.len = 0; for (;;) { OUT_NEXT_BYTE(connp); if (connp->out_next_byte == -1) { if (connp->out_tx->response_content_encoding != COMPRESSION_NONE) { connp->out_decompressor->decompress(connp->out_decompressor, &d); } else { // Send data to callbacks int rc = hook_run_all(connp->cfg->hook_response_body_data, &d); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response body data callback returned error (%d)", rc); return HTP_ERROR; } } // Ask for more data return HTP_DATA; } else { connp->out_tx->response_message_len++; connp->out_tx->response_entity_len++; connp->out_chunked_length--; d.len++; if (connp->out_chunked_length == 0) { // End of data chunk if (connp->out_tx->response_content_encoding != COMPRESSION_NONE) { connp->out_decompressor->decompress(connp->out_decompressor, &d); } else { // Send data to callbacks int rc = hook_run_all(connp->cfg->hook_response_body_data, &d); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response body data callback returned error (%d)", rc); return HTP_ERROR; } } connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA_END; return HTP_OK; } } } return HTP_ERROR; } /** * Extracts chunk length. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_BODY_CHUNKED_LENGTH(htp_connp_t *connp) { for (;;) { OUT_COPY_BYTE_OR_RETURN(connp); connp->out_tx->response_message_len++; // Have we reached the end of the line? if (connp->out_next_byte == LF) { htp_chomp(connp->out_line, &connp->out_line_len); // Extract chunk length connp->out_chunked_length = htp_parse_chunked_length(connp->out_line, connp->out_line_len); // Cleanup for the next line connp->out_line_len = 0; // Handle chunk length if (connp->out_chunked_length > 0) { // More data available // TODO Add a check for chunk length connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA; } else if (connp->out_chunked_length == 0) { // End of data connp->out_state = htp_connp_RES_HEADERS; connp->out_tx->progress = TX_PROGRESS_RES_TRAILER; } else { // Invalid chunk length htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response chunk encoding: Invalid chunk length: %d", connp->out_chunked_length); return HTP_ERROR; } return HTP_OK; } } return HTP_ERROR; } /** * Processes identity response body. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_BODY_IDENTITY(htp_connp_t *connp) { htp_tx_data_t d; d.tx = connp->out_tx; d.data = &connp->out_current_data[connp->out_current_offset]; d.len = 0; for (;;) { OUT_NEXT_BYTE(connp); if (connp->out_next_byte == -1) { // End of chunk // Send data to callbacks if (d.len != 0) { if (connp->out_tx->response_content_encoding != COMPRESSION_NONE) { connp->out_decompressor->decompress(connp->out_decompressor, &d); } else { int rc = hook_run_all(connp->cfg->hook_response_body_data, &d); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response body data callback returned error (%d)", rc); return HTP_ERROR; } } } // If we don't know the length, then we must check // to see if the stream closed; that would signal the // end of the response body (and the end of the transaction). if ((connp->out_content_length == -1) && (connp->out_status == STREAM_STATE_CLOSED)) { connp->out_state = htp_connp_RES_IDLE; connp->out_tx->progress = TX_PROGRESS_DONE; return HTP_OK; } else { // Ask for more data return HTP_DATA; } } else { connp->out_tx->response_message_len++; connp->out_tx->response_entity_len++; if (connp->out_body_data_left > 0) { // We know the length of response body connp->out_body_data_left--; d.len++; if (connp->out_body_data_left == 0) { // End of body // Send data to callbacks if (d.len != 0) { if (connp->out_tx->response_content_encoding != COMPRESSION_NONE) { connp->out_decompressor->decompress(connp->out_decompressor, &d); } else { int rc = hook_run_all(connp->cfg->hook_response_body_data, &d); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response body data callback returned error (%d)", rc); return HTP_ERROR; } } } // Done connp->out_state = htp_connp_RES_IDLE; connp->out_tx->progress = TX_PROGRESS_DONE; return HTP_OK; } } else { d.len++; // We don't know the length of the response body, which means // that the body will consume all data until the connection // is closed. // // We don't need to do anything here. } } } return HTP_ERROR; } /** * Determines presence (and encoding) of a response body. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_BODY_DETERMINE(htp_connp_t *connp) { // If the request uses the CONNECT method, then not only are we // to assume there's no body, but we need to ignore all // subsequent data in the stream. if ((connp->out_tx->request_method_number == M_CONNECT) &&(connp->out_tx->response_status_number >= 200) &&(connp->out_tx->response_status_number <= 299)) { connp->in_status = STREAM_STATE_TUNNEL; connp->out_status = STREAM_STATE_TUNNEL; connp->out_state = htp_connp_RES_IDLE; connp->out_tx->progress = TX_PROGRESS_DONE; return HTP_OK; } // Check for an interim "100 Continue" // response. Ignore it if found, and revert back to RES_FIRST_LINE. if (connp->out_tx->response_status_number == 100) { if (connp->out_tx->seen_100continue != 0) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Already seen 100-Continue"); return HTP_ERROR; } // Ignore any response headers set table_clear(connp->out_tx->response_headers); connp->out_state = htp_connp_RES_LINE; connp->out_tx->progress = TX_PROGRESS_RES_LINE; connp->out_tx->seen_100continue++; return HTP_OK; } // Check for compression htp_header_t *ce = table_getc(connp->out_tx->response_headers, "content-encoding"); if (ce != NULL) { // TODO Improve detection // TODO How would a Content-Range header affect us? if ((bstr_cmpc(ce->value, "gzip") == 0) || (bstr_cmpc(ce->value, "x-gzip") == 0)) { connp->out_decompressor = (htp_decompressor_t *) htp_gzip_decompressor_create(connp); if (connp->out_decompressor != NULL) { connp->out_tx->response_content_encoding = COMPRESSION_GZIP; connp->out_decompressor->callback = htp_connp_RES_BODY_DECOMPRESSOR_CALLBACK; } else { // No need to do anything; the error will have already // been reported by the failed decompressor. } } } // 1. Any response message which MUST NOT include a message-body // (such as the 1xx, 204, and 304 responses and any response to a HEAD // request) is always terminated by the first empty line after the // header fields, regardless of the entity-header fields present in the // message. if (((connp->out_tx->response_status_number >= 100) && (connp->out_tx->response_status_number <= 199)) || (connp->out_tx->response_status_number == 204) || (connp->out_tx->response_status_number == 304) || (connp->out_tx->request_method_number == M_HEAD)) { // There's no response body connp->out_state = htp_connp_RES_IDLE; } else { // We have a response body htp_header_t *cl = table_getc(connp->out_tx->response_headers, "content-length"); htp_header_t *te = table_getc(connp->out_tx->response_headers, "transfer-encoding"); // 2. If a Transfer-Encoding header field (section 14.40) is present and // indicates that the "chunked" transfer coding has been applied, then // the length is defined by the chunked encoding (section 3.6). if (te != NULL) { if (bstr_cmpc(te->value, "chunked") != 0) { // Invalid T-E header value htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid T-E value in response"); } // If the T-E header is present we are going to use it. connp->out_tx->response_transfer_coding = CHUNKED; // We are still going to check for the presence of C-L if (cl != NULL) { // This is a violation of the RFC connp->out_tx->flags |= HTP_REQUEST_SMUGGLING; // TODO } connp->out_state = htp_connp_RES_BODY_CHUNKED_LENGTH; connp->out_tx->progress = TX_PROGRESS_RES_BODY; }// 3. If a Content-Length header field (section 14.14) is present, its // value in bytes represents the length of the message-body. else if (cl != NULL) { // We know the exact length connp->out_tx->response_transfer_coding = IDENTITY; // Check for multiple C-L headers if (cl->flags & HTP_FIELD_REPEATED) { connp->out_tx->flags |= HTP_REQUEST_SMUGGLING; // TODO Log } // Get body length int i = htp_parse_content_length(cl->value); if (i < 0) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid C-L field in response"); return HTP_ERROR; } else { connp->out_content_length = i; connp->out_body_data_left = connp->out_content_length; if (connp->out_content_length != 0) { connp->out_state = htp_connp_RES_BODY_IDENTITY; connp->out_tx->progress = TX_PROGRESS_RES_BODY; } else { connp->out_state = htp_connp_RES_IDLE; connp->out_tx->progress = TX_PROGRESS_DONE; } } } else { // 4. If the message uses the media type "multipart/byteranges", which is // self-delimiting, then that defines the length. This media type MUST // NOT be used unless the sender knows that the recipient can parse it; // the presence in a request of a Range header with multiple byte-range // specifiers implies that the client can parse multipart/byteranges // responses. htp_header_t *ct = table_getc(connp->out_tx->response_headers, "content-type"); if (ct != NULL) { // TODO Handle multipart/byteranges if (bstr_indexofc_nocase(ct->value, "multipart/byteranges") != -1) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "C-T multipart/byteranges in responses not supported"); return HTP_ERROR; } } // 5. By the server closing the connection. (Closing the connection // cannot be used to indicate the end of a request body, since that // would leave no possibility for the server to send back a response.) connp->out_state = htp_connp_RES_BODY_IDENTITY; connp->out_tx->progress = TX_PROGRESS_RES_BODY; } } // NOTE We do not need to check for short-style HTTP/0.9 requests here because // that is done earlier, before response line parsing begins // Run hook RESPONSE_HEADERS_COMPLETE int rc = hook_run_all(connp->cfg->hook_response_headers, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response headers callback returned error (%d)", rc); return HTP_ERROR; } return HTP_OK; } /** * Parses response headers. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_HEADERS(htp_connp_t *connp) { for (;;) { OUT_COPY_BYTE_OR_RETURN(connp); if (connp->out_header_line == NULL) { connp->out_header_line = calloc(1, sizeof (htp_header_line_t)); if (connp->out_header_line == NULL) return HTP_ERROR; connp->out_header_line->first_nul_offset = -1; } // Keep track of NUL bytes if (connp->out_next_byte == 0) { // Store the offset of the first NUL if (connp->out_header_line->has_nulls == 0) { connp->out_header_line->first_nul_offset = connp->out_line_len; } // Remember how many NULs there were connp->out_header_line->flags |= HTP_FIELD_NUL_BYTE; connp->out_header_line->has_nulls++; } // Have we reached the end of the line? if (connp->out_next_byte == LF) { #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, connp->out_line, connp->out_line_len); #endif // Should we terminate headers? if (htp_connp_is_line_terminator(connp, connp->out_line, connp->out_line_len)) { // Terminator line // Parse previous header, if any if (connp->out_header_line_index != -1) { if (connp->cfg->process_response_header(connp) != HTP_OK) { // Note: downstream responsible for error logging return HTP_ERROR; } // Reset index connp->out_header_line_index = -1; } // Cleanup free(connp->out_header_line); connp->out_line_len = 0; connp->out_header_line = NULL; // We've seen all response headers if (connp->out_tx->progress == TX_PROGRESS_RES_HEADERS) { // Determine if this response has a body connp->out_state = htp_connp_RES_BODY_DETERMINE; } else { // Run hook response_TRAILER int rc = hook_run_all(connp->cfg->hook_response_trailer, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response trailer callback returned error (%d)", rc); return HTP_ERROR; } // We've completed parsing this response connp->out_state = htp_connp_RES_IDLE; } return HTP_OK; } // Prepare line for consumption size_t raw_out_line_len = connp->out_line_len; htp_chomp(connp->out_line, &connp->out_line_len); // Check for header folding if (htp_connp_is_line_folded(connp->out_line, connp->out_line_len) == 0) { // New header line // Parse previous header, if any if (connp->out_header_line_index != -1) { if (connp->cfg->process_response_header(connp) != HTP_OK) { // Note: downstream responsible for error logging return HTP_ERROR; } // Reset index connp->out_header_line_index = -1; } // Remember the index of the fist header line connp->out_header_line_index = connp->out_header_line_counter; } else { // Folding; check that there's a previous header line to add to if (connp->out_header_line_index == -1) { if (!(connp->out_tx->flags & HTP_INVALID_FOLDING)) { connp->out_tx->flags |= HTP_INVALID_FOLDING; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid response field folding"); } } } // Add the raw header line to the list if (raw_out_line_len > connp->out_line_len) { if (raw_out_line_len - connp->out_line_len == 2 && connp->out_line[connp->out_line_len] == 0x0d && connp->out_line[connp->out_line_len + 1] == 0x0a) { connp->out_header_line->terminators = NULL; } else { connp->out_header_line->terminators = bstr_memdup((char *) connp->out_line + connp->out_line_len, raw_out_line_len - connp->out_line_len); if (connp->out_header_line->terminators == NULL) { return HTP_ERROR; } } } else { connp->out_header_line->terminators = NULL; } connp->out_header_line->line = bstr_memdup((char *) connp->out_line, connp->out_line_len); if (connp->out_header_line->line == NULL) { return HTP_ERROR; } list_add(connp->out_tx->response_header_lines, connp->out_header_line); connp->out_header_line = NULL; // Cleanup for the next line connp->out_line_len = 0; if (connp->out_header_line_index == -1) { connp->out_header_line_index = connp->out_header_line_counter; } connp->out_header_line_counter++; } } return HTP_ERROR; } /** * Parses response line. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_LINE(htp_connp_t *connp) { for (;;) { // Get one byte OUT_COPY_BYTE_OR_RETURN(connp); // Have we reached the end of the line? if (connp->out_next_byte == LF) { #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, connp->out_line, connp->out_line_len); #endif // Is this a line that should be ignored? if (htp_connp_is_line_ignorable(connp, connp->out_line, connp->out_line_len)) { // We have an empty/whitespace line, which we'll note, ignore and move on connp->out_tx->response_ignored_lines++; // TODO How many lines are we willing to accept? // Start again connp->out_line_len = 0; return HTP_OK; } // Process response line htp_chomp(connp->out_line, &connp->out_line_len); // Deallocate previous response line allocations, which we woud have on a 100 response // TODO Consider moving elsewhere; no need to make these checks on every response if (connp->out_tx->response_line != NULL) { bstr_free(connp->out_tx->response_line); } if (connp->out_tx->response_protocol != NULL) { bstr_free(connp->out_tx->response_protocol); } if (connp->out_tx->response_status != NULL) { bstr_free(connp->out_tx->response_status); } if (connp->out_tx->response_message != NULL) { bstr_free(connp->out_tx->response_message); } connp->out_tx->response_line = bstr_memdup((char *) connp->out_line, connp->out_line_len); if (connp->out_tx->response_line == NULL) { return HTP_ERROR; } // Parse response line if (connp->cfg->parse_response_line(connp) != HTP_OK) { // Note: downstream responsible for error logging return HTP_ERROR; } // Run hook RESPONSE_LINE int rc = hook_run_all(connp->cfg->hook_response_line, connp); if (rc != HOOK_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response line callback returned error (%d)", rc); return HTP_ERROR; } // Clean up. connp->out_line_len = 0; // Move on to the next phase. connp->out_state = htp_connp_RES_HEADERS; connp->out_tx->progress = TX_PROGRESS_RES_HEADERS; return HTP_OK; } } return HTP_ERROR; } size_t htp_connp_res_data_consumed(htp_connp_t *connp) { return connp->out_current_offset; } /** * The response idle state will initialize response processing, as well as * finalize each transactions after we are done with it. * * @param connp * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. */ int htp_connp_RES_IDLE(htp_connp_t * connp) { // If we're here and an outgoing transaction object exists that // means we've just completed parsing a response. We need // to run the final hook in a transaction and start over. if (connp->out_tx != NULL) { // Shut down the decompressor, if we've used one if (connp->out_decompressor != NULL) { connp->out_decompressor->destroy(connp->out_decompressor); connp->out_decompressor = NULL; } connp->out_tx->progress = TX_PROGRESS_DONE; // Run hook RESPONSE int rc = hook_run_all(connp->cfg->hook_response, connp); if (rc != HTP_OK) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response callback returned error (%d)", rc); return HTP_ERROR; } // Check if the inbound parser is waiting on us. If it is that means that // there might be request data that the inbound parser hasn't consumed yet. // If we don't stop parsing we might encounter a response without a // request. if ((connp->in_status == STREAM_STATE_DATA_OTHER) && (connp->in_tx == connp->out_tx)) { connp->out_tx = NULL; return HTP_DATA_OTHER; } // Start afresh connp->out_tx = NULL; } // We want to start parsing the next response (and change // the state from IDLE) only if there's at least one // byte of data available. Otherwise we could be creating // new structures even if there's no more data on the // connection. OUT_TEST_NEXT_BYTE_OR_RETURN(connp); // Parsing a new response // Find the next outgoing transaction connp->out_tx = list_get(connp->conn->transactions, connp->out_next_tx_index); if (connp->out_tx == NULL) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Unable to match response to request"); return HTP_ERROR; } // We've used one transaction connp->out_next_tx_index++; // TODO Detect state mismatch connp->out_content_length = -1; connp->out_body_data_left = -1; connp->out_header_line_index = -1; connp->out_header_line_counter = 0; // Change state into response line parsing, except if we're following // a short HTTP/0.9 request, because such requests to not have a // response line and headers. if (connp->out_tx->protocol_is_simple) { connp->out_tx->response_transfer_coding = IDENTITY; connp->out_state = htp_connp_RES_BODY_IDENTITY; connp->out_tx->progress = TX_PROGRESS_RES_BODY; } else { connp->out_state = htp_connp_RES_LINE; connp->out_tx->progress = TX_PROGRESS_RES_LINE; } return HTP_OK; } /** * Process a chunk of outbound (server or response) data. * * @param connp * @param timestamp * @param data * @param len * @return HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed */ int htp_connp_res_data(htp_connp_t *connp, htp_time_t timestamp, unsigned char *data, size_t len) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data(connp->out_status %x)\n", connp->out_status); fprint_raw_data(stderr, __FUNCTION__, data, len); #endif // Return if the connection has had a fatal error if (connp->out_status == STREAM_STATE_ERROR) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Outbound parser is in STREAM_STATE_ERROR"); #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_DATA (previous error)\n"); #endif return STREAM_STATE_ERROR; } // If the length of the supplied data chunk is zero, proceed // only if the stream has been closed. We do not allow zero-sized // chunks in the API, but we use it internally to force the parsers // to finalize parsing. if ((len == 0) && (connp->out_status != STREAM_STATE_CLOSED)) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Zero-length data chunks are not allowed"); #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_DATA (zero-length chunk)\n"); #endif return STREAM_STATE_ERROR; } // Store the current chunk information connp->out_timestamp = timestamp; connp->out_current_data = data; connp->out_current_len = len; connp->out_current_offset = 0; connp->conn->out_data_counter += len; connp->conn->out_packet_counter++; // Return without processing any data if the stream is in tunneling // mode (which it would be after an initial CONNECT transaction. if (connp->out_status == STREAM_STATE_TUNNEL) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_TUNNEL\n"); #endif return STREAM_STATE_TUNNEL; } // Invoke a processor, in a loop, until an error // occurs or until we run out of data. Many processors // will process a request, each pointing to the next // processor that needs to run. for (;;) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: out state=%s, progress=%s\n", htp_connp_out_state_as_string(connp), htp_tx_progress_as_string(connp->out_tx)); #endif // Return if there's been an error // or if we've run out of data. We are relying // on processors to add error messages, so we'll // keep quiet here. int rc = connp->out_state(connp); if (rc == HTP_OK) { if (connp->out_status == STREAM_STATE_TUNNEL) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_TUNNEL\n"); #endif return STREAM_STATE_TUNNEL; } } else { // Do we need more data? if (rc == HTP_DATA) { return STREAM_STATE_DATA; } // Check for suspended parsing if (rc == HTP_DATA_OTHER) { // We might have actually consumed the entire data chunk? if (connp->out_current_offset >= connp->out_current_len) { // Do not send STREAM_DATE_DATA_OTHER if we've // consumed the entire chunk #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_DATA (suspended parsing)\n"); #endif return STREAM_STATE_DATA; } else { // Partial chunk consumption #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA_OTHER\n"); #endif return STREAM_STATE_DATA_OTHER; } } // Remember that we've had an error. Errors are // not possible to recover from. connp->out_status = STREAM_STATE_ERROR; return STREAM_STATE_ERROR; } } return HTP_ERROR; } suricata-1.4.7/libhtp/htp/utf8_decoder.c0000644000000000000000000001105212253546156015031 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ /* Copyright (c) 2008-2009 Bjoern Hoehrmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Copyright (c) 2008-2009 Bjoern Hoehrmann // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. #include "utf8_decoder.h" static const uint8_t utf8d[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 }; static const uint8_t utf8d_allow_overlong[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df; changed c0 and c1 0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef; changed e0 0x6,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff; changed f0 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 }; inline uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) { uint32_t type = utf8d[byte]; *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte); *state = utf8d[256 + *state*16 + type]; return *state; } inline uint32_t utf8_decode_allow_overlong(uint32_t* state, uint32_t* codep, uint32_t byte) { uint32_t type = utf8d_allow_overlong[byte]; *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte); *state = utf8d[256 + *state*16 + type]; return *state; } suricata-1.4.7/libhtp/htp/htp_connection_parser.c0000644000000000000000000002033312253546156017046 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" // NOTE The parser contains a lot of duplicated code. That is on purpose. // // Within the request parser alone there are several states in which // bytes are copied into the line buffer and lines are processed one at a time. // This code could be made more elegant by adding a new line-reading state along // with a what-fn-to-invoke-to-handle-line pointer. // // Furthermore, the entire request parser is terribly similar to the response parser. // It is imaginable that a single parser could handle both. // // After some thought, I decided not to make any changes (at least not for the time // being). State-based parsers are sometimes difficult to understand. I remember trying // to figure one once and I had a hard time following the logic because each function // was small and did exactly one thing. There was jumping all around. You could probably // say that it was elegant, but I saw it as difficult to understand, verify and maintain. // // Thus, I am keeping this inelegant but quite straightforward parser with duplicated code, // mostly for the sake of maintenance. // // For the time being, anyway. I will review at a later time. /** * Clears an existing parser error, if any. * * @param connp */ void htp_connp_clear_error(htp_connp_t *connp) { connp->last_error = NULL; } /** * Closes the connection associated with the supplied parser. * * @param connp * @param timestamp */ void htp_connp_close(htp_connp_t *connp, htp_time_t timestamp) { // Update internal information connp->conn->close_timestamp = timestamp; connp->in_status = STREAM_STATE_CLOSED; connp->out_status = STREAM_STATE_CLOSED; // Call the parsers one last time, which will allow them // to process the events that depend on stream closure htp_connp_req_data(connp, timestamp, NULL, 0); htp_connp_res_data(connp, timestamp, NULL, 0); } /** * Creates a new connection parser using the provided configuration. Because * the configuration structure is used directly, in a multithreaded environment * you are not allowed to change the structure, ever. If you have a need to * change configuration on per-connection basis, make a copy of the configuration * structure to go along with every connection parser. * * @param cfg * @return A pointer to a newly created htp_connp_t instance. */ htp_connp_t *htp_connp_create(htp_cfg_t *cfg) { htp_connp_t *connp = calloc(1, sizeof (htp_connp_t)); if (connp == NULL) return NULL; // Use the supplied configuration structure connp->cfg = cfg; // Create a new connection object connp->conn = htp_conn_create(connp); if (connp->conn == NULL) { free(connp); return NULL; } connp->in_status = HTP_OK; // Request parsing connp->in_line_size = cfg->field_limit_hard; connp->in_line_len = 0; connp->in_line = malloc(connp->in_line_size); if (connp->in_line == NULL) { htp_conn_destroy(connp->conn); free(connp); return NULL; } connp->in_header_line_index = -1; connp->in_state = htp_connp_REQ_IDLE; // Response parsing connp->out_line_size = cfg->field_limit_hard; connp->out_line_len = 0; connp->out_line = malloc(connp->out_line_size); if (connp->out_line == NULL) { free(connp->in_line); htp_conn_destroy(connp->conn); free(connp); return NULL; } connp->out_header_line_index = -1; connp->out_state = htp_connp_RES_IDLE; connp->in_status = STREAM_STATE_NEW; connp->out_status = STREAM_STATE_NEW; return connp; } /** * Creates a new configuration parser, making a copy of the supplied * configuration structure. * * @param cfg * @return A pointer to a newly created htp_connp_t instance. */ htp_connp_t *htp_connp_create_copycfg(htp_cfg_t *cfg) { htp_connp_t *connp = htp_connp_create(cfg); if (connp == NULL) return NULL; connp->cfg = htp_config_copy(cfg); if (connp->cfg == NULL) { htp_connp_destroy(connp); return NULL; } connp->is_cfg_private = 1; return connp; } /** * Destroys the connection parser and its data structures, leaving * the connection data intact. * * @param connp */ void htp_connp_destroy(htp_connp_t *connp) { if (connp == NULL) return; if (connp->out_decompressor != NULL) { connp->out_decompressor->destroy(connp->out_decompressor); connp->out_decompressor = NULL; } if (connp->in_header_line != NULL) { if (connp->in_header_line->line != NULL) { free(connp->in_header_line->line); } free(connp->in_header_line); } if (connp->in_line != NULL) free(connp->in_line); if (connp->out_header_line != NULL) { if (connp->out_header_line->line != NULL) { free(connp->out_header_line->line); } free(connp->out_header_line); } if (connp->out_line != NULL) free(connp->out_line); // Destroy the configuration structure, but only // if it is our private copy if ((connp->is_cfg_private) && (connp->cfg != NULL)) { htp_config_destroy(connp->cfg); } free(connp); } /** * Destroys the connection parser, its data structures, as well * as the connection and its transactions. * * @param connp */ void htp_connp_destroy_all(htp_connp_t *connp) { if (connp == NULL) return; if (connp->conn != NULL) { // Destroy connection htp_conn_destroy(connp->conn); connp->conn = NULL; } // Destroy everything else htp_connp_destroy(connp); } /** * Retrieve the user data associated with this connection parser. * * @param connp * @return User data, or NULL if there isn't any. */ void *htp_connp_get_data(htp_connp_t *connp) { return connp->user_data; } /** * Returns the last error that occured with this connection parser. Do note, however, * that the value in this field will only be valid immediately after an error condition, * but it is not guaranteed to remain valid if the parser is invoked again. * * @param connp * @return A pointer to an htp_log_t instance if there is an error, or NULL * if there isn't. */ htp_log_t *htp_connp_get_last_error(htp_connp_t *connp) { return connp->last_error; } /** * Opens connection. * * @param connp * @param remote_addr Remote address * @param remote_port Remote port * @param local_addr Local address * @param local_port Local port * @param timestamp */ void htp_connp_open(htp_connp_t *connp, const char *remote_addr, int remote_port, const char *local_addr, int local_port, htp_time_t timestamp) { if ((connp->in_status != STREAM_STATE_NEW) || (connp->out_status != STREAM_STATE_NEW)) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Connection is already open"); return; } if (remote_addr != NULL) { connp->conn->remote_addr = strdup(remote_addr); if (connp->conn->remote_addr == NULL) return; } connp->conn->remote_port = remote_port; if (local_addr != NULL) { connp->conn->local_addr = strdup(local_addr); if (connp->conn->local_addr == NULL) { if (connp->conn->remote_addr != NULL) { free(connp->conn->remote_addr); } return; } } connp->conn->local_port = local_port; connp->conn->open_timestamp = timestamp; connp->in_status = STREAM_STATE_OPEN; connp->out_status = STREAM_STATE_OPEN; } /** * Associate user data with the supplied parser. * * @param connp * @param user_data */ void htp_connp_set_user_data(htp_connp_t *connp, void *user_data) { connp->user_data = user_data; } void *htp_connp_get_user_data(htp_connp_t *connp) { return(connp->user_data); } suricata-1.4.7/libhtp/htp/Makefile.am0000644000000000000000000000133012253546156014344 00000000000000 h_sources = bstr.h dslib.h hooks.h htp.h utf8_decoder.h htp_decompressors.h c_sources = bstr.c hooks.c htp_config.c htp_connection_parser.c htp_request_apache_2_2.c htp_request_generic.c htp_request_parsers.c htp_response_generic.c htp_util.c dslib.c htp.c htp_connection.c htp_parsers.c htp_request.c htp_response.c htp_transaction.c utf8_decoder.c htp_decompressors.c library_includedir = $(includedir)/$(GENERIC_LIBRARY_NAME) library_include_HEADERS = $(h_sources) INCLUDES = -I$(top_srcdir) AM_CFLAGS = -D_GNU_SOURCE -g -O2 -Wall -Wextra -std=gnu99 -pedantic lib_LTLIBRARIES= libhtp.la libhtp_la_SOURCES= $(h_sources) $(c_sources) libhtp_la_LDFLAGS= -version-info $(GENERIC_LIBRARY_VERSION) -release $(GENERIC_RELEASE) suricata-1.4.7/libhtp/htp/htp_response_generic.c0000644000000000000000000002073512253546156016673 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" /** * Generic response line parser. * * @param connp * @return HTP status */ int htp_parse_response_line_generic(htp_connp_t *connp) { htp_tx_t *tx = connp->out_tx; unsigned char *data = (unsigned char *)bstr_ptr(tx->response_line); size_t len = bstr_len(tx->response_line); size_t pos = 0; // The request method starts at the beginning of the // line and ends with the first whitespace character. while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } tx->response_protocol = bstr_memdup((char *)data, pos); if (tx->response_protocol == NULL) { return HTP_ERROR; } tx->response_protocol_number = htp_parse_protocol(tx->response_protocol); #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->response_protocol), bstr_len(tx->response_protocol)); #endif // Ignore whitespace after response protocol while ((pos < len) && (isspace(data[pos]))) { pos++; } size_t start = pos; // Find the next whitespace character while ((pos < len) && (!htp_is_space(data[pos]))) { pos++; } tx->response_status = bstr_memdup((char *)data + start, pos - start); if (tx->response_status == NULL) { return HTP_ERROR; } tx->response_status_number = htp_parse_status(tx->response_status); #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->response_status), bstr_len(tx->response_status)); #endif // Ignore whitespace that follows while ((pos < len) && (isspace(data[pos]))) { pos++; } tx->response_message = bstr_memdup((char *)data + pos, len - pos); if (tx->response_message == NULL) { return HTP_ERROR; } #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->response_message), bstr_len(tx->response_message)); #endif return HTP_OK; } /** * Generic response header parser. * * @param connp * @param h * @param data * @param len * @return HTP status */ int htp_parse_response_header_generic(htp_connp_t *connp, htp_header_t *h, char *data, size_t len) { size_t name_start, name_end; size_t value_start, value_end; name_start = 0; // Look for the colon size_t colon_pos = 0; while ((colon_pos < len) && (data[colon_pos] != ':')) colon_pos++; if (colon_pos == len) { // Missing colon h->flags |= HTP_FIELD_UNPARSEABLE; if (!(connp->out_tx->flags & HTP_FIELD_UNPARSEABLE)) { connp->out_tx->flags |= HTP_FIELD_UNPARSEABLE; // Only log once per transaction htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response field invalid: colon missing"); } return HTP_ERROR; } if (colon_pos == 0) { // Empty header name h->flags |= HTP_FIELD_INVALID; if (!(connp->out_tx->flags & HTP_FIELD_INVALID)) { connp->out_tx->flags |= HTP_FIELD_INVALID; // Only log once per transaction htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Response field invalid: empty name"); } } name_end = colon_pos; // Ignore LWS after field-name size_t prev = name_end - 1; while ((prev > name_start) && (htp_is_lws(data[prev]))) { prev--; name_end--; h->flags |= HTP_FIELD_INVALID; if (!(connp->out_tx->flags & HTP_FIELD_INVALID)) { connp->out_tx->flags |= HTP_FIELD_INVALID; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Response field invalid: LWS after name"); } } // Value value_start = colon_pos; // Go over the colon if (value_start < len) { value_start++; } // Ignore LWS before field-content while ((value_start < len) && (htp_is_lws(data[value_start]))) { value_start++; } // Look for the end of field-content value_end = value_start; while (value_end < len) value_end++; // Ignore LWS after field-content prev = value_end - 1; while ((prev > value_start) && (htp_is_lws(data[prev]))) { prev--; value_end--; } // Check that the header name is a token size_t i = name_start; while (i < name_end) { if (!htp_is_token(data[i])) { h->flags |= HTP_FIELD_INVALID; if (!(connp->out_tx->flags & HTP_FIELD_INVALID)) { connp->out_tx->flags |= HTP_FIELD_INVALID; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Response header name is not a token"); } break; } i++; } // Now extract the name and the value h->name = bstr_memdup(data + name_start, name_end - name_start); if (h->name == NULL) { return HTP_ERROR; } h->value = bstr_memdup(data + value_start, value_end - value_start); if (h->value == NULL) { return HTP_ERROR; } return HTP_OK; } /** * Generic response header line(s) processor, which assembles folded lines * into a single buffer before invoking the parsing function. * * @param connp * @return HTP status */ int htp_process_response_header_generic(htp_connp_t *connp) { bstr *tempstr = NULL; char *data = NULL; size_t len = 0; // Parse header htp_header_t *h = calloc(1, sizeof (htp_header_t)); if (h == NULL) return HTP_ERROR; // Ensure we have the necessary header data in a single buffer if (connp->out_header_line_index + 1 == connp->out_header_line_counter) { // Single line htp_header_line_t *hl = list_get(connp->out_tx->response_header_lines, connp->out_header_line_index); if (hl == NULL) { // Internal error htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process response header (generic): Internal error"); free(h); return HTP_ERROR; } data = bstr_ptr(hl->line); len = bstr_len(hl->line); hl->header = h; } else { // Multiple lines (folded) int i = 0; for (i = connp->out_header_line_index; i < connp->out_header_line_counter; i++) { htp_header_line_t *hl = list_get(connp->out_tx->response_header_lines, i); len += bstr_len(hl->line); } tempstr = bstr_alloc(len); if (tempstr == NULL) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Process reqsponse header (generic): Failed to allocate bstring of %d bytes", len); free(h); return HTP_ERROR; } for (i = connp->out_header_line_index; i < connp->out_header_line_counter; i++) { htp_header_line_t *hl = list_get(connp->out_tx->response_header_lines, i); bstr_add_str_noex(tempstr, hl->line); hl->header = h; } data = bstr_ptr(tempstr); } if (htp_parse_response_header_generic(connp, h, data, len) != HTP_OK) { // Note: downstream responsible for error logging if (tempstr != NULL) { free(tempstr); } free(h); return HTP_ERROR; } // Do we already have a header with the same name? htp_header_t *h_existing = table_get(connp->out_tx->response_headers, h->name); if (h_existing != NULL) { // TODO Do we want to keep a list of the headers that are // allowed to be combined in this way? // Add to existing header h_existing->value = bstr_expand(h_existing->value, bstr_len(h_existing->value) + 2 + bstr_len(h->value)); bstr_add_mem_noex(h_existing->value, ", ", 2); bstr_add_str_noex(h_existing->value, h->value); // The header is no longer needed free(h->name); free(h->value); free(h); // Keep track of same-name headers h_existing->flags |= HTP_FIELD_REPEATED; } else { // Add as a new header table_add(connp->out_tx->response_headers, h->name, h); } if (tempstr != NULL) { free(tempstr); } return HTP_OK; } suricata-1.4.7/libhtp/htp/htp_util.c0000644000000000000000000022577412253546156014330 00000000000000/* * LibHTP (http://www.libhtp.org) * Copyright 2009,2010 Ivan Ristic * * LibHTP is an open source product, released under terms of the General Public Licence * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text * of the license. * * In addition, there is a special exception that allows LibHTP to be freely * used with any OSI-approved open source licence. Please refer to the file * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. * */ #include "htp.h" #include "utf8_decoder.h" /** * Is character a linear white space character? * * @param c * @return 0 or 1 */ int htp_is_lws(int c) { if ((c == ' ') || (c == '\t')) return 1; else return 0; } /** * Is character a separator character? * * @param c * @return 0 or 1 */ int htp_is_separator(int c) { /* separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT */ switch (c) { case '(': case ')': case '<': case '>': case '@': case ',': case ';': case ':': case '\\': case '"': case '/': case '[': case ']': case '?': case '=': case '{': case '}': case ' ': case '\t': return 1; break; default: return 0; } } /** * Is character a text character? * * @param c * @return 0 or 1 */ int htp_is_text(int c) { if (c == '\t') return 1; if (c < 32) return 0; return 1; } /** * Is character a token character? * * @param c * @return 0 or 1 */ int htp_is_token(int c) { /* token = 1* */ /* CHAR = */ if ((c < 32) || (c > 126)) return 0; if (htp_is_separator(c)) return 0; return 1; } /** * Remove one or more line terminators (LF or CRLF) from * the end of the line provided as input. * * @return 0 if nothing was removed, 1 if one or more LF characters were removed, or * 2 if one or more CR and/or LF characters were removed. */ int htp_chomp(unsigned char *data, size_t *len) { int r = 0; // Loop until there's no more stuff in the buffer while (*len > 0) { // Try one LF first if (data[*len - 1] == LF) { (*len)--; r = 1; if (*len == 0) return r; // A CR is allowed before LF if (data[*len - 1] == CR) { (*len)--; r = 2; } } else return r; } return r; } /** * Is character a white space character? * * @param c * @return 0 or 1 */ int htp_is_space(int c) { switch (c) { case ' ': case '\f': case '\v': case '\t': case '\r': case '\n': return 1; default: return 0; } } /** * Converts request method, given as a string, into a number. * * @param method * @return Method number of M_UNKNOWN */ int htp_convert_method_to_number(bstr *method) { if (method == NULL) return M_UNKNOWN; // TODO Optimize using parallel matching, or something if (bstr_cmpc(method, "GET") == 0) return M_GET; if (bstr_cmpc(method, "PUT") == 0) return M_PUT; if (bstr_cmpc(method, "POST") == 0) return M_POST; if (bstr_cmpc(method, "DELETE") == 0) return M_DELETE; if (bstr_cmpc(method, "CONNECT") == 0) return M_CONNECT; if (bstr_cmpc(method, "OPTIONS") == 0) return M_OPTIONS; if (bstr_cmpc(method, "TRACE") == 0) return M_TRACE; if (bstr_cmpc(method, "PATCH") == 0) return M_PATCH; if (bstr_cmpc(method, "PROPFIND") == 0) return M_PROPFIND; if (bstr_cmpc(method, "PROPPATCH") == 0) return M_PROPPATCH; if (bstr_cmpc(method, "MKCOL") == 0) return M_MKCOL; if (bstr_cmpc(method, "COPY") == 0) return M_COPY; if (bstr_cmpc(method, "MOVE") == 0) return M_MOVE; if (bstr_cmpc(method, "LOCK") == 0) return M_LOCK; if (bstr_cmpc(method, "UNLOCK") == 0) return M_UNLOCK; if (bstr_cmpc(method, "VERSION_CONTROL") == 0) return M_VERSION_CONTROL; if (bstr_cmpc(method, "CHECKOUT") == 0) return M_CHECKOUT; if (bstr_cmpc(method, "UNCHECKOUT") == 0) return M_UNCHECKOUT; if (bstr_cmpc(method, "CHECKIN") == 0) return M_CHECKIN; if (bstr_cmpc(method, "UPDATE") == 0) return M_UPDATE; if (bstr_cmpc(method, "LABEL") == 0) return M_LABEL; if (bstr_cmpc(method, "REPORT") == 0) return M_REPORT; if (bstr_cmpc(method, "MKWORKSPACE") == 0) return M_MKWORKSPACE; if (bstr_cmpc(method, "MKACTIVITY") == 0) return M_MKACTIVITY; if (bstr_cmpc(method, "BASELINE_CONTROL") == 0) return M_BASELINE_CONTROL; if (bstr_cmpc(method, "MERGE") == 0) return M_MERGE; if (bstr_cmpc(method, "INVALID") == 0) return M_INVALID; if (bstr_cmpc(method, "HEAD") == 0) return M_HEAD; return M_UNKNOWN; } /** * Is the given line empty? This function expects the line to have * a terminating LF. * * @param data * @param len * @return 0 or 1 */ int htp_is_line_empty(unsigned char *data, size_t len) { if ((len == 1) || ((len == 2) && (data[0] == CR))) { return 1; } return 0; } /** * Does line consist entirely of whitespace characters? * * @param data * @param len * @return 0 or 1 */ int htp_is_line_whitespace(unsigned char *data, size_t len) { size_t i; for (i = 0; i < len; i++) { if (!isspace(data[i])) { return 0; } } return 1; } /** * Parses Content-Length string (positive decimal number). * White space is allowed before and after the number. * * @param b * @return Content-Length as a number, or -1 on error. */ int htp_parse_content_length(bstr *b) { return htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(b), bstr_len(b), 10); } /** * Parses chunk length (positive hexadecimal number). * White space is allowed before and after the number. * * @param data * @param len * @return Chunk length, or -1 on error. */ int htp_parse_chunked_length(unsigned char *data, size_t len) { return htp_parse_positive_integer_whitespace(data, len, 16); } /** * A forgiving parser for a positive integer in a given base. * White space is allowed before and after the number. * * @param data * @param len * @param base * @return The parsed number, or -1 on error. */ int htp_parse_positive_integer_whitespace(unsigned char *data, size_t len, int base) { size_t pos = 0; // Ignore LWS before while ((pos < len) && (htp_is_lws(data[pos]))) pos++; if (pos == len) return -1001; int r = bstr_util_memtoip((char *) data + pos, len - pos, base, &pos); if (r < 0) return r; // Ignore LWS after while (pos < len) { if (!htp_is_lws(data[pos])) { return -1002; } pos++; } return r; } /** * Prints one log message to stderr. * * @param log */ void htp_print_log(FILE *stream, htp_log_t *log) { if (log->code != 0) { fprintf(stream, "[%d][code %d][file %s][line %d] %s\n", log->level, log->code, log->file, log->line, log->msg); } else { fprintf(stream, "[%d][file %s][line %d] %s\n", log->level, log->file, log->line, log->msg); } } /** * Records one log message. * * @param connp * @param file * @param line * @param level * @param code * @param fmt */ void htp_log(htp_connp_t *connp, const char *file, int line, int level, int code, const char *fmt, ...) { char buf[1024]; va_list args; // Ignore messages below our log level if (connp->cfg->log_level < level) { return; } va_start(args, fmt); int r = vsnprintf(buf, 1023, fmt, args); va_end(args); if (r < 0) { // TODO Will vsnprintf ever return an error? snprintf(buf, 1024, "[vnsprintf returned error %d]", r); } // Indicate overflow with a '+' at the end if (r > 1023) { buf[1022] = '+'; buf[1023] = '\0'; } // Create a new log entry... htp_log_t *log = calloc(1, sizeof (htp_log_t)); if (log == NULL) return; log->connp = connp; log->file = file; log->line = line; log->level = level; log->code = code; log->msg = strdup(buf); list_add(connp->conn->messages, log); if (level == HTP_LOG_ERROR) { connp->last_error = log; } hook_run_all(connp->cfg->hook_log, log); } /** * Determines if the given line is a continuation (of some previous line). * * @param connp * @param data * @param len * @return 0 or 1 */ int htp_connp_is_line_folded(unsigned char *data, size_t len) { // Is there a line? if (len == 0) { return -1; } if (htp_is_lws(data[0])) return 1; else return 0; } /** * Determines if the given line is a request terminator. * * @param connp * @param data * @param len * @return 0 or 1 */ int htp_connp_is_line_terminator(htp_connp_t *connp, unsigned char *data, size_t len) { // Is this the end of request headers? switch (connp->cfg->spersonality) { case HTP_SERVER_IIS_5_1: // IIS 5 will accept a whitespace line as a terminator if (htp_is_line_whitespace(data, len)) { return 1; } // Fall through default: // Treat an empty line as terminator if (htp_is_line_empty(data, len)) { return 1; } break; } return 0; } /** * Determines if the given line can be ignored when it appears before a request. * * @param connp * @param data * @param len * @return 0 or 1 */ int htp_connp_is_line_ignorable(htp_connp_t *connp, unsigned char *data, size_t len) { return htp_connp_is_line_terminator(connp, data, len); } /** * Parses request URI, making no attempt to validate the contents. * * @param connp * @param authority * @param uri * @return HTP_ERROR on memory allocation failure, HTP_OK otherwise */ int htp_parse_authority(htp_connp_t *connp, bstr *authority, htp_uri_t **uri) { int colon = bstr_chr(authority, ':'); if (colon == -1) { // Hostname alone (*uri)->hostname = bstr_strdup(authority); htp_normalize_hostname_inplace((*uri)->hostname); } else { // Hostname and port // Hostname (*uri)->hostname = bstr_strdup_ex(authority, 0, colon); // TODO Handle whitespace around hostname htp_normalize_hostname_inplace((*uri)->hostname); // Port int port = htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(authority) + colon + 1, bstr_len(authority) - colon - 1, 10); if (port < 0) { // Failed to parse port htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid server port information in request"); } else if ((port > 0) && (port < 65536)) { // Valid port (*uri)->port_number = port; } else { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid authority port"); } } return HTP_OK; } /** * Parses request URI, making no attempt to validate the contents. * * @param input * @param uri * @return HTP_ERROR on memory allocation failure, HTP_OK otherwise */ int htp_parse_uri(bstr *input, htp_uri_t **uri) { if (input == NULL) return HTP_ERROR; char *data = bstr_ptr(input); size_t len = bstr_len(input); size_t start, pos; // Allow a htp_uri_t structure to be provided on input, // but allocate a new one if there isn't one if (*uri == NULL) { *uri = calloc(1, sizeof (htp_uri_t)); if (*uri == NULL) return HTP_ERROR; } if (len == 0) { // Empty string return HTP_OK; } pos = 0; // Scheme test: if it doesn't start with a forward slash character (which it must // for the contents to be a path or an authority, then it must be the scheme part if (data[0] != '/') { // Parse scheme // Find the colon, which marks the end of the scheme part start = pos; while ((pos < len) && (data[pos] != ':')) pos++; if (pos >= len) { // We haven't found a colon, which means that the URI // is invalid. Apache will ignore this problem and assume // the URI contains an invalid path so, for the time being, // we are going to do the same. pos = 0; } else { // Make a copy of the scheme (*uri)->scheme = bstr_memdup(data + start, pos - start); // Go over the colon pos++; } } // Authority test: two forward slash characters and it's an authority. // One, three or more slash characters, and it's a path. We, however, // only attempt to parse authority if we've seen a scheme. if ((*uri)->scheme != NULL) if ((pos + 2 < len) && (data[pos] == '/') && (data[pos + 1] == '/') && (data[pos + 2] != '/')) { // Parse authority // Go over the two slash characters start = pos = pos + 2; // Authority ends with a question mark, forward slash or hash while ((pos < len) && (data[pos] != '?') && (data[pos] != '/') && (data[pos] != '#')) pos++; char *hostname_start; size_t hostname_len; // Are the credentials included in the authority? char *m = memchr(data + start, '@', pos - start); if (m != NULL) { // Credentials present char *credentials_start = data + start; size_t credentials_len = m - data - start; // Figure out just the hostname part hostname_start = data + start + credentials_len + 1; hostname_len = pos - start - credentials_len - 1; // Extract the username and the password m = memchr(credentials_start, ':', credentials_len); if (m != NULL) { // Username and password (*uri)->username = bstr_memdup(credentials_start, m - credentials_start); (*uri)->password = bstr_memdup(m + 1, credentials_len - (m - credentials_start) - 1); } else { // Username alone (*uri)->username = bstr_memdup(credentials_start, credentials_len); } } else { // No credentials hostname_start = data + start; hostname_len = pos - start; } // Parsing authority without credentials. if ((hostname_len > 0) && (hostname_start[0] == '[')) { // IPv6 address. m = memchr(hostname_start, ']', hostname_len); if (m == NULL) { // Invalid IPv6 address; use the entire string as hostname. (*uri)->hostname = bstr_memdup(hostname_start, hostname_len); if ((*uri)->hostname == NULL) return HTP_ERROR; } else { (*uri)->hostname = bstr_memdup(hostname_start, m - hostname_start + 1); if ((*uri)->hostname == NULL) return HTP_ERROR; // Is there a port? hostname_len = hostname_len - (m - hostname_start + 1); hostname_start = m + 1; m = memchr(hostname_start, ':', hostname_len); if (m != NULL) { size_t port_len = hostname_len - (m - hostname_start) - 1; hostname_len = hostname_len - port_len - 1; // Port string (*uri)->port = bstr_memdup(m + 1, port_len); if ((*uri)->port == NULL) return HTP_ERROR; } } } else { // Not IPv6 address. // Still parsing authority; is there a port provided? m = memchr(hostname_start, ':', hostname_len); if (m != NULL) { size_t port_len = hostname_len - (m - hostname_start) - 1; hostname_len = hostname_len - port_len - 1; // Port string (*uri)->port = bstr_memdup(m + 1, port_len); // We deliberately don't want to try to convert the port // string as a number. That will be done later, during // the normalization and validation process. } // Hostname (*uri)->hostname = bstr_memdup(hostname_start, hostname_len); } } // Path start = pos; // The path part will end with a question mark or a hash character, which // mark the beginning of the query part or the fragment part, respectively. while ((pos < len) && (data[pos] != '?') && (data[pos] != '#')) pos++; // Path (*uri)->path = bstr_memdup(data + start, pos - start); if (pos == len) return HTP_OK; // Query if (data[pos] == '?') { // Step over the question mark start = pos + 1; // The query part will end with the end of the input // or the beginning of the fragment part while ((pos < len) && (data[pos] != '#')) pos++; // Query string (*uri)->query = bstr_memdup(data + start, pos - start); if (pos == len) return HTP_OK; } // Fragment if (data[pos] == '#') { // Step over the hash character start = pos + 1; // Fragment; ends with the end of the input (*uri)->fragment = bstr_memdup(data + start, len - start); } return HTP_OK; } /** * Convert two input bytes, pointed to by the pointer parameter, * into a single byte by assuming the input consists of hexadecimal * characters. This function will happily convert invalid input. * * @param what * @return hex-decoded byte */ unsigned char x2c(unsigned char *what) { register unsigned char digit; digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); digit *= 16; digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); return digit; } /** * Convert a Unicode codepoint into a single-byte, using best-fit * mapping (as specified in the provided configuration structure). * * @param cfg * @param codepoint * @return converted single byte */ uint8_t bestfit_codepoint(htp_cfg_t *cfg, uint32_t codepoint) { // Is it a single-byte codepoint? if (codepoint < 0x100) { return (uint8_t) codepoint; } // Our current implementation only converts the 2-byte codepoints if (codepoint > 0xffff) { return cfg->path_replacement_char; } uint8_t *p = cfg->path_u_bestfit_map; // TODO Optimize lookup for (;;) { uint32_t x = (p[0] << 8) + p[1]; if (x == 0) { return cfg->path_replacement_char; } if (x == codepoint) { return p[2]; break; } // Move to the next triplet p += 3; } return cfg->path_replacement_char; } /** * Decode a UTF-8 encoded path. Overlong characters will be decoded, invalid * chararacters will be left as-is. Best-fit mapping will be used to convert * UTF-8 into a single-byte stream. * * @param cfg * @param tx * @param path */ void htp_utf8_decode_path_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path) { if (path == NULL) return; uint8_t *data = (unsigned char *) bstr_ptr(path); size_t len = bstr_len(path); size_t rpos = 0; size_t wpos = 0; size_t charpos = 0; uint32_t codepoint = 0; uint32_t state = UTF8_ACCEPT; uint32_t counter = 0; uint8_t seen_valid = 0; while (rpos < len) { counter++; switch (utf8_decode_allow_overlong(&state, &codepoint, data[rpos])) { case UTF8_ACCEPT: if (counter == 1) { // ASCII character data[wpos++] = (uint8_t) codepoint; } else { // A valid UTF-8 character seen_valid = 1; // Check for overlong characters and set the // flag accordingly switch (counter) { case 2: if (codepoint < 0x80) { tx->flags |= HTP_PATH_UTF8_OVERLONG; } break; case 3: if (codepoint < 0x800) { tx->flags |= HTP_PATH_UTF8_OVERLONG; } break; case 4: if (codepoint < 0x10000) { tx->flags |= HTP_PATH_UTF8_OVERLONG; } break; } // Special flag for fullwidth form evasion if ((codepoint > 0xfeff) && (codepoint < 0x010000)) { tx->flags |= HTP_PATH_FULLWIDTH_EVASION; } // Use best-fit mapping to convert to a single byte data[wpos++] = bestfit_codepoint(cfg, codepoint); } // Advance over the consumed byte rpos++; // Prepare for the next character counter = 0; charpos = rpos; break; case UTF8_REJECT: // Invalid UTF-8 character tx->flags |= HTP_PATH_UTF8_INVALID; // Is the server expected to respond with 400? if (cfg->path_invalid_utf8_handling == STATUS_400) { tx->response_status_expected_number = 400; } // Override the state in the UTF-8 decoder because // we want to ignore invalid characters state = UTF8_ACCEPT; // Copy the invalid bytes into the output stream while (charpos <= rpos) { data[wpos++] = data[charpos++]; } // Advance over the consumed byte rpos++; // Prepare for the next character counter = 0; charpos = rpos; break; default: // Keep going; the character is not yet formed rpos++; break; } } // Did the input stream seem like a valid UTF-8 string? if ((seen_valid) && (!(tx->flags & HTP_PATH_UTF8_INVALID))) { tx->flags |= HTP_PATH_UTF8_VALID; } // Adjust the length of the string, because // we're doing in-place decoding. bstr_len_adjust(path, wpos); } /** * Validate a path that is quite possibly UTF-8 encoded. * * @param cfg * @param tx * @param path */ void htp_utf8_validate_path(htp_tx_t *tx, bstr *path) { unsigned char *data = (unsigned char *) bstr_ptr(path); size_t len = bstr_len(path); size_t rpos = 0; uint32_t codepoint = 0; uint32_t state = UTF8_ACCEPT; uint32_t counter = 0; uint8_t seen_valid = 0; while (rpos < len) { counter++; switch (utf8_decode_allow_overlong(&state, &codepoint, data[rpos])) { case UTF8_ACCEPT: // ASCII character if (counter > 1) { // A valid UTF-8 character seen_valid = 1; // Check for overlong characters and set the // flag accordingly switch (counter) { case 2: if (codepoint < 0x80) { tx->flags |= HTP_PATH_UTF8_OVERLONG; } break; case 3: if (codepoint < 0x800) { tx->flags |= HTP_PATH_UTF8_OVERLONG; } break; case 4: if (codepoint < 0x10000) { tx->flags |= HTP_PATH_UTF8_OVERLONG; } break; } } // Special flag for fullwidth form evasion if ((codepoint > 0xfeff) && (codepoint < 0x010000)) { tx->flags |= HTP_PATH_FULLWIDTH_EVASION; } // Advance over the consumed byte rpos++; // Prepare for the next character counter = 0; break; case UTF8_REJECT: // Invalid UTF-8 character tx->flags |= HTP_PATH_UTF8_INVALID; // Override the state in the UTF-8 decoder because // we want to ignore invalid characters state = UTF8_ACCEPT; // Advance over the consumed byte rpos++; // Prepare for the next character counter = 0; break; default: // Keep going; the character is not yet formed rpos++; break; } } // Did the input stream seem like a valid UTF-8 string? if ((seen_valid) && (!(tx->flags & HTP_PATH_UTF8_INVALID))) { tx->flags |= HTP_PATH_UTF8_VALID; } } /** * Decode a %u-encoded character, using best-fit mapping as necessary. * * @param cfg * @param tx * @param data * @return decoded byte */ int decode_u_encoding(htp_cfg_t *cfg, htp_tx_t *tx, unsigned char *data) { unsigned int c1 = x2c(data); unsigned int c2 = x2c(data + 2); int r = cfg->path_replacement_char; if (c1 == 0x00) { r = c2; tx->flags |= HTP_PATH_OVERLONG_U; } else { // Check for fullwidth form evasion if (c1 == 0xff) { tx->flags |= HTP_PATH_FULLWIDTH_EVASION; } switch (cfg->path_unicode_mapping) { case STATUS_400: tx->response_status_expected_number = 400; break; case STATUS_404: tx->response_status_expected_number = 404; break; } // Use best-fit mapping unsigned char *p = cfg->path_u_bestfit_map; // TODO Optimize lookup for (;;) { // Have we reached the end of the map? if ((p[0] == 0) && (p[1] == 0)) { break; } // Have we found the mapping we're looking for? if ((p[0] == c1) && (p[1] == c2)) { r = p[2]; break; } // Move to the next triplet p += 3; } } // Check for encoded path separators if ((r == '/') || ((cfg->path_backslash_separators) && (r == '\\'))) { tx->flags |= HTP_PATH_ENCODED_SEPARATOR; } return r; } /** * Decode a request query according to the settings in the * provided configuration structure. * * @param cfg * @param tx * @param query */ int htp_decode_query_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *query) { if (query == NULL) return -1; unsigned char *data = (unsigned char *) bstr_ptr(query); if (data == NULL) { return -1; } size_t len = bstr_len(query); // TODO I don't like this function. It's too complex. size_t rpos = 0; size_t wpos = 0; int previous_was_separator = 0; while (rpos < len) { int c = data[rpos]; // Decode encoded characters if (c == '%') { if (rpos + 2 < len) { int handled = 0; if (cfg->query_decode_u_encoding) { // Check for the %u encoding if ((data[rpos + 1] == 'u') || (data[rpos + 1] == 'U')) { handled = 1; if (cfg->query_decode_u_encoding == STATUS_400) { tx->response_status_expected_number = 400; } if (rpos + 5 < len) { if (isxdigit(data[rpos + 2]) && (isxdigit(data[rpos + 3])) && isxdigit(data[rpos + 4]) && (isxdigit(data[rpos + 5]))) { // Decode a valid %u encoding c = decode_u_encoding(cfg, tx, &data[rpos + 2]); rpos += 6; if (c == 0) { tx->flags |= HTP_PATH_ENCODED_NUL; if (cfg->query_nul_encoded_handling == STATUS_400) { tx->response_status_expected_number = 400; } else if (cfg->query_nul_encoded_handling == STATUS_404) { tx->response_status_expected_number = 404; } } } else { // Invalid %u encoding tx->flags |= HTP_PATH_INVALID_ENCODING; switch (cfg->query_invalid_encoding_handling) { case URL_DECODER_REMOVE_PERCENT: // Do not place anything in output; eat // the percent character rpos++; continue; break; case URL_DECODER_PRESERVE_PERCENT: // Leave the percent character in output rpos++; break; case URL_DECODER_DECODE_INVALID: // Decode invalid %u encoding c = decode_u_encoding(cfg, tx, &data[rpos + 2]); rpos += 6; break; case URL_DECODER_STATUS_400: // Set expected status to 400 tx->response_status_expected_number = 400; // Decode invalid %u encoding c = decode_u_encoding(cfg, tx, &data[rpos + 2]); rpos += 6; break; break; default: // Unknown setting return -1; break; } } } else { // Invalid %u encoding (not enough data) tx->flags |= HTP_PATH_INVALID_ENCODING; if (cfg->query_invalid_encoding_handling == URL_DECODER_REMOVE_PERCENT) { // Remove the percent character from output rpos++; continue; } else { rpos++; } } } } // Handle standard URL encoding if (!handled) { if ((isxdigit(data[rpos + 1])) && (isxdigit(data[rpos + 2]))) { c = x2c(&data[rpos + 1]); if (c == 0) { tx->flags |= HTP_PATH_ENCODED_NUL; switch (cfg->query_nul_encoded_handling) { case TERMINATE: bstr_len_adjust(query, wpos); return 1; break; case STATUS_400: tx->response_status_expected_number = 400; break; case STATUS_404: tx->response_status_expected_number = 404; break; } } if ((c == '/') || ((cfg->query_backslash_separators) && (c == '\\'))) { tx->flags |= HTP_PATH_ENCODED_SEPARATOR; switch (cfg->query_decode_separators) { case STATUS_404: tx->response_status_expected_number = 404; // Fall-through case NO: // Leave encoded c = '%'; rpos++; break; case YES: // Decode rpos += 3; break; } } else { // Decode rpos += 3; } } else { // Invalid encoding tx->flags |= HTP_PATH_INVALID_ENCODING; switch (cfg->query_invalid_encoding_handling) { case URL_DECODER_REMOVE_PERCENT: // Do not place anything in output; eat // the percent character rpos++; continue; break; case URL_DECODER_PRESERVE_PERCENT: // Leave the percent character in output rpos++; break; case URL_DECODER_DECODE_INVALID: // Decode c = x2c(&data[rpos + 1]); rpos += 3; // Note: What if an invalid encoding decodes into a path // separator? This is theoretical at the moment, because // the only platform we know doesn't convert separators is // Apache, who will also respond with 400 if invalid encoding // is encountered. Thus no check for a separator here. break; case URL_DECODER_STATUS_400: // Backend will reject request with 400, which means // that it does not matter what we do. tx->response_status_expected_number = 400; // Preserve the percent character rpos++; break; default: // Unknown setting return -1; break; } } } } else { // Invalid encoding (not enough data) tx->flags |= HTP_PATH_INVALID_ENCODING; if (cfg->query_invalid_encoding_handling == URL_DECODER_REMOVE_PERCENT) { // Do not place the percent character in output rpos++; continue; } else { rpos++; } } } else { // One non-encoded character // Is it a NUL byte? if (c == 0) { switch (cfg->query_nul_raw_handling) { case TERMINATE: // Terminate path with a raw NUL byte bstr_len_adjust(query, wpos); return 1; break; case STATUS_400: // Leave the NUL byte, but set the expected status tx->response_status_expected_number = 400; break; case STATUS_404: // Leave the NUL byte, but set the expected status tx->response_status_expected_number = 404; break; } } rpos++; } // Place the character into output // Check for control characters if (c < 0x20) { if (cfg->query_control_char_handling == STATUS_400) { tx->response_status_expected_number = 400; } } // Convert backslashes to forward slashes, if necessary if ((c == '\\') && (cfg->query_backslash_separators)) { c = '/'; } // Lowercase characters, if necessary if (cfg->query_case_insensitive) { c = tolower(c); } // If we're compressing separators then we need // to track if the previous character was a separator if (cfg->query_compress_separators) { if (c == '/') { if (!previous_was_separator) { data[wpos++] = c; previous_was_separator = 1; } else { // Do nothing; we don't want // another separator in output } } else { data[wpos++] = c; previous_was_separator = 0; } } else { data[wpos++] = c; } } bstr_len_adjust(query, wpos); return 1; } /** * Decode a request path according to the settings in the * provided configuration structure. * * @param cfg * @param tx * @param path */ int htp_decode_path_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path) { if (path == NULL) return -1; unsigned char *data = (unsigned char *) bstr_ptr(path); if (data == NULL) { return -1; } size_t len = bstr_len(path); // TODO I don't like this function. It's too complex. size_t rpos = 0; size_t wpos = 0; int previous_was_separator = 0; while (rpos < len) { int c = data[rpos]; // Decode encoded characters if (c == '%') { if (rpos + 2 < len) { int handled = 0; if (cfg->path_decode_u_encoding) { // Check for the %u encoding if ((data[rpos + 1] == 'u') || (data[rpos + 1] == 'U')) { handled = 1; if (cfg->path_decode_u_encoding == STATUS_400) { tx->response_status_expected_number = 400; } if (rpos + 5 < len) { if (isxdigit(data[rpos + 2]) && (isxdigit(data[rpos + 3])) && isxdigit(data[rpos + 4]) && (isxdigit(data[rpos + 5]))) { // Decode a valid %u encoding c = decode_u_encoding(cfg, tx, &data[rpos + 2]); rpos += 6; if (c == 0) { tx->flags |= HTP_PATH_ENCODED_NUL; if (cfg->path_nul_encoded_handling == STATUS_400) { tx->response_status_expected_number = 400; } else if (cfg->path_nul_encoded_handling == STATUS_404) { tx->response_status_expected_number = 404; } } } else { // Invalid %u encoding tx->flags |= HTP_PATH_INVALID_ENCODING; switch (cfg->path_invalid_encoding_handling) { case URL_DECODER_REMOVE_PERCENT: // Do not place anything in output; eat // the percent character rpos++; continue; break; case URL_DECODER_PRESERVE_PERCENT: // Leave the percent character in output rpos++; break; case URL_DECODER_DECODE_INVALID: // Decode invalid %u encoding c = decode_u_encoding(cfg, tx, &data[rpos + 2]); rpos += 6; break; case URL_DECODER_STATUS_400: // Set expected status to 400 tx->response_status_expected_number = 400; // Decode invalid %u encoding c = decode_u_encoding(cfg, tx, &data[rpos + 2]); rpos += 6; break; break; default: // Unknown setting return -1; break; } } } else { // Invalid %u encoding (not enough data) tx->flags |= HTP_PATH_INVALID_ENCODING; if (cfg->path_invalid_encoding_handling == URL_DECODER_REMOVE_PERCENT) { // Remove the percent character from output rpos++; continue; } else { rpos++; } } } } // Handle standard URL encoding if (!handled) { if ((isxdigit(data[rpos + 1])) && (isxdigit(data[rpos + 2]))) { c = x2c(&data[rpos + 1]); if (c == 0) { tx->flags |= HTP_PATH_ENCODED_NUL; switch (cfg->path_nul_encoded_handling) { case TERMINATE: bstr_len_adjust(path, wpos); return 1; break; case STATUS_400: tx->response_status_expected_number = 400; break; case STATUS_404: tx->response_status_expected_number = 404; break; } } if ((c == '/') || ((cfg->path_backslash_separators) && (c == '\\'))) { tx->flags |= HTP_PATH_ENCODED_SEPARATOR; switch (cfg->path_decode_separators) { case STATUS_404: tx->response_status_expected_number = 404; // Fall-through case NO: // Leave encoded c = '%'; rpos++; break; case YES: // Decode rpos += 3; break; } } else { // Decode rpos += 3; } } else { // Invalid encoding tx->flags |= HTP_PATH_INVALID_ENCODING; switch (cfg->path_invalid_encoding_handling) { case URL_DECODER_REMOVE_PERCENT: // Do not place anything in output; eat // the percent character rpos++; continue; break; case URL_DECODER_PRESERVE_PERCENT: // Leave the percent character in output rpos++; break; case URL_DECODER_DECODE_INVALID: // Decode c = x2c(&data[rpos + 1]); rpos += 3; // Note: What if an invalid encoding decodes into a path // separator? This is theoretical at the moment, because // the only platform we know doesn't convert separators is // Apache, who will also respond with 400 if invalid encoding // is encountered. Thus no check for a separator here. break; case URL_DECODER_STATUS_400: // Backend will reject request with 400, which means // that it does not matter what we do. tx->response_status_expected_number = 400; // Preserve the percent character rpos++; break; default: // Unknown setting return -1; break; } } } } else { // Invalid encoding (not enough data) tx->flags |= HTP_PATH_INVALID_ENCODING; if (cfg->path_invalid_encoding_handling == URL_DECODER_REMOVE_PERCENT) { // Do not place the percent character in output rpos++; continue; } else { rpos++; } } } else { // One non-encoded character // Is it a NUL byte? if (c == 0) { switch (cfg->path_nul_raw_handling) { case TERMINATE: // Terminate path with a raw NUL byte bstr_len_adjust(path, wpos); return 1; break; case STATUS_400: // Leave the NUL byte, but set the expected status tx->response_status_expected_number = 400; break; case STATUS_404: // Leave the NUL byte, but set the expected status tx->response_status_expected_number = 404; break; } } rpos++; } // Place the character into output // Check for control characters if (c < 0x20) { if (cfg->path_control_char_handling == STATUS_400) { tx->response_status_expected_number = 400; } } // Convert backslashes to forward slashes, if necessary if ((c == '\\') && (cfg->path_backslash_separators)) { c = '/'; } // Lowercase characters, if necessary if (cfg->path_case_insensitive) { c = tolower(c); } // If we're compressing separators then we need // to track if the previous character was a separator if (cfg->path_compress_separators) { if (c == '/') { if (!previous_was_separator) { data[wpos++] = c; previous_was_separator = 1; } else { // Do nothing; we don't want // another separator in output } } else { data[wpos++] = c; previous_was_separator = 0; } } else { data[wpos++] = c; } } bstr_len_adjust(path, wpos); return 1; } /** * Normalize a previously-parsed request URI. * * @param connp * @param incomplete * @param normalized * @return HTP_OK or HTP_ERROR */ int htp_normalize_parsed_uri(htp_connp_t *connp, htp_uri_t *incomplete, htp_uri_t *normalized) { // Scheme if (incomplete->scheme != NULL) { // Duplicate and convert to lowercase normalized->scheme = bstr_dup_lower(incomplete->scheme); if (normalized->scheme == NULL) return HTP_ERROR; } // Username if (incomplete->username != NULL) { normalized->username = bstr_strdup(incomplete->username); if (normalized->username == NULL) return HTP_ERROR; htp_uriencoding_normalize_inplace(normalized->username); } // Password if (incomplete->password != NULL) { normalized->password = bstr_strdup(incomplete->password); if (normalized->password == NULL) return HTP_ERROR; htp_uriencoding_normalize_inplace(normalized->password); } // Hostname if (incomplete->hostname != NULL) { // We know that incomplete->hostname does not contain // port information, so no need to check for it here normalized->hostname = bstr_strdup(incomplete->hostname); if (normalized->hostname == NULL) return HTP_ERROR; htp_uriencoding_normalize_inplace(normalized->hostname); htp_normalize_hostname_inplace(normalized->hostname); } // Port if (incomplete->port != NULL) { // Parse provided port normalized->port_number = htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(incomplete->port), bstr_len(incomplete->port), 10); // We do not report failed port parsing, but leave // to upstream to detect and act upon it. } // Path if (incomplete->path != NULL) { // Make a copy of the path, on which we can work on normalized->path = bstr_strdup(incomplete->path); if (normalized->path != NULL) { // Decode URL-encoded (and %u-encoded) characters, as well as lowercase, // compress separators and convert backslashes. htp_decode_path_inplace(connp->cfg, connp->in_tx, normalized->path); // Handle UTF-8 in path if (connp->cfg->path_convert_utf8) { // Decode Unicode characters into a single-byte stream, using best-fit mapping htp_utf8_decode_path_inplace(connp->cfg, connp->in_tx, normalized->path); } else { // Only validate path as a UTF-8 stream htp_utf8_validate_path(connp->in_tx, normalized->path); } // RFC normalization htp_normalize_uri_path_inplace(normalized->path); } else { return HTP_ERROR; } } // Query if (incomplete->query != NULL) { // We cannot URL-decode the query string here; it needs to be // parsed into individual key-value pairs first. normalized->query = bstr_strdup(incomplete->query); if (normalized->query == NULL) return HTP_ERROR; } // Fragment if (incomplete->fragment != NULL) { normalized->fragment = bstr_strdup(incomplete->fragment); if (normalized->fragment == NULL) return HTP_ERROR; htp_uriencoding_normalize_inplace(normalized->fragment); } return HTP_OK; } /** * Normalize request hostname. Convert all characters to lowercase and * remove trailing dots from the end, if present. * * @param hostname * @return normalized hostnanme */ bstr *htp_normalize_hostname_inplace(bstr *hostname) { if (hostname == NULL) return NULL; bstr_tolowercase(hostname); char *data = bstr_ptr(hostname); size_t len = bstr_len(hostname); while (len > 0) { if (data[len - 1] != '.') return hostname; bstr_chop(hostname); len--; } return hostname; } /** * Replace the URI in the structure with the one provided as the parameter * to this function (which will typically be supplied in a Host header). * * @param connp * @param parsed_uri * @param hostname */ void htp_replace_hostname(htp_connp_t *connp, htp_uri_t *parsed_uri, bstr *hostname) { if (hostname == NULL) return; char *hostname_start = bstr_ptr(hostname); size_t hostname_len = bstr_len(hostname); if (hostname_len == 0) return; if (hostname_start[0] == '[') { // IPv6 address. char *m = memchr(hostname_start, ']', hostname_len); if (m == NULL) { // Invalid IPv6 address; use the entire string as hostname. parsed_uri->hostname = bstr_memdup(hostname_start, hostname_len); } else { parsed_uri->hostname = bstr_memdup(hostname_start, m - hostname_start + 1); // TODO Handle whitespace around hostname htp_normalize_hostname_inplace(parsed_uri->hostname); // Is there a port? hostname_len = hostname_len - (m - hostname_start + 1); hostname_start = m + 1; m = memchr(hostname_start, ':', hostname_len); if (m != NULL) { size_t port_len = hostname_len - (m - hostname_start) - 1; int port = htp_parse_positive_integer_whitespace((unsigned char *)m + 1, port_len, 10); if (port < 0) { // Failed to parse port htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid server port information in request"); } else if ((port > 0) && (port < 65536)) { // Valid port if (port != connp->conn->local_port) { // Port is different from the TCP port htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request server port number differs from the actual TCP port"); } else { parsed_uri->port_number = port; } } } } } else { int colon = bstr_chr(hostname, ':'); if (colon == -1) { // Hostname alone parsed_uri->hostname = bstr_strdup(hostname); htp_normalize_hostname_inplace(parsed_uri->hostname); } else { // Hostname parsed_uri->hostname = bstr_strdup_ex(hostname, 0, colon); // TODO Handle whitespace around hostname htp_normalize_hostname_inplace(parsed_uri->hostname); // Port int port = htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(hostname) + colon + 1, bstr_len(hostname) - colon - 1, 10); if (port < 0) { // Failed to parse port htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid server port information in request"); } else if ((port > 0) && (port < 65536)) { // Valid port if (port != connp->conn->local_port) { // Port is different from the TCP port htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request server port number differs from the actual TCP port"); } else { parsed_uri->port_number = port; } } } } } /** * Is URI character reserved? * * @param c * @return 1 if it is, 0 if it isn't */ int htp_is_uri_unreserved(unsigned char c) { if (((c >= 0x41) && (c <= 0x5a)) || ((c >= 0x61) && (c <= 0x7a)) || ((c >= 0x30) && (c <= 0x39)) || (c == 0x2d) || (c == 0x2e) || (c == 0x5f) || (c == 0x7e)) { return 1; } else { return 0; } } /** * Decode a URL-encoded string, leaving the reserved * characters and invalid encodings alone. * * @param s */ void htp_uriencoding_normalize_inplace(bstr *s) { if (s == NULL) return; unsigned char *data = (unsigned char *) bstr_ptr(s); size_t len = bstr_len(s); size_t rpos = 0; size_t wpos = 0; while (rpos < len) { if (data[rpos] == '%') { if (rpos + 2 < len) { if (isxdigit(data[rpos + 1]) && (isxdigit(data[rpos + 2]))) { unsigned char c = x2c(&data[rpos + 1]); if (!htp_is_uri_unreserved(c)) { // Leave reserved characters encoded, but convert // the hexadecimal digits to uppercase data[wpos++] = data[rpos++]; data[wpos++] = toupper(data[rpos++]); data[wpos++] = toupper(data[rpos++]); } else { // Decode unreserved character data[wpos++] = c; rpos += 3; } } else { // Invalid URL encoding: invalid hex digits // Copy over what's there data[wpos++] = data[rpos++]; data[wpos++] = toupper(data[rpos++]); data[wpos++] = toupper(data[rpos++]); } } else { // Invalid URL encoding: string too short // Copy over what's there data[wpos++] = data[rpos++]; while (rpos < len) { data[wpos++] = toupper(data[rpos++]); } } } else { data[wpos++] = data[rpos++]; } } bstr_len_adjust(s, wpos); } #if 0 /** * */ int htp_prenormalize_uri_path_inplace(bstr *s, int *flags, int case_insensitive, int backslash, int decode_separators, int remove_consecutive) { char *data = bstr_ptr(s); size_t len = bstr_len(s); size_t rpos = 0; size_t wpos = 0; while (rpos < len) { char c = data[rpos]; // Convert backslash characters where necessary if ((c == '/') || ((c == '\\') && (backslash))) { if ((!remove_consecutive) || (wpos == 0) || (data[wpos - 1] != '/')) { data[wpos++] = '/'; } rpos++; } else if ((c == '%') && (decode_separators)) { if (rpos + 2 < len) { if (isxdigit(data[rpos + 1]) && (isxdigit(data[rpos + 2]))) { unsigned char x = x2c(&data[rpos + 1]); if (x == 0) { (*flags) |= HTP_PATH_ENCODED_NUL; } if ((x == '/') || ((backslash) && (x == '\\'))) { data[wpos++] = '/'; rpos += 3; continue; } } else { // Invalid URL encoding (*flags) |= HTP_PATH_INVALID_ENCODING; // Copy over all three bytes data[wpos++] = data[rpos++]; data[wpos++] = data[rpos++]; data[wpos++] = data[rpos++]; } } else { // Not enough characters (*flags) |= HTP_PATH_INVALID_ENCODING; // Copy over what's there while (rpos < len) { data[wpos++] = data[rpos++]; } } } else { // Just copy the character if (case_insensitive) { data[wpos++] = tolower(c); } else { data[wpos++] = c; } rpos++; } } bstr_len_adjust(s, wpos); } #endif /** * Normalize URL path. This function implements the remove dot segments algorithm * speficied in RFC 3986, section 5.2.4. * * @param s */ void htp_normalize_uri_path_inplace(bstr *s) { if (s == NULL) return; char *data = bstr_ptr(s); size_t len = bstr_len(s); size_t rpos = 0; size_t wpos = 0; int c = -1; while (rpos < len) { if (c == -1) { c = data[rpos++]; } // A. If the input buffer begins with a prefix of "../" or "./", // then remove that prefix from the input buffer; otherwise, if (c == '.') { if ((rpos + 1 < len) && (data[rpos] == '.') && (data[rpos + 1] == '/')) { c = -1; rpos += 2; continue; } else if ((rpos < len) && (data[rpos + 1] == '/')) { c = -1; rpos += 2; continue; } } if (c == '/') { // B. if the input buffer begins with a prefix of "/./" or "/.", // where "." is a complete path segment, then replace that // prefix with "/" in the input buffer; otherwise, if ((rpos + 1 < len) && (data[rpos] == '.') && (data[rpos + 1] == '/')) { c = '/'; rpos += 2; continue; } else if ((rpos + 1 == len) && (data[rpos] == '.')) { c = '/'; rpos += 1; continue; } // C. if the input buffer begins with a prefix of "/../" or "/..", // where ".." is a complete path segment, then replace that // prefix with "/" in the input buffer and remove the last // segment and its preceding "/" (if any) from the output // buffer; otherwise, if ((rpos + 2 < len) && (data[rpos] == '.') && (data[rpos + 1] == '.') && (data[rpos + 2] == '/')) { c = '/'; rpos += 3; // Remove the last segment while ((wpos > 0) && (data[wpos - 1] != '/')) wpos--; if (wpos > 0) wpos--; continue; } else if ((rpos + 2 == len) && (data[rpos] == '.') && (data[rpos + 1] == '.')) { c = '/'; rpos += 2; // Remove the last segment while ((wpos > 0) && (data[wpos - 1] != '/')) wpos--; if (wpos > 0) wpos--; continue; } } // D. if the input buffer consists only of "." or "..", then remove // that from the input buffer; otherwise, if ((c == '.') && (rpos == len)) { rpos++; continue; } if ((c == '.') && (rpos + 1 == len) && (data[rpos] == '.')) { rpos += 2; continue; } // E. move the first path segment in the input buffer to the end of // the output buffer, including the initial "/" character (if // any) and any subsequent characters up to, but not including, // the next "/" character or the end of the input buffer. data[wpos++] = c; while ((rpos < len) && (data[rpos] != '/')) { // data[wpos++] = data[rpos++]; int c2 = data[rpos++]; data[wpos++] = c2; } c = -1; } bstr_len_adjust(s, wpos); } /** * */ void fprint_raw_data(FILE *stream, const char *name, unsigned char *data, size_t len) { char buf[160]; size_t offset = 0; fprintf(stream, "\n%s: data len %zd (0x%zx)\n", name, len, len); while (offset < len) { size_t i; sprintf(buf, "%08zx", offset); strcat(buf + strlen(buf), " "); i = 0; while (i < 8) { if (offset + i < len) { sprintf(buf + strlen(buf), "%02x ", data[offset + i]); } else { strcat(buf + strlen(buf), " "); } i++; } strcat(buf + strlen(buf), " "); i = 8; while (i < 16) { if (offset + i < len) { sprintf(buf + strlen(buf), "%02x ", data[offset + i]); } else { strcat(buf + strlen(buf), " "); } i++; } strcat(buf + strlen(buf), " |"); i = 0; char *p = buf + strlen(buf); while ((offset + i < len) && (i < 16)) { int c = data[offset + i]; if (isprint(c)) { *p++ = c; } else { *p++ = '.'; } i++; } *p++ = '|'; *p++ = '\n'; *p++ = '\0'; fprintf(stream, "%s", buf); offset += 16; } fprintf(stream, "\n"); } /* */ /** * */ char *htp_connp_in_state_as_string(htp_connp_t *connp) { if (connp == NULL) return "NULL"; if (connp->in_state == htp_connp_REQ_IDLE) return "REQ_IDLE"; if (connp->in_state == htp_connp_REQ_LINE) return "REQ_FIRST_LINE"; if (connp->in_state == htp_connp_REQ_PROTOCOL) return "REQ_PROTOCOL"; if (connp->in_state == htp_connp_REQ_HEADERS) return "REQ_HEADERS"; if (connp->in_state == htp_connp_REQ_BODY_DETERMINE) return "REQ_BODY_DETERMINE"; if (connp->in_state == htp_connp_REQ_BODY_IDENTITY) return "REQ_BODY_IDENTITY"; if (connp->in_state == htp_connp_REQ_BODY_CHUNKED_LENGTH) return "REQ_BODY_CHUNKED_LENGTH"; if (connp->in_state == htp_connp_REQ_BODY_CHUNKED_DATA) return "REQ_BODY_CHUNKED_DATA"; if (connp->in_state == htp_connp_REQ_BODY_CHUNKED_DATA_END) return "REQ_BODY_CHUNKED_DATA_END"; if (connp->in_state == htp_connp_REQ_CONNECT_CHECK) return "htp_connp_REQ_CONNECT_CHECK"; if (connp->in_state == htp_connp_REQ_CONNECT_WAIT_RESPONSE) return "htp_connp_REQ_CONNECT_WAIT_RESPONSE"; return "UNKNOWN"; } /** * */ char *htp_connp_out_state_as_string(htp_connp_t *connp) { if (connp == NULL) return "NULL"; if (connp->out_state == htp_connp_RES_IDLE) return "RES_IDLE"; if (connp->out_state == htp_connp_RES_LINE) return "RES_LINE"; if (connp->out_state == htp_connp_RES_HEADERS) return "RES_HEADERS"; if (connp->out_state == htp_connp_RES_BODY_DETERMINE) return "RES_BODY_DETERMINE"; if (connp->out_state == htp_connp_RES_BODY_IDENTITY) return "RES_BODY_IDENTITY"; if (connp->out_state == htp_connp_RES_BODY_CHUNKED_LENGTH) return "RES_BODY_CHUNKED_LENGTH"; if (connp->out_state == htp_connp_RES_BODY_CHUNKED_DATA) return "RES_BODY_CHUNKED_DATA"; if (connp->out_state == htp_connp_RES_BODY_CHUNKED_DATA_END) return "RES_BODY_CHUNKED_DATA_END"; return "UNKNOWN"; } /** * */ char *htp_tx_progress_as_string(htp_tx_t *tx) { if (tx == NULL) return "NULL"; switch (tx->progress) { case TX_PROGRESS_NEW: return "NEW"; case TX_PROGRESS_REQ_LINE: return "REQ_LINE"; case TX_PROGRESS_REQ_HEADERS: return "REQ_HEADERS"; case TX_PROGRESS_REQ_BODY: return "REQ_BODY"; case TX_PROGRESS_REQ_TRAILER: return "REQ_TRAILER"; case TX_PROGRESS_WAIT: return "WAIT"; case TX_PROGRESS_RES_LINE: return "RES_LINE"; case TX_PROGRESS_RES_HEADERS: return "RES_HEADERS"; case TX_PROGRESS_RES_BODY: return "RES_BODY"; case TX_PROGRESS_RES_TRAILER: return "RES_TRAILER"; case TX_PROGRESS_DONE: return "DONE"; } return "UNKNOWN"; } bstr *htp_unparse_uri_noencode(htp_uri_t *uri) { if (uri == NULL) { return NULL; } // On the first pass determine the length of the final string size_t len = 0; if (uri->scheme != NULL) { len += bstr_len(uri->scheme); len += 3; // "://" } if ((uri->username != NULL) || (uri->password != NULL)) { if (uri->username != NULL) { len += bstr_len(uri->username); } len += 1; // ":" if (uri->password != NULL) { len += bstr_len(uri->password); } len += 1; // "@" } if (uri->hostname != NULL) { len += bstr_len(uri->hostname); } if (uri->port != NULL) { len += 1; // ":" len += bstr_len(uri->port); } if (uri->path != NULL) { len += bstr_len(uri->path); } if (uri->query != NULL) { len += 1; // "?" len += bstr_len(uri->query); } if (uri->fragment != NULL) { len += 1; // "#" len += bstr_len(uri->fragment); } // On the second pass construct the string bstr *r = bstr_alloc(len); if (r == NULL) { return NULL; } if (uri->scheme != NULL) { bstr_add_str_noex(r, uri->scheme); bstr_add_cstr_noex(r, "://"); } if ((uri->username != NULL) || (uri->password != NULL)) { if (uri->username != NULL) { bstr_add_str_noex(r, uri->username); } bstr_add_cstr(r, ":"); if (uri->password != NULL) { bstr_add_str_noex(r, uri->password); } bstr_add_cstr_noex(r, "@"); } if (uri->hostname != NULL) { bstr_add_str_noex(r, uri->hostname); } if (uri->port != NULL) { bstr_add_cstr(r, ":"); bstr_add_str_noex(r, uri->port); } if (uri->path != NULL) { bstr_add_str_noex(r, uri->path); } if (uri->query != NULL) { bstr *query = bstr_strdup(uri->query); htp_uriencoding_normalize_inplace(query); bstr_add_cstr_noex(r, "?"); bstr_add_str_noex(r, query); bstr_free(query); } if (uri->fragment != NULL) { bstr_add_cstr_noex(r, "#"); bstr_add_str_noex(r, uri->fragment); } return r; } /** * Construct a bstr that contains the raw request headers. * * @param tx * @return */ bstr *htp_tx_generate_request_headers_raw(htp_tx_t *tx) { bstr *request_headers_raw = NULL; size_t i, len = 0; for (i = 0; i < list_size(tx->request_header_lines); i++) { htp_header_line_t *hl = list_get(tx->request_header_lines, i); len += bstr_len(hl->line); if (hl->terminators) len += bstr_len(hl->terminators); else len += 2; // 0d 0a } request_headers_raw = bstr_alloc(len); if (request_headers_raw == NULL) { htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Failed to allocate bstring of %d bytes", len); return NULL; } for (i = 0; i < list_size(tx->request_header_lines); i++) { htp_header_line_t *hl = list_get(tx->request_header_lines, i); bstr_add_str_noex(request_headers_raw, hl->line); if (hl->terminators) bstr_add_str_noex(request_headers_raw, hl->terminators); else bstr_add_cstr_noex(request_headers_raw, "\r\n"); } return request_headers_raw; } /** * Get a bstr that contains the raw request headers. This method will always * return an up-to-date buffer, containing the last known headers. Thus, if * it is called once after REQUEST_HEADERS phase it will return one buffer, but * it may return a different buffer if called after REQUEST_TRAILERS phase (but * only if the request actually contains trailer headers). Do not retain the * bstr pointer, as the buffer may change. If there are no changes to the * request header structure, only one buffer will be contstructed and used. (Multiple * invocations of this method will not cause multiple buffers to be created.) * * @param tx * @return */ bstr *htp_tx_get_request_headers_raw(htp_tx_t *tx) { // Check that we are not called too early if (tx->progress < TX_PROGRESS_REQ_HEADERS) return NULL; if (tx->request_headers_raw == NULL) { tx->request_headers_raw = htp_tx_generate_request_headers_raw(tx); tx->request_headers_raw_lines = list_size(tx->request_header_lines); } else { // Check that the buffer we have is not obsolete if (tx->request_headers_raw_lines < list_size(tx->request_header_lines)) { // Rebuild raw buffer bstr_free(tx->request_headers_raw); tx->request_headers_raw = htp_tx_generate_request_headers_raw(tx); tx->request_headers_raw_lines = list_size(tx->request_header_lines); } } return tx->request_headers_raw; } /** * Construct a bstr that contains the raw response headers. * * @param tx * @return */ bstr *htp_tx_generate_response_headers_raw(htp_tx_t *tx) { bstr *response_headers_raw = NULL; size_t i, len = 0; for (i = 0; i < list_size(tx->response_header_lines); i++) { htp_header_line_t *hl = list_get(tx->response_header_lines, i); len += bstr_len(hl->line); if (hl->terminators) len += bstr_len(hl->terminators); else len += 2; // 0d 0a } response_headers_raw = bstr_alloc(len); if (response_headers_raw == NULL) { htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Failed to allocate bstring of %d bytes", len); return NULL; } for (i = 0; i < list_size(tx->response_header_lines); i++) { htp_header_line_t *hl = list_get(tx->response_header_lines, i); bstr_add_str_noex(response_headers_raw, hl->line); if (hl->terminators) bstr_add_str_noex(response_headers_raw, hl->terminators); else bstr_add_cstr_noex(response_headers_raw, "\r\n"); } return response_headers_raw; } /** * Get a bstr that contains the raw response headers. This method will always * return an up-to-date buffer, containing the last known headers. Thus, if * it is called once after RESPONSE_HEADERS phase it will return one buffer, but * it may return a different buffer if called after RESPONSE_TRAILERS phase (but * only if the response actually contains trailer headers). Do not retain the * bstr pointer, as the buffer may change. If there are no changes to the * response header structure, only one buffer will be contstructed and used. (Multiple * invocations of this method will not cause multiple buffers to be created.) * * @param tx * @return */ bstr *htp_tx_get_response_headers_raw(htp_tx_t *tx) { // Check that we are not called too early if (tx->progress < TX_PROGRESS_RES_HEADERS) return NULL; if (tx->response_headers_raw == NULL) { tx->response_headers_raw = htp_tx_generate_response_headers_raw(tx); tx->response_headers_raw_lines = list_size(tx->response_header_lines); } else { // Check that the buffer we have is not obsolete if (tx->response_headers_raw_lines < list_size(tx->response_header_lines)) { // Rebuild raw buffer bstr_free(tx->response_headers_raw); tx->response_headers_raw = htp_tx_generate_response_headers_raw(tx); tx->response_headers_raw_lines = list_size(tx->response_header_lines); } } return tx->response_headers_raw; } suricata-1.4.7/libhtp/install-sh0000755000000000000000000003325512253546170013530 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # 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. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$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 $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # 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. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: suricata-1.4.7/libhtp/config.sub0000755000000000000000000010535412253546170013507 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-08-10' # This file 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 3 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, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or1k-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: suricata-1.4.7/libhtp/INSTALL0000644000000000000000000003660512253546170012557 00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. 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, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. 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 you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' 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. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. 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 can use 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 `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer 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. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= 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'. 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. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS 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 machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. 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. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. suricata-1.4.7/libhtp/htp.pc.in0000644000000000000000000000033212253546156013242 00000000000000prefix=/usr exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: HTP Description: HTTP parser Version: 0.2.13 Libs: -L${libdir} -lhtp Cflags: -I${includedir}/htp -I${libdir}/htp/include suricata-1.4.7/libhtp/NEWS0000644000000000000000000000000012253546156012205 00000000000000suricata-1.4.7/libhtp/Makefile.in0000644000000000000000000006535412253546170013576 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = INSTALL NEWS README AUTHORS ChangeLog \ $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in $(srcdir)/htp.pc.in COPYING config.guess \ config.sub install-sh missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac 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 = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = htp.pc CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-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 \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkgconfigdir)" DATA = $(pkgconfig_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GENERIC_API_VERSION = @GENERIC_API_VERSION@ GENERIC_LIBRARY_NAME = @GENERIC_LIBRARY_NAME@ GENERIC_LIBRARY_VERSION = @GENERIC_LIBRARY_VERSION@ GENERIC_RELEASE = @GENERIC_RELEASE@ GENERIC_VERSION = @GENERIC_VERSION@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = $(GENERIC_LIBRARY_NAME) test DIST_SUBDIRS = $(GENERIC_LIBRARY_NAME) test pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = htp.pc all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu 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) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(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) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 htp.pc: $(top_builddir)/config.status $(srcdir)/htp.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) # 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. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ 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; \ ($(am__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" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ 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 || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -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__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_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) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(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 \ && cd "$$am__cwd" \ || exit 1 $(am__post_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: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { 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 $(DATA) config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 html-am: info: info-recursive info-am: install-data-am: install-pkgconfigDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: 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: uninstall-pkgconfigDATA .MAKE: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ dist-xz 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-pkgconfigDATA \ 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-am uninstall \ uninstall-am uninstall-pkgconfigDATA # 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: suricata-1.4.7/libhtp/AUTHORS0000644000000000000000000000004312253546156012565 00000000000000Ivan Ristic suricata-1.4.7/libhtp/missing0000755000000000000000000001533112253546170013116 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2012-06-26.16; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 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, see . # 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 case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'automa4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: suricata-1.4.7/libhtp/Makefile.am0000644000000000000000000000022112253546156013547 00000000000000 SUBDIRS= $(GENERIC_LIBRARY_NAME) test DIST_SUBDIRS = $(GENERIC_LIBRARY_NAME) test pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = htp.pc suricata-1.4.7/libhtp/configure0000755000000000000000000145441112253546167013443 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="htp/htp.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_default_prefix=/usr/local ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM GENERIC_VERSION GENERIC_RELEASE GENERIC_LIBRARY_NAME GENERIC_LIBRARY_VERSION GENERIC_API_VERSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_htp_debug enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-htp-debug Enable debug output --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" GENERIC_LIBRARY_NAME=htp GENERIC_MAJOR_VERSION=0 GENERIC_MINOR_VERSION=2 GENERIC_MICRO_VERSION=14 # API version (often = GENERIC_MAJOR_VERSION.GENERIC_MINOR_VERSION) GENERIC_API_VERSION=1.0 # Shared library versioning GENERIC_LIBRARY_VERSION=1:2:0 # | | | # +------+ | +---+ # | | | # current:revision:age # | | | # | | +- increment if interfaces have been added # | | set to zero if interfaces have been removed # or changed # | +- increment if source code has changed # | set to zero if current is incremented # +- increment if interfaces have been added, removed or changed PACKAGE=$GENERIC_LIBRARY_NAME GENERIC_VERSION=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION.$GENERIC_MICRO_VERSION GENERIC_RELEASE=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION VERSION=$GENERIC_VERSION am__api_version='1.13' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE=$PACKAGE VERSION=$VERSION # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Check whether --enable-htp-debug was given. if test "${enable_htp_debug+set}" = set; then : enableval=$enable_htp_debug; enable_htp_debug=yes fi if test "$enable_htp_debug" = "yes"; then CFLAGS="${CFLAGS} -DHTP_DEBUG" echo "Debug mode enabled" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : else as_fn_error $? "zlib.h not found ..." "$LINENO" 5 fi ZLIB="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflate in -lz" >&5 $as_echo_n "checking for inflate in -lz... " >&6; } if ${ac_cv_lib_z_inflate+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inflate (); int main () { return inflate (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_inflate=yes else ac_cv_lib_z_inflate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflate" >&5 $as_echo "$ac_cv_lib_z_inflate" >&6; } if test "x$ac_cv_lib_z_inflate" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBZ 1 _ACEOF LIBS="-lz $LIBS" else ZLIB="no" fi if test "$ZLIB" = "no"; then echo echo " ERROR! zlib library not found" echo exit 1 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -z relro" >&5 $as_echo_n "checking for -z relro... " >&6; } TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z relro" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : SECLDFLAGS="${SECLDFLAGS} -z relro" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="${TMPLDFLAGS}" #check for os { $as_echo "$as_me:${as_lineno-$LINENO}: checking host os" >&5 $as_echo_n "checking host os... " >&6; } # If no host os was detected, try with uname if test -z "$host" ; then host="`uname`" fi case "$host" in *-*-openbsd*) CFLAGS="${CFLAGS} -fgnu89-inline" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -z now" >&5 $as_echo_n "checking for -z now... " >&6; } TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z now" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : SECLDFLAGS="${SECLDFLAGS} -z now" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="${TMPLDFLAGS}" CFLAGS="${CFLAGS} ${SECCFLAGS}" LDFLAGS="${LDFLAGS} ${SECLDFLAGS}" ac_config_files="$ac_config_files Makefile htp.pc htp/Makefile test/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "htp.pc") CONFIG_FILES="$CONFIG_FILES htp.pc" ;; "htp/Makefile") CONFIG_FILES="$CONFIG_FILES htp/Makefile" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi suricata-1.4.7/scripts/0000755000000000000000000000000012253546204011777 500000000000000suricata-1.4.7/scripts/suricatasc/0000755000000000000000000000000012253546204014140 500000000000000suricata-1.4.7/scripts/suricatasc/src/0000755000000000000000000000000012253546204014727 500000000000000suricata-1.4.7/scripts/suricatasc/src/__init__.py0000644000000000000000000000003212253546156016761 00000000000000 from suricatasc import * suricata-1.4.7/scripts/suricatasc/src/suricatasc.py0000644000000000000000000001631712253546156017400 00000000000000#!/usr/bin/python # Copyright(C) 2012 Open Information Security Foundation # 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, version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import simplejson as json import re import readline from socket import socket, AF_UNIX, error from time import sleep import sys SURICATASC_VERSION = "0.9" VERSION = "0.1" SIZE = 4096 class SuricataException(Exception): """ Generic class for suricatasc exception """ def __init__(self, value): self.value = value def __str__(self): return str(self.value) class SuricataNetException(SuricataException): """ Exception raised when network error occur. """ pass class SuricataCommandException(SuricataException): """ Exception raised when command is not correct. """ pass class SuricataReturnException(SuricataException): """ Exception raised when return message is not correct. """ pass class SuricataCompleter: def __init__(self, words): self.words = words self.generator = None def complete(self, text): for word in self.words: if word.startswith(text): yield word def __call__(self, text, state): if state == 0: self.generator = self.complete(text) try: return self.generator.next() except StopIteration: return None return None class SuricataSC: def __init__(self, sck_path, verbose=False): self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat'] self.sck_path = sck_path self.verbose = verbose def json_recv(self): cmdret = None i = 0 data = "" while i < 5: i += 1 data += self.socket.recv(SIZE) try: cmdret = json.loads(data) break except json.decoder.JSONDecodeError: sleep(0.3) return cmdret def send_command(self, command, arguments = None): if command not in self.cmd_list and command != 'command-list': raise SuricataCommandException("No such command: %s", command) cmdmsg = {} cmdmsg['command'] = command if (arguments != None): cmdmsg['arguments'] = arguments if self.verbose: print "SND: " + json.dumps(cmdmsg) self.socket.send(json.dumps(cmdmsg)) cmdret = self.json_recv() if cmdret == None: raise SuricataReturnException("Unable to get message from server") if self.verbose: print "RCV: "+ json.dumps(cmdret) return cmdret def connect(self): try: self.socket = socket(AF_UNIX) self.socket.connect(self.sck_path) except error, err: raise SuricataNetException(err) self.socket.settimeout(10) #send version if self.verbose: print "SND: " + json.dumps({"version": VERSION}) self.socket.send(json.dumps({"version": VERSION})) # get return cmdret = self.json_recv() if cmdret == None: raise SuricataReturnException("Unable to get message from server") if self.verbose: print "RCV: "+ json.dumps(cmdret) if cmdret["return"] == "NOK": raise SuricataReturnException("Error: %s" % (cmdret["message"])) cmdret = self.send_command("command-list") # we silently ignore NOK as this means server is old if cmdret["return"] == "OK": self.cmd_list = cmdret["message"]["commands"] self.cmd_list.append("quit") def close(self): self.socket.close() def interactive(self): print "Command list: " + ", ".join(self.cmd_list) try: readline.set_completer(SuricataCompleter(self.cmd_list)) readline.set_completer_delims(";") readline.parse_and_bind('tab: complete') while True: command = raw_input(">>> ").strip() arguments = None if command.split(' ', 2)[0] in self.cmd_list: if command == "quit": break; if "pcap-file " in command: try: [cmd, filename, output] = command.split(' ', 2) except: print "Error: arguments to command '%s' is missing" % (command) continue if cmd != "pcap-file": print "Error: invalid command '%s'" % (command) continue else: arguments = {} arguments["filename"] = filename arguments["output-dir"] = output elif "iface-stat" in command: try: [cmd, iface] = command.split(' ', 1) except: print "Error: unable to split command '%s'" % (command) continue if cmd != "iface-stat": print "Error: invalid command '%s'" % (command) continue else: arguments = {} arguments["iface"] = iface elif "conf-get" in command: try: [cmd, variable] = command.split(' ', 1) except: print "Error: unable to split command '%s'" % (command) continue if cmd != "conf-get": print "Error: invalid command '%s'" % (command) continue else: arguments = {} arguments["variable"] = variable else: cmd = command else: print "Error: unknown command '%s'" % (command) continue cmdret = self.send_command(cmd, arguments) #decode json message if cmdret["return"] == "NOK": print "Error:" print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': ')) else: print "Success:" print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': ')) except KeyboardInterrupt: print "[!] Interrupted" suricata-1.4.7/scripts/suricatasc/Makefile.in0000644000000000000000000003421112253546174016134 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = scripts/suricatasc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(srcdir)/suricatasc.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = suricatasc CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = setup.py suricatasc.in src/__init__.py src/suricatasc.py all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/suricatasc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/suricatasc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): suricatasc: $(top_builddir)/config.status $(srcdir)/suricatasc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am @HAVE_PYTHON_FALSE@all-local: all-am: Makefile all-local installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @HAVE_PYTHON_FALSE@uninstall-local: @HAVE_PYTHON_FALSE@distclean-local: @HAVE_PYTHON_FALSE@install-exec-local: @HAVE_PYTHON_FALSE@clean-local: clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-local dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-exec-local install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-local .MAKE: install-am install-strip .PHONY: all all-am all-local check check-am clean clean-generic \ clean-libtool clean-local cscopelist-am ctags-am distclean \ distclean-generic distclean-libtool distclean-local distdir \ 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-exec-local 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 \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-local @HAVE_PYTHON_TRUE@all-local: @HAVE_PYTHON_TRUE@ mkdir -p $(top_builddir)/scripts/suricatasc/src @HAVE_PYTHON_TRUE@ $(PYTHON) $(srcdir)/setup.py build; @HAVE_PYTHON_TRUE@install-exec-local: @HAVE_PYTHON_TRUE@ $(PYTHON) $(srcdir)/setup.py install --prefix $(DESTDIR)$(prefix) @HAVE_PYTHON_TRUE@clean-local: @HAVE_PYTHON_TRUE@ $(PYTHON) $(srcdir)/setup.py clean; @HAVE_PYTHON_TRUE@ rm -rf $(top_builddir)/scripts/suricatasc/build @HAVE_PYTHON_TRUE@uninstall-local: @HAVE_PYTHON_TRUE@ [ ! -f "$(DESTDIR)$(prefix)/bin/suricatasc" ] || rm -f "$(DESTDIR)$(prefix)/bin/suricatasc" @HAVE_PYTHON_TRUE@ find "$(DESTDIR)$(prefix)/lib" -name "suricatasc-*.egg-info" -delete ||true @HAVE_PYTHON_TRUE@distclean-local: @HAVE_PYTHON_TRUE@ -rm -rf $(top_builddir)/scripts/suricatasc/src # 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: suricata-1.4.7/scripts/suricatasc/suricatasc.in0000755000000000000000000000347412253546156016572 00000000000000#!/usr/bin/python # Copyright(C) 2013 Open Information Security Foundation # 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, version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import argparse from suricatasc import * parser = argparse.ArgumentParser(prog='suricatasc', description='Client for Suricata unix socket') parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output (including JSON dump)') parser.add_argument('socket', metavar='socket', nargs='?', help='socket file to connnect to', default=None) args = parser.parse_args() if args.socket != None: SOCKET_PATH = "@e_localstatedir@/" + args.socket[0] else: SOCKET_PATH = "@e_localstatedir@/suricata-command.socket" sc = SuricataSC(SOCKET_PATH, verbose=args.verbose) try: sc.connect() except SuricataNetException, err: print "Unable to connect to socket %s: %s" % (SOCKET_PATH, err) sys.exit(1) except SuricataReturnException, err: print "Unable to negotiate version with server: %s" % (err) sys.exit(1) try: sc.interactive() except SuricataNetException, err: print "Communication error: %s" % (err) sys.exit(1) except SuricataReturnException, err: print "Invalid return from server: %s" % (err) sys.exit(1) print "[+] Quit command client" sc.close() suricata-1.4.7/scripts/suricatasc/setup.py0000755000000000000000000000155412253546156015610 00000000000000#!/usr/bin/env python from distutils.core import setup SURICATASC_VERSION = "0.9" setup(name='suricatasc', version=SURICATASC_VERSION, description='Suricata unix socket client', author='Eric Leblond', author_email='eric@regit.org', url='https://www.suricata-ids.org/', scripts=['suricatasc'], packages=['suricatasc'], package_dir={'suricatasc':'src'}, provides=['suricatasc'], requires=['argparse','simplejson'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Operating System :: POSIX', 'Programming Language :: Python', 'Topic :: System :: Systems Administration', ], ) suricata-1.4.7/scripts/suricatasc/Makefile.am0000644000000000000000000000117012253546156016121 00000000000000EXTRA_DIST = setup.py suricatasc.in src/__init__.py src/suricatasc.py if HAVE_PYTHON all-local: mkdir -p $(top_builddir)/scripts/suricatasc/src $(PYTHON) $(srcdir)/setup.py build; install-exec-local: $(PYTHON) $(srcdir)/setup.py install --prefix $(DESTDIR)$(prefix) clean-local: $(PYTHON) $(srcdir)/setup.py clean; rm -rf $(top_builddir)/scripts/suricatasc/build uninstall-local: [ ! -f "$(DESTDIR)$(prefix)/bin/suricatasc" ] || rm -f "$(DESTDIR)$(prefix)/bin/suricatasc" find "$(DESTDIR)$(prefix)/lib" -name "suricatasc-*.egg-info" -delete ||true distclean-local: -rm -rf $(top_builddir)/scripts/suricatasc/src endif suricata-1.4.7/scripts/Makefile.in0000644000000000000000000004607212253546174014003 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = scripts DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-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 \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = suricatasc all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ 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; \ ($(am__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" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ 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 || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -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: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-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-am 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: suricata-1.4.7/scripts/Makefile.am0000644000000000000000000000002312253546156013754 00000000000000SUBDIRS=suricatasc suricata-1.4.7/config.guess0000755000000000000000000013036112253546173012561 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-06-10' # This file 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 3 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, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: suricata-1.4.7/configure.ac0000644000000000000000000016717112253546156012541 00000000000000#TODO A better place for default CFLAGS? AC_INIT(configure.ac) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE(suricata, 1.4.7) CFLAGS="${CFLAGS} -DRELEASE" AC_LANG_C AC_PROG_CC_C99 AC_PROG_LIBTOOL AC_DEFUN([FAIL_MESSAGE],[ echo echo echo "**********************************************" echo " ERROR: unable to find" $1 echo " checked in the following places" for i in `echo $2`; do echo " $i" done echo "**********************************************" echo exit 1 ]) AC_DEFUN([LIBNET_FAIL_WARN],[ echo echo "*************************************************************************" echo " Warning! libnet version 1.1.x could not be found in " $1 echo " Reject keywords will not be supported." echo " If you require reject support plese install libnet 1.1.x. " echo " If libnet is not installed in a non-standard location please use the" echo " --with-libnet-includes and --with-libnet-libraries configure options" echo "*************************************************************************" echo ]) if test `basename $CC` = "clang"; then CFLAGS="$CFLAGS -Wextra -Werror-implicit-function-declaration" AC_MSG_CHECKING([clang __sync_bool_compare_and_swap]) AC_TRY_COMPILE([#include ], [ unsigned int i = 0; (void)__sync_bool_compare_and_swap(&i, 1, 1);], [ AC_DEFINE([__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1], [1], [Fake GCC atomic support]) AC_DEFINE([__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2], [1], [Fake GCC atomic support]) AC_DEFINE([__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4], [1], [Fake GCC atomic support]) AC_DEFINE([__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8], [1], [Fake GCC atomic support]) AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])]) fi if test `basename $CC` = "gcc"; then dnl get gcc version AC_MSG_CHECKING([gcc version]) gccver=$($CC -dumpversion) gccvermajor=$(echo $gccver | cut -d . -f1) gccverminor=$(echo $gccver | cut -d . -f2) gccvernum=$(expr $gccvermajor "*" 100 + $gccverminor) AC_MSG_RESULT($gccver) if test "$gccvernum" -ge "400"; then dnl gcc 4.0 or later CFLAGS="$CFLAGS -Wextra -Werror-implicit-function-declaration" # remove optimization options that break our code # VJ 2010/06/27: no-tree-pre added. It breaks ringbuffers code. CFLAGS="$CFLAGS -fno-tree-pre" else CFLAGS="$CFLAGS -W" fi fi CFLAGS="$CFLAGS -Wall -fno-strict-aliasing" CFLAGS="$CFLAGS -Wno-unused-parameter" CFLAGS="$CFLAGS -std=gnu99" # Checks for programs. AC_PROG_AWK AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PATH_PROG(HAVE_PKG_CONFIG, pkg-config, "no") if test "$HAVE_PKG_CONFIG" = "no"; then echo echo " ERROR! pkg-config not found, go get it " echo " http://pkg-config.freedesktop.org/wiki/ " echo " or install from your distribution " echo exit 1 fi AC_PATH_PROG(HAVE_COCCINELLE_CONFIG, spatch, "no") if test "$HAVE_COCCINELLE_CONFIG" = "no"; then echo echo " Warning! spatch not found, you will not be " echo " able to run code checking with coccinelle " echo " get it from http://coccinelle.lip6.fr " echo " or install from your distribution " echo fi AM_CONDITIONAL([HAVE_COCCINELLE], [test "$HAVE_COCCINELLE_CONFIG" != "no"]) AC_PATH_PROG(HAVE_PYTHON_CONFIG, python, "no") if test "$HAVE_PYTHON_CONFIG" = "no"; then echo echo " Warning! python not found, you will not be " echo " able to install surictasc unix socket client " echo enable_python="no" else enable_python="yes" fi AM_CONDITIONAL([HAVE_PYTHON], [test "$HAVE_PYTHON_CONFIG" != "no"]) # Checks for libraries. # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h assert.h ctype.h errno.h fcntl.h inttypes.h]) AC_CHECK_HEADERS([getopt.h]) AC_CHECK_HEADERS([limits.h netdb.h netinet/in.h poll.h sched.h signal.h]) AC_CHECK_HEADERS([stdarg.h stdint.h stdio.h stdlib.h string.h sys/ioctl.h]) AC_CHECK_HEADERS([syslog.h sys/prctl.h sys/socket.h sys/stat.h sys/syscall.h]) AC_CHECK_HEADERS([sys/time.h time.h unistd.h]) AC_CHECK_HEADERS([sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h]) AC_CHECK_HEADERS([sys/socket.h net/if.h sys/mman.h linux/if_arp.h], [], [], [[#ifdef HAVE_SYS_SOCKET_H #include #include #endif ]]) AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h], [], [], [[#define _X86_ ]]) AC_CHECK_HEADERS([w32api/winbase.h], [], [], [[#define _X86_ #include ]]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_INT32_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T AC_HEADER_STDBOOL # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([gettimeofday memset strcasecmp strchr strdup strerror strncasecmp strtol strtoul memchr]) # Add large file support AC_SYS_LARGEFILE #check for os AC_MSG_CHECKING([host os]) # If no host os was detected, try with uname if test -z "$host" ; then host="`uname`" fi echo -n "installation for $host OS... " e_magic_file="/usr/share/file/magic" case "$host" in *-*-*freebsd*) CFLAGS="${CFLAGS} -DOS_FREEBSD" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet11" LDFLAGS="${LDFLAGS} -L/usr/local/lib -L/usr/local/lib/libnet11" e_magic_file="/usr/share/misc/magic" ;; *-*-openbsd5.1) CFLAGS="${CFLAGS} -D__OpenBSD__ -fgnu89-inline" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet-1.1" LDFLAGS="${LDFLAGS} -L/usr/local/lib -I/usr/local/lib/libnet-1.1" e_magic_file="/usr/local/share/misc/magic.mgc" ;; *-*-openbsd5.2) CFLAGS="${CFLAGS} -D__OpenBSD__" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet-1.1" LDFLAGS="${LDFLAGS} -L/usr/local/lib -I/usr/local/lib/libnet-1.1" e_magic_file="/usr/local/share/misc/magic.mgc" ;; *-*-openbsd*) CFLAGS="${CFLAGS} -D__OpenBSD__ -fgnu89-inline" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet-1.1" LDFLAGS="${LDFLAGS} -L/usr/local/lib -I/usr/local/lib/libnet-1.1" e_magic_file="/usr/local/share/file/magic.mgc" ;; *darwin*|*Darwin*) CFLAGS="${CFLAGS} -DOS_DARWIN" CPPFLAGS="${CPPFLAGS} -I/opt/local/include" LDFLAGS="${LDFLAGS} -L/opt/local/lib" ;; *-*-linux*) #for now do nothing ;; *-*-mingw32*) CFLAGS="${CFLAGS} -DOS_WIN32" LDFLAGS="${LDFLAGS} -lws2_32" WINDOWS_PATH="yes" ;; *-*-cygwin) WINDOWS_PATH="yes" ;; *) AC_MSG_WARN([unsupported OS this may or may not work]) ;; esac AC_MSG_RESULT(ok) #Enable support for gcc compile time security options. There is no great way to do detection of valid cflags that I have found #AX_CFLAGS_GCC_OPTION don't seem to do a better job than the code below and are a pain because of extra m4 files etc. #These flags seem to be supported on CentOS 5+, Ubuntu 8.04+, and FedoreCore 11+ #Options are taken from https://wiki.ubuntu.com/CompilerFlags AC_ARG_ENABLE(gccprotect, AS_HELP_STRING([--enable-gccprotect], [Detect and use gcc hardening options]),,[enable_gccprotect=no]) AS_IF([test "x$enable_gccprotect" = "xyes"], [ #buffer overflow protection AC_MSG_CHECKING(for -fstack-protector) TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -fstack-protector" AC_TRY_LINK(,,SECCFLAGS="${SECCFLAGS} -fstack-protector" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #compile-time best-practices errors for certain libc functions, provides checks of buffer lengths and memory regions AC_MSG_CHECKING(for -D_FORTIFY_SOURCE=2) TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -D_FORTIFY_SOURCE=2" AC_TRY_COMPILE(,,SECCFLAGS="${SECCFLAGS} -D_FORTIFY_SOURCE=2" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #compile-time warnings about misuse of format strings AC_MSG_CHECKING(for -Wformat -Wformat-security) TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wformat -Wformat-security" AC_TRY_COMPILE(,,SECCFLAGS="${SECCFLAGS} -Wformat -Wformat-security" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #provides a read-only relocation table area in the final ELF AC_MSG_CHECKING(for -z relro) TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z relro" AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z relro" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) LDFLAGS="${TMPLDFLAGS}" #forces all relocations to be resolved at run-time AC_MSG_CHECKING(for -z now) TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z now" AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z now" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) LDFLAGS="${TMPLDFLAGS}" CFLAGS="${CFLAGS} ${SECCFLAGS}" LDFLAGS="${LDFLAGS} ${SECLDFLAGS}" ]) #enable profile generation AC_ARG_ENABLE(gccprofile, AS_HELP_STRING([--enable-gccprofile], [Enable gcc profile info i.e -pg flag is set]),,[enable_gccprofile=no]) AS_IF([test "x$enable_gccprofile" = "xyes"], [ CFLAGS="${CFLAGS} -pg" ]) #enable gcc march=native gcc 4.2 or later AC_ARG_ENABLE(gccmarch_native, AS_HELP_STRING([--enable-gccmarch-native], [Enable gcc march=native gcc 4.2 and later only]),,[enable_gccmarch_native=yes]) AS_IF([test "x$enable_gccmarch_native" = "xyes"], [ if test `basename $CC` = "clang"; then OFLAGS="$CFLAGS" CFLAGS="$CFLAGS -march=native" AC_MSG_CHECKING([checking if $CC supports -march=native]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]])], [ AC_MSG_RESULT([yes]) CFLAGS="$OFLAGS -march=native" ], [ AC_MSG_RESULT([no]) CFLAGS="$OFLAGS" enable_gccmarch_native=no ] ) fi if test `basename $CC` = "gcc"; then case $host in *darwin*|*Darwin*) if test "$gccvernum" -ge "403"; then dnl gcc 4.3 or later CFLAGS="$CFLAGS -march=native" else enable_gccmarch_native=no fi ;; *) if test "$gccvernum" -ge "402"; then dnl gcc 4.2 or later CFLAGS="$CFLAGS -march=native" fi ;; esac fi ]) # options # enable the running of unit tests AC_ARG_ENABLE(unittests, AS_HELP_STRING([--enable-unittests], [Enable compilation of the unit tests]),,[enable_unittests=no]) AS_IF([test "x$enable_unittests" = "xyes"], [ UT_ENABLED="yes" CFLAGS="${CFLAGS} -DUNITTESTS" ]) AM_CONDITIONAL([BUILD_UNITTESTS], [test "x$enable_unittests" = "xyes"]) # enable workaround for old barnyard2 for unified alert output AC_ARG_ENABLE(old-barnyard2, AS_HELP_STRING([--enable-old-barnyard2], [Use workaround for old barnyard2 in unified2 output]),,[enable_old_barnyard2=no]) AS_IF([test "x$enable_old_barnyard2" = "xyes"], [ CFLAGS="${CFLAGS} -DHAVE_OLD_BARNYARD2" ]) # enable debug output AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [Enable debug output]),,[enable_debug=no]) AS_IF([test "x$enable_debug" = "xyes"], [ CFLAGS="${CFLAGS} -DDEBUG" ]) # enable debug validation functions & macro's output AC_ARG_ENABLE(debug-validation, AS_HELP_STRING([--enable-debug-validation], [Enable (debug) validation code output]),,[enable_debug_validation=no]) AS_IF([test "x$enable_debug_validation" = "xyes"], [ CFLAGS="${CFLAGS} -DDEBUG_VALIDATION" ]) # profiling support AC_ARG_ENABLE(profiling, AS_HELP_STRING([--enable-profiling], [Enable performance profiling]),,[enable_profiling=no]) AS_IF([test "x$enable_profiling" = "xyes"], [ case "$host" in *-*-openbsd*) AC_MSG_ERROR([profiling is not supported on OpenBSD]) ;; *) CFLAGS="${CFLAGS} -DPROFILING" ;; esac ]) # profiling support, locking AC_ARG_ENABLE(profiling-locks, AS_HELP_STRING([--enable-profiling-locks], [Enable performance profiling for locks]),,[enable_profiling_locks=no]) AS_IF([test "x$enable_profiling_locks" = "xyes"], [ CFLAGS="${CFLAGS} -DPROFILING -DPROFILE_LOCKING" ]) # enable support for IPFW AC_ARG_ENABLE(ipfw, AS_HELP_STRING([--enable-ipfw], [Enable FreeBSD IPFW support for inline IDP]),,[enable_ipfw=no]) AS_IF([test "x$enable_ipfw" = "xyes"], [ CFLAGS="$CFLAGS -DIPFW" ]) # libraries #libpcre AC_ARG_WITH(libpcre_includes, [ --with-libpcre-includes=DIR libpcre include directory], [with_libpcre_includes="$withval"],[with_libpcre_includes=no]) AC_ARG_WITH(libpcre_libraries, [ --with-libpcre-libraries=DIR libpcre library directory], [with_libpcre_libraries="$withval"],[with_libpcre_libraries="no"]) if test "$with_libpcre_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libpcre_includes}" fi AC_CHECK_HEADER(pcre.h,,[AC_ERROR(pcre.h not found ...)]) if test "$with_libpcre_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libpcre_libraries}" fi PCRE="" AC_CHECK_LIB(pcre, pcre_get_substring,, PCRE="no") if test "$PCRE" = "no"; then echo echo " ERROR! pcre library not found, go get it" echo " from www.pcre.org." echo exit 1 fi # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work # see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful PCRE="" TMPLIBS="${LIBS}" AC_CHECK_LIB(pcre, pcre_dfa_exec,, PCRE="no") if test "$PCRE" = "no"; then echo echo " ERROR! pcre library was found but version was < 6.0" echo " please upgrade to a newer version of pcre which you can get from" echo " www.pcre.org." echo exit 1 fi LIBS="${TMPLIBS}" AC_TRY_COMPILE([ #include ], [ int eo = 0; eo |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; ], [ pcre_match_limit_recursion_available=yes ], [:] ) if test "$pcre_match_limit_recursion_available" != "yes"; then CFLAGS="${CFLAGS} -DNO_PCRE_MATCH_RLIMIT" echo echo " Warning! pcre extra opt PCRE_EXTRA_MATCH_LIMIT_RECURSION not found" echo " This could lead to potential DoS please upgrade to pcre >= 6.5" echo " Continuing for now...." echo " from www.pcre.org." echo fi #enable support for PCRE-jit available since pcre-8.20 AC_MSG_CHECKING(for PCRE JIT support) AC_TRY_COMPILE([ #include ], [ int jit = 0; pcre_config(PCRE_CONFIG_JIT, &jit); ], [ pcre_jit_available=yes ], [ pcre_jit_available=no ] ) if test "x$pcre_jit_available" = "xyes"; then AC_MSG_RESULT(yes) AC_DEFINE([PCRE_HAVE_JIT], [1], [Pcre with JIT compiler support enabled]) AC_MSG_CHECKING(for PCRE JIT support usability) AC_TRY_COMPILE([ #include ], [ const char* regexstr = "(a|b|c|d)"; pcre *re; const char *error; pcre_extra *extra; int err_offset; re = pcre_compile(regexstr,0, &error, &err_offset,NULL); extra = pcre_study(re, PCRE_STUDY_JIT_COMPILE, &error); if (extra == NULL) exit(EXIT_FAILURE); int jit = 0; int ret = pcre_fullinfo(re, extra, PCRE_INFO_JIT, &jit); if (ret != 0 || jit != 1) exit(EXIT_FAILURE); exit(EXIT_SUCCESS); ], [ pcre_jit_works=yes ], [:] ) if test "x$pcre_jit_works" != "xyes"; then AC_MSG_RESULT(no) echo echo " PCRE JIT support detection worked but testing it failed" echo " something odd is going on, please file a bug report." echo exit 1 else AC_MSG_RESULT(yes) fi else AC_MSG_RESULT(no) fi # libyaml AC_ARG_WITH(libyaml_includes, [ --with-libyaml-includes=DIR libyaml include directory], [with_libyaml_includes="$withval"],[with_libyaml_includes=no]) AC_ARG_WITH(libyaml_libraries, [ --with-libyaml-libraries=DIR libyaml library directory], [with_libyaml_libraries="$withval"],[with_libyaml_libraries="no"]) if test "$with_libyaml_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libyaml_includes}" fi AC_CHECK_HEADER(yaml.h,,LIBYAML="no") if test "$with_libyaml_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libyaml_libraries}" fi LIBYAML="" AC_CHECK_LIB(yaml,yaml_parser_initialize,,LIBYAML="no") if test "$LIBYAML" = "no"; then echo echo " ERROR! libyaml library not found, go get it" echo " from http://pyyaml.org/wiki/LibYAML " echo " or your distribution:" echo echo " Ubuntu: apt-get install libyaml-dev" echo " Fedora: yum install libyaml-devel" echo exit 1 fi # libpthread AC_ARG_WITH(libpthread_includes, [ --with-libpthread-includes=DIR libpthread include directory], [with_libpthread_includes="$withval"],[with_libpthread_includes=no]) AC_ARG_WITH(libpthread_libraries, [ --with-libpthread-libraries=DIR libpthread library directory], [with_libpthread_libraries="$withval"],[with_libpthread_libraries="no"]) if test "$with_libpthread_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libpthread_includes}" fi dnl AC_CHECK_HEADER(pthread.h,,[AC_ERROR(pthread.h not found ...)]) if test "$with_libpthread_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libpthread_libraries}" fi PTHREAD="" AC_CHECK_LIB(pthread, pthread_create,, PTHREAD="no") if test "$PTHREAD" = "no"; then echo echo " ERROR! libpthread library not found, glibc problem?" echo exit 1 fi # libjansson enable_jansson="no" AC_ARG_WITH(libjansson_includes, [ --with-libjansson-includes=DIR libjansson include directory], [with_libjansson_includes="$withval"],[with_libjansson_includes=no]) AC_ARG_WITH(libjansson_libraries, [ --with-libjansson-libraries=DIR libjansson library directory], [with_libjansson_libraries="$withval"],[with_libjansson_libraries="no"]) if test "$with_libjansson_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libjansson_includes}" fi enable_jansson="no" enable_unixsocket="no" AC_ARG_ENABLE(unix-socket, AS_HELP_STRING([--enable-unix-socket], [Enable unix socket [default=test]]),[enable_unixsocket="$enableval"],[enable_unixsocket=test]) AC_CHECK_HEADER(jansson.h,JANSSON="yes",JANSSON="no") if test "$JANSSON" = "yes"; then if test "$with_libjansson_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libjansson_libraries}" fi AC_CHECK_LIB(jansson, json_dump_callback,, JANSSON="no") enable_jansson="yes" if test "$JANSSON" = "no"; then echo echo " Jansson >= 2.2 is required for features like unix socket" echo " Go get it from your distribution of from:" echo " http://www.digip.org/jansson/" echo if test "x$enable_unixsocket" = "xyes"; then exit 1 fi enable_unixsocket="no" enable_jansson="no" else case $host in *-*-mingw32*) ;; *-*-cygwin) ;; *) if test "x$enable_unixsocket" = "xtest"; then enable_unixsocket="yes" fi ;; esac fi else if test "x$enable_unixsocket" = "xyes"; then echo echo " Jansson >= 2.2 is required for features like unix socket" echo " Go get it from your distribution of from:" echo " http://www.digip.org/jansson/" echo exit 1 fi enable_unixsocket="no" fi AS_IF([test "x$enable_unixsocket" = "xyes"], [AC_DEFINE([BUILD_UNIX_SOCKET], [1], [Unix socket support enabled])]) #enable support for NFQUEUE AC_ARG_ENABLE(nfqueue, AS_HELP_STRING([--enable-nfqueue], [Enable NFQUEUE support for inline IDP]),,[enable_nfqueue=no]) AS_IF([test "x$enable_nfqueue" = "xyes"], [ CFLAGS="$CFLAGS -DNFQ" # libnfnetlink case $host in *-*-mingw32*) ;; *) AC_ARG_WITH(libnfnetlink_includes, [ --with-libnfnetlink-includes=DIR libnfnetlink include directory], [with_libnfnetlink_includes="$withval"],[with_libnfnetlink_includes=no]) AC_ARG_WITH(libnfnetlink_libraries, [ --with-libnfnetlink-libraries=DIR libnfnetlink library directory], [with_libnfnetlink_libraries="$withval"],[with_libnfnetlink_libraries="no"]) if test "$with_libnfnetlink_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libnfnetlink_includes}" fi AC_CHECK_HEADER(libnfnetlink/libnfnetlink.h,,[AC_ERROR(libnfnetlink.h not found ...)]) if test "$with_libnfnetlink_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libnfnetlink_libraries}" fi NFNL="" AC_CHECK_LIB(nfnetlink, nfnl_fd,, NFNL="no") if test "$NFNL" = "no"; then echo echo " ERROR! nfnetlink library not found, go get it" echo " from www.netfilter.org." echo " we automatically append libnetfilter_queue/ when searching" echo " for headers etc. when the --with-libnfnetlink-inlcudes directive" echo " is used" echo exit 1 fi ;; esac #libnetfilter_queue AC_ARG_WITH(libnetfilter_queue_includes, [ --with-libnetfilter_queue-includes=DIR libnetfilter_queue include directory], [with_libnetfilter_queue_includes="$withval"],[with_libnetfilter_queue_includes=no]) AC_ARG_WITH(libnetfilter_queue_libraries, [ --with-libnetfilter_queue-libraries=DIR libnetfilter_queue library directory], [with_libnetfilter_queue_libraries="$withval"],[with_libnetfilter_queue_libraries="no"]) if test "$with_libnetfilter_queue_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libnetfilter_queue_includes}" fi AC_CHECK_HEADER(libnetfilter_queue/libnetfilter_queue.h,,[AC_ERROR(libnetfilter_queue/libnetfilter_queue.h not found ...)]) if test "$with_libnetfilter_queue_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libnetfilter_queue_libraries}" fi #LDFLAGS="${LDFLAGS} -lnetfilter_queue" NFQ="" case $host in *-*-mingw32*) AC_CHECK_LIB(netfilter_queue, nfq_open,, NFQ="no",-lws2_32) AC_ARG_WITH(netfilterforwin_includes, [ --with-netfilterforwin-includes=DIR netfilterforwin include directory], [with_netfilterforwin_includes="$withval"],[with_netfilterforwin_includes=no]) if test "$with_netfilterforwin_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_netfilterforwin_includes}" else CPPFLAGS="${CPPFLAGS} -I../../netfilterforwin" fi ;; *) AC_CHECK_LIB(netfilter_queue, nfq_open,, NFQ="no",) AC_CHECK_LIB([netfilter_queue], [nfq_set_queue_maxlen],AC_DEFINE_UNQUOTED([HAVE_NFQ_MAXLEN],[1],[Found queue max length support in netfilter_queue]) ,,[-lnfnetlink]) AC_CHECK_LIB([netfilter_queue], [nfq_set_verdict2],AC_DEFINE_UNQUOTED([HAVE_NFQ_SET_VERDICT2],[1],[Found nfq_set_verdict2 function in netfilter_queue]) ,,[-lnfnetlink]) AC_CHECK_LIB([netfilter_queue], [nfq_set_queue_flags],AC_DEFINE_UNQUOTED([HAVE_NFQ_SET_QUEUE_FLAGS],[1],[Found nfq_set_queue_flags function in netfilter_queue]) ,,[-lnfnetlink]) # check if the argument to nfq_get_payload is signed or unsigned AC_MSG_CHECKING([for signed nfq_get_payload payload argument]) STORECFLAGS="${CFLAGS}" if test `basename $CC` = "clang"; then CFLAGS="${CFLAGS} -Werror=incompatible-pointer-types" else CFLAGS="${CFLAGS} -Werror" fi AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [ #include ], [ char *pktdata; nfq_get_payload(NULL, &pktdata); ])], [libnetfilter_queue_nfq_get_payload_signed="yes"], [libnetfilter_queue_nfq_get_payload_signed="no"]) AC_MSG_RESULT($libnetfilter_queue_nfq_get_payload_signed) if test "x$libnetfilter_queue_nfq_get_payload_signed" = "xyes"; then AC_DEFINE([NFQ_GET_PAYLOAD_SIGNED], [1], [For signed version of nfq_get_payload]) fi CFLAGS="${STORECFLAGS}" ;; esac if test "$NFQ" = "no"; then echo echo " ERROR! libnetfilter_queue library not found, go get it" echo " from www.netfilter.org." echo " we automatically append libnetfilter_queue/ when searching" echo " for headers etc. when the --with-libnfq-includes directive" echo " is used" echo exit 1 fi ]) # prelude AC_ARG_ENABLE(prelude, AS_HELP_STRING([--enable-prelude], [Enable Prelude support for alerts]),,[enable_prelude=no]) AS_IF([test "x$enable_prelude" = "xyes"], [ CFLAGS="$CFLAGS -DPRELUDE" AM_PATH_LIBPRELUDE(0.9.9, , AC_MSG_ERROR(Cannot find libprelude: Is libprelude-config in the path?), no) if test "x${LIBPRELUDE_CFLAGS}" != "x"; then CPPFLAGS="${CPPFLAGS} ${LIBPRELUDE_CFLAGS}" fi if test "x${LIBPRELUDE_LDFLAGS}" != "x"; then LDFLAGS="${LDFLAGS} ${LIBPRELUDE_LDFLAGS}" fi if test "x${LIBPRELUDE_LIBS}" != "x"; then LDFLAGS="${LDFLAGS} ${LIBPRELUDE_LIBS}" fi ]) # libnet AC_ARG_WITH(libnet_includes, [ --with-libnet-includes=DIR libnet include directory], [with_libnet_includes="$withval"],[with_libnet_includes="no"]) AC_ARG_WITH(libnet_libraries, [ --with-libnet-libraries=DIR libnet library directory], [with_libnet_libraries="$withval"],[with_libnet_libraries="no"]) if test "x$with_libnet_includes" != "xno"; then CPPFLAGS="${CPPFLAGS} -I${with_libnet_includes}" libnet_dir="${with_libnet_includes}" else libnet_dir="/usr/include /usr/local/include /usr/local/include/libnet11 /opt/local/include /usr/local/include/libnet-1.1" fi if test "x$with_libnet_libraries" != "xno"; then LDFLAGS="${LDFLAGS} -L${with_libnet_libraries}" fi LIBNET_DETECT_FAIL="no" LIBNET_INC_DIR="" for i in $libnet_dir; do if test -r "$i/libnet.h"; then LIBNET_INC_DIR="$i" fi done AC_MSG_CHECKING(for libnet.h version 1.1.x) if test "$LIBNET_INC_DIR" != ""; then if eval "grep LIBNET_VERSION $LIBNET_INC_DIR/libnet.h | grep -v 1.1 >/dev/null"; then AC_MSG_RESULT(no) LIBNET_DETECT_FAIL="yes" LIBNET_FAIL_WARN($libnet_dir) else AC_MSG_RESULT(yes) fi #CentOS, Fedora, Ubuntu-LTS, Ubuntu all set defines to the same values. libnet-config seems #to have been depreciated but all distro's seem to include it as part of the package. if test "$LIBNET_DETECT_FAIL" = "no"; then LLIBNET="" AC_CHECK_LIB(net, libnet_write,, LLIBNET="no") if test "$LLIBNET" != "no"; then CFLAGS="${CFLAGS} -DHAVE_LIBNET11 -D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H" else #if we displayed a warning already no reason to do it again. if test "$LIBNET_DETECT_FAIL" = "no"; then LIBNET_DETECT_FAIL="yes" LIBNET_FAIL_WARN($libnet_dir) fi fi # see if we have the patched libnet 1.1 # http://www.inliniac.net/blog/2007/10/16/libnet-11-ipv6-fixes-and-additions.html # # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work # see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful if test "$LIBNET_DETECT_FAIL" = "no"; then LLIBNET="" TMPLIBS="${LIBS}" AC_CHECK_LIB(net, libnet_build_icmpv6_unreach,, LLIBNET="no") if test "$LLIBNET" != "no"; then CFLAGS="$CFLAGS -DHAVE_LIBNET_ICMPV6_UNREACH" fi LIBS="${TMPLIBS}" fi fi else LIBNET_DETECT_FAIL="yes" LIBNET_FAIL_WARN($libnet_dir) fi # libpfring (currently only supported for libpcap enabled pfring) # Error on the side of caution. If libpfring enabled pcap is being used and we don't link against -lpfring compilation will fail. AC_ARG_ENABLE(pfring, AS_HELP_STRING([--enable-pfring], [Enable Native PF_RING support]),,[enable_pfring=no]) AS_IF([test "x$enable_pfring" = "xyes"], [ CFLAGS="$CFLAGS -DHAVE_PFRING" #We have to set CFLAGS for AC_TRY_COMPILE as it doesn't pay attention to CPPFLAGS AC_ARG_WITH(libpfring_includes, [ --with-libpfring-includes=DIR libpfring include directory], [with_libpfring_includes="$withval"],[with_libpfring_includes=no]) AC_ARG_WITH(libpfring_libraries, [ --with-libpfring-libraries=DIR libpfring library directory], [with_libpfring_libraries="$withval"],[with_libpfring_libraries="no"]) if test "$with_libpfring_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libpfring_includes}" fi if test "$with_libpfring_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libpfring_libraries}" fi LIBPFRING="" AC_CHECK_LIB(pfring, pfring_open,, LIBPFRING="no", [-lpcap]) if test "$LIBPFRING" = "no"; then LIBPFRING="" AC_CHECK_LIB(pfring, pfring_stats,, LIBPFRING="no", [-lpcap -lrt]) if test "$LIBPFRING" = "no"; then if test "x$enable_pfring" = "xyes"; then echo echo " ERROR! --enable-pfring was passed but the library was not found or version is >4, go get it" echo " from http://www.ntop.org/PF_RING.html" echo exit 1 fi else LIBS="${LIBS} -lrt" fi fi LIBPFRING_ENABLE_RING="" AC_CHECK_LIB(pfring, pfring_enable_ring,, LIBPFRING_ENABLE_RING="no", [-lpcap]) if test "$LIBPFRING_ENABLE_RING" != "no"; then AC_DEFINE([HAVE_PFRING_ENABLE],[1],[PF_RING pfring_enable_ring is available]) fi LIBPFRING_CLUSTER_TYPE="" AC_CHECK_LIB(pfring, pfring_set_cluster, , LIBPFRING_CLUSTER_TYPE="no", [-lpcap]) if test "$LIBPFRING_CLUSTER_TYPE" != "no"; then AC_DEFINE([HAVE_PFRING_CLUSTER_TYPE],[1],[PF_RING pfring_set_cluster is available]) fi LIBPFRING_BPF_FILTER="" AC_CHECK_LIB(pfring, pfring_set_bpf_filter, , LIBPFRING_BPF_FILTER="no", [-lpcap]) LIBPFRING_REMOVE_BPF_FILTER="" AC_CHECK_LIB(pfring, pfring_remove_bpf_filter, , LIBPFRING_REMOVE_BPF_FILTER="no", [-lpcap]) if test "$LIBPFRING_BPF_FILTER" != "no" -a "$LIBPFRING_REMOVE_BPF_FILTER" != "no"; then AC_DEFINE([HAVE_PFRING_SET_BPF_FILTER],[1],[PF_RING pfring_set_bpf_filter is available]) fi STORE_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Werror" AC_MSG_CHECKING([if pfring_recv expects u_char**]) AC_TRY_COMPILE([ #include ], [ u_char *buffer; pfring_recv(NULL, &buffer, 0, NULL, 1); ], [ pfring_recv_uchar_buff=yes ], [:]) CFLAGS="${STORE_CFLAGS}" if test "$pfring_recv_uchar_buff" = "yes"; then AC_DEFINE([HAVE_PFRING_RECV_UCHAR],[1],[PF_RING pfring_recv buffer is u_char**]) AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi # check if the argument to nfq_get_payload is signed or unsigned AC_MSG_CHECKING([for post 5.4.0 pfring_open function]) STORECFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Werror" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [ #include ], [ pfring_open(NULL, 0, 0); ])], [pfring_new_open="yes"], [pfring_new_open="no"]) AC_MSG_RESULT($pfring_new_open) if test "x$pfring_new_open" = "xyes"; then AC_DEFINE([HAVE_PFRING_OPEN_NEW], [1], [For post 5.4.0 version of pfring_open]) fi CFLAGS="${STORECFLAGS}" ]) # libpcap AC_ARG_WITH(libpcap_includes, [ --with-libpcap-includes=DIR libpcap include directory], [with_libpcap_includes="$withval"],[with_libpcap_includes=no]) AC_ARG_WITH(libpcap_libraries, [ --with-libpcap-libraries=DIR libpcap library directory], [with_libpcap_libraries="$withval"],[with_libpcap_libraries="no"]) if test "$with_libpcap_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libpcap_includes}" fi AC_CHECK_HEADER(pcap.h,,[AC_ERROR(pcap.h not found ...)]) if test "$with_libpcap_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libpcap_libraries}" fi AC_CHECK_HEADERS([pcap.h pcap/pcap.h pcap/bpf.h]) LIBPCAP="" AC_CHECK_LIB(pcap, pcap_open_live,, LIBPCAP="no", [-lpthread]) if test "$LIBPCAP" = "no"; then echo echo " ERROR! libpcap library not found, go get it" echo " from http://www.tcpdump.org or your distribution:" echo echo " Ubuntu: apt-get install libpcap-dev" echo " Fedora: yum install libpcap-devel" echo exit 1 fi # pcap_activate and pcap_create only exists in libpcap >= 1.0 LIBPCAPVTEST="" #To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work #see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful TMPLIBS="${LIBS}" AC_CHECK_LIB(pcap, pcap_activate,, LPCAPVTEST="no") if test "$LPCAPVTEST" != "no"; then AC_PATH_PROG(HAVE_PCAP_CONFIG, pcap-config, "no") if test "$HAVE_PCAP_CONFIG" = "no"; then CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=1" else CFLAGS="${CFLAGS} `pcap-config --defines` `pcap-config --cflags` -DLIBPCAP_VERSION_MAJOR=1" fi else CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=0" fi LIBS="${TMPLIBS}" #Appears as if pcap_set_buffer_size is linux only? LIBPCAPSBUFF="" #To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work #see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful TMPLIBS="${LIBS}" AC_CHECK_LIB(pcap, pcap_set_buffer_size,, LPCAPSBUFF="no") if test "$LPCAPSBUFF" != "no"; then CFLAGS="${CFLAGS} -DHAVE_PCAP_SET_BUFF" fi LIBS="${TMPLIBS}" # AF_PACKET support AC_ARG_ENABLE(af-packet, AS_HELP_STRING([--enable-af-packet], [Enable AF_PACKET support [default=yes]]), ,[enable_af_packet=yes]) AS_IF([test "x$enable_af_packet" = "xyes"], [ AC_CHECK_DECL([TPACKET_V2], AC_DEFINE([HAVE_AF_PACKET],[1],[AF_PACKET support is available]), [enable_af_packet="no"], [[#include #include ]]) AC_CHECK_DECL([PACKET_FANOUT], AC_DEFINE([HAVE_PACKET_FANOUT],[1],[Packet fanout support is available]), [], [[#include ]]) ]) # libhtp AC_ARG_ENABLE(non-bundled-htp, AS_HELP_STRING([--enable-non-bundled-htp], [Enable the use of an already installed version of htp]),,[enable_non_bundled_htp=no]) AS_IF([test "x$enable_non_bundled_htp" = "xyes"], [ AC_ARG_WITH(libhtp_includes, [ --with-libhtp-includes=DIR libhtp include directory], [with_libhtp_includes="$withval"],[with_libhtp_includes=no]) AC_ARG_WITH(libhtp_libraries, [ --with-libhtp-libraries=DIR libhtp library directory], [with_libhtp_libraries="$withval"],[with_libhtp_libraries="no"]) if test "$with_libhtp_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libhtp_includes}" fi if test "$with_libhtp_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libhtp_libraries}" fi AC_CHECK_HEADER(htp/htp.h,,[AC_ERROR(htp/htp.h not found ...)]) LIBHTP="" AC_CHECK_LIB(htp, htp_conn_create,, LIBHTP="no") if test "$LIBHTP" = "no"; then echo echo " ERROR! libhtp library not found" echo exit 1 fi PKG_CHECK_MODULES(LIBHTPMINVERSION, htp >= 0.2.3,[libhtp_minver_found="yes"],[libhtp_minver_found="no"]) if test "$libhtp_minver_found" = "no"; then echo echo " ERROR! libhtp was found but is not the minimum version required >=0.2.3" echo exit 1 fi PKG_CHECK_MODULES(LIBHTPMAXVERSION, htp <= 0.3.0,[libhtp_maxver_found="yes"],[libhtp_maxver_found="no"]) if test "$libhtp_maxver_found" = "no"; then echo echo " ERROR! libhtp 0.3.x was found but only 0.2.x is supported" echo exit 1 fi AC_CHECK_LIB([htp], [htp_config_register_request_uri_normalize],AC_DEFINE_UNQUOTED([HAVE_HTP_URI_NORMALIZE_HOOK],[1],[Found htp_config_register_request_uri_normalize function in libhtp]) ,,[-lhtp]) # check for htp_tx_get_response_headers_raw AC_CHECK_LIB([htp], [htp_tx_get_response_headers_raw],AC_DEFINE_UNQUOTED([HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW],[1],[Found htp_tx_get_response_headers_raw in libhtp]) ,,[-lhtp]) AC_CHECK_LIB([htp], [htp_decode_query_inplace],AC_DEFINE_UNQUOTED([HAVE_HTP_DECODE_QUERY_INPLACE],[1],[Found htp_decode_query_inplace function in libhtp]) ,,[-lhtp]) AC_EGREP_HEADER(htp_config_set_path_decode_u_encoding, htp/htp.h, AC_DEFINE_UNQUOTED([HAVE_HTP_SET_PATH_DECODE_U_ENCODING],[1],[Found usable htp_config_set_path_decode_u_encoding function in libhtp]) ) ]) # even if we are using an installed htp lib we still need to gen Makefiles inside of htp AC_CONFIG_SUBDIRS([libhtp]) AM_CONDITIONAL([BUILD_LIBHTP], [test "x$enable_non_bundled_htp" = "xno"]) AS_IF([test "x$enable_non_bundled_htp" = "xno"], [ AC_DEFINE_UNQUOTED([HAVE_HTP_URI_NORMALIZE_HOOK],[1],[Assuming htp_config_register_request_uri_normalize function in bundled libhtp]) AC_DEFINE_UNQUOTED([HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW],[1],[Assuming htp_tx_get_response_headers_raw function in bundled libhtp]) AC_DEFINE_UNQUOTED([HAVE_HTP_DECODE_QUERY_INPLACE],[1],[Assuming htp_decode_query_inplace function in bundled libhtp]) ]) # enable CUDA output AC_ARG_ENABLE(cuda, AS_HELP_STRING([--enable-cuda], [Enable experimental CUDA pattern matching]),,[enable_cuda=no]) AS_IF([test "x$enable_cuda" = "xyes"], [ AC_ARG_WITH(cuda_includes, [ --with-cuda-includes=DIR cuda include directory], [with_cuda_includes="$withval"],[with_cuda_includes=no]) AC_ARG_WITH(cuda_libraries, [ --with-cuda-libraries=DIR cuda library directory], [with_cuda_libraries="$withval"],[with_cuda_libraries="no"]) AC_ARG_WITH(cuda_nvcc, [ --with-cuda-nvcc=DIR cuda nvcc compiler directory], [with_cuda_nvcc="$withval"],[with_cuda_nvcc=no]) CFLAGS="${CFLAGS} -D__SC_CUDA_SUPPORT__" if test "$with_cuda_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_cuda_includes}" else CPPFLAGS="${CPPFLAGS} -I/usr/local/cuda/include" fi if test "$with_cuda_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_cuda_libraries}" fi if test "$with_cuda_nvcc" != "no"; then NVCC_DIR="${with_cuda_nvcc}" else NVCC_DIR="/usr/local/cuda/bin" fi AC_CHECK_HEADER(cuda.h,,[AC_ERROR(cuda.h not found ...)]) LIBCUDA="" AC_CHECK_LIB(cuda, cuArray3DCreate,, LIBCUDA="no") if test "$LIBCUDA" = "no"; then echo echo " ERROR! libcuda library not found" echo exit 1 fi AC_PATH_PROG([NVCC], [nvcc], no, [$PATH:$NVCC_DIR]) if test "x$NVCC" = "xno"; then echo echo " ERROR! CUDA nvcc compiler not found: use --with-cuda-nvcc=DIR" echo exit 1 fi AC_MSG_CHECKING(for nvcc version) NVCCVER=`$NVCC --version | grep "release" | sed 's/.*release \(@<:@0-9@:>@\)\.\(@<:@0-9@:>@\).*/\1\2/'` AC_MSG_RESULT($NVCCVER) if test "$NVCCVER" -lt 31; then echo echo " Warning! Your CUDA nvcc version might be outdated." echo " If compilation fails try the latest CUDA toolkit from" echo " www.nvidia.com/object/cuda_develop.html" echo fi AM_PATH_PYTHON(,, no) if test "x$PYTHON" = "xno"; then echo echo " ERROR! Compiling CUDA kernels requires python." echo exit 1 fi ]) AM_CONDITIONAL([BUILD_CUDA], [test "x$enable_cuda" = "xyes"]) # Check for libcap-ng case $host in *-*-linux*) AC_ARG_WITH(libcap_ng_includes, [ --with-libcap_ng-includes=DIR libcap_ng include directory], [with_libcap-ng_includes="$withval"],[with_libcap_ng_includes=no]) AC_ARG_WITH(libcap_ng_libraries, [ --with-libcap_ng-libraries=DIR libcap_ng library directory], [with_libcap_ng_libraries="$withval"],[with_libcap_ng_libraries="no"]) if test "$with_libcap_ng_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libcap_ng_includes}" fi if test "$with_libcap_ng_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libcap_ng_libraries}" fi AC_CHECK_HEADER(cap-ng.h,,LIBCAP_NG="no") if test "$LIBCAP_NG" != "no"; then LIBCAP_NG="" AC_CHECK_LIB(cap-ng,capng_clear,,LIBCAP_NG="no") fi if test "$LIBCAP_NG" != "no"; then CFLAGS="${CFLAGS} -DHAVE_LIBCAP_NG" fi if test "$LIBCAP_NG" = "no"; then echo echo " WARNING! libcap-ng library not found, go get it" echo " from http://people.redhat.com/sgrubb/libcap-ng/" echo " or your distribution:" echo echo " Ubuntu: apt-get install libcap-ng-dev" echo " Fedora: yum install libcap-ng-devel" echo echo " Suricata will be built without support for dropping privs." echo fi ;; esac # Check for DAG support. AC_ARG_ENABLE(dag, [ --enable-dag Enable DAG capture], [ enable_dag=yes ], [ enable_dag=no]) AC_ARG_WITH(dag_includes, [ --with-dag-includes=DIR dagapi include directory], [with_dag_includes="$withval"],[with_dag_includes="no"]) AC_ARG_WITH(dag_libraries, [ --with-dag-libraries=DIR dagapi library directory], [with_dag_libraries="$withval"],[with_dag_libraries="no"]) if test "$enable_dag" = "yes"; then if test "$with_dag_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_dag_includes}" fi if test "$with_dag_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_dag_libraries}" fi AC_CHECK_HEADER(dagapi.h,DAG="yes",DAG="no") if test "$DAG" != "no"; then DAG="" AC_CHECK_LIB(dag,dag_open,,DAG="no",) fi if test "$DAG" != "no"; then CFLAGS="${CFLAGS} -DHAVE_DAG" fi if test "$DAG" = "no"; then echo echo " ERROR! libdag library not found" echo exit 1 fi fi # libnspr enable_nspr="no" AC_ARG_WITH(libnspr_includes, [ --with-libnspr-includes=DIR libnspr include directory], [with_libnspr_includes="$withval"],[with_libnspr_includes=no]) AC_ARG_WITH(libnspr_libraries, [ --with-libnspr-libraries=DIR libnspr library directory], [with_libnspr_libraries="$withval"],[with_libnspr_libraries="no"]) if test "$with_libnspr_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libnspr_includes}" fi AC_CHECK_HEADER(nspr.h,NSPR="yes",NSPR="no") if test "$NSPR" = "yes"; then if test "$with_libnspr_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libnspr_libraries}" fi AC_CHECK_LIB(nspr4, PR_GetCurrentThread,, NSPR="no") if test "$NSPR" = "no"; then echo echo " ERROR! libnspr library not found, go get it" echo " from Mozilla or your distribution:" echo echo " Ubuntu: apt-get install libnspr4-dev" echo " Fedora: yum install nspr-devel" echo exit 1 fi enable_nspr="yes" fi # libnss enable_nss="no" AC_ARG_WITH(libnss_includes, [ --with-libnss-includes=DIR libnss include directory], [with_libnss_includes="$withval"],[with_libnss_includes=no]) AC_ARG_WITH(libnss_libraries, [ --with-libnss-libraries=DIR libnss library directory], [with_libnss_libraries="$withval"],[with_libnss_libraries="no"]) if test "$with_libnss_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libnss_includes}" fi AC_CHECK_HEADER(sechash.h,NSS="yes",NSS="no") if test "$NSS" = "yes"; then if test "$with_libnss_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libnss_libraries}" fi AC_CHECK_LIB(nss3, HASH_Begin,, NSS="no") if test "$NSS" = "no"; then echo echo " ERROR! libnss library not found, go get it" echo " from Mozilla or your distribution:" echo echo " Ubuntu: apt-get install libnss3-dev" echo " Fedora: yum install nss-devel" echo exit 1 fi AC_DEFINE([HAVE_NSS],[1],[libnss available for md5]) enable_nss="yes" fi # libmagic AC_ARG_WITH(libmagic_includes, [ --with-libmagic-includes=DIR libmagic include directory], [with_libmagic_includes="$withval"],[with_libmagic_includes=no]) AC_ARG_WITH(libmagic_libraries, [ --with-libmagic-libraries=DIR libmagic library directory], [with_libmagic_libraries="$withval"],[with_libmagic_libraries="no"]) if test "$with_libmagic_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libmagic_includes}" fi AC_CHECK_HEADER(magic.h,,[AC_ERROR(magic.h not found ...)]) if test "$with_libmagic_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libmagic_libraries}" fi MAGIC="" AC_CHECK_LIB(magic, magic_open,, MAGIC="no") if test "$MAGIC" = "no"; then echo echo " ERROR! magic library not found, go get it" echo " from http://www.darwinsys.com/file/ or your distribution:" echo echo " Ubuntu: apt-get install libmagic-dev" echo " Fedora: yum install file-devel" echo exit 1 fi # Napatech - Using the 3GD API AC_ARG_ENABLE(napatech, [ --enable-napatech Enabled Napatech Devices], [ enable_napatech=yes ], [ enable_napatech=no]) AC_ARG_WITH(napatech_includes, [ --with-napatech-includes=DIR napatech include directory], [with_napatech_includes="$withval"],[with_napatech_includes="/opt/napatech3/include"]) AC_ARG_WITH(napatech_libraries, [ --with-napatech-libraries=DIR napatech library directory], [with_napatech_libraries="$withval"],[with_napatech_libraries="/opt/napatech3/lib"]) if test "$enable_napatech" = "yes"; then CPPFLAGS="${CPPFLAGS} -I${with_napatech_includes}" LDFLAGS="${LDFLAGS} -L${with_napatech_libraries} -lntapi" AC_CHECK_HEADER(nt.h,NAPATECH="yes",NAPATECH="no") if test "$NAPATECH" != "no"; then NAPATECH="" AC_CHECK_LIB(ntapi, NT_Init,NAPATECH="yes",NAPATECH="no") fi if test "$NAPATECH" != "no"; then CFLAGS="${CFLAGS} -DHAVE_NAPATECH" fi if test "$NAPATECH" = "no"; then echo echo " ERROR! libntapi library not found" echo exit 1 fi fi # libluajit AC_ARG_ENABLE(luajit, [ --enable-luajit Enable Luajit support], [ enable_luajit="yes"], [ enable_luajit="no"]) AC_ARG_WITH(libluajit_includes, [ --with-libluajit-includes=DIR libluajit include directory], [with_libluajit_includes="$withval"],[with_libluajit_includes="no"]) AC_ARG_WITH(libluajit_libraries, [ --with-libluajit-libraries=DIR libluajit library directory], [with_libluajit_libraries="$withval"],[with_libluajit_libraries="no"]) if test "$enable_luajit" = "yes"; then if test "$with_libluajit_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libluajit_includes}" else PKG_CHECK_MODULES([LUAJIT], [luajit], , LUAJIT="no") CPPFLAGS="${CPPFLAGS} ${LUAJIT_CFLAGS}" fi AC_CHECK_HEADER(lualib.h,LUAJIT="yes",LUAJIT="no") if test "$LUAJIT" = "yes"; then if test "$with_libluajit_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libluajit_libraries}" else PKG_CHECK_MODULES([LUAJIT], [luajit]) LDFLAGS="${LDFLAGS} ${LUAJIT_LIBS}" fi AC_CHECK_LIB(luajit-5.1, luaL_openlibs,, LUAJIT="no") if test "$LUAJIT" = "no"; then echo echo " ERROR! libluajit library not found, go get it" echo " from http://luajit.org/index.html or your distribution:" echo echo " Ubuntu: apt-get install libluajit-5.1-dev" echo echo " If you installed software in a non-standard prefix" echo " consider adjusting the PKG_CONFIG_PATH environment variable" echo " or use --with-libluajit-libraries configure option." echo exit 1 fi AC_DEFINE([HAVE_LUAJIT],[1],[libluajit available]) enable_luajit="yes" else echo echo " ERROR! libluajit headers not found, go get them" echo " from http://luajit.org/index.html or your distribution:" echo echo " Ubuntu: apt-get install libluajit-5.1-dev" echo echo " If you installed software in a non-standard prefix" echo " consider adjusting the PKG_CONFIG_PATH environment variable" echo " or use --with-libluajit-includes and --with-libluajit-libraries" echo " configure option." echo exit 1 fi fi # libgeoip AC_ARG_ENABLE(geoip, [ --enable-geoip Enable GeoIP support], [ enable_geoip="yes"], [ enable_geoip="no"]) AC_ARG_WITH(libgeoip_includes, [ --with-libgeoip-includes=DIR libgeoip include directory], [with_libgeoip_includes="$withval"],[with_libgeoip_includes="no"]) AC_ARG_WITH(libgeoip_libraries, [ --with-libgeoip-libraries=DIR libgeoip library directory], [with_libgeoip_libraries="$withval"],[with_libgeoip_libraries="no"]) if test "$enable_geoip" = "yes"; then if test "$with_libgeoip_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libgeoip_includes}" fi AC_CHECK_HEADER(GeoIP.h,GEOIP="yes",GEOIP="no") if test "$GEOIP" = "yes"; then if test "$with_libgeoip_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libgeoip_libraries}" fi AC_CHECK_LIB(GeoIP, GeoIP_country_code_by_ipnum,, GEOIP="no") fi if test "$GEOIP" = "no"; then echo echo " ERROR! libgeoip library not found, go get it" echo " from http://www.maxmind.com/en/geolite or your distribution:" echo echo " Ubuntu: apt-get install libgeoip-dev" echo " Fedora: yum install GeoIP-devel" echo exit 1 fi if test "$GEOIP" = "yes"; then AC_DEFINE([HAVE_GEOIP],[1],[libgeoip available]) enable_geoip="yes" fi fi # get revision if test -f ./revision; then REVISION=`cat ./revision` CFLAGS="${CFLAGS} -DREVISION=\"${REVISION}\"" else AC_PATH_PROG(HAVE_GIT_CMD, git, "no") if test "$HAVE_GIT_CMD" != "no"; then if [ test -d .git ]; then REVISION=`git rev-parse --short HEAD` CFLAGS="${CFLAGS} -DREVISION=\"${REVISION}\"" fi fi fi AC_SUBST(CFLAGS) AC_SUBST(LDFLAGS) AC_SUBST(CPPFLAGS) define([EXPAND_VARIABLE], [$2=[$]$1 if test $prefix = 'NONE'; then prefix="/usr/local" fi while true; do case "[$]$2" in *\[$]* ) eval "$2=[$]$2" ;; *) break ;; esac done eval "$2=[$]$2$3" ])dnl EXPAND_VARIABLE # suricata log dir if test "$WINDOWS_PATH" = "yes"; then systemtype="`systeminfo | grep \"based PC\"`" case "$systemtype" in *x64*) e_winbase="C:\\\\Program Files (x86)\\\\Suricata" ;; *) e_winbase="C:\\\\Program Files\\\\Suricata" ;; esac e_sysconfdir="$e_winbase\\\\" e_sysconfrulesdir="$e_winbase\\\\rules\\\\" e_magic_file="$e_winbase\\\\magic.mgc" e_logdir="$e_winbase\\\\log" e_logfilesdir="$e_logdir\\\\files" else EXPAND_VARIABLE(localstatedir, e_logdir, "/log/suricata/") EXPAND_VARIABLE(localstatedir, e_rundir, "/run/") EXPAND_VARIABLE(localstatedir, e_logfilesdir, "/log/suricata/files") EXPAND_VARIABLE(sysconfdir, e_sysconfdir, "/suricata/") EXPAND_VARIABLE(sysconfdir, e_sysconfrulesdir, "/suricata/rules") EXPAND_VARIABLE(localstatedir, e_localstatedir, "/run/suricata") fi AC_SUBST(e_logdir) AC_SUBST(e_rundir) AC_SUBST(e_logfilesdir) AC_SUBST(e_sysconfdir) AC_SUBST(e_sysconfrulesdir) AC_SUBST(e_localstatedir) AC_DEFINE_UNQUOTED([CONFIG_DIR],["$e_sysconfdir"],[Our CONFIG_DIR]) AC_SUBST(e_magic_file) AC_OUTPUT(Makefile src/Makefile qa/Makefile qa/coccinelle/Makefile rules/Makefile doc/Makefile contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile suricata.yaml scripts/Makefile scripts/suricatasc/Makefile scripts/suricatasc/suricatasc) SURICATA_BUILD_CONF="Suricata Configuration: AF_PACKET support: ${enable_af_packet} PF_RING support: ${enable_pfring} NFQueue support: ${enable_nfqueue} IPFW support: ${enable_ipfw} DAG enabled: ${enable_dag} Napatech enabled: ${enable_napatech} Unix socket enabled: ${enable_unixsocket} libnss support: ${enable_nss} libnspr support: ${enable_nspr} libjansson support: ${enable_jansson} Prelude support: ${enable_prelude} PCRE jit: ${pcre_jit_available} libluajit: ${enable_luajit} libgeoip: ${enable_geoip} Non-bundled htp: ${enable_non_bundled_htp} Old barnyard2 support: ${enable_old_barnyard2} CUDA enabled: ${enable_cuda} Suricatasc install: ${enable_python} Unit tests enabled: ${enable_unittests} Debug output enabled: ${enable_debug} Debug validation enabled: ${enable_debug_validation} Profiling enabled: ${enable_profiling} Profiling locks enabled: ${enable_profiling_locks} Generic build parameters: Installation prefix (--prefix): ${prefix} Configuration directory (--sysconfdir): ${e_sysconfdir} Log directory (--localstatedir) : ${e_logdir} Host: ${host} GCC binary: ${CC} GCC Protect enabled: ${enable_gccprotect} GCC march native enabled: ${enable_gccmarch_native} GCC Profile enabled: ${enable_gccprofile}" echo echo "$SURICATA_BUILD_CONF" echo "printf(" >${ac_builddir}/src/build-info.h echo "$SURICATA_BUILD_CONF" | sed -e 's/^/"/' | sed -e 's/$/\\n"/' >>${ac_builddir}/src/build-info.h echo ");" >>${ac_builddir}/src/build-info.h echo " To build and install run 'make' and 'make install'. You can run 'make install-conf' if you want to install initial configuration files to ${e_sysconfdir}. Running 'make install-full' will install configuration and rules and provide you a ready-to-run suricata." echo echo "To install Suricata into /usr/bin/suricata, have the config in /etc/suricata and use /var/log/suricata as log dir, use: ./configure --prefix=/usr/ --sysconfdir=/etc/ --localstatedir=/var/" echo suricata-1.4.7/depcomp0000755000000000000000000005601612253546174011623 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 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, see . # 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 . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} 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 # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # 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 cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc 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. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## 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). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - 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 -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # 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. ## 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. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -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 -ne 0; then 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 ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # 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 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, 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. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 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. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # 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 ;; #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 preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | 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) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | 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 preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" 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 preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # 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 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: suricata-1.4.7/ChangeLog0000644000000000000000000005556012253546156012023 000000000000001.4.7 -- 2013-12-16 Bug #996: tag keyword: tagging sessions per time is broken Bug #1000: delayed detect inits thresholds before de_ctx Bug #1001: ip_rep loading problem with multiple values for a single ip Bug #1022: StreamTcpPseudoPacketSetupHeader : port swap logic isn't consistent Bug #1047: detect-engine.profile - custom value parsing broken Bug #1063: rule ordering with multiple vars 1.4.6 -- 2013-09-24 Bug #955: SSL parsing issue Bug #971: AC memory read error Bug #934: Suricata failed to parse address Bug #937: wrong IP version - on stacked layers Bug #938: 1.4.5: decode-ipv6.c: void function cannot return value Bug #965: duplicate of #964 - Modify negated content handling Bug #969: unified2 not logging tagged packets 1.4.5 -- 2013-07-26 - Bug #906: icmp_seq and icmp_id keyword with icmpv6 traffic - Bug #908: ipv6 ext hdr parsing issue 1.4.4 -- 2013-07-18 - Bug #834: Unix socket - showing as compiled when it is not desired to do so - Bug #835: Unix Socket not working as expected - Bug #841: configure --enable-unix-socket does not err out if libs/pkgs are not present - Bug #846: FP on IP frag and sig use udp port 0, thanks to Rmkml - Bug #864: backport packet action macro's - Bug #876: htp tunnel fix - Bug #877: Flowbit check with content doesn't match consistently, thanks to Francis Trudeau 1.4.3 -- 2013-06-20 - Fix missed detection in bytetest, bytejump and byteextract for negative offset (#828) - Fix IPS mode being unable to drop tunneled packets (#826) - Fix OS X Unix Socket build (#829) 1.4.2 -- 2013-05-29 - No longer force nocase to be used on http_host - Invalidate rule if uppercase content is used for http_host w/o nocase - Warn user if bpf is used in af-packet IPS mode - Better test for available libjansson version - Fixed accuracy issues with relative pcre matching (#784) - Improved accuracy of file_data keyword (#788) - Invalidate negative depth (#770) - Fix http host parsing for IPv6 addresses (#761) - Fix fast.log formatting issues (#773) - Fixed deadlock in flowvar set code for http buffers (#801) - Various signature ordering improvements - Minor stream engine fix 1.4.1 -- 2013-03-08 - GeoIP keyword, allowing matching on Maxmind's database, contributed by Ignacio Sanchez (#559) - Introduce http_host and http_raw_host keywords (#733, #743) - Add python module for interacting with unix socket (#767) - Add new unix socket commands: fetching config, counters, basic runtime info (#764, #765) - Big Napatech support update by Matt Keeler - Configurable sensor id in unified2 output, contributed by Jake Gionet (#667) - FreeBSD IPFW fixes by Nikolay Denev - Add "default" interface setting to capture configuration in yaml (#679) - Make sure "snaplen" can be set by the user (#680) - Improve HTTP URI query string normalization (#739) - Improved error reporting in MD5 loading (#693) - Improve reference.config parser error reporting (#737) - Improve build info output to include all configure options (#738) - Segfault in TLS parsing reported by Charles Smutz (#725) - Fix crash in teredo decoding, reported by Rmkml (#736) - fixed UDPv4 packets without checksum being detected as invalid (#760) - fixed DCE/SMB parsers getting confused in some fragmented cases (#764) - parsing ipv6 address/subnet parsing in thresholding was fixed by Jamie Strandboge (#697) - FN: IP-only rule ip_proto not matching for some protocols (#689) - Fix build failure with other libhtp installs (#688) - Fix malformed yaml loading leading to a crash (#694) - Various Mac OS X fixes (#700, #701, #703) - Fix for autotools on Mac OS X by Jason Ish (#704) - Fix AF_PACKET under high load not updating stats (#706) 1.3.6 -- 2013-03-07 - fix decoder event rules not checked in all cases (#671) - checksum detection for icmpv6 was fixed (#673) - crash in HTTP server body inspection code fixed (#675) - fixed a icmpv6 payload bug (#676) - IP-only rule ip_proto not matching for some protocols was addressed (#690) - fixed malformed yaml crashing suricata (#702) - parsing ipv6 address/subnet parsing in thresholding was fixed by Jamie Strandboge (#717) - crash in tls parser was fixed (#759) - fixed UDPv4 packets without checksum being detected as invalid (#762) - fixed DCE/SMB parsers getting confused in some fragmented cases (#763) 1.4 2012-12-13 - Decoder event matching fixed (#672) - Unified2 would overwrite files if file rotation happened within a second of file creation, leading to loss of events/alerts (#665) - Add more events to IPv6 extension header anomolies (#678) - Fix ICMPv6 payload and checksum calculation (#677, #674) - Clean up flow timeout handling (#656) - Fix a shutdown bug when using AF_PACKET under high load (#653) - Fix TCP sessions being cleaned up to early (#652) 1.3.5 2012-12-06 - Flow engine memory leak fixed by Ludovico Cavedon (#651) - Unified2 would overwrite files if file rotation happened within a second of file creation, leading to loss of events/alerts (#664) - Flow manager mutex used unintialized, fixed by Ludovico Cavedon (#654) - Windows building in CYGWIN fixed (#630) 1.4rc1 2012-11-29 - Interactive unix socket mode (#571, #552) - IP Reputation: loading and matching (#647) - Improved --list-keywords commandline option gives detailed info for supported keyword, including doc link (#435) - Rule analyzer improvement wrt ipv4/ipv6, invalid rules (#494) - User-Agent added to file log and filestore meta files (#629) - Endace DAG supports live stats and at exit drop stats (#638) - Add support for libhtp event "request port doesn't match tcp port" (#650) - Rules with negated addresses will not be considered IP-only (#599) - Rule reloads complete much faster in low traffic conditions (#526) - Suricata -h now displays all available options (#419) - Luajit configure time detection was improved (#636) - Flow manager mutex used w/o initialization (#628) - Cygwin work around for windows shell mangling interface string (#372) - Fix a Prelude output crash with alerts generated by rules w/o classtype or msg (#648) - CLANG compiler build fixes (#649) - Several fixes found by code analyzers 1.4beta3 2012-11-14 - support for Napatech cards was greatly improved by Matt Keeler from Npulse (#430, #619) - support for pkt_data keyword was added - user and group to run as can now be set in the config file - make HTTP request and response body inspection sizes configurable per HTTP server config (#560) - PCAP/AF_PACKET/PF_RING packet stats are now printed in stats.log (#561, #625) - add contrib directory to the dist (#567) - performance improvements to signatures with dsize option - improved rule analyzer: print fast_pattern along with the rule (#558) - fixes to stream engine reducing the number of events generated (#604) - add stream event to match on overlaps with different data in stream reassembly (#603) - stream.inline option new defaults to "auto", meaning enabled in IPS mode, disabled in IDS mode (#592) - HTTP handling in OOM condition was greatly improved (#557) - filemagic keyword performance was improved (#585) - fixes and improvements to daemon mode (#624) - fix drop rules not working correctly when thresholded (#613) - fixed a possible FP when a regular and "chopped" fast_pattern were the same (#581) - fix a false possitive condition in http_header (#607) - fix inaccuracy in byte_jump keyword when using "from_beginning" option (#627) - fixes to rule profiling (#576) - cleanups and misc fixes (#379, #395) - updated bundled libhtp to 0.2.11 - build system improvements and cleanups - fix to SSL record parsing 1.3.4 -- 2012-11-14 - fix crash in flow and host engines in cases of low memory or low memcap settings (#617) - improve http handling in low memory conditions (#620) - fix inaccuracy in byte_jump keyword when using "from_beginning" option (#626) - fix building on OpenBSD 5.2 - update default config's defrag settings to reflect all available options - fixes to make check - fix to SSL record parsing 1.3.3 -- 2012-11-01 - fix drop rules not working correctly when thresholded (#615) - fix a false possitive condition in http_header (#606) - fix extracted file corruption (#601) - fix a false possitive condition with the pcre keyword and relative matching (#588) - fix PF_RING set cluster problem on dma interfaces (#598) - improve http handling in low memory conditions (#586, #587) - fix FreeBSD inline mode crash (#612) - suppress pcre jit warning (#579) 1.4beta2 -- 2012-10-04 - New keyword: "luajit" to inspect packet, payload and all HTTP buffers with a Lua script (#346) - Added ability to control per server HTTP parser settings in much more detail (#503) - Rewrite of IP Defrag engine to improve performance and fix locking logic (#512, #540) - Big performance improvement in inspecting decoder, stream and app layer events (#555) - Pool performance improvements (#541) - Improved performance of signatures with simple pattern setups (#577) - Bundled docs are installed upon make install (#527) - Support for a number of global vs rule thresholds [3] was added (#425) - Improved rule profiling performance - If not explicit fast_pattern is set, pick HTTP patterns over stream patterns. HTTP method, stat code and stat msg are excluded. - Fix compilation on architectures other than x86 and x86_64 (#572) - Fix FP with anchored pcre combined with relative matching (#529) - Fix engine hanging instead of exitting if the pcap device doesn't exist (#533) - Work around for potential FP, will get properly fixed in next release (#574) - Improve ERF handling. Thanks to Jason Ish - Always set cluster_id in PF_RING - IPFW: fix broken broadcast handling - AF_PACKET kernel offset issue, IPS fix and cleanup - Fix stream engine sometimes resending the same data to app layer - Fix multiple issues in HTTP multipart parsing - Fixed a lockup at shutdown with NFQ (#537) 1.3.2 -- 2012-10-03 - Fixed a possible FP when a regular and "chopped" fast_pattern were the same (#562) - Fixed a FN condition with the flow:no_stream option (#575) - Fix building of perf profiling code on i386 platform. By Simon Moon (#534) - Fix multiple issues in HTTP multipart parsing - Fix stream engine sometimes resending the same data to app layer - Always set cluster_id in PF_RING - Defrag: silence some potentially noisy errors/warnings - IPFW: fix broken broadcast handling - AF_PACKET kernel offset issue 1.4beta1 -- 2012-09-06 - Custom HTTP logging contributed by Ignacio Sanchez (#530) - TLS certificate logging and fingerprint computation and keyword (#443) - TLS certificate store to disk feature (#444) - Decoding of IPv4-in-IPv6, IPv6-in-IPv6 and Teredo tunnels (#462, #514, #480) - AF_PACKET IPS support (#516) - Rules can be set to inspect only IPv4 or IPv6 (#494) - filesize keyword for matching on sizes of files in HTTP (#489) - Delayed detect initialization. Starts processing packets right away and loads detection engine in the background (#522) - NFQ fail open support (#507) - Highly experimental lua scripting support for detection - Live reloads now supports HTTP rule updates better (#522) - AF_PACKET performance improvements (#197, #415) - Make defrag more configurable (#517, #528) - Improve pool performance (#518) - Improve file inspection keywords by adding a separate API (#531) - Example threshold.config file provided (#302) - Fix building of perf profiling code on i386 platform. By Simon Moon (#534) - Various spelling corrections by Simon Moon (#533) 1.3.1 -- 2012-08-21 - AF_PACKET performance improvements - Defrag engine performance improvements - HTTP: add per server options to enable/disable double decoding of URI (#464, #504) - Stream engine packet handling for packets with non-standard flag combinations (#508) - Improved stream engine handling of packet loss (#523) - Stream engine checksum alerting fixed - Various rule analyzer fixes (#495, #496, #497) - (Rule) profiling fixed and improved (#460, #466) - Enforce limit on max-pending-packets (#510) - fast_pattern on negated content improved - TLS rule keyword parsing issues - Windows build fixes (#502) - Host OS parsing issues fixed (#499) - Reject signatures where content length is bigger than "depth" setting (#505) - Removed unused "prune-flows" option - Set main thread and live reload thread names (#498) 1.3 -- 2012-07-06 - make live rule reloads optional and disabled by default - fix a shutdown bug - fix several memory leaks (#492) - warn user if global and rule thresholding conflict (#455) - set thread names on FreeBSD (Nikolay Denev) - Fix PF_RING building on Ubuntu 12.04 - rule analyzer updates - file inspection improvements when dealing with limits (#493) 1.3rc1 -- 2012-06-29 - experimental live rule reload by sending a USR2 signal (#279) - AF_PACKET BPF support (#449) - AF_PACKET live packet loss counters (#441) - Rule analyzer (#349) - add pcap workers runmode for use with libpcap wrappers that support load balancing, such as Napatech's or Myricom's - negated filemd5 matching, allowing for md5 whitelisting - signatures with depth and/or offset are now checked against packets in addition to the stream (#404) - http_cookie keyword now also inspects "Set-Cookie" header (#479) - filemd5 keyword no longer depends on log-file output module (#447) - http_raw_header keyword inspects original header line terminators (#475) - deal with double encoded URI (#464) - improved SMB/SMB2/DCERPC robustness - ICMPv6 parsing fixes - improve HTTP body inspection - stream.inline accuracy issues fixed (#339) - general stability fixes (#482, #486) - missing unittests added (#471) - "threshold.conf not found" error made more clear (#446) - IPS mode segment logging for Unified2 improved 1.3beta2 -- 2012-06-08 - experimental support for matching on large lists of known file MD5 checksums - Improved performance for file_data, http_server_body and http_client_body keywords - Improvements to HTTP handling: multipart parsing, gzip decompression - Byte_extract can support negative offsets now (#445) - Support for PF_RING 5.4 added. Many thanks to Chris Wakelin (#459) - HOME_NET and EXTERNAL_NET and the other vars are now checked for common errors (#454) - Improved error reporting when using too long address strings (#451) - MD5 calculation improvements for daemon mode and other cases (#449) - File inspection scripts: Added Syslog action for logging to local syslog. Thanks to Martin Holste. - Rule parser is made more strict. - Unified2 output overhaul, logging individual segments in more cases. - detection_filter keyword accuracy problem was fixed (#453) - Don't inspect cookie header with http header (#461) - Crash with a rule with two byte_extract keywords (#456) - SSL parser fixes. Thanks to Chris Wakelin for testing the patches! (#476) - Accuracy issues in HTTP inspection fixed. Thanks to Rmkml (#452) - Improve escaping of some characters in logs (#418) - Checksum calculation bugs fixed - IPv6 parsing issues fixed. Thanks to Michel Saborde. - Endace DAG issues fixed. Thanks to Jason Ish from Endace. - Various OpenBSD related fixes. - Fixes for bugs found by Coverity source code analyzer. 1.3beta1 -- 2012-04-04 - TLS/SSL handshake parser, tls.subjectdn and tls.issuerdn keywords (#296, contributed by Pierre Chifflier) - Napatech capture card support (contributed by Randy Caldejon -- nPulse) - Scripts for looking up files / file md5's at Virus Total and others (contributed by Martin Holste) - Test mode: -T option to test the config (#271) - Ringbuffer and zero copy support for AF_PACKET - Commandline options to list supported app layer protocols and keywords (#344, #414) - File extraction for HTTP POST request that do not use multipart bodies - On the fly md5 checksum calculation of extracted files - Line based file log, in json format - Basic support for including other yaml files into the main yaml - New multi pattern engine: ac-bs - Profiling improvements, added lock profiling code - Improved HTTP CONNECT support in libhtp (#427, Brian Rectanus -- Qualys) - Unified yaml naming convention, including fallback support (by Nikolay Denev) - Improved Endace DAG support (#431, Jason Ish -- Endace) - New default runmode: "autofp" (#433) - Major rewrite of flow engine, improving scalability. - Improved http_stat_msg and http_stat_code keywords (#394) - Improved scalability for Tag and Threshold subsystems - Made the rule keyword parser much stricter in detecting syntax errors - Split "file" output into "file-store" and "file-log" outputs - Much improved file extraction - CUDA build fixes (#421) - Various FP's reported by Rmkml (#403, #405, #411) - IPv6 decoding and detection issues (reported by Michel Sarborde) - PCAP logging crash (#422) - Fixed many (potential) issues with the help of the Coverity source code analyzer - Fixed several (potential) issues with the help of the cppcheck and clang/scan-build source code analyzers 1.2.1 -- 2012-01-20 - fix malformed unified2 records when writing alerts trigger by stream inspection (#402) - only force a pseudo packet inspection cycle for TCP streams in a state >= established 1.2 -- 2012-01-19 - improved Windows/CYGWIN path handling (#387) - fixed some issues with passing an interface or ip address with -i - make live worker runmode threads adhere to the 'detect' cpu affinity settings 1.2rc1 -- 2012-01-11 - app-layer-events keyword: similar to the decoder-events and stream-events, this will allow matching on HTTP and SMTP events - auto detection of checksum offloading per interface (#311) - urilen options to match on raw or normalized URI (#341) - flow keyword option "only_stream" and "no_stream" - unixsock output options for all outputs except unified2 (PoC python script in the qa/ dir) (#250) - in IPS mode, reject rules now also drop (#399) - http_header now also inspects response headers (#389) - "worker" runmodes for NFQ and IPFW - performance improvement for "ac" pattern matcher - allow empty/non-initialized flowints to be incremented - PCRE-JIT is now enabled by default if available (#356) - many file inspection and extraction improvements - flowbits and flowints are now modified in a post-match action list - general performance increasements - fixed parsing really high sid numbers >2 Billion (#393) - fixed ICMPv6 not matching in IP-only sigs (#363) 1.2beta1 -- 2011-12-19 - File name, type inspection and extraction for HTTP - filename, fileext, filemagic and filestore keywords added - "file" output for storing extracted files to disk - file_data keyword support, inspecting normalized, dechunked, decompressed HTTP response body (feature #241 - new keyword http_server_body, pcre regex /S option - Option to enable/disable core dumping from the suricata.yaml (enabled by default) - Human readable size limit settings in suricata.yaml - PF_RING bpf support (required PF_RING >= 5.1) (feature #334) - tos keyword support (feature #364) - IPFW IPS mode does now support multiple divert sockets - New IPS running modes, Linux and FreeBSD do now support "worker" and "autofp" - Improved alert accuracy in autofp and single runmodes - major performance optimizations for the ac-gfbs pattern matcher implementation - unified2 output fixes - PF_RING supports privilege dropping now (bug #367) - Improved detection of duplicate signatures 1.1.1 -- 2011-12-07 - Fix for a error in the smtp parser that could crash Suricata. - Fix for AF_PACKET not compiling on modern linux systems like Fedora 16. 1.1 -- 2011-11-10 - CUDA build fixed - minor pcap, AF_PACKET and PF_RING fixes (#368) - bpf handling fix - Windows CYGWIN build - more cleanups 1.1rc1 -- 2011-11-03 - extended HTTP request logging for use with (among other things) http_agent for Sguil (#38) - AF_PACKET report drop stats on shutdown (#325) - new counters in stats.log for flow and stream engines (#348) - SMTP parsing code support for BDAT command (#347) - HTTP URI normalization no longer converts to lowercase (#362) - AF_PACKET works with privileges dropping now (#361) - Prelude output for state matches (#264, #355) - update of the pattern matching code that should improve accuracy - rule parser was made more strict (#295, #312) - multiple event suppressions for the same SID was fixed (#366) - several accuracy fixes - removal of the unified1 output plugins (#353) 1.1beta3 -- 2011-10-25 - af-packet support for high speed packet capture - "replace" keyword support (#303) - new "workers" runmode for multi-dev and/or clustered PF_RING, AF_PACKET, pcap - added "stream-event" keyword to match on TCP session anomalies - support for suppress keyword was added (#274) - byte_extract keyword support was added - improved handling of timed out TCP sessions in the detection engine - unified2 payload logging if detection was in the HTTP state (#264) - improved accuracy of the HTTP transaction logging - support for larger (64 bit) Flow/Stream memcaps (#332) - major speed improvements for PCRE, including support for PCRE JIT - support setting flowbits in ip-only rules (#292) - performance increases on SSE3+ CPU's - overhaul of the packet acquisition subsystem - packet based performance profiling subsystem was added - TCP SACK support was added to the stream engine - updated included libhtp to 0.2.6 which fixes several issues 1.1beta2 -- 2011-04-13 - New keyword support: http_raw_uri (including /I for pcre), ssl_state, ssl_version (#258, #259, #260, #262). - Inline mode for the stream engine (#230, #248). - New keyword support: nfq_set_mark - Included an example decoder-events.rules file - api for adding and selecting runmodes was added - pcap logging / recording output was added - basic SCTP protocol parsing was added - more fine grained CPU affinity setting support was added - stream engine inspects stream in larger chunks - fast_pattern support for http_method content modifier (#255) - negation support for isdataat keyword (#257) - configurable interval for stats.log updates (#247) - new pf_ring runmode was added that scales better - pcap live mode now handles the monitor interface going up and down - several QA additions to "make check" - NFQ (linux inline) mode was improved - Alerts classification fix (#275) - compiles and runs on big-endian systems (#63) - unified2 output works around barnyard2 issues with DLT_RAW + IPv6 1.1beta1 -- 2010-12-21 - New keyword support: http_raw_header, http_stat_msg, http_stat_code. - A new default pattern matcher, Aho-Corasick based, that uses much less memory. - reference.config support as supplied by ET/ETpro and VRT. - Much improved fast_pattern support, including for http_uri, http_client_body, http_header, http_raw_header. - Improved parsers, especially the DCERPC parser. - Much improved performance & accuracy. 1.0.5 -- 2011-07-25 - Fix stream reassembly bug #300. Thanks to Rmkml for the report. - Fix several (potential) issues fixed after a source code scan with Coverity generously contributed by RedHat. 1.0.4 -- 2011-06-24 - LibHTP updated to 0.2.6 - Large number of (potential) issues fixed after a source code scan with Coverity generously contributed by RedHat. - Large number of (potential) issues fixed after source code scans with the Clang static analizer. 1.0.3 -- 2011-04-13 - Fix broken checksum calculation for TCP/UDP in some cases - Fix errors in the byte_test, byte_jump, http_method and http_header keywords - Fix a ASN1 parsing issue - Improve LibHTP memory handling - Fix a defrag issue - Fix several stream engine issues suricata-1.4.7/qa/0000755000000000000000000000000012253546204010711 500000000000000suricata-1.4.7/qa/coccinelle/0000755000000000000000000000000012253546204013011 500000000000000suricata-1.4.7/qa/coccinelle/pktnotset-packet.cocci0000644000000000000000000000054012253546156017240 00000000000000@zeroed@ typedef Packet; typedef uint8_t; Packet *p; position p1; @@ memset(p@p1, 0, ...); @isset@ Packet *p; position zeroed.p1; @@ memset(p@p1, 0, ...); ... when != p p->pkt @script:python depends on !isset@ p1 << zeroed.p1; @@ print "Packet zeroed at %s:%s but pkt field is not set afterward." % (p1[0].file, p1[0].line) import sys sys.exit(1) suricata-1.4.7/qa/coccinelle/direct-packet.cocci0000644000000000000000000000037012253546156016460 00000000000000@directpacket@ identifier p; typedef Packet; position p1; @@ Packet p@p1; @ script:python @ p1 << directpacket.p1; @@ print "Invalid Packet definition, explicit allocation must be used at %s:%s" % (p1[0].file, p1[0].line) import sys sys.exit(1) suricata-1.4.7/qa/coccinelle/run_check.sh0000755000000000000000000000126412253546156015242 00000000000000#!/bin/sh if [ $1 ]; then case $1 in *[ch]) LIST=$@; ;; *..*) LIST=$(git diff --pretty="format:" --name-only $1 | grep -E '[ch]$') PREFIX=$(git rev-parse --show-toplevel)/ ;; *) LIST=$(git show --pretty="format:" --name-only $1 | grep -E '[ch]$') PREFIX=$(git rev-parse --show-toplevel)/ ;; esac else LIST=$(git ls-tree -r --name-only --full-tree HEAD src/ | grep -E '*.c$') PREFIX=$(git rev-parse --show-toplevel)/ fi for SMPL in $(git rev-parse --show-toplevel)/qa/coccinelle/*.cocci; do echo "Testing cocci file: $SMPL" for FILE in $LIST ; do spatch --very-quiet -sp_file $SMPL --undefined UNITTESTS $PREFIX$FILE || exit 1; done done exit 0 suricata-1.4.7/qa/coccinelle/access-pkt-packet.cocci0000644000000000000000000000133612253546156017246 00000000000000@init@ typedef Packet; Packet *p; expression E; statement S; @@ ( memset(p, ...); p->pkt = E; | p = SCCalloc(...); S p->pkt = E; ) @pktfield depends on !init@ identifier func !~ "^PacketCopyDataOffset$"; Packet *p; position p1; @@ func(...) { <... p->pkt@p1 ...> } @ script:python @ p1 << pktfield.p1; @@ print "Invalid Packet->pkt usage, GET_PKT_DATA macro must be used at %s:%s" % (p1[0].file, p1[0].line) import sys sys.exit(1) @pktlenfield@ identifier func !~ "^PacketCopyDataOffset$"; Packet *p; position p1; @@ func(...) { <... p->pktlen@p1 ...> } @ script:python @ p1 << pktlenfield.p1; @@ print "Invalid Packet->pktlen usage, GET_PKT_LEN macro must be used at %s:%s" % (p1[0].file, p1[0].line) import sys sys.exit(1) suricata-1.4.7/qa/coccinelle/Makefile.in0000644000000000000000000003204112253546174015004 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = qa/coccinelle DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = access-pkt-packet.cocci banned-functions.cocci direct-packet.cocci \ pktnotset-packet.cocci run_check.sh all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu qa/coccinelle/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu qa/coccinelle/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir 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 \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am @HAVE_COCCINELLE_TRUE@check: @HAVE_COCCINELLE_TRUE@ $(top_srcdir)/qa/coccinelle/run_check.sh # 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: suricata-1.4.7/qa/coccinelle/banned-functions.cocci0000644000000000000000000000043112253546156017174 00000000000000@banned@ identifier func =~ "^\(sprintf\|strcat\|strcpy\|strncpy\|strncat\)$"; position p1; @@ <+... func(...)@p1 ...+> @ script:python @ p1 << banned.p1; func << banned.func; @@ print "Banned function %s() used at %s:%s" % (func, p1[0].file, p1[0].line) import sys sys.exit(1) suricata-1.4.7/qa/coccinelle/Makefile.am0000644000000000000000000000030212253546156014766 00000000000000EXTRA_DIST= access-pkt-packet.cocci banned-functions.cocci direct-packet.cocci \ pktnotset-packet.cocci run_check.sh if HAVE_COCCINELLE check: $(top_srcdir)/qa/coccinelle/run_check.sh endif suricata-1.4.7/qa/wirefuzz.pl0000755000000000000000000005545312253546156013100 00000000000000#!/usr/bin/perl -w #Author:William Metcalf #File:wirefuzz.pl #Copyright (C) 2010 Open Information Security Foundation #You can copy, redistribute or modify this Program under the terms of #the GNU General Public License version 2 as published by the Free #Software Foundation. # #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 #version 2 along with this program; if not, write to the Free Software #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA #02110-1301, USA. #This script is useful if you want to fuzz and or otherwise try to make suricata explode during decoding/proto parsing using saved pcaps. #It is simply a reimplimentation of the technique described here, hence the name: #http://wiki.wireshark.org/FuzzTesting # #Options for getting thre required perl modules: #Ubuntu 9.10 #sudo apt-get install libdevel-gdb-perl libcapture-tiny-perl # #RedHatES/CentOS 5 #yum -y install cpanspec perl-Module-Build #cpanspec --packager OISF -v -s --follow Capture::Tiny #cpanspec --packager OISF -v -s --follow Devel::GDB #rpmbuild --rebuild *.src.rpm #rpm -ivh /usr/src/redhat/RPMS/noarch/perl-Devel-GDB*.rpm #rpm -ivh /usr/src/redhat/RPMS/noarch/perl-Capture-Tiny*.rpm # #Fedora Core 12 #yum -y install perl-Capture-Tiny perl-Devel-GDB # #Other debain based versions, try the Ubunutu instructions if this doesn't work try the following. #sudo apt-get install dh-make-perl #mkdir fuzzmodules && cd fuzzmodules #dh-make-perl --cpan Devel-GDB --build #dh-make-perl --cpan Capture-Tiny --build #sudo dpkg -i *.deb #TODO: Figure out a better way to deal with signal handling. #TODO: Try to determine flow/stream that caused segv by extracting from the bt and extract it from the pcap. #TODO: E-mail notification on segv? #TODO: Parse Valgrind output and alert on errors use strict; use warnings; use Capture::Tiny 'capture'; use List::Util 'shuffle'; use Devel::GDB; use File::Find; use Getopt::Long; use File::Basename; #globals my %config; my @tmpfiles; my @files; my $suricatabin; my $loopnum; my $rules; my $logdir; my $configfile; my $editeratio; my $valgrindopt; my $shuffle; my $useltsuri; my $ltsuribin; my $core_dump; my $excluderegex; my %excludefuzz; my $timestamp; my $keeplogs; my $file_was_fuzzed = 0; Getopt::Long::Configure("prefix_pattern=(-|--)"); GetOptions( \%config, qw(n=s r=s c=s e=s v=s p=s l=s s=s x=s k y z=s h help) ); &parseopts(); #Parse the options sub parseopts { #display help if asked if ( $config{h} || $config{help} ) { &printhelp(); } #filemask of pcaps to read? if ( $config{r} ) { @tmpfiles = <$config{r}>; if(@tmpfiles eq 0){ print "parseopts: Pcap filemask was invalid we couldn't find any matching files\n"; exit; } else { #escapes for filenames foreach my $file (@tmpfiles) { $file =~ s/\(/\\(/g; $file =~ s/\)/\\)/g; $file =~ s/\&/\\&/g; } } } else { print "parseopts: Pcap filemask not specified or doesn't exist\n"; &printhelp(); } #filemask do we have a path to suricata bin? if ( $config{p} && -e $config{p} ) { $suricatabin = $config{p}; #do wrapper script detection lt-suricata won't be created until first run but .libs/suricata should exist. if ( -T $suricatabin ) { open my $in, '<', $suricatabin or die "Can't read old file: $!"; while (<$in>) { if ( $_ =~ m/suricata \- temporary wrapper script for \.libs\/suricata/ ) { print "parseopts: suricata bin file appears to be a wrapper script going to try to find the real bin for gdb.\n"; my $tmpdirname = dirname $suricatabin; my $tmpltsuriname = $tmpdirname . "/.libs/suricata"; if ( -e $tmpltsuriname && -B $tmpltsuriname ) { $ltsuribin = $tmpltsuriname; print "parseopts: telling gdb to use " . $ltsuribin . "\n"; $useltsuri = "yes"; } last; } } close $in; } elsif ( -B $suricatabin ) { print "parseopts: suricata bin file checks out\n"; } else { print "parseopts: suricata bin file is not a text or a bin exiting.\n"; exit; } } else { print "parseopts: Path to suricata bin not provided or doesn't exist\n"; &printhelp(); } #number of times to loop if ( $config{n} ) { $loopnum = $config{n}; print "parseopts: looping through the pcaps " . $loopnum . " times or until we have an error\n"; } else { print "parseopts: looping through the pcaps forever or until we have an error\n"; $loopnum = "infinity"; } #rules file do we have a path and does it exist if ( $config{s} && -e $config{s} ) { $rules = $config{s}; print "parseopts: telling suricata to use rules file " . $rules . "\n"; } else { print("parseopts: rules file not specified or doesn't exist\n"); } #log dir does it exist if ( $config{l} && -e $config{l} ) { $logdir = $config{l}; print "parseopts: using log dir " . $logdir . "\n"; } else { $logdir = "./"; } #config file do we have a path and does it exist if ( $config{c} && -e $config{c} ) { $configfile = $config{c}; print "parseopts: telling suricata to use the config file " . $configfile . "\n"; } else { print "parseopts: config file not specified or doesn't exist\n"; &printhelp(); } #% chance that a byte will be modified. if ( $config{e} ) { #valid range? my $tmperatio = $config{e} * 100; if ( $tmperatio <= 100 && $tmperatio >= 0 ) { $editeratio = $config{e}; print "parseopts: using error ratio " . $editeratio . "\n"; } else { print "parseopts: error ratio specified but outside of range. Valid range is 0.00-1.0\n"; exit; } } else { print("parseopts: not going to fuzz pcap(s)\n"); } #parse the valgrind opts if ( $config{v} ) { if ( $config{v} =~ /^(memcheck|drd|helgrind|callgrind)$/ ) { $valgrindopt = $config{v}; print "parseopts: using valgrind opt " . $valgrindopt . "\n"; } else { print "invalid valgrind opt " . $valgrindopt . "\n"; } } #shuffle the array if we are starting multiple fuzzers at once. GO-GO gadget shuffle if ( $config{y} ) { print "parseopts: going to shuffle the array\n"; $shuffle = "yes"; } #keep logs instead of removing them after each run if ( $config{k} ) { print "parseopts: going to keep logs instead of removing them\n"; $keeplogs = "yes"; } else { $keeplogs = "no"; } #we want to process some files but not fuzz them add them to a hash and check it later if ( $config{z} ) { print "will process but not fuzz files that match regex of " . $config{z} . "\n"; $excluderegex = $config{z}; my $tmpfilepos = 0; while ($tmpfilepos <= $#tmpfiles) { if ($tmpfiles[$tmpfilepos] =~ m/$excluderegex/) { print "adding " . $tmpfiles[$tmpfilepos] . " to fuzz_exclude_hash because it matches our regex\n"; $excludefuzz{$tmpfiles[$tmpfilepos]} = 1; } $tmpfilepos++ } } #maybe we want to exclude a file based on some regex so we can restart the fuzzer after an error #and not have to worry about hitting the same file. if ( $config{x} ) { print "excluding files that match regex of " . $config{x} . "\n"; $excluderegex = $config{x}; my $tmpfilepos = 0; while ($tmpfilepos <= $#tmpfiles) { if ($tmpfiles[$tmpfilepos] =~ m/$excluderegex/) { print "removing " . $tmpfiles[$tmpfilepos] . " because it matches our exclude regex\n"; splice(@tmpfiles, $tmpfilepos, 1); } else { $tmpfilepos++ } } } print "******************Initialization Complete**********************\n"; return; } sub printhelp { print " -h or help -r= -n=<(optional) number of iterations or if not specified will run until error> -s=<(optional) path to ids rules file will be passed as -s to suricata> -e=<(optional) editcap error ratio to introduce if not specified will not fuzz. Valid range for this is 0.00 - 1.0> -p= -l=<(optional) log dir for output if not specified will use current directory.> -v=<(optional) (memcheck|drd|helgrind|callgrind) will run the command through one of the specified valgrind tools.> -x=<(optional) regex for excluding certian files incase something blows up but we want to continue fuzzing .> -z=<(optional) regex for excluding certian files from fuzzing but still process them note: the original files will be processed and not removed.> -y -k Example usage: First thing to do is download and build suricata from git with -O0 so vars don't get optimized out. See the example below: git clone git://phalanx.openinfosecfoundation.org/oisf.git suricatafuzz1 && cd suricatafuzz1 && ./autogen.sh && CFLAGS=\"-g -O0\" ./configure && make Second thing to do is to edit suricata.yaml to fit your environment. Third go ahead and run the script. In the example below the script will loop forever until an error is encountered will behave in the following way. 1.-r Process all pcaps in subdirectories of /home/somepath/pcaps/ 2.-s Tell suricata to use the rules file /home/somepath/current-all.rules 3.-y Shuffle the array of pcaps this is useful if running multiple instances of this script. 4.-c Tell suricata to use the suricata.yaml in the current dir. 6.-e Tell editcap to introduce a 2% error ratio, i.e. there is a 2% chance that a byte will be fuzzed see http://wiki.wireshark.org/FuzzTesting for more info. 7.-p Use src/suricata as our suricata bin file. The script will determin if the argument passed is a bin file or a txt wrapper and will adjust accordingly. /usr/bin/wirefuzz.pl -r=/home/somepath/pcaps/*/* -s=/home/somepath/current-all.rules -y -c=suricata.yaml -e=0.02 -p src/suricata If an error is encountered a file named ERR.txt will be created in the log dir (current dir in this example) that will contain output from stderr,stdout, and gdb. Take a look at the opts make it work for you environtment and from the OISF QA team thanks for helping us make our meerkat fuzzier! ;-)\n"; exit; } my $logfile = $logdir . "wirefuzzlog.txt"; open( LOGFILE, ">>$logfile" ) || die( print "error: Could not open logfile! $logfile\n" ); my $successcnt = 0; while ( $successcnt < $loopnum ) { if ( defined $shuffle ) { @files = shuffle(@tmpfiles); } else { @files = @tmpfiles; } foreach my $file (@files) { my $file_was_fuzzed = 0; #split out the path from the filename my $filedir = dirname $file; my $filename = basename $file; my ( $fuzzedfile, $editcapcmd, $editcapout, $editcaperr, $editcapexit, $editcap_sys_signal, $editcap_sys_coredump ); my ( $fuzzedfiledir, $fuzzedfilename, $fullcmd, $out, $err, $exit, $suricata_sys_signal, $suricata_sys_coredump, $report); print "Going to work with file: $file\n"; my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time); $timestamp = sprintf "%4d-%02d-%02d-%02d-%02d-%02d", $year + 1900, $mon + 1, $mday, $hour, $min, $sec; if ( defined $editeratio and !exists $excludefuzz{$file}) { $file_was_fuzzed = 1; $fuzzedfile = $logdir . $filename . "-fuzz-" . $timestamp; $editcapcmd = "editcap -E " . $editeratio . " " . $file . " " . $fuzzedfile; print( "editcap: " . $editcapcmd . "\n" ); ( $editcapout, $editcaperr ) = capture { system $editcapcmd; $editcapexit = $? >> 8; $editcap_sys_signal = $? & 127; $editcap_sys_coredump = $? & 128; }; if ( $editcapexit ne 0 ) { #this could still cause us to loop forever if all pcaps are bad but it's better than nothing. if ( @files < 2 ) { print "editcap: had an error and this was our only pcap:" . $editcaperr . "\n"; exit; } else { print "editcap: had an error going to the next pcap:" . $editcaperr . "\n"; next; } } elsif ( $editcap_sys_signal eq 2 ) { print "editcap: system() got a ctl+c we are bailing as well\n"; exit; } else { print("editcap: ran successfully\n"); print "******************Editcap Complete**********************\n"; } } else { $fuzzedfile = $file; } #split out the path from the filename $fuzzedfiledir = dirname $fuzzedfile; $fuzzedfilename = basename $fuzzedfile; $fullcmd = "ulimit -c unlimited; "; if ( defined $valgrindopt ) { if ( $valgrindopt eq "memcheck" ) { $fullcmd = $fullcmd . "valgrind -v --log-file=" . $logdir . $fuzzedfilename . $timestamp . "-memcheck-vg.log "; } elsif ( $valgrindopt eq "drd" ) { $fullcmd = $fullcmd . "valgrind --tool=drd --var-info=yes -v --log-file=" . $logdir . $fuzzedfilename . $timestamp . "-drd-vg.log "; } elsif ( $valgrindopt eq "helgrind" ) { $fullcmd = $fullcmd . "valgrind --tool=helgrind -v --log-file=" . $logdir . $fuzzedfilename . $timestamp . "-helgrind-vg.log "; } elsif ( $valgrindopt eq "callgrind" ) { $fullcmd = $fullcmd . "valgrind --tool=callgrind -v --callgrind-out-file=" . $logdir . $fuzzedfilename . $timestamp . "-callgrind-vg.log "; } } $fullcmd = $fullcmd . $suricatabin . " -c " . $configfile . " -r " . $fuzzedfile . " -l " . $logdir; if ( defined $rules ) { $fullcmd = $fullcmd . " -s " . $rules; } print "suricata: $fullcmd \n"; my $starttime = time(); ( $out, $err ) = capture { system $fullcmd; $exit = $? >> 8; $suricata_sys_signal = $? & 127; $suricata_sys_coredump = $? & 128; }; my $stoptime = time(); my $timetotal = $stoptime - $starttime; print LOGFILE $fullcmd . "," . $timetotal . "," . $exit . "," . $suricata_sys_signal . "," . $suricata_sys_coredump . "\n"; print "suricata: exit value $exit\n"; if ( $exit ne 0 ) { my $knownerr = 0; #fuzzer genrated some random link type we can't deal with if ( $err =~ /datalink type \d+ not \(yet\) supported in module PcapFile\./ ) { print "suricata: we matched a known error going to the next file\n"; $knownerr = 1; } if ( $knownerr eq 1 ) { $successcnt++; print "suricata: we have run with success " . $successcnt . " times\n"; if( $keeplogs eq "yes" ) { &keep_logs($fuzzedfilename); $report = $logdir . $fuzzedfilename . "-OUT.txt"; &generate_report($report, $fullcmd, $out, $err, $exit, "none"); } &clean_logs($fuzzedfilename,$file_was_fuzzed); } else { my $report = $logdir . $fuzzedfilename . "-ERR.txt"; &process_core_dump(); if ($core_dump) { print "core dump \n $core_dump"; system( "mv " . $ENV{'PWD'} . "/core* " . $logdir . $fuzzedfilename . ".core" ); &generate_report($report, $fullcmd, $out, $err, $exit, $core_dump); }else{ &generate_report($report, $fullcmd, $out, $err, $exit, "none"); } exit; } } elsif ( $suricata_sys_signal eq 2 ) { print "suricata: system() got a ctl+c we are bailing as well\n"; if( $keeplogs eq "yes" ) { &keep_logs($fuzzedfilename); } &clean_logs($fuzzedfilename,$file_was_fuzzed); exit; } else { if ( $out =~ /Max memuse of stream engine \d+ \(in use (\d+)\)/ ) { if ($1 != 0) { $report = $logdir . $fuzzedfilename . "-OUT.txt"; &generate_report($report, $fullcmd, $out, $err, $exit, "none"); print "Stream leak detected " . $1 . " was still in use at exit see " . $report . " for more details\n"; exit; } } else { print "Stream mem counter could not be found in output\n"; } $successcnt++; print "suricata: we have run with success " . $successcnt . " times\n"; print "******************Suricata Complete**********************\n"; if( $keeplogs eq "yes" ) { &keep_logs($fuzzedfilename); $report = $logdir . $fuzzedfilename . "-OUT.txt"; &generate_report($report, $fullcmd, $out, $err, $exit, "none"); } &clean_logs($fuzzedfilename,$file_was_fuzzed); print "******************Next Packet or Exit *******************\n"; } } } sub process_core_dump { my $gdbbin; my $gdb = new Devel::GDB(); my $coremask = $ENV{'PWD'} . "/core*"; my @coredumps = <${coremask}>; if (@coredumps eq 1 ) { my $corefile = $coredumps[0]; print "gdb: core dump found $corefile processesing with"; if ( $useltsuri eq "yes" ) { $gdbbin = $ltsuribin; } else { $gdbbin = $suricatabin; } print " the following bin file" . $gdbbin . "\n"; $core_dump .= join '', $gdb->get("file $gdbbin"), $gdb->get("core $corefile"), $gdb->get('info threads'), $gdb->get('thread apply all bt full'); print "gdb: core dump \n $core_dump"; } elsif ( @coredumps > 1 ) { print "gdb: multiple core dumps, please clear all core dumps and try the test again. We found:\n"; foreach my $corefile (@coredumps) { print $corefile . "\n"; } } else { print "gdb: no coredumps found returning.\n"; print @coredumps; print " $#coredumps" . "\n"; } print "******************GDB Complete**********************\n"; return; } sub clean_logs { my $deleteme = shift; my $file_was_fuzzed = shift; my $deletemerge = $logdir . $deleteme; my $rmcmd; if ( defined $editeratio and $file_was_fuzzed) { if ( unlink($deletemerge) == 1 ) { print "clean_logs: " . $deletemerge . " deleted successfully.\n"; } else { print "clean_logs: error " . $deletemerge . " was not deleted. You may have to delete the file manually.\n"; } } if ( defined $valgrindopt ) { #uncomment the following lines if you want to remove valgrind logs #$rmcmd = "rm -f " . $deletemerge . "*vg.log"; #print( "running " . $rmcmd . "\n" ); #system("$rmcmd"); } if ( unlink(<$logdir . unified*>) > 0 ) { print "clean_logs: removed unified logs for next run \n"; } else { print "clean_logs: failed to delete unified logs\n:"; } print "******************Log Cleanup Complete**********************\n"; return; } sub keep_logs { my $saveme = shift; unless(defined($editeratio) || $loopnum eq '1'){ my $saveme = $saveme . "-" . $timestamp; } my $savecmd; if (-e $logdir . "alert-debug.log"){ $savecmd = "mv -f " . $logdir . "alert-debug.log " . $logdir . $saveme . "-alert-debug.log"; system($savecmd); } if (-e $logdir . "fast.log"){ $savecmd = "mv -f " . $logdir . "fast.log " . $logdir . $saveme . "-fast.log"; system($savecmd); } if (-e $logdir . "http.log"){ $savecmd = "mv -f " . $logdir . "http.log " . $logdir . $saveme . "-http.log"; system($savecmd); } if (-e $logdir . "stats.log"){ $savecmd = "mv -f " . $logdir . "stats.log " . $logdir . $saveme . "-stats.log"; system($savecmd); } print "******************Log Move Complete**********************\n"; return; } sub generate_report { my ($report, $fullcmd, $stdout, $stderr, $exit, $coredump) = ($_[0], $_[1], $_[2], $_[3], $_[4], $_[5]); open( REPORT, ">$report" ) || ( print "Could not open report file! $report\n" ); print REPORT "COMMAND:$fullcmd\n"; print REPORT "EXITVAL:$exit\n"; print REPORT "STDERR:$stderr\n"; print REPORT "STDOUT:$stdout\n"; if($coredump ne "none"){ print REPORT "COREDUMP:$coredump\n"; } close(REPORT); } suricata-1.4.7/qa/Makefile.in0000644000000000000000000004613112253546174012711 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = qa DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-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 \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = coccinelle EXTRA_DIST = wirefuzz.pl sock_to_gzip_file.py all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu qa/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu qa/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ 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; \ ($(am__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" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ 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 || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -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: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-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-am 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: suricata-1.4.7/qa/Makefile.am0000644000000000000000000000010312253546156012665 00000000000000SUBDIRS = coccinelle EXTRA_DIST = wirefuzz.pl sock_to_gzip_file.py suricata-1.4.7/qa/sock_to_gzip_file.py0000755000000000000000000000371312253546156014711 00000000000000#!/usr/bin/python #I love the python Power Glove. It's so bad! #Usage: sudo -u suricata ./sock_to_gzip_file.py --output-file="http.log.gz" --listen-sock="http.log.sock" import socket,os import gzip import sys from optparse import OptionParser if __name__ == "__main__": parser = OptionParser() #Path to the socket parser.add_option("--listen-sock", dest="lsock", type="string", help="Path to the socket we will listen on.") #Path to gzip file we will write parser.add_option("--output-file", dest="output", type="string", help="Path to file name to output gzip file we will write to.") #parse the opts (options, args) = parser.parse_args() options.usage = "example: sudo -u suricata ./sock_to_gzip_file.py --output-file=\"http.log.gz\" --listen-sock=\"http.log.sock\"\n" #Open the output file if options.output: try: f = gzip.open(options.output, 'wb') except Exception,e: print("Error: could not open output file %s:\n%s\n", options.output, e) sys.exit(-1) else: print("Error: --output-file option required and was not specified\n%s" % (options.usage)) sys.exit(-1) #Open our socket and bind if options.lsock: if os.path.exists(options.lsock): try: os.remove(options.lsock) except OSError: pass try: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.bind(options.lsock) s.listen(1) conn, addr = s.accept() except Exception,e: print("Error: Failed to bind socket %s\n%s\n", options.lsock, e) sys.exit(-1) else: print("Error: --listen-sock option required and was not specified\n%s" % (options.usage)) sys.exit(-1) #Read data from the socket and write to the file while 1: data = conn.recv(1024) if not data: break f.write(data) conn.close() f.close() suricata-1.4.7/COPYING0000644000000000000000000004313112253546156011273 00000000000000 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. Copyright (C) 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. , 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. suricata-1.4.7/rules/0000755000000000000000000000000012253546204011442 500000000000000suricata-1.4.7/rules/files.rules0000644000000000000000000000547012253546156013554 00000000000000# Example rules for using the file handling and extraction functionality in Suricata. # # For storing files make sure you enable the "file" output. # Also, make sure you read the comments that go with it in the suricata.yaml file. # Alert on files with jpg or bmp extensions #alert http any any -> any any (msg:"FILEEXT JPG file claimed"; fileext:"jpg"; sid:1; rev:1;) #alert http any any -> any any (msg:"FILEEXT BMP file claimed"; fileext:"bmp"; sid:3; rev:1;) # Store all files with jpg or pdf extension. #alert http any any -> any any (msg:"FILESTORE jpg"; flow:established,to_server; fileext:"jpg"; filestore; sid:6; rev:1;) #alert http any any -> any any (msg:"FILESTORE pdf"; flow:established,to_server; fileext:"pdf"; filestore; sid:8; rev:1;) # Store all PDF files, regardless of their name. #alert http any any -> any any (msg:"FILEMAGIC pdf"; flow:established,to_server; filemagic:"PDF document"; filestore; sid:9; rev:1;) # Same for JPEG's. #alert http any any -> any any (msg:"FILEMAGIC jpg(1)"; flow:established,to_server; filemagic:"JPEG image data"; filestore; sid:10; rev:1;) #alert http any any -> any any (msg:"FILEMAGIC jpg(2)"; flow:established,to_server; filemagic:"JFIF"; filestore; sid:11; rev:1;) # Unually short file #alert http any any -> any any (msg:"FILEMAGIC short"; flow:established,to_server; filemagic:"very short file (no magic)"; filestore; sid:12; rev:1;) # Simply store all files we encounter, no alerts. #alert http any any -> any any (msg:"FILE store all"; filestore; noalert; sid:15; rev:1;) # Store all JPG files, don't alert. #alert http any any -> any any (msg:"FILE magic"; filemagic:"JFIF"; filestore; noalert; sid:16; rev:1;) #alert http any any -> any any (msg:"FILE magic"; filemagic:"GIF"; filestore; noalert; sid:16; rev:1;) #alert http any any -> any any (msg:"FILE magic"; filemagic:"PNG"; filestore; noalert; sid:17; rev:1;) # Store all Windows executables #alert http any any -> any any (msg:"FILE magic -- windows"; flow:established,to_client; filemagic:"executable for MS Windows"; filestore; sid:18; rev:1;) # Alert on PNG with 1x1 pixels (tracking) #alert http any any -> any any (msg:"FILE tracking PNG (1x1 pixel) (1)"; filemagic:"PNG image data, 1 x 1,"; sid:19; rev:1;) #alert http any any -> any any (msg:"FILE tracking PNG (1x1 pixel) (2)"; filemagic:"PNG image data, 1 x 1|00|"; sid:20; rev:1;) # Alert on GIT with 1x1 pixels (tracking) # The pattern matches on |00| which is the end of the magic buffer, this way we won't match on 1 x 128. #alert http any any -> any any (msg:"FILE tracking GIF (1x1 pixel)"; filemagic:"GIF image data, version 89a, 1 x 1|00|"; sid:21; rev:1;) # Alert and store pdf attachment but not pdf file #alert http any any -> any any (msg:"FILE pdf claimed, but not pdf"; flow:established,to_client; fileext:"pdf"; filemagic:!"PDF document"; filestore; sid:22; rev:1;) suricata-1.4.7/rules/stream-events.rules0000644000000000000000000002263612253546156015252 00000000000000# Stream events -- rules for matching on TCP stream engine events. # # SID's fall in the 2210000+ range. See http://doc.emergingthreats.net/bin/view/Main/SidAllocation # alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake with ack in wrong dir"; stream-event:3whs_ack_in_wrong_dir; sid:2210000; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake async wrong sequence"; stream-event:3whs_async_wrong_seq; sid:2210001; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake right seq wrong ack evasion"; stream-event:3whs_right_seq_wrong_ack_evasion; sid:2210002; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake SYNACK in wrong direction"; stream-event:3whs_synack_in_wrong_direction; sid:2210003; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake SYNACK resend with different ack"; stream-event:3whs_synack_resend_with_different_ack; sid:2210004; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake SYNACK resend with different seq"; stream-event:3whs_synack_resend_with_diff_seq; sid:2210005; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake SYNACK to server on SYN recv"; stream-event:3whs_synack_toserver_on_syn_recv; sid:2210006; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake SYNACK with wrong ack"; stream-event:3whs_synack_with_wrong_ack; sid:2210007; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake SYN resend different seq on SYN recv"; stream-event:3whs_syn_resend_diff_seq_on_syn_recv; sid:2210008; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake SYN to client on SYN recv"; stream-event:3whs_syn_toclient_on_syn_recv; sid:2210009; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 3way handshake wrong seq wrong ack"; stream-event:3whs_wrong_seq_wrong_ack; sid:2210010; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 4way handshake SYNACK with wrong ACK"; stream-event:4whs_synack_with_wrong_ack; sid:2210011; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 4way handshake SYNACK with wrong SYN"; stream-event:4whs_synack_with_wrong_syn; sid:2210012; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 4way handshake wrong seq"; stream-event:4whs_wrong_seq; sid:2210013; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM 4way handshake invalid ack"; stream-event:4whs_invalid_ack; sid:2210014; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM CLOSEWAIT ACK out of window"; stream-event:closewait_ack_out_of_window; sid:2210015; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM CLOSEWAIT FIN out of window"; stream-event:closewait_fin_out_of_window; sid:2210016; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM CLOSEWAIT invalid ACK"; stream-event:closewait_invalid_ack; sid:2210017; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM CLOSING ACK wrong seq"; stream-event:closing_ack_wrong_seq; sid:2210018; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM CLOSING invalid ACK"; stream-event:closing_invalid_ack; sid:2210019; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED packet out of window"; stream-event:est_packet_out_of_window; sid:2210020; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYNACK resend"; stream-event:est_synack_resend; sid:2210022; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYNACK resend with different ACK"; stream-event:est_synack_resend_with_different_ack; sid:2210023; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYNACK resend with different seq"; stream-event:est_synack_resend_with_diff_seq; sid:2210024; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYNACK to server"; stream-event:est_synack_toserver; sid:2210025; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYN resend"; stream-event:est_syn_resend; sid:2210026; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYN resend with different seq"; stream-event:est_syn_resend_diff_seq; sid:2210027; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED SYN to client"; stream-event:est_syn_toclient; sid:2210028; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED invalid ack"; stream-event:est_invalid_ack; sid:2210029; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM FIN invalid ack"; stream-event:fin_invalid_ack; sid:2210030; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM FIN1 ack with wrong seq"; stream-event:fin1_ack_wrong_seq; sid:2210031; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM FIN1 FIN with wrong seq"; stream-event:fin1_fin_wrong_seq; sid:2210032; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM FIN1 invalid ack"; stream-event:fin1_invalid_ack; sid:2210033; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM FIN2 ack with wrong seq"; stream-event:fin2_ack_wrong_seq; sid:2210034; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM FIN2 FIN with wrong seq"; stream-event:fin2_fin_wrong_seq; sid:2210035; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM FIN2 invalid ack"; stream-event:fin2_invalid_ack; sid:2210036; rev:1;) # very common when looking at midstream traffic after IDS started #alert tcp any any -> any any (msg:"SURICATA STREAM FIN recv but no session"; stream-event:fin_but_no_session; sid:2210037; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM FIN out of window"; stream-event:fin_out_of_window; sid:2210038; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM Last ACK with wrong seq"; stream-event:lastack_ack_wrong_seq; sid:2210039; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM Last ACK invalid ACK"; stream-event:lastack_invalid_ack; sid:2210040; rev:1;) # very common when looking at midstream traffic after IDS started #alert tcp any any -> any any (msg:"SURICATA STREAM RST recv but no session"; stream-event:rst_but_no_session; sid:2210041; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM TIMEWAIT ACK with wrong seq"; stream-event:timewait_ack_wrong_seq; sid:2210042; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM TIMEWAIT invalid ack"; stream-event:timewait_invalid_ack; sid:2210043; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM Packet with invalid timestamp"; stream-event:pkt_invalid_timestamp; sid:2210044; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM Packet with invalid ack"; stream-event:pkt_invalid_ack; sid:2210045; rev:1;) # Broken TCP: ack field non 0, but ACK flag not set. http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set # Often result of broken load balancers, firewalls and such. #alert tcp any any -> any any (msg:"SURICATA STREAM Packet with broken ack"; stream-event:pkt_broken_ack; sid:2210051; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM SHUTDOWN RST invalid ack"; stream-event:rst_invalid_ack; sid:2210046; rev:1;) # SYN (re)send during shutdown (closing, closewait, finwait1, finwait2, lastack, timewait states) #alert tcp any any -> any any (msg:"SURICATA STREAM SYN resend"; stream-event:shutdown_syn_resend; sid:2210049; rev:1;) # Sequence gap: missing data in the reassembly engine. Usually due to packet loss. Will be very noisy on a overloaded link / sensor. #alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; sid:2210048; rev:1;) alert tcp any any -> any any (msg:"SURICATA STREAM reassembly overlap with different data"; stream-event:reassembly_overlap_different_data; sid:2210050; rev:1;) # retransmission detection # # The rules below match on retransmissions detected in various stages of the # stream engine. They are all "noalert" rules that increment the counter # tcp.retransmission.count. The last rule sid:2210054 matches if the counter # reaches 10. Increase this number if the rule is too noisy. # # "regular" retransmissions, only count alert tcp any any -> any any (msg:"SURICATA STREAM ESTABLISHED retransmission packet before last ack"; stream-event:est_pkt_before_last_ack; flowint:tcp.retransmission.count,+,1; noalert; classtype:protocol-command-decode; sid:2210021; rev:3;) # retransmission, only count alert tcp any any -> any any (msg:"SURICATA STREAM CLOSEWAIT retransmission packet before last ack"; stream-event:closewait_pkt_before_last_ack; flowint:tcp.retransmission.count,+,1; noalert; classtype:protocol-command-decode; sid:2210052; rev:3;) # retransmission of pkt before reassembly window, only count alert tcp any any -> any any (msg:"SURICATA STREAM reassembly segment before base seq (retransmission)"; stream-event:reassembly_segment_before_base_seq; flowint:tcp.retransmission.count,+,1; noalert; classtype:protocol-command-decode; sid:2210047; rev:2;) # count "general" retransmissions alert tcp any any -> any any (msg:"SURICATA STREAM Packet is retransmission"; stream-event:pkt_retransmission; flowint:tcp.retransmission.count,+,1; noalert; classtype:protocol-command-decode; sid:2210053; rev:1;) # rule to alert if a stream has excessive retransmissions alert tcp any any -> any any (msg:"SURICATA STREAM excessive retransmissions"; flowbits:isnotset,tcp.retransmission.alerted; flowint:tcp.retransmission.count,>=,10; flowbits:set,tcp.retransmission.alerted; classtype:protocol-command-decode; sid:2210054; rev:1;) # next sid 2210055 suricata-1.4.7/rules/Makefile.in0000644000000000000000000003164312253546174013444 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = rules DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = \ decoder-events.rules \ stream-events.rules \ smtp-events.rules \ http-events.rules \ files.rules all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu rules/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu rules/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir 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 \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am 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: suricata-1.4.7/rules/decoder-events.rules0000644000000000000000000002774512253546156015372 00000000000000# Decoder event signatures for Suricata. # SID's fall in the 2200000+ range. See http://doc.emergingthreats.net/bin/view/Main/SidAllocation alert pkthdr any any -> any any (msg:"SURICATA IPv4 packet too small"; decode-event:ipv4.pkt_too_small; sid:2200000; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 header size too small"; decode-event:ipv4.hlen_too_small; sid:2200001; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 total length smaller than header size"; decode-event:ipv4.iplen_smaller_than_hlen; sid:2200002; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 truncated packet"; decode-event:ipv4.trunc_pkt; sid:2200003; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 invalid option"; decode-event:ipv4.opt_invalid; sid:2200004; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 invalid option length"; decode-event:ipv4.opt_invalid_len; sid:2200005; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 malformed option"; decode-event:ipv4.opt_malformed; sid:2200006; rev:1;) #alert pkthdr any any -> any any (msg:"SURICATA IPv4 padding required "; decode-event:ipv4.opt_pad_required; sid:2200007; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 option end of list required"; decode-event:ipv4.opt_eol_required; sid:2200008; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 duplicated IP option"; decode-event:ipv4.opt_duplicate; sid:2200009; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 unknown IP option"; decode-event:ipv4.opt_unknown; sid:2200010; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4 wrong IP version"; decode-event:ipv4.wrong_ip_version; sid:2200011; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 packet too small"; decode-event:ipv6.pkt_too_small; sid:2200012; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 truncated packet"; decode-event:ipv6.trunc_pkt; sid:2200013; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 truncated extension header"; decode-event:ipv6.trunc_exthdr; sid:2200014; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 duplicated Fragment extension header"; decode-event:ipv6.exthdr_dupl_fh; sid:2200015; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 useless Fragment extension header"; decode-event:ipv6.exthdr_useless_fh; sid:2200080; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 duplicated Routing extension header"; decode-event:ipv6.exthdr_dupl_rh; sid:2200016; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 duplicated Hop-By-Hop Options extension header"; decode-event:ipv6.exthdr_dupl_hh; sid:2200017; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 duplicated Destination Options extension header"; decode-event:ipv6.exthdr_dupl_dh; sid:2200018; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 duplicated Authentication Header extension header"; decode-event:ipv6.exthdr_dupl_ah; sid:2200019; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 duplicate ESP extension header"; decode-event:ipv6.exthdr_dupl_eh; sid:2200020; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 invalid option lenght in header"; decode-event:ipv6.exthdr_invalid_optlen; sid:2200021; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6 wrong IP version"; decode-event:ipv6.wrong_ip_version; sid:2200022; rev:1;) # RFC 4302 states the reserved field should be 0. alert pkthdr any any -> any any (msg:"SURICATA IPv6 AH reserved field not 0"; decode-event:ipv6.exthdr_ah_res_not_null; sid:2200081; rev:1;) # HOP option that we don't understand alert pkthdr any any -> any any (msg:"SURICATA IPv6 HOPOPTS unknown option"; decode-event:ipv6.hopopts_unknown_opt; sid:2200086; rev:1;) # HOP header with only padding, covert channel? alert pkthdr any any -> any any (msg:"SURICATA IPv6 HOPOPTS only padding"; decode-event:ipv6.hopopts_only_padding; sid:2200087; rev:1;) # DST option that we don't understand alert pkthdr any any -> any any (msg:"SURICATA IPv6 DSTOPTS unknown option"; decode-event:ipv6.dstopts_unknown_opt; sid:2200088; rev:1;) # DST header with only padding, covert channel? alert pkthdr any any -> any any (msg:"SURICATA IPv6 DSTOPTS only padding"; decode-event:ipv6.dstopts_only_padding; sid:2200089; rev:1;) alert ipv6 any any -> any any (msg:"SURICATA IPv6 with ICMPv4 header"; decode-event:ipv6.icmpv4; sid:2200090; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 packet too small"; decode-event:icmpv4.pkt_too_small; sid:2200023; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 unknown type"; decode-event:icmpv4.unknown_type; sid:2200024; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 unknown code"; decode-event:icmpv4.unknown_code; sid:2200025; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 truncated packet"; decode-event:icmpv4.ipv4_trunc_pkt; sid:2200026; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 unknown version"; decode-event:icmpv4.ipv4_unknown_ver; sid:2200027; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 packet too small"; decode-event:icmpv6.pkt_too_small; sid:2200028; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown type"; decode-event:icmpv6.unknown_type; sid:2200029; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown code"; decode-event:icmpv6.unknown_code; sid:2200030; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 truncated packet"; decode-event:icmpv6.ipv6_trunc_pkt; sid:2200031; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown version"; decode-event:icmpv6.ipv6_unknown_version; sid:2200032; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP packet too small"; decode-event:tcp.pkt_too_small; sid:2200033; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP header length too small"; decode-event:tcp.hlen_too_small; sid:2200034; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP invalid option length"; decode-event:tcp.invalid_optlen; sid:2200035; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP option invalid length"; decode-event:tcp.opt_invalid_len; sid:2200036; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP duplicated option"; decode-event:tcp.opt_duplicate; sid:2200037; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA UDP packet too small"; decode-event:udp.pkt_too_small; sid:2200038; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA UDP header length too small"; decode-event:udp.hlen_too_small; sid:2200039; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA UDP invalid header length"; decode-event:udp.hlen_invalid; sid:2200040; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA SLL packet too small"; decode-event:sll.pkt_too_small; sid:2200041; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA Ethernet packet too small"; decode-event:ethernet.pkt_too_small; sid:2200042; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPP packet too small"; decode-event:ppp.pkt_too_small; sid:2200043; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPP VJU packet too small"; decode-event:ppp.vju_pkt_too_small; sid:2200044; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPP IPv4 packet too small"; decode-event:ppp.ip4_pkt_too_small; sid:2200045; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPP IPv6 too small"; decode-event:ppp.ip6_pkt_too_small; sid:2200046; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPP wrong type"; decode-event:ppp.wrong_type; sid:2200047; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPP unsupported protocol"; decode-event:ppp.unsup_proto; sid:2200048; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPPOE packet too small"; decode-event:pppoe.pkt_too_small; sid:2200049; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPPOE wrong code"; decode-event:pppoe.wrong_code; sid:2200050; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA PPPOE malformed tags"; decode-event:pppoe.malformed_tags; sid:2200051; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE packet too small"; decode-event:gre.pkt_too_small; sid:2200052; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE wrong version"; decode-event:gre.wrong_version; sid:2200053; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v0 recursion control"; decode-event:gre.version0_recur; sid:2200054; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v0 flags"; decode-event:gre.version0_flags; sid:2200055; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v0 header too big"; decode-event:gre.version0_hdr_too_big; sid:2200056; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 checksum present"; decode-event:gre.version1_chksum; sid:2200057; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 routing present"; decode-event:gre.version1_route; sid:2200058; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 strict source route"; decode-event:gre.version1_ssr; sid:2200059; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 recursion control"; decode-event:gre.version1_recur; sid:2200060; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 flags"; decode-event:gre.version1_flags; sid:2200061; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 no key present"; decode-event:gre.version1_no_key; sid:2200062; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 wrong protocol"; decode-event:gre.version1_wrong_protocol; sid:2200063; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 malformed Source Route Entry header"; decode-event:gre.version1_malformed_sre_hdr; sid:2200064; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA GRE v1 header too big"; decode-event:gre.version1_hdr_too_big; sid:2200065; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA VLAN header too small "; decode-event:vlan.header_too_small; sid:2200066; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA VLAN unknown type"; decode-event:vlan.unknown_type; sid:2200067; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IP raw invalid IP version "; decode-event:ipraw.invalid_ip_version; sid:2200068; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv4 Packet size too large"; decode-event:ipv4.frag_too_large; sid:2200069; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv4 Fragmentation overlap"; decode-event:ipv4.frag_overlap; sid:2200070; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv6 Packet size too large"; decode-event:ipv6.frag_too_large; sid:2200071; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv6 Fragmentation overlap"; decode-event:ipv6.frag_overlap; sid:2200072; rev:1;) # checksum rules alert ip any any -> any any (msg:"SURICATA IPv4 invalid checksum"; ipv4-csum:invalid; sid:2200073; rev:1;) alert tcp any any -> any any (msg:"SURICATA TCPv4 invalid checksum"; tcpv4-csum:invalid; sid:2200074; rev:1;) alert udp any any -> any any (msg:"SURICATA UDPv4 invalid checksum"; udpv4-csum:invalid; sid:2200075; rev:1;) alert icmp any any -> any any (msg:"SURICATA ICMPv4 invalid checksum"; icmpv4-csum:invalid; sid:2200076; rev:1;) alert tcp any any -> any any (msg:"SURICATA TCPv6 invalid checksum"; tcpv6-csum:invalid; sid:2200077; rev:1;) alert udp any any -> any any (msg:"SURICATA UDPv6 invalid checksum"; udpv6-csum:invalid; sid:2200078; rev:1;) alert icmp any any -> any any (msg:"SURICATA ICMPv6 invalid checksum"; icmpv6-csum:invalid; sid:2200079; rev:1;) # IPv4 in IPv6 rules alert pkthdr any any -> any any (msg:"SURICATA IPv4-in-IPv6 packet too short"; decode-event:ipv6.ipv4_in_ipv6_too_small; sid:2200082; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv4-in-IPv6 invalid protocol"; decode-event:ipv6.ipv4_in_ipv6_wrong_version; sid:2200083; rev:1;) # IPv6 in IPv6 rules alert pkthdr any any -> any any (msg:"SURICATA IPv6-in-IPv6 packet too short"; decode-event:ipv6.ipv6_in_ipv6_too_small; sid:2200084; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IPv6-in-IPv6 invalid protocol"; decode-event:ipv6.ipv6_in_ipv6_wrong_version; sid:2200085; rev:1;) # next sid is 2200091 suricata-1.4.7/rules/smtp-events.rules0000644000000000000000000000451412253546156014735 00000000000000# SMTP event rules # # SID's fall in the 2220000+ range. See http://doc.emergingthreats.net/bin/view/Main/SidAllocation # # These sigs fire at most once per connection. # # A flowint smtp.anomaly.count is incremented for each match. By default it will be 0. # alert smtp any any -> any any (msg:"SURICATA SMTP invalid reply"; flow:established,to_client; app-layer-event:smtp.invalid_reply; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220000; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP unable to match reply with request"; flow:established,to_client; app-layer-event:smtp.unable_to_match_reply_with_request; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220001; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP max command line len exceeded"; flow:established; app-layer-event:smtp.max_command_line_len_exceeded; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220002; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP max reply line len exceeded"; flow:established,to_client; app-layer-event:smtp.max_reply_line_len_exceeded; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220003; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP invalid pipelined sequence"; flow:established,to_server; app-layer-event:smtp.invalid_pipelined_sequence; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220004; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP bdat chunk len exceeded"; flow:established; app-layer-event:smtp.bdat_chunk_len_exceeded; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220005; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP no server welcome message"; flow:established,to_client; app-layer-event:smtp.no_server_welcome_message; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220006; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP tls rejected"; flow:established; app-layer-event:smtp.tls_rejected; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220007; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP data command rejected"; flow:established,to_client; app-layer-event:smtp.data_command_rejected; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220008; rev:1;) suricata-1.4.7/rules/Makefile.am0000644000000000000000000000016012253546156013421 00000000000000EXTRA_DIST = \ decoder-events.rules \ stream-events.rules \ smtp-events.rules \ http-events.rules \ files.rules suricata-1.4.7/rules/http-events.rules0000644000000000000000000001553112253546156014732 00000000000000# HTTP event rules # # SID's fall in the 2221000+ range. See http://doc.emergingthreats.net/bin/view/Main/SidAllocation # # These sigs fire at most once per connection. # # A flowint http.anomaly.count is incremented for each match. By default it will be 0. # alert http any any -> any any (msg:"SURICATA HTTP unknown error"; flow:established; app-layer-event:http.unknown_error; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221000; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP gzip decompression failed"; flow:established; app-layer-event:http.gzip_decompression_failed; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221001; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP request field missing colon"; flow:established,to_server; app-layer-event:http.request_field_missing_colon; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221002; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP response field missing colon"; flow:established,to_client; app-layer-event:http.response_field_missing_colon; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221020; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid request chunk len"; flow:established,to_server; app-layer-event:http.invalid_request_chunk_len; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221003; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid response chunk len"; flow:established,to_client; app-layer-event:http.invalid_response_chunk_len; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221004; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid transfer encoding value in request"; flow:established,to_server; app-layer-event:http.invalid_transfer_encoding_value_in_request; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221005; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid transfer encoding value in response"; flow:established,to_client; app-layer-event:http.invalid_transfer_encoding_value_in_response; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221006; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid content length field in request"; flow:established,to_server; app-layer-event:http.invalid_content_length_field_in_request; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221007; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid content length field in response"; flow:established,to_client; app-layer-event:http.invalid_content_length_field_in_response; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221008; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP status 100-Continue already seen"; flow:established,to_client; app-layer-event:http.100_continue_already_seen; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221009; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP unable to match response to request"; flow:established,to_client; app-layer-event:http.unable_to_match_response_to_request; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221010; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid server port in request"; flow:established,to_server; app-layer-event:http.invalid_server_port_in_request; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221011; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid authority port"; flow:established; app-layer-event:http.invalid_authority_port; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221012; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP request header invalid"; flow:established,to_server; app-layer-event:http.request_header_invalid; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221013; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP response header invalid"; flow:established,to_client; app-layer-event:http.response_header_invalid; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221021; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP missing Host header"; flow:established,to_server; app-layer-event:http.missing_host_header; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221014; rev:1;) # Alert if hostname is both part of URL and Host header and they are not the same. alert http any any -> any any (msg:"SURICATA HTTP Host header ambiguous"; flow:established,to_server; app-layer-event:http.host_header_ambiguous; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221015; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid request field folding"; flow:established,to_server; app-layer-event:http.invalid_request_field_folding; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221016; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP invalid response field folding"; flow:established,to_client; app-layer-event:http.invalid_response_field_folding; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221017; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP request field too long"; flow:established,to_server; app-layer-event:http.request_field_too_long; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221018; rev:1;) alert http any any -> any any (msg:"SURICATA HTTP response field too long"; flow:established,to_client; app-layer-event:http.response_field_too_long; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221019; rev:1;) # Multipart parser detected generic error. alert http any any -> any any (msg:"SURICATA HTTP multipart generic error"; flow:established,to_server; app-layer-event:http.multipart_generic_error; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221022; rev:1;) # Multipart header claiming a file to present, but no actual filedata available. alert http any any -> any any (msg:"SURICATA HTTP multipart no filedata"; flow:established,to_server; app-layer-event:http.multipart_no_filedata; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221023; rev:1;) # Multipart header invalid. alert http any any -> any any (msg:"SURICATA HTTP multipart invalid header"; flow:established,to_server; app-layer-event:http.multipart_invalid_header; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221024; rev:1;) # Warn when the port in the Host: header doesn't match the actual TCP Server port. alert http any any -> any any (msg:"SURICATA HTTP request server port doesn't match TCP port"; flow:established,to_server; app-layer-event:http.request_server_port_tcp_port_mismatch; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221026; rev:1;) # next sid 2221026 suricata-1.4.7/mkinstalldirs0000755000000000000000000000672212253546174013053 00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2009-04-28.21; # UTC # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' IFS=" "" $nl" errstatus=0 dirmode= usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit $? ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 $scriptversion" exit $? ;; --) # 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 # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and # mkdir -p a/c at the same time, both will detect that a is missing, # one will create a, then the other will try to create a and die with # a "File exists" error. This is a problem when calling mkinstalldirs # from a parallel make. We use --version in the probe to restrict # ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the 'mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because '.' already # exists. test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi ;; *) if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./--version "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac for file do case $file in /*) pathcomp=/ ;; *) pathcomp= ;; esac oIFS=$IFS IFS=/ set fnord $file shift IFS=$oIFS for d do test "x$d" = x && continue 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 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: suricata-1.4.7/doc/0000755000000000000000000000000012253546204011055 500000000000000suricata-1.4.7/doc/Setting_up_IPSinline_for_Linux.txt0000644000000000000000000000603412253546156017627 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Setting_up_IPSinline_for_Linux Setting up IPS/inline for Linux In this guide will be explained how to work with Suricata in inline mode and how to set iptables for that purpose. First start with compiling Suricata with NFQ support. For instructions see Ubuntu_Installation. For more information about NFQ and iptables, see suricata.yaml. To check if you have NFQ enabled in your Suricata, enter the following command: suricata --build-info and examine if you have NFQ between the features. To run suricata with the NFQ mode, you have to make use of the -q option. This option tells Suricata which of the queue numbers it should use. sudo suricata -c /etc/suricata/suricata.yaml -q 0 Iptables configuration First of all it is important to know which traffic you would like to send to Suricata. Traffic that passes your computer or traffic that is generated by your computer. If Suricata is running on a gateway and is meant to protect the computers behind that gateway you are dealing with the first scenario: forward_ing . If Suricata has to protect the computer it is running on, you are dealing with the second scenario: host (see drawing 2). These two ways of using Suricata can also be combined. The easiest rule in case of the gateway-scenario to send traffic to Suricata is: sudo iptables -I FORWARD -j NFQUEUE In this case, all forwarded traffic goes to Suricata. In case of the host situation, these are the two most simple iptable rules; sudo iptables -I INPUT -j NFQUEUE sudo iptables -I OUTPUT -j NFQUEUE It is possible to set a queue number. If you do not, the queue number will be 0 by default. Imagine you want Suricata to check for example just TCP-traffic, or all incoming traffic on port 80, or all traffic on destination-port 80, you can do so like this: sudo iptables -I INPUT -p tcp -j NFQUEUE sudo iptables -I OUTPUT -p tcp -j NFQUEUE In this case, Suricata checks just TCP traffic. sudo iptables -I INPUT -p tcp --sport 80 -j NFQUEUE sudo iptables -I OUTPUT -p tcp --dport 80 -j NFQUEUE In this example, Suricata checks all input and output on port 80. To see if you have set your iptables rules correct make sure Suricata is running and enter: sudo iptables -vnL In the example you can see if packets are being logged. This description of the use of iptables is the way to use it with IPv4. To use it with IPv6 all previous mentioned commands have to start with 'ip6tables'. It is also possible to let Suricata check both kinds of traffic. There is also a way to use iptables with multiple networks (and interface cards). Example: sudo iptables -I FORWARD -i eth0 -o eth1 -j NFQUEUE sudo iptables -I FORWARD -i eth1 -o eth0 -j NFQUEUE The options -i (input) -o (output) can be combined with all previous mentioned options If you would stop Suricata and use internet, the traffic will not come through. To make internet work correctly, you have to erase all iptable rules. To erase all iptable rules, enter: sudo iptables -F suricata-1.4.7/doc/OpenBSD_Installation_from_GIT.txt0000644000000000000000000000403512253546156017247 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/OpenBSD_Installation_from_GIT OpenBSD Installation from GIT Pre-installation Requirements Before you can build Suricata for your system, run the following commands to ensure that you have everything you need for the installation. pkg_add gcc pkg_add pcre pkg_add libtool pkg_add libyaml pkg_add libnet-1.1.2.1p0 If you would like to build from Git sources, you have to install the following building tools: pkg_add git pkg_add autoconf pkg_add automake If you use OpenBSD 4.8, enter the following: pkg_add git autoconf-2.61p3 automake-1.10.3 HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. Suricata Next, clone the repository and run autogen: git clone git://phalanx.openinfosecfoundation.org/oisf.git cd oisf export AUTOCONF_VERSION=2.61 export AUTOMAKE_VERSION=1.10 ./autogen.sh Enter the following to configure: CPPFLAGS="-I/usr/local/include" CFLAGS="-L/usr/local/lib" ./configure -- prefix=/opt/suricata To build and install Suricata, enter the following in your command line: make make install Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Next, continue with the Basic_Setup. Source: http://home.regit.org/?p=478 suricata-1.4.7/doc/Third_Party_Installation_Guides.txt0000644000000000000000000000066312253546156020023 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Third_Party_Installation_Guides Third Party Installation Guides On this page you can find links to third party installation guides for Suricata. Beware that none of these guides is reviewed by us. Feel free to add a link to your Suricata installation guide. http://aldeid.com/index.php/Suricata/Installation-and-basic-configuration suricata-1.4.7/doc/Mac_OS_X_106x.txt0000644000000000000000000000437312253546156013721 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Mac_OS_X_106x Mac OS X (10.6.x) Pre-installation requirements These instructions have been tested with Mac OS X (10.6.1). To begin, you will need an essential development environment much like gcc/make. You can download Xcode from http://developer.apple.com/technology/xcode.html. MacPorts is required for you to fetch the depends, so you will also need to install MacPorts, if you have not already done so. The online installation guide is located at http://guide.macports.org/#installing. Before you can build Suricata for your system, you must run the following command to ensure that you have everything you need for the installation. port install autoconf automake gcc44 make libnet11 libpcap pcre \ libyaml libtool export AC_PROG_LIBTOOL=$( which libtool ) Depending on the current status of your system, it may take a while to complete this process. HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS If you would like to have IPS capabilities with IPFW, then you should run configure like this: ./configure --enable-ipfw --prefix=/usr --sysconfdir=/etc --localstatedir=/ var and execute the rest of the commands the same as above. Suricata To download and build Suricata, enter the following: wget http://www.openinfosecfoundation.org/download/suricata-1.3.3.tar.gz tar -xvzf suricata-1.3.3.tar.gz cd suricata-1.3.3 You will also need to have an ipfw rule set for the engine to see the packets from ipfw. For example: ipfw add 100 divert 8000 ip from any to any The 8000 above should be the same number you pass on the command line of suricata with the option -d, that is, -d 8000: suricata -c config_file.yaml -d 8000 You will need a Suricata rule set with IPS options (drop, reject, etc). For this, please refer to the Emerging Threats rule sets. If you are building from Git sources, enter the following: bash autogen.sh If you are not building from Git sources, enter the following: ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var make sudo make install Please continue with the Basic_Setup. suricata-1.4.7/doc/Ubuntu_Installation_from_GIT.txt0000644000000000000000000000552312253546156017302 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Ubuntu_Installation_from_GIT Ubuntu Installation from GIT In this document will be explained how to install and use the most recent code of Suricata on Ubuntu. Installing from GIT on other operating systems is basically the same, except that some commands are Ubuntu-specific (like sudo and apt-get). In case you are using another operating system, you should replace those commands by your operating-specific commands. Pre-installation requirements Before you can build Suricata for your system, run the following command to ensure that you have everything you need for the installation. sudo apt-get -y install libpcre3 libpcre3-dbg libpcre3-dev \ build-essential autoconf automake libtool libpcap-dev libnet1-dev \ libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 \ make libmagic-dev sudo apt-get install git-core Depending on the current status of your system, it may take a while to complete this process. HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS By default, Suricata works as an IDS. If you want to use it as a IDS and IPS program, enter: sudo apt-get -y install libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 Suricata First, it is convenient to create a directory for Suricata. Name it 'suricata' for example. Open the terminal and enter: mkdir suricata Followed by: cd suricata Next, enter the following line in the terminal: git clone git://phalanx.openinfosecfoundation.org/oisf.git cd oisf Followed by: ./autogen.sh To configure, please enter: ./configure To compile, please enter: make To install Suricata, enter: sudo make install sudo ldconfig Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Please continue with Basic_Setup. In case you have already made a map for the most recent code, downloaded the code into that map, and want to download recent code again, please enter: cd suricata/oisf next, enter: git pull After that, you start again at running autogen. suricata-1.4.7/doc/Debian_Installation.txt0000644000000000000000000000475512253546156015462 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Debian_Installation Debian Installation Pre-installation requirements Before you can build Suricata for your system, run the following command to ensure that you have everything you need for the installation. Make sure you will enter all the following commands as root/super-user, otherwise it will not work. apt-get -y install libpcre3 libpcre3-dbg libpcre3-dev \ build-essential autoconf automake libtool libpcap-dev libnet1-dev \ libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libmagic-dev libcap-ng-dev \ pkg-config Depending on the current status of your system, it may take a while to complete this process. HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS By default, Suricata works as an IDS. If you want to use it as a IDS and IPS program, enter: apt-get -y install libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink- dev libnfnetlink0 Suricata To download and build Suricata, enter the following: wget http://www.openinfosecfoundation.org/download/suricata-1.3.3.tar.gz tar -xvzf suricata-1.3.3.tar.gz cd suricata-1.3.3 Compile and install the program If you plan to build Suricata with IPS capabilities, enter: ./configure --enable-nfqueue --prefix=/usr --sysconfdir=/etc -- localstatedir=/var instead of ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var Continue with the next commands: ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var make make install To make sure the existing list with libraries will be updated with the new library, enter: ldconfig Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Please continue with the Basic_Setup. suricata-1.4.7/doc/Installation_with_CUDA_on_Scientific_Linux_6.txt0000644000000000000000000000520512253546156022276 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Installation_with_CUDA_on_Scientific_Linux_6 Installation with CUDA on Scientific Linux 6 Hardware used: HP Proliant G7, 16 cores, 30 GB RAM, NVIDIA CUDA Quadro 4000 graphics card For setup you need to be root. Enter the following: mkdir /root/src cd /root/src Pre installation requirements Run the following command to ensure that you have everything you need for the installation: yum install mpfr-2.4.1-6.el6.x86_64 cpp-4.4.4-13.el6.x86_64 ppl-0.10.2- 11.el6.x86_64 \ cloog-ppl-0.15.7-1.2.el6.x86_64 gcc-4.4.4-13.el6.x86_64 kernel-devel-2.6.32- 131.2.1.el6.x86_64 \ pcre-devel-7.8-3.1.el6.x86_64 libpcap-devel-1.0.0- 6.20091201git117cb5.el6.x86_64 \ yum-plugin-priorities-1.1.26-11.el6.noarch yum-conf-sl6x-1-1.noarch libyaml- 0.1.3-1.el6.rf.x86_64 \ libyaml-devel-0.1.3-1.el6.rf.x86_64 libnet-1.1.2.1-2.2.el6.rf.x86_64 flex- 2.5.35-8.el6.x86_64 \ bison-2.4.1-5.el6.x86_64 gcc-c++-4.4.4-13.el6.x86_64 CUDA Download and install NVIDIA CUDA drivers: wget http://us.download.nvidia.com/XFree86/Linux-x86_64/270.41.19/NVIDIA- Linux-x86_64-270.41.19.run chmod +x NVIDIA-Linux-x86_64-270.41.19.run ./NVIDIA-Linux-x86_64-270.41.19.run You also need to download and install the CUDA toolkit for RHEL6 : wget http://developer.download.nvidia.com/compute/cuda/4_0/toolkit/ cudatoolkit_4.0.17_linux_64_rhel6.0.run chmod +x cudatoolkit_4.0.17_linux_64_rhel6.0.run ./cudatoolkit_4.0.17_linux_64_rhel6.0.run Make sure the kernel modules are loaded: /sbin/modprobe -r nouveau && /sbin/modprobe nvidia To ensure the proper NVIDIA CUDA modules get loaded on reboot, add the above line to your /etc/rc.local file. Suricata Download and install Suricata: wget http://www.openinfosecfoundation.org/download/suricata-1.1beta2.tar.gz And unpack it: tar -xvzf suricata-1.1beta2.tar.gz Change to the unpacked directory: cd suricata-1.1beta2 Compile and install the engine with CUDA support: ./configure --enable-gccprotect --enable-profiling --enable-cuda \ --with-cuda-includes=/usr/local/cuda/include --with-cuda-libraries=/usr/ local/cuda/lib64/ make make install Rules Read the information in Rule_Management_with_Oinkmaster Add rules to suricata: cd /etc/suricata wget https://rules.emergingthreatspro.com/open-nogpl/suricata/ emerging.rules.tar.gz tar -xvzf emerging.rules.tar.gz Make sure your .yaml file includes the /etc/suricata/rules/emerging-*.rules files (they may need to be uncommented). Run Suricata as followed: cd /etc/suricata /usr/local/bin/suricata -c /etc/suricata/suricata.yaml -i eth0 suricata-1.4.7/doc/Basic_Setup.txt0000644000000000000000000000706412253546156013754 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Basic_Setup Basic Setup When using Debian or FreeBSD, make sure you enter all commands as root/super- user because for these operating systems it is not possible to use 'sudo'. Start with creating a directory for Suricata's log information. sudo mkdir /var/log/suricata To prepare the system for using it, enter: sudo mkdir /etc/suricata The next step is to copy classification.config, reference.config and suricata.yaml from the base build/installation directory (ex. from git it will be the oisf directory) to the /etc/suricata directory. Do so by entering the following: sudo cp classification.config /etc/suricata sudo cp reference.config /etc/suricata sudo cp suricata.yaml /etc/suricata Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Setting variables Make sure every variable of the vars, address-groups and port-groups in the yaml file is set correctly for your needs. A full explanation is available in the Rule_vars_section_of_the_yaml. You need to set the ip-address(es) of your local network at HOME_NET. It is recommended to set EXTERNAL_NET to !$HOME_NET. This way, every ip-address but the one set at HOME_NET will be treated as external. It is also possible to set EXTERNAL_NET to 'any', only the recommended setting is more precise and lowers the change that false positives will be generated. HTTP_SERVERS, SMTP_SERVERS , SQL_SERVERS , DNS_SERVERS and TELNET_SERVERS are by default set to HOME_NET. AIM_SERVERS is by default set at 'any'. These variables have to be set for servers on your network. All settings have to be set to let it have a more accurate effect. Next, make sure the following ports are set to your needs: HTTP_PORTS, SHELLCODE_PORTS, ORACLE_PORTS and SSH_PORTS. Finally, set the host-os-policy to your needs. See Host_OS_Policy_in_the_yaml for a full explanation. windows:[] bsd: [] bsd-right: [] old-linux: [] linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000: 0000"] old-solaris: [] solaris: ["::1"] hpux10: [] hpux11: [] irix: [] macos: [] vista: [] windows2k3: [] Note that bug #499 may prevent you from setting old-linux, bsd-right and old- solaris right now. Interface cards To check the available interface cards, enter: ifconfig Now you can see which one you would like Suricata to use. To start the engine and include the interface card of your preference, enter: sudo suricata -c /etc/suricata/suricata.yaml -i wlan0 Instead of wlan0, you can enter the interface card of your preference. To see if the engine is working correctly and receives and inspects traffic, enter: cd /var/log/suricata Followed by: tail http.log And: tail -n 50 stats.log To make sure the information displayed is up-dated in real time, use the - f option before http.log and stats.log: tail -f http.log stats.log suricata-1.4.7/doc/Windows.txt0000644000000000000000000001413112253546156013176 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Windows Windows NOTE - A new instruction set for Suricata installation (and/or compilation from scratch) can be found here: https://redmine.openinfosecfoundation.org/projects/suricata/files also a windows binary - self extracting auto install package is available here: http://www.openinfosecfoundation.org/index.php/download-suricata Preparing the build environment The instructions below should be followed in the order they appear. If your configuration requires unique actions to compile the package and/or you significantly modify the configure shell script, please e-mail the details of your requirements and/or solution to bugreports@openinfosecfoundation.org. Set up MinGW environment from http://mingw.org/ Do not use the automatic installer, as it is deprecated. Instead, manually unpack the following packages to c:\mingw (you may use newer versions if you prefer): * binutils o binutils-2.20-1-mingw32-bin.tar.gz * mingw-runtime (dev and dll) o mingwrt-3.17-mingw32-dll.tar.gz o mingwrt-3.17-mingw32-dev.tar.gz * w32api o w32api-3.14-mingw32-dev.tar.gz * Required runtime libraries for GCC (gmp, libiconv, MPFR and pthreads) o gmp-4.2.4-mingw32-dll.tar.gz o libiconv-1.13.1-1-mingw32-dll-2.tar.lzma o mpfr-2.4.1-mingw32-dll.tar.gz o pthreads-w32-2.8.0-mingw32-dll.tar.gz * gcc-core (bin and dll) o gcc-core-4.4.0-mingw32-bin.tar.gz o gcc-core-4.4.0-mingw32-dll.tar.gz * make o make-3.81-20090914-mingw32-bin.tar.gz * zlib o libz-1.2.3-1-mingw32-dll-1.tar.gz + libz-1.2.3-1-mingw32-dev.tar.gz Download MSYS Get MSYS from http://sourceforge.net/projects/mingw/files/ and install MSYS-1.0.11.exe (MSYS Base System) msysDTK-1.0.1.exe (MSYS Suplementary Tools) autoconf-2.63-1-msys-1.0.11-bin.tar.lzma automake-1.11-1-msys-1.0.11-bin.tar.lzma libtool-2.2.7a-1-msys-1.0.11-bin.tar.lzma MSYS will ask the following questions during installation. Accept Post Install: [y] MinGW Installed? : [y] path to MinGW: [c:/MinGW] Download pkg-config Install pkg-config taken from http://wiki.videolan.org/Win32CompileMSYSNew#PKG- CONFIG Download and extract the following into c:\Msys\1.0 http://ftp.gnome.org/pub/GNOME/binaries/win32/glib/2.18/glib_2.18.2- 1_win32.zip ftp://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config_0.23- 3_win32.zip ftp://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config- dev_0.23-3_win32.zip Set PKG_CONFIG_PATH=/win32/lib/pkgconfig (e.g. by adding the Windows environment variable PKG_CONFIG_PATH in "Control Panel"->"System"->"Advanced System Settings"->"Environment Variables" and setting the value to /win32/lib/pkgconfig) Download Git sources Get Git sources from http://code.google.com/p/msysgit/ Unpack to /msys/1.0 Remember to edit ~/.gitconfig to set your username Download libpcre Get libpcre from http://www.pcre.org/ ./configure --enable-utf8 --disable-cpp --prefix=/mingw make make install Download libyaml Download libyaml from http://pyyaml.org/wiki/LibYAML Though libyaml does not support mingw compilation, it does work in static mode. ./configure --prefix=/mingw CFLAGS="-DYAML_DECLARE_STATIC" make make install Download libpcap Download the developer pack from http://www.winpcap.org/devel.htm To have the driver in the system, download and install a corresponding installer package from http://www.winpcap.org/install/default.htm Copy includes to c:/mingw/include and libs (.a) to c:/mingw/lib Rename libwpcap.a to libpcap.a Get and compile Suricata git clone git://phalanx.openinfosecfoundation.org/oisf.git cd oisf Because of an autotools port bug, you will need to do the following: dos2unix.exe libhtp/configure.ac dos2unix.exe libhtp/htp.pc.in dos2unix.exe libhtp/Makefile.am ./autogen.sh ./configure CFLAGS="-DYAML_DECLARE_STATIC" Add --enable-nfqueue as a configurable parameter to enable inline mode. make If the full installation is successful, suricata.exe will be located in src/.lib. To test your build, you will need libpcre-0.dll, libz-1.dll, and pthreadGC2.dll, all of which should already be installed under c:/mingw or c:/ msys. preparing the runtime environment. To prepare the runtime environment, you must copy the executable and DLLs to a dedicated directory. Get the classification.config and suricata.yaml, and then edit suricata.yaml to ensure the directories are correctly identified. pcap mode If you have not already done so, install winpcap runtime and its driver. Then, determine your eth device UUID in the registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ suricata.exe -c suricata.yaml -i \device\ In the example above, device should be replaced with your device uuid. Inline mode To operate in inline mode, you must download, compile and install netfilterforwin, which is the netfilter.sys driver and Windows port of the libnetfilter_queue library. Download and install the Windows Driver Kit from Microsoft http://www.microsoft.com/downloads/ details.aspx?displaylang=en&FamilyID=36a2630f-5d56-43b5-b996-7633f2ec14ff Download netfilterforwin from http://sourceforge.net/projects/netfilterforwin/ Unpack it so the netfilterforwin directory is beside the oisf directory. You must omit the version from its name. Compile the driver Open the correct build environment from your Start menu Start > All Programs > Windows Driver Kits > WDK xxxx.yyyy.z > Build Environments > Windows Server 2003 > x86 Free Build Environment At your command line prompt, enter the following: cd netfilterforwin/netfilter nmake Install the driver Copy inf/* files and the freshly built netfilter.sys to a separate directory, and then open the network connections. Right-click an interface, then select Properties Click install... Select Service Click Add Click Have disk... Browse to the directory with the inf files and netfilter.sys, select netfilter.inf, and then click Ok. Confirm everything The driver is now installed. Run Suricata in inline mode suricata.exe -c suricata.yaml -q 0 suricata-1.4.7/doc/TODO0000644000000000000000000000011312253546156011466 00000000000000Plenty, and you're welcome to help! http://suricata-ids.org/participate/ suricata-1.4.7/doc/Installation_with_CUDA_on_Ubuntu_server_1104.txt0000644000000000000000000001113112253546156022122 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Installation_with_CUDA_on_Ubuntu_server_1104 Installation with CUDA on Ubuntu server 11.04 THIS WOULD NOT WORK ON A VIRTUAL MACHINE! This guide is written using: Ubuntu Server 11.04 Linux ubuntu 2.6.38-8-generic x86_64 GNU/Linux Pre installation requirements apt-get update apt-get upgrade Get the CUDA toolkit http://developer.nvidia.com/cuda-toolkit-40 Pick up the correct NVIDIA drivers for your card and system http://www.nvidia.com/Download/index.aspx?lang=en-us Go to your download directory and chmod the 2 *.run files that you just downloaded. Example: chmod 655 cudatoolkit_4.0.17_linux_64_ubuntu10.10.run chmod 655 NVIDIA-Linux-x86_64-280.13.run sudo apt-get -y install libpcre3 libpcre3-dbg libpcre3-dev \ build-essential autoconf automake libtool libpcap-dev libnet1-dev \ libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 \ make flex bison git Run the cuda toolkit installation package: sudo ./cudatoolkit_4.0.17_linux_64_ubuntu10.10.run Close all windows and as you are logged in press: Ctr+Alt+F1 Log in with your credentials sudo -i And enter your password Stop the x server: /etc/init.d/gdm stop Uninstall xserver video drivers: apt-get remove --purge xserver-xorg-video-nouveau Go to the directory where you downloaded nvidia/cuda drivers. Run the NVIDIA*******.run: ./NVIDIA********.run Ok and yes your way out. At some point it will ask you to make a special configuration file to disable a "nouveau" driver that the system is currently using and prevents the NVIDIA drivers to be installed - say yes! Reboot: shutdown -r now After reboot log in as you would normally through the GUI Log in as you would normally. Go to shell: Ctrl+Alt+F1 Type in your credentials and pass sudo -i Stop the xserver again: /etc/init.d/gdm stop Run the NVIDIA driver again. This time it would finish and be successful.... Reboot: shutdown -r now After start you would notice that the display has much better resolution - it is a good thing. Log in as you would normally. Because the 11.04 Ubuntu comes with gcc version 4.5 by default we need to install gcc 4.4 since we must use 4.4 for the cuda compilation: apt-get install gcc-4.4 gcc-4.4-base g++-4.4 Then we switch and make ubuntu use the gcc 4.4 by default: sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.5 40 -- slave /usr/bin/g++ g++ /usr/bin/g++-4.5 udo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.4 60 -- slave /usr/bin/g++ g++ /usr/bin/g++-4.4 We make sure that this is the case: sudo update-alternatives --config gcc "" update-alternatives --config gcc (as root) There are 2 choices for the alternative gcc (providing /usr/bin/gcc). * 0 /usr/bin/gcc-4.4 60 auto mode 1 /usr/bin/gcc-4.4 60 manual mode 2 /usr/bin/gcc-4.5 40 manual mode Selection Path Priority Status ------------------------------------------------------------ Press enter to keep the current choice[*], or type selection number: "" Suricata Enter the following in your download directory: git clone git://phalanx.openinfosecfoundation.org/oisf.git cd oisf/ ./autogen.sh ./configure --enable-gccprotect --enable-profiling --enable-cuda \ --with-cuda-includes=/usr/local/cuda/include --with-cuda-libraries=/usr/ local/cuda/lib64/ After that you should get the following result: "" Suricata Configuration: NFQueue support: no IPFW support: no PF_RING support: no Prelude support: no Unit tests enabled: no Debug output enabled: no Debug validation enabled: no CUDA enabled: yes DAG enabled: no Profiling enabled: yes GCC Protect enabled: yes GCC march native enabled: yes GCC Profile enabled: no Unified native time: no Non-bundled htp: no PCRE sljit: no "" make && make install ldconfig Proceed with Basic_Setup After you start suricata , you should see cuda example : "" suricata -c suricata.yaml -i eth0 [12406] 13/8/2011 -- 10:14:39 - (suricata.c:622) (main) -- This is Suricata version 1.1beta2 (rev b3f7e6a) [12406] 13/8/2011 -- 10:14:39 - (util-cpu.c:171) (UtilCpuPrintSummary) -- CPUs/cores online: 8 [12406] 13/8/2011 -- 10:14:39 - (util-cuda.c:4504) (SCCudaPrintBasicDeviceInfo) -- GPU Device 1: GeForce 310M, 2 Multiprocessors, 1468MHz, CUDA Compute Capability 1.2................... ........................ "" suricata-1.4.7/doc/Installation_with_CUDA_and_PF_RING_on_Ubuntu_server_1104.txt0000644000000000000000000001701512253546156024157 00000000000000Autogenerated on 2012-01-11 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Installation_with_CUDA_and_PF_RING_on_Ubuntu_server_1104 Installation with CUDA and PF RING on Ubuntu server 11.04 THIS WOULD NOT WORK ON A VIRTUAL MACHINE! This guide is written using: Ubuntu Server 11.04 Linux ubuntu 2.6.38-8-generic x86_64 GNU/Linux Pre installation requirements apt-get update apt-get upgrade To get the CUDA toolkit, enter: http://developer.nvidia.com/cuda-toolkit-40 Pick up the correct NVIDIA drivers for your card and system http://www.nvidia.com/Download/index.aspx?lang=en-us Go to your download directory chmod the 2 *.run files that you just downloaded. For example: chmod 655 cudatoolkit_4.0.17_linux_64_ubuntu10.10.run chmod 655 NVIDIA-Linux-x86_64-280.13.run sudo apt-get -y install libpcre3 libpcre3-dbg libpcre3-dev \ build-essential autoconf automake libtool libpcap-dev libnet1-dev \ libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 \ make flex bison git Run the cuda toolkit installation package: sudo ./cudatoolkit_4.0.17_linux_64_ubuntu10.10.run Close all windows and as you are logged in press: Ctr+Alt+F1 Log in with your credentials sudo -i And enter your password Stop the x server: /etc/init.d/gdm stop Uninstall xserver video drivers: apt-get remove --purge xserver-xorg-video-nouveau Go to the directory where you downloaded nvidia/cuda drivers. Run the NVIDIA*******.run: ./NVIDIA********.run Ok and yes your way out. At some point it will ask you to make a special configuration file to disable a "nouveau" driver that the system is currently using - say yes! Reboot: shutdown -r now After reboot log in as you would normally do through the GUI Log in as you would normally. Go to shell: Ctrl+Alt+F1 Type in your credentials and pass sudo -i Stop the xserver again: /etc/init.d/gdm stop Run the NVIDIA driver again. This time it would finish and be successful.... Reboot: shutdown -r now After start you would notice that the display has much better resolution - it is a good thing. Log in as you would normally. Because the 11.04 Ubuntu comes with gcc version 4.5 by default, you need to install gcc 4.4 since you must use 4.4 for the cuda compilation: apt-get install gcc-4.4 gcc-4.4-base g++-4.4 Then we switch and make ubuntu use the gcc 4.4 by default: sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.5 40 -- slave /usr/bin/g++ g++ /usr/bin/g++-4.5 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.4 60 -- slave /usr/bin/g++ g++ /usr/bin/g++-4.4 Make sure that this is the case: sudo update-alternatives --config gcc "" update-alternatives --config gcc (as root) There are 2 choices for the alternative gcc (providing /usr/bin/gcc). Selection Path Priority Status ------------------------------------------------------------ * 0 /usr/bin/gcc-4.4 60 auto mode 1 /usr/bin/gcc-4.4 60 manual mode 2 /usr/bin/gcc-4.5 40 manual mode Press enter to keep the current choice[*], or type selection number (as root) "" PF_RING installation. Install pre-requisites: cd /opt apt-get install subversion gobjc++-4.4-multilib gobjc++-4.4 Get the latest PF_RING: svn --force export https://svn.ntop.org/svn/ntop/trunk/PF_RING/ PF_RING Install PF_RING: cd /kernel make && make install sudo insmod ./pf_ring.ko cd ../userland make && make install cd /lib ./configure && make && make install cd ../libpcap ./configure && make && make install cd ../examples echo "options pf_ring transparent_mode=0 min_num_slots=32768 enable_tx_capture=0" > /etc/modprobe.d/pf_ring.conf Check info: cat /proc/net/pf_ring/info "" cd ../kernel cat /proc/net/pf_ring/info PF_RING Version : 4.7.3 ($Revision: exported$) Ring slots : 4096 Slot version : 13 Capture TX : Yes [RX+TX] IP Defragment : No Socket Mode : Standard Transparent mode : Yes (mode 0) Total rings : 0 Total plugins : 0 "" Check functionality: ./pfcount -i eth0 You should see something even if you have no traffic at the moment: "" cd /opt/PF_RING/userland/examples ./pfcount -i eth0 Using PF_RING v.4.7.3 Capturing from eth0 [88:AE:1D:56:90:FA] 1. Device RX channels: 1 2. Polling threads: 1 ========================= Absolute Stats: [0 pkts rcvd][0 pkts dropped] Total Pkts=0/Dropped=0.0 % 0 pkts - 0 bytes ========================= ========================= Absolute Stats: [0 pkts rcvd][0 pkts dropped] Total Pkts=0/Dropped=0.0 % 0 pkts - 0 bytes [0.00 pkt/sec - 0.00 Mbit/sec] ========================= Actual Stats: 0 pkts [1'000.32 ms][0.00 pkt/sec] ========================= ^CLeaving... ========================= Absolute Stats: [0 pkts rcvd][0 pkts dropped] Total Pkts=0/Dropped=0.0 % 0 pkts - 0 bytes [0.00 pkt/sec - 0.00 Mbit/sec] ========================= Actual Stats: 0 pkts [629.37 ms][0.00 pkt/sec] ========================= cd /opt/PF_RING/userland/examples "" Suricata Go to directory of your choice and get Suricata: git clone git://phalanx.openinfosecfoundation.org/oisf.git cd oisf/ Configure: ./autogen.sh ./configure --enable-gccprotect --enable-profiling --enable-cuda --with-cuda- includes=/usr/local/cuda/include \ --with-cuda-libraries=/usr/local/cuda/lib64 --enable-pfring You should get at the end: "" Suricata Configuration: NFQueue support: no IPFW support: no PF_RING support: yes Prelude support: no Unit tests enabled: no Debug output enabled: no Debug validation enabled: no CUDA enabled: yes DAG enabled: no Profiling enabled: yes GCC Protect enabled: yes GCC march native enabled: yes GCC Profile enabled: no Unified native time: no Non-bundled htp: no PCRE sljit: no "" Install: make && make install ldconfig Verify: suricata --build-info [1840] 13/8/2011 -- 14:26:39 - (suricata.c:622) (main) -- This is Suricata version 1.1beta2 (rev b3f7e6a) [1840] 13/8/2011 -- 14:26:39 - (suricata.c:507) (SCPrintBuildInfo) - - Features: PCAP_SET_BUFF LIBPCAP_VERSION_MAJOR=1 CUDA PF_RING LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK [1840] 13/8/2011 -- 14:26:39 - (suricata.c:521) (SCPrintBuildInfo) - - 64-bits, Little-endian architecture [1840] 13/8/2011 -- 14:26:39 - (suricata.c:523) (SCPrintBuildInfo) - - GCC version 4.4.5, C version 199901 [1840] 13/8/2011 -- 14:26:39 - (suricata.c:529) (SCPrintBuildInfo) - - __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 [1840] 13/8/2011 -- 14:26:39 - (suricata.c:532) (SCPrintBuildInfo) - - __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 [1840] 13/8/2011 -- 14:26:39 - (suricata.c:535) (SCPrintBuildInfo) - - __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 [1840] 13/8/2011 -- 14:26:39 - (suricata.c:538) (SCPrintBuildInfo) - - __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 [1840] 13/8/2011 -- 14:26:39 - (suricata.c:541) (SCPrintBuildInfo) - - __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 [1840] 13/8/2011 -- 14:26:39 - (suricata.c:545) (SCPrintBuildInfo) - - compiled with -fstack-protector [1840] 13/8/2011 -- 14:26:39 - (suricata.c:551) (SCPrintBuildInfo) - - compiled with _FORTIFY_SOURCE=2 Run Suricata: suricata -c /etc/suricata/suricata.yaml\ --pfring-int=eth0 --pfring-cluster-id=99 --pfring-cluster-type=cluster_flow suricata-1.4.7/doc/README0000644000000000000000000000000012253546156011651 00000000000000suricata-1.4.7/doc/CentOS5.txt0000644000000000000000000000700612253546156012767 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/CentOS5 CentOS5 Pre-installation requirements You will have to use the Fedora EPEL repository for some packages to enable this repository. It is the same for i386 and x86_64: sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release- 5-3.noarch.rpm Before you can build Suricata for your system, run the following command to ensure that you have everything you need for the installation. sudo yum -y install libpcap libpcap-devel libnet libnet-devel pcre \ pcre-devel gcc gcc-c++ automake autoconf libtool make libyaml \ libyaml-devel zlib zlib-devel Depending on the current status of your system, it may take a while to complete this process. HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS If you plan to build Suricata with IPS capabilities via ./configure --enable- nfqueue, there are no pre-built packages in the CentOS base or EPEL for libnfnetlink and libnetfilter_queue. If you wish, you may use the rpms in the Emerging Threats Cent OS 5 repository: i386 sudo rpm -Uvh http://rules.emergingthreatspro.com/projects/emergingrepo/i386/ libnetfilter_queue-0.0.15-1.i386.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/i386/ libnetfilter_queue-devel-0.0.15-1.i386.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/i386/libnfnetlink- 0.0.30-1.i386.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/i386/libnfnetlink- devel-0.0.30-1.i386.rpm x86_64 sudo rpm -Uvh http://rules.emergingthreatspro.com/projects/emergingrepo/ x86_64/libnetfilter_queue-0.0.15-1.x86_64.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/x86_64/ libnetfilter_queue-devel-0.0.15-1.x86_64.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/x86_64/ libnfnetlink-0.0.30-1.x86_64.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/x86_64/ libnfnetlink-devel-0.0.30-1.x86_64.rpm libcap-ng installation This installation is needed for dropping privileges. wget http://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.6.4.tar.gz tar -xzvf libcap-ng-0.6.4.tar.gz cd libcap-ng-0.6.4 ./configure make sudo make install Suricata To download and build Suricata, enter the following: wget http://www.openinfosecfoundation.org/download/suricata-1.3.3.tar.gz tar -xvzf suricata-1.3.3.tar.gz cd suricata-1.3.3 If you are building from Git sources, enter all the following commands: bash autogen.sh If you are not building from Git sources, enter only: ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var make sudo make install Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Please continue with the Basic_Setup. suricata-1.4.7/doc/FreeBSD_8.txt0000644000000000000000000000543012253546156013207 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/FreeBSD_8 FreeBSD 8 & 9 Pre-installation requirements Before you can build Suricata for your system, run the following command to ensure that you have everything you need for the installation. Make sure you enter all commands as root/super-user, otherwise it will not work. For FreeBSD 8: pkg_add -r autoconf262 automake19 gcc45 libyaml pcre libtool \ libnet11 libpcap gmake For FreeBSD 9.0: pkg_add -r autoconf268 automake111 gcc libyaml pcre libtool \ libnet11 libpcap gmake Depending on the current status of your system, it may take a while to complete this process. HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS If you would like to build suricata on FreeBSD with IPS capabilities with IPFW via --enable-ipfw, enter the following to enable ipfw and divert socket support before starting the engine with -d: Edit /etc/rc.conf and add or modify the following lines: firewall_enable="YES" firewall_type="open" Edit /boot/loader.conf and add or modify the following lines: ipfw_load="YES" ipfw_nat_load="YES" ipdivert_load="YES" dummynet_load="YES" libalias_load="YES" Suricata To download and build Suricata, enter the following: wget http://www.openinfosecfoundation.org/download/suricata-1.3.3.tar.gz tar -xvzf suricata-1.3.3.tar.gz cd suricata-1.3.3 If you are building from Git sources, enter all the following commands until the end of this file: bash autogen.sh If you are not building from Git sources, do not enter the above mentioned commands. Continue enter the following: ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var make make install zerocopy bpf mkdir /var/log/suricata/ FreeBSD 8 has support for zerocopy bpf in libpcap. To test this functionality, issue the following command and then start/restart the engine: sysctl net.bpf.zerocopy_enable=1 Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Please continue with the Basic_Setup. suricata-1.4.7/doc/Installation_with_CUDA_and_PFRING_on_Scientific_Linux_6.txt0000644000000000000000000001041312253546156024162 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Installation_with_CUDA_and_PFRING_on_Scientific_Linux_6 Installation with CUDA and PFRING on Scientific Linux 6 For setup and install you need to be root: mkdir /root/src cd /root/src Pre installation requirements Install the following packages, to make sure you have everything needed for the installation: yum install mpfr-2.4.1-6.el6.x86_64 cpp-4.4.4-13.el6.x86_64 ppl-0.10.2- 11.el6.x86_64 \ cloog-ppl-0.15.7-1.2.el6.x86_64 gcc-4.4.4-13.el6.x86_64 kernel-devel-2.6.32- 131.2.1.el6.x86_64 \ pcre-devel-7.8-3.1.el6.x86_64 libpcap-devel-1.0.0- 6.20091201git117cb5.el6.x86_64 \ yum-plugin-priorities-1.1.26-11.el6.noarch yum-conf-sl6x-1-1.noarch libyaml- 0.1.3-1.el6.rf.x86_64 \ libyaml-devel-0.1.3-1.el6.rf.x86_64 libnet-1.1.2.1-2.2.el6.rf.x86_64 flex- 2.5.35-8.el6.x86_64 \ bison-2.4.1-5.el6.x86_64 gcc-c++-4.4.4-13.el6.x86_64 CUDA Download and install NVIDIA CUDA drivers: wget http://us.download.nvidia.com/XFree86/Linux-x86_64/270.41.19/NVIDIA- Linux-x86_64-270.41.19.run chmod +x NVIDIA-Linux-x86_64-270.41.19.run ./NVIDIA-Linux-x86_64-270.41.19.run You also need to download and install the CUDA toolkit for RHEL6 : wget http://developer.download.nvidia.com/compute/cuda/4_0/toolkit/ cudatoolkit_4.0.17_linux_64_rhel6.0.run chmod +x cudatoolkit_4.0.17_linux_64_rhel6.0.run ./cudatoolkit_4.0.17_linux_64_rhel6.0.run Make sure the kernel modules are loaded: /sbin/modprobe -r nouveau && /sbin/modprobe nvidia To ensure the proper NVIDIA CUDA modules get loaded on reboot, add the above line to your /etc/rc.local file. PF_RING Go to your download directory and get the latest PF_RING: svn export https://svn.ntop.org/svn/ntop/trunk/PF_RING/ pfring-svn- latest Compile and install Next, enter the following commands for configuration and installation: cd pfring-svn-latest/kernel make && sudo make install cd ../userland/lib ./configure --prefix=/usr/local/pfring && make && sudo make install cd ../libpcap-1.1.1-ring ./configure --prefix=/usr/local/pfring && make && sudo make install cd ../tcpdump-4.1.1 ./configure --prefix=/usr/local/pfring && make && sudo make install Load the pf_ring kernel module: /sbin/modprobe pf_ring To ensure the pf_ring module gets loaded on reboot, add the above line to your /etc/rc.local file. Suricata Download and install Suricata: wget http://www.openinfosecfoundation.org/download/suricata-1.1beta2.tar.gz And unpack it: tar -xvzf suricata-1.1beta2.tar.gz Change to the unpacked directory: cd suricata-1.1beta2 Now compile and install Suricata with PF_RING and CUDA support: ./configure --enable-gccprotect --enable-profiling --enable-cuda --with-cuda- includes=/usr/local/cuda/include \ --with-cuda-libraries=/usr/local/cuda/lib64 --enable-pfring --with-libpfring- libraries=/usr/local/lib \ --with-libpfring-includes=/usr/local/include --with-libpcap-libraries=/usr/ local/lib --with-libpcap-includes=/usr/local/include make make install Continue with the Basic_Setup Next, you need to edit max-pending-packets in your /etc/suricata/suricata.yaml. If you don't have one, download a generic one to get started: cd /etc/suricata wget https://rules.emergingthreatspro.com/open-nogpl/suricata/suricata- open.yaml Edit your suricata-open.yaml file accordingly. The number of packets allowed to be processed simultaneously can be whatever you want but it is recommended that it be 4000 or more. For example: max-pending-packets: 12288 Next make sure the following line is present in the multi pattern algorithm section: mpm-algo: b2g_cuda Rules Read the information in Rule_Management_with_Oinkmaster Add rules to suricata: cd /etc/suricata wget https://rules.emergingthreatspro.com/open-nogpl/suricata/ emerging.rules.tar.gz tar -xvzf emerging.rules.tar.gz Make sure your .yaml file includes the /etc/suricata/rules/emerging-*.rules files (they may need to be uncommented). Run Suricata as followed: cd /etc/suricata /usr/local/bin/suricata -c /etc/suricata/suricata.yaml\ --pfring-int=eth0 --pfring-cluster-id=99 --pfring-cluster-type=cluster_flow touch /var/lock/subsys/local References PF_RING http://www.ntop.org/products/pf_ring/ suricata-1.4.7/doc/GITGUIDE0000644000000000000000000000575112253546156012137 00000000000000Guide for using GIT Working with Git is significantly different that working with SVN. In particular, although similar, git pull is not svn update, git push is not svn commit, and git add is not svn add. If you are a SVN user, be sure to read the man pages for the different git commands. The following workflow is recommended by Evan and is the guideline for contributing code to Rubinius. 1. Create a local working copy of the source code (we did this earlier.) # See above for the exact invocation 2. Change to the newly created directory that contains the local working copy. (Substitute the directory if you created it with a different name, obviously.) cd code 3. Create a branch for your work. This will make a copy of the current branch (master) and name it "new_feature". Now you can work in this new branch without breaking the main one. git checkout -b new_feature 4. Edit the code and test your changes. Then commit to your local working copy git commit -a 5. When you are ready to send your local changes back to the Rubinius repository, you first need to ensure that your local copy is up-to-date. First, ensure you have committed your local changes. Then switch from your topic branch to the master branch. git checkout master 6. Update your local copy with changes from the Rubinius repository git pull 7. Switch back to your topic branch and integrate any new changes. The git rebase command will save your changes away, update the topic branch, and then reapply them. git checkout new_feature git rebase master Warning! If you are sharing a branch, you must use: git merge master Rebase causes the commit layout to change and will confuse anyone you've shared this branch with. 8. If there are conflicts applying your changes during the git rebase command, fix them and use the following to finish applying them git rebase --continue 9. Now, switch back to the master branch and merge your changes from the topic branch git checkout master git merge new_feature 10. You might want to check that your commits ended up as you intended. To do so, you can have a look at the log git log 11. Get your changes in the main repository. If you have commit rights, you can just use the git push command. Otherwise, see the section below for information on creating a set of patches to send. git push 12. At this point, you can delete the branch if you like. git branch -d new_feature When you're familiar with the workflow, you can use the rake tasks to help you out. For example, rake git will fetch the latest code from remote repo, rebase the current branch to master, fast-forward the changes to master and push the commits to the remote. This saves a lot of typing. Check rake -T git for all the git related tasks. Taken from: http://rubinius.lighthouseapp.com/projects/5089/using-git suricata-1.4.7/doc/INSTALL.PF_RING0000644000000000000000000001503412253546156013162 00000000000000An up to date version of this document is available online at: https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Installation_with_PF_RING #Install DKMS apt-get install dkms #We need subversion for checking out the PF_RING code we need flex and bisonfor libpcap apt-get install subversion flex bison #Install the debs needed for suricata. apt-get install libpcre3-dev libpcap-dev libyaml-dev zlib1g-dev libcap-ng-dev libnet1-dev #In the exmple we will build from the GIT repo so we will need some extra packages apt-get install git-core automake autoconf libtool #Go to /usr/src/ we will need to be here to build our modules cd /usr/src/ #Checkout the PF_RING code svn --force export https://svn.ntop.org/svn/ntop/trunk/PF_RING/ PF_RING_CURRENT_SVN #Create the DKMS build directory and copy files over for the main PF_RING module mkdir /usr/src/pf_ring-4 cp -Rf /usr/src/PF_RING_CURRENT_SVN/kernel/* /usr/src/pf_ring-4/ cd /usr/src/pf_ring-4/ #Create a file called dkms.conf and place the following into the file. nano dkms.conf PACKAGE_NAME="pf_ring" PACKAGE_VERSION="4" BUILT_MODULE_NAME[0]="pf_ring" DEST_MODULE_LOCATION[0]="/kernel/net/pf_ring/" AUTOINSTALL="yes" #Build and install the module we don't build a deb as currently this appears to be broken in Ubuntu-10.04 dkms add -m pf_ring -v 4 dkms build -m pf_ring -v 4 dkms install -m pf_ring -v 4 #if you issue the following command you can see that pf_ring should now be installed as DKMS module dkms status #Now lets go through the steps to build a e1000e PF_RING aware driver. mkdir /usr/src/e1000e-pf_ring-1.3.10a cd /usr/src/PF_RING_CURRENT_SVN/drivers/intel/e1000e/e1000e-1.3.10a/src/ #We copy this over so that DKMS can find it for driver rebuilds cp -Rf /usr/src/PF_RING_CURRENT_SVN/drivers/intel/e1000e/e1000e-1.3.10a/src/* /usr/src/e1000e-pf_ring-1.3.10a/ cp -f /usr/src/PF_RING_CURRENT_SVN/kernel/linux/pf_ring.h /usr/src/e1000e-pf_ring-1.3.10a/ #Fix the path to pf_ring.h cd /usr/src/e1000e-pf_ring-1.3.10a/ sed -i -e 's/\.\.\/\.\.\/\.\.\/\.\.\/\.\.\/kernel\/linux\/pf\_ring\.h/pf\_ring\.h/' netdev.c #Create a file called dkms.conf and place the following into the file. nano dkms.conf PACKAGE_NAME="e1000e-pf_ring" PACKAGE_VERSION="1.3.10a" BUILT_MODULE_NAME[0]="e1000e" DEST_MODULE_LOCATION[0]="/kernel/drivers/net/e1000e/" AUTOINSTALL="yes" #Build and install the module we don't build a deb as currently this appears to be broken in Ubuntu-10.04 dkms add -m e1000e-pf_ring -v 1.3.10a dkms build -m e1000e-pf_ring -v 1.3.10a dkms install -m e1000e-pf_ring -v 1.3.10a #Now lets go through the steps to build a e1000 PF_RING aware driver. mkdir /usr/src/e1000-pf_ring-8.0.30 cd /usr/src/PF_RING_CURRENT_SVN/drivers/intel/e1000/e1000-8.0.30/src/ #We copy this over so that DKMS can find it for driver rebuilds cp -Rf /usr/src/PF_RING_CURRENT_SVN/drivers/intel/e1000/e1000-8.0.30/src/* /usr/src/e1000-pf_ring-8.0.30 cp -f /usr/src/PF_RING_CURRENT_SVN/kernel/linux/pf_ring.h /usr/src/e1000-pf_ring-8.0.30 #Fix the path to pf_ring.h cd /usr/src/e1000-pf_ring-8.0.30 sed -i -e 's/\.\.\/\.\.\/\.\.\/\.\.\/\.\.\/kernel\/linux\/pf\_ring\.h/pf\_ring\.h/' e1000_main.c #Create a file called dkms.conf and place the following into the file. nano dkms.conf PACKAGE_NAME="e1000-pf_ring" PACKAGE_VERSION="8.0.30" BUILT_MODULE_NAME[0]="e1000" DEST_MODULE_LOCATION[0]="/kernel/drivers/net/e1000/" AUTOINSTALL="yes" dkms add -m e1000-pf_ring -v 8.0.30 dkms build -m e1000-pf_ring -v 8.0.30 dkms install -m e1000-pf_ring -v 8.0.30 #Make the dir structure to hold are PF_RING enabled userland Apps. mkdir -p /opt/PF_RING/{bin,lib,include/linux,sbin} #Build and install the userland lib. cp -f /usr/src/PF_RING_CURRENT_SVN/kernel/linux/pf_ring.h /opt/PF_RING/include/linux/ cd /usr/src/PF_RING_CURRENT_SVN/userland/lib ./configure sed -i -e 's/INSTDIR = \${DESTDIR}\/usr\/local/INSTDIR = \${DESTDIR}\/opt\/PF_RING/' Makefile cp -f pfring_e1000e_dna.h /opt/PF_RING/include make && make install #Build and install the PF_RING enabled libpcap #PF_RING enabled libpcap cd /usr/src/PF_RING_CURRENT_SVN/userland/libpcap-1.1.1-ring ./configure sed -i -e 's/\.\.\/lib\/libpfring\.a/\/opt\/PF_RING\/lib\/libpfring\.a/' Makefile sed -i -e 's/\.\.\/lib\/libpfring\.a/\/opt\/PF_RING\/lib\/libpfring\.a/' Makefile.in ./configure --prefix=/opt/PF_RING && make && make install #Build and install tcpdump using the PF_RING enabled version of libpcap cd /usr/src/PF_RING_CURRENT_SVN/userland/tcpdump-4.1.1 ./configure LD_RUN_PATH="/opt/PF_RING/lib:/usr/lib:/usr/local/lib" --prefix=/opt/PF_RING/ --enable-ipv6 && make && make install #Pull down the latest version of suricata from the git repo and build with PF_RING support. cd /usr/src/PF_RING_CURRENT_SVN/userland/ git clone git://phalanx.openinfosecfoundation.org/oisf.git oisfnew cd oisfnew ./autogen.sh ./configure --enable-pfring --with-libpfring-libraries=/opt/PF_RING/lib --with-libpfring-includes=/opt/PF_RING/include --with-libpcap-libraries=/opt/PF_RING/lib --with-libpcap-includes=/opt/PF_RING/include LD_RUN_PATH="/opt/PF_RING/lib:/usr/lib:/usr/local/lib" --prefix=/opt/PF_RING/ make && make install #Make config and log directories for a more complete getting started see http://www.inliniac.net/blog/2010/05/10/setting-up-suricata-0-9-0-for-initial-use-on-ubuntu-lucid-10-04.html mkdir /etc/suricata cp suricata.yaml /etc/suricata/ cp classification.config /etc/suricata/ mkdir /var/log/suricata #Setup options for when we intialize the module (here is the output from modinfo) #parm: num_slots:Number of ring slots (uint) #parm: transparent_mode:0=standard Linux, 1=direct2pfring+transparent, 2=direct2pfring+non transparentFor 1 and 2 you need to use a PF_RING aware driver (uint) #parm: enable_tx_capture:Set to 1 to capture outgoing packets (uint) #parm: enable_ip_defrag:Set to 1 to enable IP defragmentation(only rx traffic is defragmentead) (uint) echo "options pf_ring transparent_mode=0 num_slots=32768 enable_tx_capture=0" > /etc/modprobe.d/pf_ring.conf #start up suricata with PF_RING support currently these options don't have very much effect with the AutoMode but see src/runmodes.c for more more options. /opt/PF_RING/bin/suricata --pfring-int=eth0 --pfring-cluster-id=99 --pfring-cluster-type=cluster_flow -c /etc/suricata/suricata.yaml #To check the status of PF_RING modinfo pf_ring && cat /proc/net/pf_ring/info #If you need to uninstall PF_RING or rollback your PF_RING aware drivers to their previous state you can do so with the following commands. dkms remove -m e1000e-pf_ring -v 1.3.10a --all dkms remove -m e1000 -v 8.0.30 --all dkms remove -m pf_ring -v 4 --all suricata-1.4.7/doc/INSTALL0000644000000000000000000000077012253546156012040 00000000000000About ===== Suricata is a multi-threaded intrusion detection/prevention engine. engine available from the Open Information Security Foundation (http://www.openinfosecfoundation.org). Suricata and the HTP library are licensed under the GPLv2. A copy of this license is available in this tarball, or at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt Up to date installation guides are available online, at: https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Installation suricata-1.4.7/doc/NEWS0000644000000000000000000000003712253546156011502 00000000000000http://suricata-ids.org/news/ suricata-1.4.7/doc/Makefile.in0000644000000000000000000003757012253546174013064 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = doc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(dist_doc_DATA) AUTHORS INSTALL \ NEWS README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(docdir)" DATA = $(dist_doc_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = ${datarootdir}/doc/${PACKAGE} dvidir = @dvidir@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = \ AUTHORS \ GITGUIDE \ INSTALL \ NEWS \ README \ TODO \ INSTALL.PF_RING \ INSTALL.WINDOWS \ \ Basic_Setup.txt \ CentOS5.txt \ CentOS_56_Installation.txt \ Debian_Installation.txt \ Fedora_Core.txt \ FreeBSD_8.txt \ HTP_library_installation.txt \ Installation_from_GIT_with_PF_RING_on_Ubuntu_server_1104.txt \ Installation_with_CUDA_on_Ubuntu_server_1104.txt \ Installation_with_CUDA_and_PFRING_on_Scientific_Linux_6.txt \ Installation_with_PF_RING.txt \ Installation_with_CUDA_and_PF_RING_on_Ubuntu_server_1104.txt \ Installation_from_GIT_with_PCRE-JIT.txt \ Installation_with_CUDA_on_Scientific_Linux_6.txt \ Mac_OS_X_106x.txt \ OpenBSD_Installation_from_GIT.txt \ Setting_up_IPSinline_for_Linux.txt \ Third_Party_Installation_Guides.txt \ Ubuntu_Installation.txt \ Ubuntu_Installation_from_GIT.txt \ Windows.txt dist_doc_DATA = ${EXTRA_DIST} all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(docdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_docDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_docDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_docDATA 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 maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-dist_docDATA # 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: suricata-1.4.7/doc/HTP_library_installation.txt0000644000000000000000000000112312253546156016501 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTP_library_installation HTP library installation The installation of the HTP library is the same for several operating systems, except you can not use 'sudo' with Debian and FreeBSD. Using Debian or FreeBSD you have to Make sure you enter all following commands as root/super-user. To download and build HTP, enter the following: wget http://www.openinfosecfoundation.org/download/libhtp-0.2.3.tar.gz tar -xzvf libhtp-0.2.3.tar.gz cd libhtp-0.2.3 ./configure make make install suricata-1.4.7/doc/Fedora_Core.txt0000644000000000000000000000423312253546156013716 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Fedora_Core Fedora pre-installation requirements Before you can build Suricata for your system, run the following command to ensure that you have everything you need for the installation. sudo yum -y install libpcap libpcap-devel libnet libnet-devel pcre \ pcre-devel gcc gcc-c++ automake autoconf libtool make libyaml \ libyaml-devel zlib zlib-devel libcap-ng libcap-ng-devel file-devel file Depending on the current status of your system, it may take a while to complete this process. HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS If you plan to build Suricata with IPS capabilities via ./configure --enable- nfqueue, enter the following: sudo yum -y install libnfnetlink libnfnetlink-devel \ libnetfilter_queue libnetfilter_queue-devel Suricata To download and build Suricata, enter the following: wget http://www.openinfosecfoundation.org/download/suricata-1.3.3.tar.gz tar -xvzf suricata-1.3.3.tar.gz cd suricata-1.3.3 If you are building from Git sources, enter all the following commands: bash autogen.sh If you are not building from Git sources, enter only the following: ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var make sudo make install Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Please continue with the Basic_Setup. suricata-1.4.7/doc/Installation_from_GIT_with_PF_RING_on_Ubuntu_server_1104.txt0000644000000000000000000000372212253546156024267 00000000000000Autogenerated on 2012-01-11 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Installation_from_GIT_with_PF_RING_on_Ubuntu_server_1104 Installation from GIT with PF RING on Ubuntu server 11.04 This guide is based on using Ubuntu Server 11.04 Linux ubuntu 2.6.38-8-generic x86_64 GNU/Linux Pre installation requirements Install the following packages, to make sure you have everything needed for the installation: sudo apt-get -y install libpcre3 libpcre3-dbg libpcre3-dev \ build-essential autoconf automake libtool libpcap-dev libnet1-dev \ libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 \ make flex bison git subversion Go to your download directory and get the latest PF_RING: svn --force export https://svn.ntop.org/svn/ntop/trunk/PF_RING/ PF_RING Compile and install Next, enter the following commands for configuration and installation: cd PF_RING/kernel make && make install sudo insmod ./pf_ring.ko cd ../userland make && make install cd /lib ./configure && make && make install cd ../libpcap ./configure && make && make install cd /examples echo "options pf_ring transparent_mode=0 min_num_slots=32768 enable_tx_capture=0" > /etc/modprobe.d/pf_ring.conf To check if you have everything you need, enter: lsmod |grep pf_ring sudo modprobe pf_ring sudo modinfo pf_ring && cat /proc/net/pf_ring/info To check if PF_RING is functional, enter the following: ./pfcount -i eth0 Suricata Go to your download directory of choice, and enter: git clone git://phalanx.openinfosecfoundation.org/oisf.git cd oisf sudo ./autogen.sh sudo ./configure --enable-pfring && make && make install You can always check if PF_RING is build in properly, by entering: suricata --build-info To run Suricata with PF_RING, enter: suricata --pfring-int=eth0 --pfring-cluster-id=99 --pfring-cluster- type=cluster_flow -c /etc/suricata/suricata.yaml Continue with the Basic_Setup. Thanks to Peter Manev suricata-1.4.7/doc/Installation_with_PF_RING.txt0000644000000000000000000001466612253546156016461 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Installation_with_PF_RING Installation with PF RING This is the installation guide for Suricata with PF_RING support and a guide to install PF_RING. To install DKMS, enter: sudo apt-get install dkms To get subversion for checking out the PF_RING code, flex and bison for libpcap, enter: sudo apt-get install subversion flex bison To install the debs needed for Suricata, enter the following: sudo apt-get install libpcre3-dev libpcap-dev libyaml-dev zlib1g-dev libcap- ng-dev libnet1-dev In the example you will build from the GIT repository, so you will need some extra packages: sudo apt-get install git-core automake autoconf libtool To build your modules, please go to: cd /usr/src/ Checkout the PF_RING code: sudo svn --force export https://svn.ntop.org/svn/ntop/trunk/PF_RING/ PF_RING_CURRENT_SVN Create the DKMS build directory and copy files over for the main PF_RING module by entering the following: sudo mkdir /usr/src/pf_ring-4 sudo cp -Rf /usr/src/PF_RING_CURRENT_SVN/kernel/* /usr/src/pf_ring-4/ cd /usr/src/pf_ring-4/ Create a file called 'dkms.conf' sudo nano dkms.conf and place the following into the file: PACKAGE_NAME="pf_ring" PACKAGE_VERSION="4" BUILT_MODULE_NAME[0]="pf_ring" DEST_MODULE_LOCATION[0]="/kernel/net/pf_ring/" AUTOINSTALL="yes" To close the file, do so by pressing Ctrl and X at the same time, followed by y and enter. Build and install the kernel -module of PF_RING: sudo dkms add -m pf_ring -v 4 sudo dkms build -m pf_ring -v 4 sudo dkms install -m pf_ring -v 4 development headers.(zie aantekeningen) sudo mkdir -p /opt/PF_RING/{bin,lib,include/linux,sbin} Next, build and install the userland lib.: sudo cp -f /usr/src/PF_RING_CURRENT_SVN/kernel/linux/pf_ring.h /opt/PF_RING/ include/linux/ cd /usr/src/PF_RING_CURRENT_SVN/userland/lib sudo ./configure sudo sed -i -e 's/INSTDIR = \${DESTDIR}\/usr\/local/INSTDIR = \$ {DESTDIR}\/opt\/PF_RING/' Makefile sudo cp -f pfring_e1000e_dna.h /opt/PF_RING/include sudo make sudo make install Enter the following to pull down the latest version of Suricata from the git repository and build with PF_RING support: cd /usr/src/PF_RING_CURRENT_SVN/userland/ sudo git clone git://phalanx.openinfosecfoundation.org/oisf.git oisfnew cd oisfnew sudo ./autogen.sh sudo ./configure --enable-pfring --with-libpfring-libraries=/opt/PF_RING/lib --with-libpfring-includes=/opt/PF_RING/include --with-libpcap-libraries=/opt/ PF_RING/lib --with-libpcap-includes=/opt/PF_RING/include LD_RUN_PATH="/opt/ PF_RING/lib:/usr/lib:/usr/local/lib" --prefix=/opt/PF_RING/ sudo make install sudo make sudo mkdir etc/suricata To make config and log directories for a more complete getting started, see: Basic_Setup. sudo mkdir /etc/suricata sudo cp suricata.yaml /etc/suricata/ sudo cp classification.config /etc/suricata/ sudo mkdir /var/log/suricata The information about the setup options for when you initialise the module: min_num_slots:Number of ring slots (uint) transparent_mode:0=standard Linux, 1=direct2pfring+transparent, 2=direct2pfring+non transparent. For 1 and 2 you need to use a PF_RING aware driver (uint) . enable_tx_capture:Set to 1 to capture outgoing packets (uint) enable_ip_defrag:Set to 1 to enable IP defragmentation(only rx traffic is defragmentead) (uint) Enter the following as super-user: echo "options pf_ring transparent_mode=0 min_num_slots=32768 enable_tx_capture=0" > /etc/modprobe.d/pf_ring.conf To check the status of PF_RING : sudo modprobe pf_ring sudo modinfo pf_ring && cat /proc/net/pf_ring/info Start up Suricata with PF_RING support: sudo /opt/PF_RING/bin/suricata --pfring-int=eth0 --pfring-cluster-id=99 -- pfring-cluster-type=cluster_flow -c /etc/suricata/suricata.yaml If you need to uninstall PF_RING or rollback your PF_RING aware drivers to their previous state you can do so with the following commands: sudo dkms remove -m pf_ring -v 4 --all Optional The following part is optional. sudo dkms remove -m e1000e-pf_ring -v 1.0.15 --all If you issue the following command, you can see that PF_RING should now be installed as DKMS module: dkms status Now go through the steps to build a PF_RING aware driver: sudo mkdir /usr/src/e1000e-pf_ring-1.0.15 sudo cp -Rf /usr/src/PF_RING_CURRENT_SVN/drivers/intel/e1000e/old/e1000e- 1.0.15/src/* /usr/src/e1000e-pf_ring-1.0.15/ Enter the following so that DKMS can find it for driver rebuilds: sudo cp -f /usr/src/PF_RING_CURRENT_SVN/kernel/linux/pf_ring.h /usr/src/ e1000e-pf_ring-1.0.15/ cd /usr/src/e1000e-pf_ring-1.0.15/ After that, fix the path to pf_ring.h: sed -i -e 's/\.\.\/\.\.\/\.\.\/\.\.\/kernel\/linux\/pf\_ring\.h/pf\_ring\.h/ ' netdev.c Then create a file called 'dkms.conf'. sudo nano dkms.conf and place the following into the file: PACKAGE_NAME="e1000e-pf_ring" PACKAGE_VERSION="1.0.15" BUILT_MODULE_NAME[0]="e1000e" DEST_MODULE_LOCATION[0]="/kernel/drivers/net/e1000e/" AUTOINSTALL="yes" Build and install the module of the e1000e-pf_ring network driver: sudo dkms add -m e1000e-pf_ring -v 1.0.15 sudo dkms build -m e1000e-pf_ring -v 1.0.15 sudo dkms install -m e1000e-pf_ring -v 1.0.15 After that, build and install the PF_RING enabled libpcap: cd /usr/src/PF_RING_CURRENT_SVN/userland/libpcap-1.0.0-ring ./configure sed -i -e 's/\.\.\/lib\/libpfring\.a/\/opt\/PF_RING\/lib\/libpfring\.a/ ' Makefile sed -i -e 's/\.\.\/lib\/libpfring\.a/\/opt\/PF_RING\/lib\/libpfring\.a/ ' Makefile.in ./configure --prefix=/opt/PF_RING && make && make install Subsequently, build and install tcpdump using the PF_RING enabled version of libpcap: cd /usr/src/PF_RING_CURRENT_SVN/userland/tcpdump-4.0.0 sudo ./configure sudo sed -i -e 's/\.\.\/lib\/libpfring\.a/\/opt\/PF_RING\/lib\/libpfring\.a/ ' Makefile sudo sed -i -e 's/\.\.\/lib\/libpfring\.a/\/opt\/PF_RING\/lib\/libpfring\.a/ ' Makefile.in sudo sed -i -e 's/-I \.\.\/libpcap-1\.0\.0-ring/-I \/opt\/PF_RING\/include/ ' Makefile sudo sed -i -e 's/-I \.\.\/libpcap-1\.0\.0-ring/-I \/opt\/PF_RING\/include/ ' Makefile.in sudo sed -i -e 's/-L \.\.\/libpcap-1\.0\.0-ring\/-L /\/opt\/PF_RING\/lib\// ' Makefile sed -i -e 's/-L \.\.\/libpcap-1\.0\.0-ring\/-L /\/opt\/PF_RING\/lib\// ' Makefile.in sudo ./configure LD_RUN_PATH="/opt/PF_RING/lib:/usr/lib:/usr/local/lib" -- prefix=/opt/PF_RING/ --enable-ipv6 && make && make install suricata-1.4.7/doc/AUTHORS0000644000000000000000000000017312253546156012054 00000000000000Team: http://suricata-ids.org/about/team/ All contributors: https://www.ohloh.net/p/suricata-engine/contributors/summary suricata-1.4.7/doc/Ubuntu_Installation.txt0000644000000000000000000000447712253546156015563 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Ubuntu_Installation Ubuntu Installation Pre-installation requirements Before you can build Suricata for your system, run the following command to ensure that you have everything you need for the installation. sudo apt-get -y install libpcre3 libpcre3-dbg libpcre3-dev \ build-essential autoconf automake libtool libpcap-dev libnet1-dev \ libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 \ make libmagic-dev Depending on the current status of your system, it may take a while to complete this process. HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS By default, Suricata works as an IDS. If you want to use it as a IDS and IPS program, enter: sudo apt-get -y install libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 Suricata To download and build Suricata, enter the following: wget http://www.openinfosecfoundation.org/download/suricata-1.3.3.tar.gz tar -xvzf suricata-1.3.3.tar.gz cd suricata-1.3.3 Compile and install the engine If you plan to build Suricata with IPS capabilities, enter: ./configure --enable-nfqueue --prefix=/usr --sysconfdir=/etc -- localstatedir=/var instead of ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var Continue with the next commands: ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var make sudo make install sudo ldconfig Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Please continue with Basic_Setup. suricata-1.4.7/doc/CentOS_56_Installation.txt0000644000000000000000000000704112253546156015734 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/CentOS_56_Installation CentOS 5.6 Installation Pre-installation requirements You will have to use the Fedora EPEL repository for some packages to enable this repository. It is the same for i386 and x86_64: sudo rpm -Uvh http://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5- 4.noarch.rpm Before you can build Suricata for your system, run the following command to ensure that you have everything you need for the installation. sudo yum -y install libpcap libpcap-devel libnet libnet-devel pcre \ pcre-devel gcc gcc-c++ automake autoconf libtool make libyaml \ libyaml-devel zlib zlib-devel Depending on the current status of your system, it may take a while to complete this process. HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS If you plan to build Suricata with IPS capabilities via ./configure --enable- nfqueue, there are no pre-built packages in the CentOS base or EPEL for libnfnetlink and libnetfilter_queue. If you wish, you may use the rpms in the Emerging Threats Cent OS 5 repository: i386 sudo rpm -Uvh http://rules.emergingthreatspro.com/projects/emergingrepo/i386/ libnetfilter_queue-0.0.15-1.i386.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/i386/ libnetfilter_queue-devel-0.0.15-1.i386.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/i386/libnfnetlink- 0.0.30-1.i386.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/i386/libnfnetlink- devel-0.0.30-1.i386.rpm x86_64 sudo rpm -Uvh http://rules.emergingthreatspro.com/projects/emergingrepo/ x86_64/libnetfilter_queue-0.0.15-1.x86_64.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/x86_64/ libnetfilter_queue-devel-0.0.15-1.x86_64.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/x86_64/ libnfnetlink-0.0.30-1.x86_64.rpm \ http://rules.emergingthreatspro.com/projects/emergingrepo/x86_64/ libnfnetlink-devel-0.0.30-1.x86_64.rpm libcap-ng installation This installation is needed for dropping privileges. wget http://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.6.4.tar.gz tar -xzvf libcap-ng-0.6.4.tar.gz cd libcap-ng-0.6.4 ./configure make sudo make install Suricata To download and build Suricata, enter the following: wget http://www.openinfosecfoundation.org/download/suricata-1.3.3.tar.gz tar -xvzf suricata-1.3.3.tar.gz cd suricata-1.3.3 If you are building from Git sources, enter all the following commands: bash autogen.sh If you are not building from Git sources, enter only: ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var make sudo make install Auto setup You can also use the available auto setup features of Suricata: ex: ./configure && make && make install-conf make install-conf would do the regular "make install" and then it would automatically create/ setup all the necessary directories and suricata.yaml for you. ./configure && make && make install-rules make install-rules would do the regular "make install" and then it would automatically download and set up the latest ruleset from Emerging Threats available for Suricata ./configure && make && make install-full make install-full would combine everything mentioned above (install-conf and install-rules) - and will present you with a ready to run (configured and set up) Suricata Please continue with the Basic_Setup. suricata-1.4.7/doc/Installation_from_GIT_with_PCRE-JIT.txt0000644000000000000000000000604412253546156020227 00000000000000Autogenerated on 2012-11-29 from - https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Installation_from_GIT_with_PCRE-JIT Installation from GIT with PCRE-JIT In this guide will be explained how to install and use the most recent code of Suricata on Ubuntu together with PCRE with JIT 8.20-RC1 support. The goal of PCRE-JIT is to improve the pcre pattern matching performance of the pcre library. The easiest way to see performance difference is to create a couple of pcre only rules or use for example the SSN rules from ET, and compare the performance statistics for rules. Installing from GIT on other operating systems is basically the same, except that some commands are Ubuntu-specific (like sudo and apt-get). In case you are using another operating system, you should replace those commands by your operating-specific commands. Pre-installation requirements Before you can build Suricata with PCRE-JIT for your system, run the following command to ensure that you have everything you need for the installation. sudo apt-get -y install build-essential autoconf automake \ libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev \ zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 \ make g++ sudo apt-get install git-core Depending on the current status of your system, it may take a while to complete this process. PCRE with JIT support Enter the following commands for PCRE JIT installation: wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/Testing/pcre-8.20- RC1.tar.gz tar -xzvf pcre-8.20-RC1.tar.gz cd pcre-8.20-RC1 ./configure --enable-jit Make sure you see that JIT compiling support is enabled, see example: make sudo make install HTP HTP is bundled with Suricata and installed automatically. If you need to install HTP manually for other reasons, instructions can be found at HTP library_installation. IPS By default, Suricata works as an IDS. If you want to use it as a IDS and IPS program, enter: sudo apt-get -y install libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 Suricata First, it is convenient to create a directory for Suricata. Name it 'suricata' for example. Open the terminal and enter: mkdir suricata Followed by: cd suricata Next, enter the following line in the terminal: git clone git://phalanx.openinfosecfoundation.org/oisf.git cd oisf Followed by: ./autogen.sh Compile and install To configure, please enter: ./configure --enable-pcre-jit \ --with-libpcre-includes=/usr/local/include \ --with-libpcre-libraries=/usr/local/lib After entering the previous, make sure that your screen looks like the following example and you have PCRE with JIT support: make sudo make install sudo ldconfig To check the build information you can enter: suricata --build-info Please continue with Basic_Setup. In case you have already made a map for the most recent code, downloaded the code into that map, and want to download recent code again, please enter: cd suricata/oisf next, enter: git pull After that, you start again at running autogen. suricata-1.4.7/doc/Makefile.am0000644000000000000000000000160112253546156013035 00000000000000EXTRA_DIST = \ AUTHORS \ GITGUIDE \ INSTALL \ NEWS \ README \ TODO \ INSTALL.PF_RING \ INSTALL.WINDOWS \ \ Basic_Setup.txt \ CentOS5.txt \ CentOS_56_Installation.txt \ Debian_Installation.txt \ Fedora_Core.txt \ FreeBSD_8.txt \ HTP_library_installation.txt \ Installation_from_GIT_with_PF_RING_on_Ubuntu_server_1104.txt \ Installation_with_CUDA_on_Ubuntu_server_1104.txt \ Installation_with_CUDA_and_PFRING_on_Scientific_Linux_6.txt \ Installation_with_PF_RING.txt \ Installation_with_CUDA_and_PF_RING_on_Ubuntu_server_1104.txt \ Installation_from_GIT_with_PCRE-JIT.txt \ Installation_with_CUDA_on_Scientific_Linux_6.txt \ Mac_OS_X_106x.txt \ OpenBSD_Installation_from_GIT.txt \ Setting_up_IPSinline_for_Linux.txt \ Third_Party_Installation_Guides.txt \ Ubuntu_Installation.txt \ Ubuntu_Installation_from_GIT.txt \ Windows.txt docdir = ${datarootdir}/doc/${PACKAGE} dist_doc_DATA = ${EXTRA_DIST} suricata-1.4.7/doc/INSTALL.WINDOWS0000644000000000000000000001365012253546156013172 00000000000000Before you start ================ An up to date version of this document can be found online: https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Windows Alternatively, an installation document for using CYGWIN instead of MinGW can be found here: https://redmine.openinfosecfoundation.org/attachments/download/676/SurWinInstallGuide.pdf This file describes how to build and run Suricata on Windows. Currently Windows XP and above are supported. Preparing the build environment =============================== 1. Setup MinGW environment from http://mingw.org Do not use the automatic installer as it is deprecated. Manually unpack the following packages to c:\mingw (use newer versions if you like): * binutils o binutils-2.20–1-mingw32-bin.tar.gz * mingw-runtime (dev and dll): o mingwrt-3.17-mingw32-dll.tar.gz o mingwrt-3.17-mingw32-dev.tar.gz * w32api o w32api-3.14-mingw32-dev.tar.gz * required runtime libraries for GCC (gmp, libiconv, MPFR and pthreads): o gmp-4.2.4-mingw32-dll.tar.gz o libiconv-1.13.1–1-mingw32-dll-2.tar.lzma o mpfr-2.4.1-mingw32-dll.tar.gz o pthreads-w32–2.8.0-mingw32-dll.tar.gz * gcc-core (bin and dll): o gcc-core-4.4.0-mingw32-bin.tar.gz o gcc-core-4.4.0-mingw32-dll.tar.gz * make o make-3.81–20090914-mingw32-bin.tar.gz * zlib o libz-1.2.3-1-mingw32-dll-1.tar.gz o libz-1.2.3-1-mingw32-dev.tar.gz 2. Install MSYS http://sourceforge.net/projects/mingw/files/ MSYS-1.0.11.exe (MSYS Base System) msysDTK-1.0.1.exe (MSYS Suplementary Tools) autoconf-2.63–1-msys-1.0.11-bin.tar.lzma automake-1.11–1-msys-1.0.11-bin.tar.lzma libtool-2.2.7a-1-msys-1.0.11-bin.tar.lzma MSYS will ask questions during the installation: Accept Post Install: [y] MinGW Installed? : [y] path to MinGW: [c:/MinGW] 3. Install pkg-config taken from http://wiki.videolan.org/Win32CompileMSYSNew#PKG-CONFIG Download and extract the following into c:\Msys\1.0 http://ftp.gnome.org/pub/GNOME/binaries/win32/glib/2.18/glib_2.18.2-1_win32.zip ftp://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config_0.23-3_win32.zip ftp://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config-dev_0.23-3_win32.zip Set PKG_CONFIG_PATH=/win32/lib/pkgconfig (e.g. by adding the Windows enviroment variable PKG_CONFIG_PATH in "Control Panel"->"System"->"Advanced System Settings"->"Environment Variables" and setting the value to /win32/lib/pkgconfig) 4. Get git Download portable GIT from this URL: http://code.google.com/p/msysgit/ - unpack to /msys/1.0 - don't forget to edit your ~/.gitconfig to at least give youreself a name :-) 5. Get libpcre http://www.pcre.org/ ./configure --enable-utf8 --disable-cpp --prefix=/mingw make make install 6. Get libyaml http://pyyaml.org/wiki/LibYAML It does not support mingw compilation. However it works in static mode: ./configure --prefix=/mingw CFLAGS="-DYAML_DECLARE_STATIC" make make install 7. Get libpcap Guide can be found here: - Download Devlopers pack http://www.winpcap.org/devel.htm - Download and install a coresponding installer package http://www.winpcap.org/install/default.htm (to have the driver in the system) - Copy includes to c:/mingw/include and libs (.a) to c:/mingw/lib - Rename libwpcap to libpcap 8. Get and compile Suricata git clone git://phalanx.openinfosecfoundation.org/oisf.git cd oisf Because of some weird autools port bug we do the following: dos2unix.exe libhtp/configure.ac dos2unix.exe libhtp/htp.pc.in dos2unix.exe libhtp/Makefile.am ./autogen.sh ./configure CFLAGS="-DYAML_DECLARE_STATIC" # add --enable-nfqueue as parameter to configure to enable inline mode make If everything goes well, you'll end up with suricata.exe in src/.lib. To test it you will need libpcre-0.dll, libz-1.dll, and pthreadGC2.dll which you already have somewhere under c:/mingw or c:/msys. To prepare the runtime environment: - copy the executable and the DLLs to a dedicated directory - get there classification.config and suricata.yaml - edit suricata.yaml (at least set the directories correctly) PCAP Mode ========= Make sure you have winpcap runtime and driver installed and then: - determine your eth device UUID in the registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ - now cross your fingers and do: suricata.exe -c suricata.yaml -i \DEVICE\{your device uuid} Inline Mode =========== You need to downoad, compile and install netfilterforwin (the netfilter.sys driver and Windows port of the libnetfilter_queue library): 1. Download and install Windows Driver Kit from Microsoft http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=36a2630f-5d56-43b5-b996-7633f2ec14ff 2. Download netfilterforwin http://sourceforge.net/projects/netfilterforwin/ Unpack it so the netfilterforwin directory (omit the version from its name) is beside the oisf directory. 3. Compile the driver - Open the build environment from you Start menu: Start->All Programs->windows Driver Kits->WDK xxxx.yyyy.z->Build Environments ->Windows Server 2003->x86 Free Build Environment (or the one which is proper for your system) - cd to netfilterforwin/netfilter - enter command: nmake 4. Install the driver - copy inf/* files and the freshly built netfilter.sys to a separate directory - open network connecions - right-click an interface, select properties - click install... - select service - click add - click 'have disk...' - browse to the directory with the inf files and netfilter.sys, select netfilter.inf anc click ok - confirm everything You should have the driver installed now. 5. Run Suricata in inline mode: suricata.exe -c suricata.yaml -q 0 suricata-1.4.7/ltmain.sh0000644000000000000000000105204412253546170012060 00000000000000 # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.3ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.2 Debian-2.4.2-1.3ubuntu1" TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 suricata-1.4.7/config.h.in0000644000000000000000000002624312253546173012267 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Unix socket support enabled */ #undef BUILD_UNIX_SOCKET /* Our CONFIG_DIR */ #undef CONFIG_DIR /* AF_PACKET support is available */ #undef HAVE_AF_PACKET /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ASSERT_H /* Define to 1 if you have the header file. */ #undef HAVE_CTYPE_H /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* libgeoip available */ #undef HAVE_GEOIP /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Assuming htp_decode_query_inplace function in bundled libhtp */ #undef HAVE_HTP_DECODE_QUERY_INPLACE /* Found usable htp_config_set_path_decode_u_encoding function in libhtp */ #undef HAVE_HTP_SET_PATH_DECODE_U_ENCODING /* Assuming htp_tx_get_response_headers_raw function in bundled libhtp */ #undef HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW /* Assuming htp_config_register_request_uri_normalize function in bundled libhtp */ #undef HAVE_HTP_URI_NORMALIZE_HOOK /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `cap-ng' library (-lcap-ng). */ #undef HAVE_LIBCAP_NG /* Define to 1 if you have the `cuda' library (-lcuda). */ #undef HAVE_LIBCUDA /* Define to 1 if you have the `dag' library (-ldag). */ #undef HAVE_LIBDAG /* Define to 1 if you have the `GeoIP' library (-lGeoIP). */ #undef HAVE_LIBGEOIP /* Define to 1 if you have the `htp' library (-lhtp). */ #undef HAVE_LIBHTP /* Define to 1 if you have the `jansson' library (-ljansson). */ #undef HAVE_LIBJANSSON /* Define to 1 if you have the `luajit-5.1' library (-lluajit-5.1). */ #undef HAVE_LIBLUAJIT_5_1 /* Define to 1 if you have the `magic' library (-lmagic). */ #undef HAVE_LIBMAGIC /* Define to 1 if you have the `net' library (-lnet). */ #undef HAVE_LIBNET /* Define to 1 if you have the `netfilter_queue' library (-lnetfilter_queue). */ #undef HAVE_LIBNETFILTER_QUEUE /* Define to 1 if you have the `nfnetlink' library (-lnfnetlink). */ #undef HAVE_LIBNFNETLINK /* Define to 1 if you have the `nspr4' library (-lnspr4). */ #undef HAVE_LIBNSPR4 /* Define to 1 if you have the `nss3' library (-lnss3). */ #undef HAVE_LIBNSS3 /* Define to 1 if you have the `pcap' library (-lpcap). */ #undef HAVE_LIBPCAP /* Define to 1 if you have the `pcre' library (-lpcre). */ #undef HAVE_LIBPCRE /* Define to 1 if you have the `pfring' library (-lpfring). */ #undef HAVE_LIBPFRING /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD /* Define to 1 if you have the `yaml' library (-lyaml). */ #undef HAVE_LIBYAML /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FILTER_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_IF_ARP_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_IF_ETHER_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_IF_PACKET_H /* libluajit available */ #undef HAVE_LUAJIT /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the `memchr' function. */ #undef HAVE_MEMCHR /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_H /* Found queue max length support in netfilter_queue */ #undef HAVE_NFQ_MAXLEN /* Found nfq_set_queue_flags function in netfilter_queue */ #undef HAVE_NFQ_SET_QUEUE_FLAGS /* Found nfq_set_verdict2 function in netfilter_queue */ #undef HAVE_NFQ_SET_VERDICT2 /* libnss available for md5 */ #undef HAVE_NSS /* Packet fanout support is available */ #undef HAVE_PACKET_FANOUT /* Define to 1 if you have the header file. */ #undef HAVE_PCAP_BPF_H /* Define to 1 if you have the header file. */ #undef HAVE_PCAP_H /* Define to 1 if you have the header file. */ #undef HAVE_PCAP_PCAP_H /* PF_RING pfring_set_cluster is available */ #undef HAVE_PFRING_CLUSTER_TYPE /* PF_RING pfring_enable_ring is available */ #undef HAVE_PFRING_ENABLE /* For post 5.4.0 version of pfring_open */ #undef HAVE_PFRING_OPEN_NEW /* PF_RING pfring_recv buffer is u_char** */ #undef HAVE_PFRING_RECV_UCHAR /* PF_RING pfring_set_bpf_filter is available */ #undef HAVE_PFRING_SET_BPF_FILTER /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #undef HAVE_REALLOC /* Define to 1 if you have the header file. */ #undef HAVE_SCHED_H /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the `strtoul' function. */ #undef HAVE_STRTOUL /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PRCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SYSCALL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_W32API_WINBASE_H /* Define to 1 if you have the header file. */ #undef HAVE_WINDOWS_H /* Define to 1 if you have the header file. */ #undef HAVE_WINSOCK2_H /* Define to 1 if you have the header file. */ #undef HAVE_WS2TCPIP_H /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* For signed version of nfq_get_payload */ #undef NFQ_GET_PAYLOAD_SIGNED /* 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 home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Pcre with JIT compiler support enabled */ #undef PCRE_HAVE_JIT /* Define whether application use libtool >= 2.0 */ #undef PRELUDE_APPLICATION_USE_LIBTOOL2 /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef was allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef was allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef was allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Fake GCC atomic support */ #undef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 /* Fake GCC atomic support */ #undef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 /* Fake GCC atomic support */ #undef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 /* Fake GCC atomic support */ #undef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to `int' if does not define. */ #undef pid_t /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t suricata-1.4.7/src/0000755000000000000000000000000012253546204011077 500000000000000suricata-1.4.7/src/detect-tag.h0000644000000000000000000000642012253546156013221 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * \author Victor Julien */ #ifndef __DETECT_TAG_H__ #define __DETECT_TAG_H__ #include "suricata-common.h" #include "suricata.h" #include "util-time.h" /* Limit the number of times a session can be tagged by the * same rule without finishing older tags */ #define DETECT_TAG_MATCH_LIMIT 10 /* Limit the number of tags that a session can have */ #define DETECT_TAG_MAX_TAGS 50 /* Limit the number of pkts to capture. Change this to * zero to make it unlimited * TODO: load it from config (var tagged_packet_limit) */ #define DETECT_TAG_MAX_PKTS 256 /* Type of tag: session or host */ enum { DETECT_TAG_TYPE_SESSION, DETECT_TAG_TYPE_HOST, DETECT_TAG_TYPE_MAX }; enum { DETECT_TAG_DIR_SRC, DETECT_TAG_DIR_DST, DETECT_TAG_DIR_MAX }; enum { DETECT_TAG_METRIC_PACKET, DETECT_TAG_METRIC_SECONDS, DETECT_TAG_METRIC_BYTES, DETECT_TAG_METRIC_MAX }; /** This will be the rule options/parameters */ typedef struct DetectTagData_ { uint8_t type; /**< tag type */ uint8_t direction; /**< host direction */ uint32_t count; /**< count */ uint32_t metric; /**< metric */ } DetectTagData; /** This is the installed data at the session/global or host table */ typedef struct DetectTagDataEntry_ { uint8_t flags:3; uint8_t metric:5; uint8_t pad0; uint16_t cnt_match; /**< number of times this tag was reset/updated */ uint32_t count; /**< count setting from rule */ uint32_t sid; /**< sid originating the tag */ uint32_t gid; /**< gid originating the tag */ union { uint32_t packets; /**< number of packets (metric packets) */ uint32_t bytes; /**< number of bytes (metric bytes) */ }; uint32_t first_ts; /**< First time seen (for metric = seconds) */ uint32_t last_ts; /**< Last time seen (to prune old sessions) */ #if __WORDSIZE == 64 uint32_t pad1; #endif struct DetectTagDataEntry_ *next; /**< Pointer to the next tag of this * session/src_host/dst_host (if any from other rule) */ } DetectTagDataEntry; #define TAG_ENTRY_FLAG_DIR_SRC 0x01 #define TAG_ENTRY_FLAG_DIR_DST 0x02 #define TAG_ENTRY_FLAG_SKIPPED_FIRST 0x04 /* prototypes */ void DetectTagRegister (void); void DetectTagDataFree(void *ptr); void DetectTagDataListFree(void *ptr); #endif /* __DETECT_TAG_H__ */ suricata-1.4.7/src/detect-isdataat.h0000644000000000000000000000237212253546156014242 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_ISDATAAT_H__ #define __DETECT_ISDATAAT_H__ #define ISDATAAT_RELATIVE 0x01 #define ISDATAAT_RAWBYTES 0x02 #define ISDATAAT_NEGATED 0x04 #define ISDATAAT_OFFSET_BE 0x08 #define ISDATAAT_MIN 0 #define ISDATAAT_MAX 65535 typedef struct DetectIsdataatData_ { uint16_t dataat; /* data offset to match */ uint8_t flags; /* isdataat options*/ } DetectIsdataatData; /* prototypes */ void DetectIsdataatRegister (void); #endif /* __DETECT_ISDATAAT_H__ */ suricata-1.4.7/src/action-globals.h0000644000000000000000000000221112253546156014070 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __ACTION_GLOBALS_H__ #define __ACTION_GLOBALS_H__ /* Changing them as flags, so later we can have alerts * and drop simultaneously */ #define ACTION_ALERT 0x01 #define ACTION_DROP 0x02 #define ACTION_REJECT 0x04 #define ACTION_REJECT_DST 0x08 #define ACTION_REJECT_BOTH 0x10 #define ACTION_PASS 0x20 #endif /* __ACTION_GLOBALS_H__ */ suricata-1.4.7/src/detect-engine-state.h0000644000000000000000000001755512253546156015044 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup sigstate * * @{ */ /** * \file * * \brief Data structures and function prototypes for keeping * state for the detection engine. * * \author Victor Julien */ /* On DeState and locking. * * The DeState is part of a flow, but it can't be protected by the flow lock. * Reason is we need to lock the DeState data for an entire detection run, * as we're looping through on "continued" detection and rely on only a single * detection instance setting it up on first run. We can't keep the entire flow * locked during detection for performance reasons, it would slow us down too * much. * * So a new lock was introduced. The only part of the process where we need * the flow lock is obviously when we're getting/setting the de_state ptr from * to the flow. */ #ifndef __DETECT_ENGINE_STATE_H__ #define __DETECT_ENGINE_STATE_H__ /** number of DeStateStoreItem's in one DeStateStore object */ #define DE_STATE_CHUNK_SIZE 15 /* per stored sig flags */ #define DE_STATE_FLAG_PAYLOAD_MATCH 1 /**< payload part of the sig matched */ #define DE_STATE_FLAG_URI_MATCH 1 << 1 /**< uri part of the sig matched */ #define DE_STATE_FLAG_DCE_MATCH 1 << 2 /**< dce payload inspection part matched */ #define DE_STATE_FLAG_HCBD_MATCH 1 << 3 /**< hcbd payload inspection part matched */ #define DE_STATE_FLAG_HSBD_MATCH 1 << 4 /**< hcbd payload inspection part matched */ #define DE_STATE_FLAG_HHD_MATCH 1 << 5 /**< hhd payload inspection part matched */ #define DE_STATE_FLAG_HRHD_MATCH 1 << 6 /**< hrhd payload inspection part matched */ #define DE_STATE_FLAG_HMD_MATCH 1 << 7 /**< hmd payload inspection part matched */ #define DE_STATE_FLAG_HCD_MATCH 1 << 8 /**< hcd payload inspection part matched */ #define DE_STATE_FLAG_HRUD_MATCH 1 << 9 /**< hrud payload inspection part matched */ #define DE_STATE_FLAG_FILE_TC_MATCH 1 << 10 #define DE_STATE_FLAG_FILE_TS_MATCH 1 << 11 #define DE_STATE_FLAG_FULL_MATCH 1 << 12 /**< sig already fully matched */ #define DE_STATE_FLAG_SIG_CANT_MATCH 1 << 13 /**< signature has no chance of matching */ #define DE_STATE_FLAG_HSMD_MATCH 1 << 14 /**< hsmd payload inspection part matched */ #define DE_STATE_FLAG_HSCD_MATCH 1 << 15 /**< hscd payload inspection part matched */ #define DE_STATE_FLAG_HUAD_MATCH 1 << 16 /**< huad payload inspection part matched */ #define DE_STATE_FLAG_HHHD_MATCH 1 << 17 /**< hhhd payload inspection part matched */ #define DE_STATE_FLAG_HRHHD_MATCH 1 << 18 /**< hrhhd payload inspection part matched */ #define DE_STATE_FLAG_URI_INSPECT DE_STATE_FLAG_URI_MATCH /**< uri part of the sig inspected */ #define DE_STATE_FLAG_DCE_INSPECT DE_STATE_FLAG_DCE_MATCH /**< dce payload inspection part inspected */ #define DE_STATE_FLAG_HCBD_INSPECT DE_STATE_FLAG_HCBD_MATCH /**< hcbd payload inspection part inspected */ #define DE_STATE_FLAG_HSBD_INSPECT DE_STATE_FLAG_HSBD_MATCH /**< hsbd payload inspection part inspected */ #define DE_STATE_FLAG_HHD_INSPECT DE_STATE_FLAG_HHD_MATCH /**< hhd payload inspection part inspected */ #define DE_STATE_FLAG_HRHD_INSPECT DE_STATE_FLAG_HRHD_MATCH /**< hrhd payload inspection part inspected */ #define DE_STATE_FLAG_HMD_INSPECT DE_STATE_FLAG_HMD_MATCH /**< hmd payload inspection part inspected */ #define DE_STATE_FLAG_HCD_INSPECT DE_STATE_FLAG_HCD_MATCH /**< hcd payload inspection part inspected */ #define DE_STATE_FLAG_HRUD_INSPECT DE_STATE_FLAG_HRUD_MATCH /**< hrud payload inspection part inspected */ #define DE_STATE_FLAG_FILE_TC_INSPECT DE_STATE_FLAG_FILE_TC_MATCH #define DE_STATE_FLAG_FILE_TS_INSPECT DE_STATE_FLAG_FILE_TS_MATCH #define DE_STATE_FLAG_HSMD_INSPECT DE_STATE_FLAG_HSMD_MATCH /**< hsmd payload inspection part inspected */ #define DE_STATE_FLAG_HSCD_INSPECT DE_STATE_FLAG_HSCD_MATCH /**< hscd payload inspection part inspected */ #define DE_STATE_FLAG_HUAD_INSPECT DE_STATE_FLAG_HUAD_MATCH /**< huad payload inspection part inspected */ #define DE_STATE_FLAG_HHHD_INSPECT DE_STATE_FLAG_HHHD_MATCH /**< hhhd payload inspection part inspected */ #define DE_STATE_FLAG_HRHHD_INSPECT DE_STATE_FLAG_HRHHD_MATCH /**< hrhhd payload inspection part inspected */ /* state flags */ #define DE_STATE_FILE_STORE_DISABLED 0x0001 #define DE_STATE_FILE_TC_NEW 0x0002 #define DE_STATE_FILE_TS_NEW 0x0004 /** per signature detection engine state */ typedef enum { DE_STATE_MATCH_NOSTATE = 0, /**< no state for this sig*/ DE_STATE_MATCH_FULL, /**< sig already fully matched */ DE_STATE_MATCH_PARTIAL, /**< partial state match */ DE_STATE_MATCH_NEW, /**< new (full) match this run */ DE_STATE_MATCH_NOMATCH, /**< not a match */ } DeStateMatchResult; /** \brief State storage for a single signature */ typedef struct DeStateStoreItem_ { SigIntId sid; /**< Signature internal id to store the state for (16 or * 32 bit depending on how SigIntId is defined). */ uint32_t flags; /**< flags */ SigMatch *nm; /**< next sig match to try, or null if done */ } DeStateStoreItem; /** \brief State store "chunk" for x number of signature */ typedef struct DeStateStore_ { DeStateStoreItem store[DE_STATE_CHUNK_SIZE]; /**< array of storage objects */ struct DeStateStore_ *next; /**< ptr to the next array */ } DeStateStore; /** \brief State store main object */ typedef struct DetectEngineState_ { DeStateStore *head; /**< signature state storage */ DeStateStore *tail; /**< tail item of the storage list */ SigIntId cnt; /**< number of sigs in the storage */ uint16_t toclient_version; /**< app layer state "version" inspected * last in to client direction */ uint16_t toserver_version; /**< app layer state "version" inspected * last in to server direction */ uint16_t toclient_filestore_cnt;/**< number of sigs with filestore that * cannot match in to client direction. */ uint16_t toserver_filestore_cnt;/**< number of sigs with filestore that * cannot match in to server direction. */ uint16_t flags; } DetectEngineState; void DeStateRegisterTests(void); DeStateStore *DeStateStoreAlloc(void); void DeStateStoreFree(DeStateStore *); void DetectEngineStateReset(DetectEngineState *state); DetectEngineState *DetectEngineStateAlloc(void); void DetectEngineStateFree(DetectEngineState *); int DeStateFlowHasState(Flow *, uint8_t, uint16_t); int DeStateDetectStartDetection(ThreadVars *, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, uint16_t, uint16_t); int DeStateDetectContinueDetection(ThreadVars *, DetectEngineCtx *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, uint16_t, uint16_t); const char *DeStateMatchResultToString(DeStateMatchResult); int DeStateUpdateInspectTransactionId(Flow *, char); #endif /* __DETECT_ENGINE_STATE_H__ */ /** * @} */ suricata-1.4.7/src/detect-stream_size.h0000644000000000000000000000246712253546156015002 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh */ #ifndef _DETECT_STREAM_SIZE_H #define _DETECT_STREAM_SIZE_H #define DETECTSSIZE_LT 0 #define DETECTSSIZE_LEQ 1 #define DETECTSSIZE_EQ 2 #define DETECTSSIZE_NEQ 3 #define DETECTSSIZE_GT 4 #define DETECTSSIZE_GEQ 5 #define STREAM_SIZE_SERVER 0x01 #define STREAM_SIZE_CLIENT 0x02 #define STREAM_SIZE_BOTH 0x04 #define STREAM_SIZE_EITHER 0x08 typedef struct DetectStreamSizeData_ { uint8_t flags; uint8_t mode; uint32_t ssize; }DetectStreamSizeData; void DetectStreamSizeRegister(void); #endif /* _DETECT_STREAM_SIZE_H */ suricata-1.4.7/src/detect-iprep.c0000644000000000000000000002415512253546156013565 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the iprep keyword */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "threads.h" #include "flow.h" #include "flow-bit.h" #include "flow-util.h" #include "detect-iprep.h" #include "util-spm.h" #include "app-layer-parser.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "util-debug.h" #include "reputation.h" #include "host.h" #define PARSE_REGEX "\\s*(any|src|dst|both)\\s*,\\s*([A-Za-z0-9\\-\\_]+)\\s*,\\s*(\\<|\\>|\\=)\\s*,\\s*([0-9]+)\\s*" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectIPRepMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectIPRepSetup (DetectEngineCtx *, Signature *, char *); void DetectIPRepFree (void *); void IPRepRegisterTests(void); void DetectIPRepRegister (void) { sigmatch_table[DETECT_IPREP].name = "iprep"; sigmatch_table[DETECT_IPREP].Match = DetectIPRepMatch; sigmatch_table[DETECT_IPREP].Setup = DetectIPRepSetup; sigmatch_table[DETECT_IPREP].Free = DetectIPRepFree; sigmatch_table[DETECT_IPREP].RegisterTests = IPRepRegisterTests; /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_IPREP].flags |= SIGMATCH_IPONLY_COMPAT; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } static uint8_t GetHostRepSrc(Packet *p, uint8_t cat, uint32_t version) { uint8_t val = 0; Host *h = NULL; if (p->flags & PKT_HOST_SRC_LOOKED_UP && p->host_src == NULL) { return 0; } else if (p->host_src != NULL) { h = (Host *)p->host_src; HostLock(h); } else { h = HostLookupHostFromHash(&(p->src)); p->flags |= PKT_HOST_SRC_LOOKED_UP; if (h == NULL) return 0; HostReference(&p->host_src, h); } if (h->iprep == NULL) { HostRelease(h); return 0; } SReputation *r = (SReputation *)h->iprep; /* allow higher versions as this happens during * rule reload */ if (r->version >= version) val = r->rep[cat]; else SCLogDebug("version mismatch %u != %u", r->version, version); HostRelease(h); return val; } static uint8_t GetHostRepDst(Packet *p, uint8_t cat, uint32_t version) { uint8_t val = 0; Host *h = NULL; if (p->flags & PKT_HOST_DST_LOOKED_UP && p->host_dst == NULL) { return 0; } else if (p->host_dst != NULL) { h = (Host *)p->host_dst; HostLock(h); } else { h = HostLookupHostFromHash(&(p->dst)); p->flags |= PKT_HOST_DST_LOOKED_UP; if (h == NULL) { return 0; } HostReference(&p->host_dst, h); } if (h->iprep == NULL) { HostRelease(h); return 0; } SReputation *r = (SReputation *)h->iprep; /* allow higher versions as this happens during * rule reload */ if (r->version >= version) val = r->rep[cat]; else SCLogDebug("version mismatch %u != %u", r->version, version); HostRelease(h); return val; } static inline int RepMatch(uint8_t op, uint8_t val1, uint8_t val2) { if (op == DETECT_IPREP_OP_GT && val1 > val2) { return 1; } else if (op == DETECT_IPREP_OP_LT && val1 < val2) { return 1; } else if (op == DETECT_IPREP_OP_EQ && val1 == val2) { return 1; } return 0; } /* * returns 0: no match * 1: match * -1: error */ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectIPRepData *rd = (DetectIPRepData *)m->ctx; if (rd == NULL) return 0; uint32_t version = det_ctx->de_ctx->srep_version; uint8_t val = 0; SCLogDebug("rd->cmd %u", rd->cmd); switch(rd->cmd) { case DETECT_IPREP_CMD_ANY: val = GetHostRepSrc(p, rd->cat, version); if (val > 0) { if (RepMatch(rd->op, val, rd->val) == 1) return 1; } val = GetHostRepDst(p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } break; case DETECT_IPREP_CMD_SRC: val = GetHostRepSrc(p, rd->cat, version); SCLogDebug("checking src -- val %u (looking for cat %u, val %u)", val, rd->cat, rd->val); if (val > 0) { return RepMatch(rd->op, val, rd->val); } break; case DETECT_IPREP_CMD_DST: SCLogDebug("checking dst"); val = GetHostRepDst(p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } break; case DETECT_IPREP_CMD_BOTH: val = GetHostRepSrc(p, rd->cat, version); if (val == 0 || RepMatch(rd->op, val, rd->val) == 0) return 0; val = GetHostRepDst(p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } break; } return 0; } int DetectIPRepSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectIPRepData *cd = NULL; SigMatch *sm = NULL; char *cmd_str = NULL, *name = NULL, *op_str = NULL, *value = NULL; uint8_t cmd = 0; #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 != 5) { SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for iprep", rawstr); return -1; } const char *str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } cmd_str = (char *)str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } name = (char *)str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } op_str = (char *)str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } value = (char *)str_ptr; if (strcmp(cmd_str,"any") == 0) { cmd = DETECT_IPREP_CMD_ANY; } else if (strcmp(cmd_str,"both") == 0) { cmd = DETECT_IPREP_CMD_BOTH; } else if (strcmp(cmd_str,"src") == 0) { cmd = DETECT_IPREP_CMD_SRC; } else if (strcmp(cmd_str,"dst") == 0) { cmd = DETECT_IPREP_CMD_DST; } else { SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: iprep \"%s\" is not supported.", cmd_str); goto error; } //SCLogInfo("category %s", name); uint8_t cat = SRepCatGetByShortname(name); if (cat == 0) { SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown iprep category \"%s\"", name); goto error; } uint8_t op = 0; uint8_t val = 0; if (op_str == NULL || strlen(op_str) != 1) { goto error; } switch(op_str[0]) { case '<': op = DETECT_IPREP_OP_LT; break; case '>': op = DETECT_IPREP_OP_GT; break; case '=': op = DETECT_IPREP_OP_EQ; break; default: goto error; break; } if (value != NULL && strlen(value) > 0) { int ival = atoi(value); if (ival < 0 || ival > 127) goto error; val = (uint8_t)ival; } cd = SCMalloc(sizeof(DetectIPRepData)); if (unlikely(cd == NULL)) goto error; cd->cmd = cmd; cd->cat = cat; cd->op = op; cd->val = val; SCLogDebug("cmd %u, cat %u, op %u, val %u", cd->cmd, cd->cat, cd->op, cd->val); pcre_free_substring(name); name = NULL; pcre_free_substring(cmd_str); cmd_str = NULL; /* 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_IPREP; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (name != NULL) pcre_free_substring(name); if (cmd_str != NULL) pcre_free_substring(cmd_str); if (cd != NULL) SCFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectIPRepFree (void *ptr) { DetectIPRepData *fd = (DetectIPRepData *)ptr; if (fd == NULL) return; SCFree(fd); } #ifdef UNITTESTS #endif /* UNITTESTS */ /** * \brief this function registers unit tests for IPRep */ void IPRepRegisterTests(void) { #ifdef UNITTESTS #endif /* UNITTESTS */ } suricata-1.4.7/src/util-daemon.c0000644000000000000000000001147312253546156013415 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias Galvan * * Daemonization process */ #include "suricata.h" #include "suricata-common.h" #include "runmodes.h" #include "util-daemon.h" #include "util-debug.h" #include "conf.h" #ifndef OS_WIN32 #include #include #include static volatile sig_atomic_t sigflag = 0; /** * \brief Signal handler used to take the parent process out of stand-by */ static void SignalHandlerSigusr1 (int signo) { sigflag = 1; } /** * \brief Tell the parent process the child is ready * * \param pid pid of the parent process to signal */ static void TellWaitingParent (pid_t pid) { kill(pid, SIGUSR1); } /** * \brief Set the parent on stand-by until the child is ready * * \param pid pid of the child process to wait */ static void WaitForChild (pid_t pid) { int status; SCLogDebug("Daemon: Parent waiting for child to be ready..."); /* Wait until child signals is ready */ while (sigflag == 0) { if (waitpid(pid, &status, WNOHANG)) { /* Check if the child is still there, otherwise the parent should exit */ if (WIFEXITED(status) || WIFSIGNALED(status)) { SCLogError(SC_ERR_DAEMON, "Child died unexpectedly"); exit(EXIT_FAILURE); } } /* sigsuspend(); */ sleep(1); } } /** * \brief Close stdin, stdout, stderr.Redirect logging info to syslog * */ static void SetupLogging (void) { /* Redirect stdin, stdout, stderr to /dev/null */ int fd = open("/dev/null", O_RDWR); if (fd < 0) return; if (dup2(fd, 0) < 0) return; if (dup2(fd, 1) < 0) return; if (dup2(fd, 2) < 0) return; close(fd); } /** * \brief Daemonize the process * */ void Daemonize (void) { pid_t pid, sid; /* Register the signal handler */ signal(SIGUSR1, SignalHandlerSigusr1); /** \todo We should check if wie allow more than 1 instance to run simultaneously. Maybe change the behaviour through conf file */ /* Creates a new process */ pid = fork(); if (pid < 0) { /* Fork error */ SCLogError(SC_ERR_DAEMON, "Error forking the process"); exit(EXIT_FAILURE); } else if (pid == 0) { /* Child continues here */ char *daemondir; umask(027); sid = setsid(); if (sid < 0) { SCLogError(SC_ERR_DAEMON, "Error creating new session"); exit(EXIT_FAILURE); } if (ConfGet("daemon-directory", &daemondir) == 1) { if ((chdir(daemondir)) < 0) { SCLogError(SC_ERR_DAEMON, "Error changing to working directory"); exit(EXIT_FAILURE); } } #ifndef OS_WIN32 else { if (chdir("/") < 0) { SCLogError(SC_ERR_DAEMON, "Error changing to working directory '/'"); } } #endif SetupLogging(); /* Child is ready, tell its parent */ TellWaitingParent(getppid()); /* Daemon is up and running */ SCLogDebug("Daemon is running"); return; } /* Parent continues here, waiting for child to be ready */ SCLogDebug("Parent is waiting for child to be ready"); WaitForChild(pid); /* Parent exits */ SCLogDebug("Child is ready, parent exiting"); exit(EXIT_SUCCESS); } #endif /* ifndef OS_WIN32 */ /** * \brief Check for a valid combination daemon/mode * * \param daemon daemon on or off * \param mode selected mode * * \retval 1 valid combination * \retval 0 invalid combination */ int CheckValidDaemonModes (int daemon, int mode) { if (daemon) { switch (mode) { case RUNMODE_PCAP_FILE: SCLogError(SC_ERR_INVALID_RUNMODE, "ERROR: pcap offline mode cannot run as daemon"); return 0; case RUNMODE_UNITTEST: SCLogError(SC_ERR_INVALID_RUNMODE, "ERROR: unittests cannot run as daemon"); return 0; default: SCLogDebug("Allowed mode"); break; } } return 1; } suricata-1.4.7/src/tm-threads.h0000644000000000000000000001444112253546156013252 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha */ #ifndef __TM_THREADS_H__ #define __TM_THREADS_H__ #include "tmqh-packetpool.h" #include "tm-threads-common.h" #include "tm-modules.h" typedef TmEcode (*TmSlotFunc)(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); typedef struct TmSlot_ { /* the TV holding this slot */ ThreadVars *tv; /* function pointers */ SC_ATOMIC_DECLARE(TmSlotFunc, SlotFunc); TmEcode (*PktAcqLoop)(ThreadVars *, void *, void *); TmEcode (*SlotThreadInit)(ThreadVars *, void *, void **); void (*SlotThreadExitPrintStats)(ThreadVars *, void *); TmEcode (*SlotThreadDeinit)(ThreadVars *, void *); /* data storage */ void *slot_initdata; SC_ATOMIC_DECLARE(void *, slot_data); /* queue filled by the SlotFunc with packets that will * be processed futher _before_ the current packet. * The locks in the queue are NOT used */ PacketQueue slot_pre_pq; /* queue filled by the SlotFunc with packets that will * be processed futher _after_ the current packet. The * locks in the queue are NOT used */ PacketQueue slot_post_pq; /* store the thread module id */ int tm_id; /* slot id, only used my TmVarSlot to know what the first slot is */ int id; /* linked list, only used when you have multiple slots(used by TmVarSlot) */ struct TmSlot_ *slot_next; } TmSlot; extern ThreadVars *tv_root[TVT_MAX]; extern SCMutex tv_root_lock; void TmSlotSetFuncAppend(ThreadVars *, TmModule *, void *); void TmSlotSetFuncAppendDelayed(ThreadVars *, TmModule *, void *, int delayed); TmSlot *TmSlotGetSlotForTM(int); ThreadVars *TmThreadCreate(char *, char *, char *, char *, char *, char *, void *(fn_p)(void *), int); ThreadVars *TmThreadCreatePacketHandler(char *, char *, char *, char *, char *, char *); ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), int); ThreadVars *TmThreadCreateCmdThread(char *name, void *(fn_p)(void *), int); TmEcode TmThreadSpawn(ThreadVars *); void TmThreadSetFlags(ThreadVars *, uint8_t); void TmThreadSetAOF(ThreadVars *, uint8_t); void TmThreadKillThread(ThreadVars *); void TmThreadKillThreadsFamily(int family); void TmThreadKillThreads(void); void TmThreadClearThreadsFamily(int family); void TmThreadAppend(ThreadVars *, int); void TmThreadRemove(ThreadVars *, int); TmEcode TmThreadSetCPUAffinity(ThreadVars *, uint16_t); TmEcode TmThreadSetThreadPriority(ThreadVars *, int); TmEcode TmThreadSetCPU(ThreadVars *, uint8_t); TmEcode TmThreadSetupOptions(ThreadVars *); void TmThreadSetPrio(ThreadVars *); int TmThreadGetNbThreads(uint8_t type); void TmThreadInitMC(ThreadVars *); void TmThreadTestThreadUnPaused(ThreadVars *); void TmThreadContinue(ThreadVars *); void TmThreadContinueThreads(void); void TmThreadPause(ThreadVars *); void TmThreadPauseThreads(void); void TmThreadCheckThreadState(void); TmEcode TmThreadWaitOnThreadInit(void); ThreadVars *TmThreadsGetCallingThread(void); void TmThreadActivateDummySlot(void); void TmThreadDeActivateDummySlot(void); int TmThreadsCheckFlag(ThreadVars *, uint16_t); void TmThreadsSetFlag(ThreadVars *, uint16_t); void TmThreadsUnsetFlag(ThreadVars *, uint16_t); void TmThreadWaitForFlag(ThreadVars *, uint16_t); TmEcode TmThreadsSlotVarRun (ThreadVars *tv, Packet *p, TmSlot *slot); ThreadVars *TmThreadsGetTVContainingSlot(TmSlot *); void TmThreadDisableThreadsWithTMS(uint8_t tm_flags); TmSlot *TmThreadGetFirstTmSlotForPartialPattern(const char *); /** * \brief Process the rest of the functions (if any) and queue. */ static inline TmEcode TmThreadsSlotProcessPkt(ThreadVars *tv, TmSlot *s, Packet *p) { TmEcode r = TM_ECODE_OK; if (s == NULL) { tv->tmqh_out(tv, p); return r; } if (TmThreadsSlotVarRun(tv, p, s) == TM_ECODE_FAILED) { TmqhOutputPacketpool(tv, p); TmSlot *slot = s; while (slot != NULL) { SCMutexLock(&slot->slot_post_pq.mutex_q); TmqhReleasePacketsToPacketPool(&slot->slot_post_pq); SCMutexUnlock(&slot->slot_post_pq.mutex_q); slot = slot->slot_next; } TmThreadsSetFlag(tv, THV_FAILED); r = TM_ECODE_FAILED; } else { tv->tmqh_out(tv, p); /* post process pq */ TmSlot *slot = s; while (slot != NULL) { if (slot->slot_post_pq.top != NULL) { while (1) { SCMutexLock(&slot->slot_post_pq.mutex_q); Packet *extra_p = PacketDequeue(&slot->slot_post_pq); SCMutexUnlock(&slot->slot_post_pq.mutex_q); if (extra_p == NULL) break; if (slot->slot_next != NULL) { r = TmThreadsSlotVarRun(tv, extra_p, slot->slot_next); if (r == TM_ECODE_FAILED) { SCMutexLock(&slot->slot_post_pq.mutex_q); TmqhReleasePacketsToPacketPool(&slot->slot_post_pq); SCMutexUnlock(&slot->slot_post_pq.mutex_q); TmqhOutputPacketpool(tv, extra_p); TmThreadsSetFlag(tv, THV_FAILED); break; } } tv->tmqh_out(tv, extra_p); } } /* if (slot->slot_post_pq.top != NULL) */ slot = slot->slot_next; } /* while (slot != NULL) */ } return r; } #endif /* __TM_THREADS_H__ */ suricata-1.4.7/src/detect-pktvar.c0000644000000000000000000001557312253546156013761 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the pktvar keyword */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "threads.h" #include "pkt-var.h" #include "detect-pktvar.h" #include "util-spm.h" #include "util-debug.h" #define PARSE_REGEX "(.*),(.*)" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectPktvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectPktvarSetup (DetectEngineCtx *, Signature *, char *); void DetectPktvarRegister (void) { sigmatch_table[DETECT_PKTVAR].name = "pktvar"; sigmatch_table[DETECT_PKTVAR].Match = DetectPktvarMatch; sigmatch_table[DETECT_PKTVAR].Setup = DetectPktvarSetup; sigmatch_table[DETECT_PKTVAR].Free = NULL; sigmatch_table[DETECT_PKTVAR].RegisterTests = NULL; sigmatch_table[DETECT_PKTVAR].flags |= SIGMATCH_PAYLOAD; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /* * returns 0: no match * 1: match * -1: error */ int DetectPktvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { int ret = 0; DetectPktvarData *pd = (DetectPktvarData *)m->ctx; PktVar *pv = PktVarGet(p, pd->name); if (pv != NULL) { uint8_t *ptr = SpmSearch(pv->value, pv->value_len, pd->content, pd->content_len); if (ptr != NULL) ret = 1; } return ret; } static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectPktvarData *cd = NULL; SigMatch *sm = NULL; char *str = rawstr; char dubbed = 0; uint16_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 != 3) { SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for pktvar.", rawstr); return -1; } const char *str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } varname = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } varcontent = (char *)str_ptr; } SCLogDebug("varname %s, varcontent %s", varname, varcontent); if (varcontent[0] == '\"' && varcontent[strlen(varcontent)-1] == '\"') { str = SCStrdup(varcontent+1); if (unlikely(str == NULL)) { return -1; } str[strlen(varcontent)-2] = '\0'; dubbed = 1; } len = strlen(str); if (len == 0) { if (dubbed) SCFree(str); return -1; } cd = SCMalloc(sizeof(DetectPktvarData)); if (unlikely(cd == NULL)) goto error; char converted = 0; { uint16_t i, x; uint8_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((unsigned char)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) { uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF; 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 if (SCLogDebugEnabled()) { for (i = 0; i < x; i++) { if (isprint((unsigned char)str[i])) printf("%c", str[i]); else printf("\\x%02u", str[i]); } printf("\n"); } #endif if (converted) len = x; } cd->content = SCMalloc(len); if (cd->content == NULL) { SCFree(cd); if (dubbed) SCFree(str); return -1; } cd->name = SCStrdup(varname); if (cd->name == NULL) { SCFree(cd); if (dubbed) SCFree(str); return -1; } 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_PKTVAR; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); if (cd) { if (cd->name) SCFree(cd->name); SCFree(cd); } if (sm) SCFree(sm); return -1; } suricata-1.4.7/src/tmqh-nfq.h0000644000000000000000000000157112253546156012735 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __TMQH_NFQ_H__ #define __TMQH_NFQ_H__ void TmqhNfqRegister (void); #endif /* __TMQH_NFQ_H__ */ suricata-1.4.7/src/detect-ssl-state.c0000644000000000000000000007534112253546156014370 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implements support for ssl_state keyword. */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "detect-ssl-state.h" #include "stream-tcp.h" #include "app-layer-ssl.h" #define PARSE_REGEX1 "^\\s*([_a-zA-Z0-9]+)(.*)$" static pcre *parse_regex1; static pcre_extra *parse_regex1_study; #define PARSE_REGEX2 "^(?:\\s*[|]\\s*([_a-zA-Z0-9]+))(.*)$" static pcre *parse_regex2; static pcre_extra *parse_regex2_study; int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); int DetectSslStateSetup(DetectEngineCtx *, Signature *, char *); void DetectSslStateRegisterTests(void); void DetectSslStateFree(void *); /** * \brief Registers the keyword handlers for the "ssl_state" keyword. */ void DetectSslStateRegister(void) { sigmatch_table[DETECT_AL_SSL_STATE].name = "ssl_state"; sigmatch_table[DETECT_AL_SSL_STATE].Match = NULL; sigmatch_table[DETECT_AL_SSL_STATE].AppLayerMatch = DetectSslStateMatch; sigmatch_table[DETECT_AL_SSL_STATE].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_SSL_STATE].Setup = DetectSslStateSetup; sigmatch_table[DETECT_AL_SSL_STATE].Free = DetectSslStateFree; sigmatch_table[DETECT_AL_SSL_STATE].RegisterTests = DetectSslStateRegisterTests; const char *eb; int eo; int opts = 0; SCLogDebug("registering ssl_state rule option"); /* PARSE_REGEX1 */ parse_regex1 = pcre_compile(PARSE_REGEX1, opts, &eb, &eo, NULL); if (parse_regex1 == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX1, eo, eb); goto error; } parse_regex1_study = pcre_study(parse_regex1, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } /* PARSE_REGEX2 */ parse_regex2 = pcre_compile(PARSE_REGEX2, opts, &eb, &eo, NULL); if (parse_regex2 == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX2, eo, eb); goto error; } parse_regex2_study = pcre_study(parse_regex2, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } error: return; } /** * \brief App layer match function ssl_state keyword. * * \param tv Pointer to threadvars. * \param det_ctx Pointer to the thread's detection context. * \param f Pointer to the flow. * \param flags Flags. * \param state App layer state. * \param s Sig we are currently inspecting. * \param m SigMatch we are currently inspecting. * * \retval 1 Match. * \retval 0 No match. */ int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *alstate, Signature *s, SigMatch *m) { int result = 1; DetectSslStateData *ssd = (DetectSslStateData *)m->ctx; SSLState *ssl_state = (SSLState *)alstate; if (ssl_state == NULL) { SCLogDebug("no app state, no match"); return 0; } FLOWLOCK_RDLOCK(f); if ((ssd->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && !(ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO)) { result = 0; goto end; } if ((ssd->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && !(ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO)) { result = 0; goto end; } if ((ssd->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) && !(ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX)) { result = 0; goto end; } if ((ssd->flags & SSL_AL_FLAG_STATE_SERVER_KEYX) && !(ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_KEYX)) { result = 0; goto end; } end: FLOWLOCK_UNLOCK(f); return result; } /** * \brief Parse the arg supplied with ssl_state and return it in a * DetectSslStateData instance. * * \param arg Pointer to the string to be parsed. * * \retval ssd Pointer to DetectSslStateData on succese. * \retval NULL On failure. */ DetectSslStateData *DetectSslStateParse(char *arg) { #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov1[MAX_SUBSTRINGS]; int ov2[MAX_SUBSTRINGS]; const char *str1; const char *str2; uint32_t flags = 0; DetectSslStateData *ssd = NULL; ret = pcre_exec(parse_regex1, parse_regex1_study, arg, strlen(arg), 0, 0, ov1, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid arg \"%s\" supplied to " "ssl_state keyword.", arg); goto error; } res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 1, &str1); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (strcmp("client_hello", str1) == 0) { flags |= DETECT_SSL_STATE_CLIENT_HELLO; } else if (strcmp("server_hello", str1) == 0) { flags |= DETECT_SSL_STATE_SERVER_HELLO; } else if (strcmp("client_keyx", str1) == 0) { flags |= DETECT_SSL_STATE_CLIENT_KEYX; } else if (strcmp("server_keyx", str1) == 0) { flags |= DETECT_SSL_STATE_SERVER_KEYX; } else if (strcmp("unknown", str1) == 0) { flags |= DETECT_SSL_STATE_UNKNOWN; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "Found invalid option \"%s\" " "in ssl_state keyword.", str1); goto error; } pcre_free_substring(str1); res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 2, &str1); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } while (res > 0) { ret = pcre_exec(parse_regex2, parse_regex2_study, str1, strlen(str1), 0, 0, ov2, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid arg \"%s\" supplied to " "ssl_state keyword.", arg); goto error; } res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 1, &str2); if (res <= 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (strcmp("client_hello", str2) == 0) { flags |= DETECT_SSL_STATE_CLIENT_HELLO; } else if (strcmp("server_hello", str2) == 0) { flags |= DETECT_SSL_STATE_SERVER_HELLO; } else if (strcmp("client_keyx", str2) == 0) { flags |= DETECT_SSL_STATE_CLIENT_KEYX; } else if (strcmp("server_keyx", str2) == 0) { flags |= DETECT_SSL_STATE_SERVER_KEYX; } else if (strcmp("unknown", str2) == 0) { flags |= DETECT_SSL_STATE_UNKNOWN; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "Found invalid option \"%s\" " "in ssl_state keyword.", str2); goto error; } res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 2, &str2); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } pcre_free_substring(str1); str1 = str2; } if ( (ssd = SCMalloc(sizeof(DetectSslStateData))) == NULL) { goto error; } ssd->flags = flags; return ssd; error: if (ssd != NULL) DetectSslStateFree(ssd); return NULL; } /** * \internal * \brief Setup function for ssl_state keyword. * * \param de_ctx Pointer to the Detection Engine Context. * \param s Pointer to the Current Signature * \param arg String holding the arg. * * \retval 0 On success. * \retval -1 On failure. */ int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectSslStateData *ssd = NULL; SigMatch *sm = NULL; ssd = DetectSslStateParse(arg); if (ssd == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_AL_SSL_STATE; sm->ctx = ssd; if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Rule contains conflicting keywords. Have non-tls alproto " "set for a rule containing \"ssl_state\" keyword"); goto error; } s->alproto = ALPROTO_TLS; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); return 0; error: if (ssd != NULL) DetectSslStateFree(ssd); if (sm != NULL) SCFree(sm); return -1; } /** * \brief Free memory associated with DetectSslStateData. * * \param ptr pointer to the data to be freed. */ void DetectSslStateFree(void *ptr) { if (ptr != NULL) SCFree(ptr); return; } /************************************Unittests*********************************/ #ifdef UNITTESTS int DetectSslStateTest01(void) { DetectSslStateData *ssd = DetectSslStateParse("client_hello"); if (ssd == NULL) { printf("ssd == NULL\n"); return 0; } if (ssd->flags == DETECT_SSL_STATE_CLIENT_HELLO) { SCFree(ssd); return 1; } return 0; } int DetectSslStateTest02(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_hello"); if (ssd == NULL) { printf("ssd == NULL\n"); return 0; } if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_HELLO)) { SCFree(ssd); return 1; } return 0; } int DetectSslStateTest03(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " "client_hello"); if (ssd == NULL) { printf("ssd == NULL\n"); return 0; } if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_KEYX | DETECT_SSL_STATE_CLIENT_HELLO)) { SCFree(ssd); return 1; } return 0; } int DetectSslStateTest04(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " "client_hello | server_keyx | " "unknown"); if (ssd == NULL) { printf("ssd == NULL\n"); return 0; } if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_KEYX | DETECT_SSL_STATE_CLIENT_HELLO | DETECT_SSL_STATE_SERVER_KEYX | DETECT_SSL_STATE_UNKNOWN)) { SCFree(ssd); return 1; } return 0; } int DetectSslStateTest05(void) { DetectSslStateData *ssd = DetectSslStateParse("| server_hello | client_keyx | " "client_hello | server_keyx | " "unknown"); if (ssd != NULL) { printf("ssd != NULL - failure\n"); SCFree(ssd); return 0; } return 1; } int DetectSslStateTest06(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " "client_hello | server_keyx | " "unknown | "); if (ssd != NULL) { printf("ssd != NULL - failure\n"); SCFree(ssd); return 0; } return 1; } /** * \test Test a valid dce_iface entry for a bind and bind_ack */ static int DetectSslStateTest07(void) { uint8_t chello_buf[] = { 0x80, 0x67, 0x01, 0x03, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, 0x00, 0x00, 0x39, 0x00, 0x00, 0x38, 0x00, 0x00, 0x35, 0x00, 0x00, 0x33, 0x00, 0x00, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x15, 0x00, 0x00, 0x12, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, 0xa8, 0xb8, 0x93, 0xbb, 0x90, 0xe9, 0x2a, 0xa2, 0x4d, 0x6d, 0xcc, 0x1c, 0xe7, 0x2a, 0x80, 0x21 }; uint32_t chello_buf_len = sizeof(chello_buf); uint8_t shello_buf[] = { 0x16, 0x03, 0x00, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x46, 0x03, 0x00, 0x44, 0x4c, 0x94, 0x8f, 0xfe, 0x81, 0xed, 0x93, 0x65, 0x02, 0x88, 0xa3, 0xf8, 0xeb, 0x63, 0x86, 0x0e, 0x2c, 0xf6, 0x8d, 0xd0, 0x0f, 0x2c, 0x2a, 0xd6, 0x4f, 0xcd, 0x2d, 0x3c, 0x16, 0xd7, 0xd6, 0x20, 0xa0, 0xfb, 0x60, 0x86, 0x3d, 0x1e, 0x76, 0xf3, 0x30, 0xfe, 0x0b, 0x01, 0xfd, 0x1a, 0x01, 0xed, 0x95, 0xf6, 0x7b, 0x8e, 0xc0, 0xd4, 0x27, 0xbf, 0xf0, 0x6e, 0xc7, 0x56, 0xb1, 0x47, 0xce, 0x98, 0x00, 0x35, 0x00, 0x16, 0x03, 0x00, 0x03, 0x44, 0x0b, 0x00, 0x03, 0x40, 0x00, 0x03, 0x3d, 0x00, 0x03, 0x3a, 0x30, 0x82, 0x03, 0x36, 0x30, 0x82, 0x02, 0x9f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x81, 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x58, 0x59, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0c, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x44, 0x65, 0x73, 0x65, 0x72, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x54, 0x6f, 0x77, 0x6e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x4f, 0x69, 0x6c, 0x2c, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0c, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x4f, 0x69, 0x6c, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0f, 0x63, 0x61, 0x40, 0x73, 0x6e, 0x61, 0x6b, 0x65, 0x6f, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x33, 0x30, 0x33, 0x30, 0x35, 0x31, 0x36, 0x34, 0x37, 0x34, 0x35, 0x5a, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x30, 0x33, 0x31, 0x36, 0x34, 0x37, 0x34, 0x35, 0x5a, 0x30, 0x81, 0xa7, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x58, 0x59, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0c, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x44, 0x65, 0x73, 0x65, 0x72, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x54, 0x6f, 0x77, 0x6e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x4f, 0x69, 0x6c, 0x2c, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0e, 0x57, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x6e, 0x61, 0x6b, 0x65, 0x6f, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x77, 0x77, 0x77, 0x40, 0x73, 0x6e, 0x61, 0x6b, 0x65, 0x6f, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa4, 0x6e, 0x53, 0x14, 0x0a, 0xde, 0x2c, 0xe3, 0x60, 0x55, 0x9a, 0xf2, 0x42, 0xa6, 0xaf, 0x47, 0x12, 0x2f, 0x17, 0xce, 0xfa, 0xba, 0xdc, 0x4e, 0x63, 0x56, 0x34, 0xb9, 0xba, 0x73, 0x4b, 0x78, 0x44, 0x3d, 0xc6, 0x6c, 0x69, 0xa4, 0x25, 0xb3, 0x61, 0x02, 0x9d, 0x09, 0x04, 0x3f, 0x72, 0x3d, 0xd8, 0x27, 0xd3, 0xb0, 0x5a, 0x45, 0x77, 0xb7, 0x36, 0xe4, 0x26, 0x23, 0xcc, 0x12, 0xb8, 0xae, 0xde, 0xa7, 0xb6, 0x3a, 0x82, 0x3c, 0x7c, 0x24, 0x59, 0x0a, 0xf8, 0x96, 0x43, 0x8b, 0xa3, 0x29, 0x36, 0x3f, 0x91, 0x7f, 0x5d, 0xc7, 0x23, 0x94, 0x29, 0x7f, 0x0a, 0xce, 0x0a, 0xbd, 0x8d, 0x9b, 0x2f, 0x19, 0x17, 0xaa, 0xd5, 0x8e, 0xec, 0x66, 0xa2, 0x37, 0xeb, 0x3f, 0x57, 0x53, 0x3c, 0xf2, 0xaa, 0xbb, 0x79, 0x19, 0x4b, 0x90, 0x7e, 0xa7, 0xa3, 0x99, 0xfe, 0x84, 0x4c, 0x89, 0xf0, 0x3d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x6e, 0x30, 0x6c, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x14, 0x30, 0x12, 0x81, 0x10, 0x77, 0x77, 0x77, 0x40, 0x73, 0x6e, 0x61, 0x6b, 0x65, 0x6f, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x30, 0x3a, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x2d, 0x16, 0x2b, 0x6d, 0x6f, 0x64, 0x5f, 0x73, 0x73, 0x6c, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x06, 0x40, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xae, 0x79, 0x79, 0x22, 0x90, 0x75, 0xfd, 0xa6, 0xd5, 0xc4, 0xb8, 0xc4, 0x99, 0x4e, 0x1c, 0x05, 0x7c, 0x91, 0x59, 0xbe, 0x89, 0x0d, 0x3d, 0xc6, 0x8c, 0xa3, 0xcf, 0xf6, 0xba, 0x23, 0xdf, 0xb8, 0xae, 0x44, 0x68, 0x8a, 0x8f, 0xb9, 0x8b, 0xcb, 0x12, 0xda, 0xe6, 0xa2, 0xca, 0xa5, 0xa6, 0x55, 0xd9, 0xd2, 0xa1, 0xad, 0xba, 0x9b, 0x2c, 0x44, 0x95, 0x1d, 0x4a, 0x90, 0x59, 0x7f, 0x83, 0xae, 0x81, 0x5e, 0x3f, 0x92, 0xe0, 0x14, 0x41, 0x82, 0x4e, 0x7f, 0x53, 0xfd, 0x10, 0x23, 0xeb, 0x8a, 0xeb, 0xe9, 0x92, 0xea, 0x61, 0xf2, 0x8e, 0x19, 0xa1, 0xd3, 0x49, 0xc0, 0x84, 0x34, 0x1e, 0x2e, 0x6e, 0xf6, 0x98, 0xe2, 0x87, 0x53, 0xd6, 0x55, 0xd9, 0x1a, 0x8a, 0x92, 0x5c, 0xad, 0xdc, 0x1e, 0x1c, 0x30, 0xa7, 0x65, 0x9d, 0xc2, 0x4f, 0x60, 0xd2, 0x6f, 0xdb, 0xe0, 0x9f, 0x9e, 0xbc, 0x41, 0x16, 0x03, 0x00, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00 }; uint32_t shello_buf_len = sizeof(shello_buf); uint8_t client_change_cipher_spec_buf[] = { 0x16, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00, 0x80, 0x65, 0x51, 0x2d, 0xa6, 0xd4, 0xa7, 0x38, 0xdf, 0xac, 0x79, 0x1f, 0x0b, 0xd9, 0xb2, 0x61, 0x7d, 0x73, 0x88, 0x32, 0xd9, 0xf2, 0x62, 0x3a, 0x8b, 0x11, 0x04, 0x75, 0xca, 0x42, 0xff, 0x4e, 0xd9, 0xcc, 0xb9, 0xfa, 0x86, 0xf3, 0x16, 0x2f, 0x09, 0x73, 0x51, 0x66, 0xaa, 0x29, 0xcd, 0x80, 0x61, 0x0f, 0xe8, 0x13, 0xce, 0x5b, 0x8e, 0x0a, 0x23, 0xf8, 0x91, 0x5e, 0x5f, 0x54, 0x70, 0x80, 0x8e, 0x7b, 0x28, 0xef, 0xb6, 0x69, 0xb2, 0x59, 0x85, 0x74, 0x98, 0xe2, 0x7e, 0xd8, 0xcc, 0x76, 0x80, 0xe1, 0xb6, 0x45, 0x4d, 0xc7, 0xcd, 0x84, 0xce, 0xb4, 0x52, 0x79, 0x74, 0xcd, 0xe6, 0xd7, 0xd1, 0x9c, 0xad, 0xef, 0x63, 0x6c, 0x0f, 0xf7, 0x05, 0xe4, 0x4d, 0x1a, 0xd3, 0xcb, 0x9c, 0xd2, 0x51, 0xb5, 0x61, 0xcb, 0xff, 0x7c, 0xee, 0xc7, 0xbc, 0x5e, 0x15, 0xa3, 0xf2, 0x52, 0x0f, 0xbb, 0x32, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03, 0x00, 0x00, 0x40, 0xa9, 0xd8, 0xd7, 0x35, 0xbc, 0x39, 0x56, 0x98, 0xad, 0x87, 0x61, 0x2a, 0xc4, 0x8f, 0xcc, 0x03, 0xcb, 0x93, 0x80, 0x81, 0xb0, 0x4a, 0xc4, 0xd2, 0x09, 0x71, 0x3e, 0x90, 0x3c, 0x8d, 0xe0, 0x95, 0x44, 0xfe, 0x56, 0xd1, 0x7e, 0x88, 0xe2, 0x48, 0xfd, 0x76, 0x70, 0x76, 0xe2, 0xcd, 0x06, 0xd0, 0xf3, 0x9d, 0x13, 0x79, 0x67, 0x1e, 0x37, 0xf6, 0x98, 0xbe, 0x59, 0x18, 0x4c, 0xfc, 0x75, 0x56 }; uint32_t client_change_cipher_spec_buf_len = sizeof(client_change_cipher_spec_buf); uint8_t server_change_cipher_spec_buf[] = { 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03, 0x00, 0x00, 0x40, 0xce, 0x7c, 0x92, 0x43, 0x59, 0xcc, 0x3d, 0x90, 0x91, 0x9c, 0x58, 0xf0, 0x7a, 0xce, 0xae, 0x0d, 0x08, 0xe0, 0x76, 0xb4, 0x86, 0xb1, 0x15, 0x5b, 0x32, 0xb8, 0x77, 0x53, 0xe7, 0xa6, 0xf9, 0xd0, 0x95, 0x5f, 0xaa, 0x07, 0xc3, 0x96, 0x7c, 0xc9, 0x88, 0xc2, 0x7a, 0x20, 0x89, 0x4f, 0xeb, 0xeb, 0xb6, 0x19, 0xef, 0xaa, 0x27, 0x73, 0x9d, 0xa6, 0xb4, 0x9f, 0xeb, 0x34, 0xe2, 0x4d, 0x9f, 0x6b }; uint32_t server_change_cipher_spec_buf_len = sizeof(server_change_cipher_spec_buf); uint8_t toserver_app_data_buf[] = { 0x17, 0x03, 0x00, 0x01, 0xb0, 0x4a, 0xc3, 0x3e, 0x9d, 0x77, 0x78, 0x01, 0x2c, 0xb4, 0xbc, 0x4c, 0x9a, 0x84, 0xd7, 0xb9, 0x90, 0x0c, 0x21, 0x10, 0xf0, 0xfa, 0x00, 0x7c, 0x16, 0xbb, 0x77, 0xfb, 0x72, 0x42, 0x4f, 0xad, 0x50, 0x4a, 0xd0, 0xaa, 0x6f, 0xaa, 0x44, 0x6c, 0x62, 0x94, 0x1b, 0xc5, 0xfe, 0xe9, 0x1c, 0x5e, 0xde, 0x85, 0x0b, 0x0e, 0x05, 0xe4, 0x18, 0x6e, 0xd2, 0xd3, 0xb5, 0x20, 0xab, 0x81, 0xfd, 0x18, 0x9a, 0x73, 0xb8, 0xd7, 0xef, 0xc3, 0xdd, 0x74, 0xd7, 0x9c, 0x1e, 0x6f, 0x21, 0x6d, 0xf8, 0x24, 0xca, 0x3c, 0x70, 0x78, 0x36, 0x12, 0x7a, 0x8a, 0x9c, 0xac, 0x4e, 0x1c, 0xa8, 0xfb, 0x27, 0x30, 0xba, 0x9a, 0xf4, 0x2f, 0x0a, 0xab, 0x80, 0x6a, 0xa1, 0x60, 0x74, 0xf0, 0xe3, 0x91, 0x84, 0xe7, 0x90, 0x88, 0xcc, 0xf0, 0x95, 0x7b, 0x0a, 0x22, 0xf2, 0xf9, 0x27, 0xe0, 0xdd, 0x38, 0x0c, 0xfd, 0xe9, 0x03, 0x71, 0xdc, 0x70, 0xa4, 0x6e, 0xdf, 0xe3, 0x72, 0x9e, 0xa1, 0xf0, 0xc9, 0x00, 0xd6, 0x03, 0x55, 0x6a, 0x67, 0x5d, 0x9c, 0xb8, 0x75, 0x01, 0xb0, 0x01, 0x9f, 0xe6, 0xd2, 0x44, 0x18, 0xbc, 0xca, 0x7a, 0x10, 0x39, 0xa6, 0xcf, 0x15, 0xc7, 0xf5, 0x35, 0xd4, 0xb3, 0x6d, 0x91, 0x23, 0x84, 0x99, 0xba, 0xb0, 0x7e, 0xd0, 0xc9, 0x4c, 0xbf, 0x3f, 0x33, 0x68, 0x37, 0xb7, 0x7d, 0x44, 0xb0, 0x0b, 0x2c, 0x0f, 0xd0, 0x75, 0xa2, 0x6b, 0x5b, 0xe1, 0x9f, 0xd4, 0x69, 0x9a, 0x14, 0xc8, 0x29, 0xb7, 0xd9, 0x10, 0xbb, 0x99, 0x30, 0x9a, 0xfb, 0xcc, 0x13, 0x1f, 0x76, 0x4e, 0xe6, 0xdf, 0x14, 0xaa, 0xd5, 0x60, 0xbf, 0x91, 0x49, 0x0d, 0x64, 0x42, 0x29, 0xa8, 0x64, 0x27, 0xd4, 0x5e, 0x1b, 0x18, 0x03, 0xa8, 0x73, 0xd6, 0x05, 0x6e, 0xf7, 0x50, 0xb0, 0x09, 0x6b, 0x69, 0x7a, 0x12, 0x28, 0x58, 0xef, 0x5a, 0x86, 0x11, 0xde, 0x71, 0x71, 0x9f, 0xca, 0xbd, 0x79, 0x2a, 0xc2, 0xe5, 0x9b, 0x5e, 0x32, 0xe7, 0xcb, 0x97, 0x6e, 0xa0, 0xea, 0xa4, 0xa4, 0x6a, 0x32, 0xf9, 0x37, 0x39, 0xd8, 0x37, 0x6d, 0x63, 0xf3, 0x08, 0x1c, 0xdd, 0x06, 0xdd, 0x2c, 0x2b, 0x9f, 0x04, 0x88, 0x5f, 0x36, 0x42, 0xc1, 0xb1, 0xc7, 0xe8, 0x2d, 0x5d, 0xa4, 0x6c, 0xe5, 0x60, 0x94, 0xae, 0xd0, 0x90, 0x1e, 0x88, 0xa0, 0x87, 0x52, 0xfb, 0xed, 0x97, 0xa5, 0x25, 0x5a, 0xb7, 0x55, 0xc5, 0x13, 0x07, 0x85, 0x27, 0x40, 0xed, 0xb8, 0xa0, 0x26, 0x13, 0x44, 0x0c, 0xfc, 0xcc, 0x5a, 0x09, 0xe5, 0x44, 0xb5, 0x63, 0xa1, 0x43, 0x51, 0x23, 0x4f, 0x17, 0x21, 0x89, 0x2e, 0x58, 0xfd, 0xf9, 0x63, 0x74, 0x04, 0x70, 0x1e, 0x7d, 0xd0, 0x66, 0xba, 0x40, 0x5e, 0x45, 0xdc, 0x39, 0x7c, 0x53, 0x0f, 0xa8, 0x38, 0xb2, 0x13, 0x99, 0x27, 0xd9, 0x4a, 0x51, 0xe9, 0x9f, 0x2a, 0x92, 0xbb, 0x9c, 0x90, 0xab, 0xfd, 0xf1, 0xb7, 0x40, 0x05, 0xa9, 0x7a, 0x20, 0x63, 0x36, 0xc1, 0xef, 0xb9, 0xad, 0xa2, 0xe0, 0x1d, 0x20, 0x4f, 0xb2, 0x34, 0xbd, 0xea, 0x07, 0xac, 0x21, 0xce, 0xf6, 0x8a, 0xa2, 0x9e, 0xcd, 0xfa }; uint32_t toserver_app_data_buf_len = sizeof(toserver_app_data_buf); int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; SSLState *ssl_state = NULL; int r = 0; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_TLS; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; ssl_state:client_hello; " "sid:1;)"); if (s == NULL) goto end; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " "ssl_state:client_hello | server_hello; " "sid:2;)"); if (s == NULL) goto end; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " "ssl_state:client_hello | server_hello | " "client_keyx; sid:3;)"); if (s == NULL) goto end; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " "ssl_state:client_hello | server_hello | " "client_keyx | server_keyx; sid:4;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } ssl_state = f.alstate; if (ssl_state == NULL) { printf("no ssl state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; if (PacketAlertCheck(p, 2)) goto end; if (PacketAlertCheck(p, 3)) goto end; if (PacketAlertCheck(p, 4)) goto end; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, shello_buf_len); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; if (!PacketAlertCheck(p, 2)) goto end; if (PacketAlertCheck(p, 3)) goto end; if (PacketAlertCheck(p, 4)) goto end; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; if (PacketAlertCheck(p, 2)) goto end; if (!PacketAlertCheck(p, 3)) goto end; if (PacketAlertCheck(p, 4)) goto end; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; if (PacketAlertCheck(p, 2)) goto end; if (PacketAlertCheck(p, 3)) goto end; if (PacketAlertCheck(p, 4)) goto end; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, toserver_app_data_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; if (PacketAlertCheck(p, 2)) goto end; if (PacketAlertCheck(p, 3)) goto end; if (PacketAlertCheck(p, 4)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void DetectSslStateRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectSslStateTest01", DetectSslStateTest01, 1); UtRegisterTest("DetectSslStateTest02", DetectSslStateTest02, 1); UtRegisterTest("DetectSslStateTest03", DetectSslStateTest03, 1); UtRegisterTest("DetectSslStateTest04", DetectSslStateTest04, 1); UtRegisterTest("DetectSslStateTest05", DetectSslStateTest05, 1); UtRegisterTest("DetectSslStateTest06", DetectSslStateTest06, 1); UtRegisterTest("DetectSslStateTest07", DetectSslStateTest07, 1); #endif return; } suricata-1.4.7/src/flow-private.h0000644000000000000000000000530612253546156013621 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __FLOW_PRIVATE_H__ #define __FLOW_PRIVATE_H__ #include "flow-hash.h" #include "flow-queue.h" #include "util-atomic.h" /* global flow flags */ /** Flow engine is in emergency mode. This means it doesn't have enough spare * flows for new flows and/or it's memcap limit it reached. In this state the * flow engine with evaluate flows with lower timeout settings. */ #define FLOW_EMERGENCY 0x01 /* Flow Time out values */ #define FLOW_DEFAULT_NEW_TIMEOUT 30 #define FLOW_DEFAULT_EST_TIMEOUT 300 #define FLOW_DEFAULT_CLOSED_TIMEOUT 0 #define FLOW_IPPROTO_TCP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_TCP_EST_TIMEOUT 300 #define FLOW_IPPROTO_UDP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_UDP_EST_TIMEOUT 300 #define FLOW_IPPROTO_ICMP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_ICMP_EST_TIMEOUT 300 #define FLOW_DEFAULT_EMERG_NEW_TIMEOUT 10 #define FLOW_DEFAULT_EMERG_EST_TIMEOUT 100 #define FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT 0 #define FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT 10 #define FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT 100 #define FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT 10 #define FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT 100 #define FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT 10 #define FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT 100 enum { FLOW_PROTO_DEFAULT = 0, FLOW_PROTO_TCP, FLOW_PROTO_UDP, FLOW_PROTO_ICMP, FLOW_PROTO_SCTP, /* should be last */ FLOW_PROTO_MAX, }; /* * Variables */ /** FlowProto specific timeouts and free/state functions */ FlowProto flow_proto[FLOW_PROTO_MAX]; /** spare/unused/prealloced flows live here */ FlowQueue flow_spare_q; FlowBucket *flow_hash; FlowConfig flow_config; /** flow memuse counter (atomic), for enforcing memcap limit */ SC_ATOMIC_DECLARE(long long unsigned int, flow_memuse); //#define FLOWBITS_STATS #ifdef FLOWBITS_STATS uint64_t flowbits_memuse; uint64_t flowbits_memuse_max; uint32_t flowbits_added; uint32_t flowbits_removed; SCMutex flowbits_mutex; #endif /* FLOWBITS_STATS */ #endif /* __FLOW_PRIVATE_H__ */ suricata-1.4.7/src/util-classification-config.h0000644000000000000000000000427612253546156016420 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_CLASSIFICATION_CONFIG_H__ #define __UTIL_CLASSIFICATION_CONFIG_H__ /** * \brief Container for a Classtype from the Classification.config file. */ typedef struct SCClassConfClasstype_ { /* The index of the classification within classification.confg */ uint8_t classtype_id; /* The classtype name. This is the primary key for a Classification. */ char *classtype; /* Description for a classification. Would be used while printing out * the classification info for a Signature, by the fast-log module. */ char *classtype_desc; /* The priority this classification type carries */ int priority; } SCClassConfClasstype; SCClassConfClasstype *SCClassConfAllocClasstype(uint8_t, const char *, const char *, int); void SCClassConfDeAllocClasstype(SCClassConfClasstype *); void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *); SCClassConfClasstype *SCClassConfGetClasstype(const char *, DetectEngineCtx *); void SCClassConfDeInitContext(DetectEngineCtx *); void SCClassConfRegisterTests(void); /* for unittests */ void SCClassConfGenerateValidDummyClassConfigFD01(void); void SCClassConfGenerateInValidDummyClassConfigFD02(void); void SCClassConfGenerateInValidDummyClassConfigFD03(void); void SCClassConfDeleteDummyClassificationConfigFD(void); #endif /* __UTIL_CLASSIFICATION_CONFIG_H__ */ suricata-1.4.7/src/detect-asn1.c0000644000000000000000000012425012253546156013305 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file detect-asn1.c * * \author Pablo Rincon Crespo * * Implements "asn1" keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "flow.h" #include "detect-asn1.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-byte.h" #include "util-debug.h" #include "util-decode-asn1.h" /* delimiters for functions/arguments */ const char *ASN_DELIM = " \t,\n"; int DetectAsn1Match(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectAsn1Setup (DetectEngineCtx *, Signature *, char *); void DetectAsn1RegisterTests(void); void DetectAsn1Free(void *); /** * \brief Registration function for asn1 */ void DetectAsn1Register(void) { sigmatch_table[DETECT_ASN1].name = "asn1"; sigmatch_table[DETECT_ASN1].Match = DetectAsn1Match; sigmatch_table[DETECT_ASN1].Setup = DetectAsn1Setup; sigmatch_table[DETECT_ASN1].Free = DetectAsn1Free; sigmatch_table[DETECT_ASN1].RegisterTests = DetectAsn1RegisterTests; return; } /** * \brief The main checks are done here * This function implements the detection of the following options: * - oversize_length * - bitstring_overflow * - double_overflow * We can add more checks here easily since we have all the data of the * node avaliable. If we need all the tree, we can just pass the * ASN1 ctx as argument and perform the checks here * \param node pointer to the Asn1Node to inspect * \param ad pointer to the parsed options of the asn1 keyword (which hold the * checks that we want to perform, and the lenght of oversize check * \retval 1 if any of the options match, 0 if not */ static uint8_t DetectAsn1Checks(Asn1Node *node, DetectAsn1Data *ad) { /* oversize_length will check if a node has a length greater than * the user supplied length */ if (ad->flags & ASN1_OVERSIZE_LEN) { if (node->len.len > ad->oversize_length || node->data.len > ad->oversize_length) return 1; } /* 8.6 */ /* bitstring_overflow check a malformed option where the number of bits * to ignore is greater than the length decoded (in bits) */ if (ad->flags & ASN1_BITSTRING_OVF) { if (node->id.class_tag == ASN1_BER_CLASS_UNIV && node->id.tag_num == ASN1_UNITAG_BIT_STRING && node->id.tag_type == ASN1_TAG_TYPE_PRIMITIVE) { if (node->len.len > 0 && node->data.ptr != NULL && (node->len.len) * 8 < (uint8_t) *node->data.ptr) { return 1; } } } /* double_overflow checks a known issue that affect the MSASN1 library * when decoding double/real types. If the endoding is ASCII, * and the buffer is greater than 256, the array is overflown */ if (ad->flags & ASN1_DOUBLE_OVF) { if (node->id.class_tag == ASN1_BER_CLASS_UNIV && node->id.tag_num == ASN1_UNITAG_REAL && node->id.tag_type == ASN1_TAG_TYPE_PRIMITIVE) { if (node->len.len > 0 && node->data.ptr != NULL && !((uint8_t) *node->data.ptr & 0xC0) && (node->len.len > 256 || node->data.len > 256)) { return 1; } } } /* Good to know :) */ return 0; } /** * \brief This function will decode the asn1 data and inspect the resulting * nodes to detect if any of the specified checks match this data * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectAsn1Data * * \retval 0 no match * \retval 1 match */ int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { uint8_t ret = 0; if (p->payload_len == 0) { /* No error, parser done, no data in bounds to decode */ return 0; } DetectAsn1Data *ad = (DetectAsn1Data *)m->ctx; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; if (ad->flags & ASN1_ABSOLUTE_OFFSET) { SCAsn1CtxInit(ac, p->payload + ad->absolute_offset, p->payload_len - ad->absolute_offset); } else if (ad->flags & ASN1_RELATIVE_OFFSET) { SCAsn1CtxInit(ac, p->payload + ad->relative_offset, p->payload_len - ad->relative_offset); } else { SCAsn1CtxInit(ac, p->payload, p->payload_len); } SCAsn1Decode(ac, ac->cur_frame); /* Ok, now we have all the data. Let's check the nodes */ if (ac->cur_frame > 0 || (ac->asn1_stack[0] != NULL && ac->asn1_stack[0]->id.ptr != NULL)) { /* We spect at least one node */ uint16_t n_iter = 0; ret = 0; for (; n_iter <= ac->cur_frame; n_iter++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); if (node == NULL || node->id.ptr == NULL) continue; /* Should not happen */ ret = DetectAsn1Checks(node, ad); /* Got a match? */ if (ret == 1) break; } } SCAsn1CtxDestroy(ac); return ret; } /** * \brief This function is used to parse asn1 options passed via asn1: keyword * * \param asn1str Pointer to the user provided asn1 options * * \retval fd pointer to DetectAsn1Data on success * \retval NULL on failure */ DetectAsn1Data *DetectAsn1Parse(char *asn1str) { DetectAsn1Data *fd = NULL; char *tok = NULL; uint32_t ov_len = 0; uint32_t abs_off = 0; int32_t rel_off = 0; uint8_t flags = 0; tok = strtok(asn1str, ASN_DELIM); if (tok == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed asn1 argument: %s", asn1str); return NULL; } while (tok != NULL) { if (strcasecmp("bitstring_overflow", tok) == 0) { /* No arg here, just set the flag */ flags |= ASN1_BITSTRING_OVF; } else if (strcasecmp("double_overflow", tok) == 0) { /* No arg here, just set the flag */ flags |= ASN1_DOUBLE_OVF; } else if (strcasecmp("oversize_length", tok) == 0) { flags |= ASN1_OVERSIZE_LEN; /* get the param */ tok = strtok(NULL, ASN_DELIM); if ( tok == NULL || ByteExtractStringUint32(&ov_len, 10, 0, tok) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed value for " "oversize_length: %s", tok); goto error; } } else if (strcasecmp("absolute_offset", tok) == 0) { flags |= ASN1_ABSOLUTE_OFFSET; /* get the param */ tok = strtok(NULL, ASN_DELIM); if (tok == NULL || ByteExtractStringUint32(&abs_off, 10, 0, tok) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed value for " "absolute_offset: %s", tok); goto error; } } else if (strcasecmp("relative_offset",tok) == 0) { flags |= ASN1_RELATIVE_OFFSET; /* get the param */ tok = strtok(NULL, ASN_DELIM); if (tok == NULL || ByteExtractStringInt32(&rel_off, 10, 0, tok) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed value for " "relative_offset: %s", tok); goto error; } } else { SCLogError(SC_ERR_INVALID_VALUE, "Malformed asn1 argument: %s", asn1str); return NULL; } tok = strtok(NULL, ASN_DELIM); } fd = SCMalloc(sizeof(DetectAsn1Data)); if (unlikely(fd == NULL)) { exit(EXIT_FAILURE); } memset(fd, 0x00, sizeof(DetectAsn1Data)); fd->flags = flags; fd->oversize_length = ov_len; /* Length argument if needed */ fd->absolute_offset = abs_off; /* Length argument if needed */ fd->relative_offset = rel_off; /* Length argument if needed */ return fd; error: return NULL; } /** * \brief this function is used to add the parsed asn1 data into * the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param asn1str pointer to the user provided asn1 options * * \retval 0 on Success * \retval -1 on Failure */ int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) { DetectAsn1Data *ad = NULL; SigMatch *sm = NULL; ad = DetectAsn1Parse(asn1str); if (ad == 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_ASN1; sm->ctx = (void *)ad; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (ad != NULL) DetectAsn1Free(ad); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectAsn1Data * * \param ad pointer to DetectAsn1Data */ void DetectAsn1Free(void *ptr) { DetectAsn1Data *ad = (DetectAsn1Data *)ptr; SCFree(ad); } #ifdef UNITTESTS /** * \test DetectAsn1TestParse01 check that we parse oversize_length correctly */ int DetectAsn1TestParse01(void) { int result = 0; char str[] = "oversize_length 1024"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL) { if (ad->oversize_length == 1024 && (ad->flags & ASN1_OVERSIZE_LEN)) { result = 1; } DetectAsn1Free(ad); } return result; } /** * \test DetectAsn1TestParse02 check that we parse absolute_offset correctly */ int DetectAsn1TestParse02(void) { int result = 0; DetectAsn1Data *ad = NULL; char str[] = "absolute_offset 1024"; ad = DetectAsn1Parse(str); if (ad != NULL && ad->absolute_offset == 1024 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1TestParse03 check that we parse relative_offset correctly */ int DetectAsn1TestParse03(void) { int result = 0; char str[] = "relative_offset 1024"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && ad->relative_offset == 1024 && (ad->flags & ASN1_RELATIVE_OFFSET)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1TestParse04 check that we parse bitstring_overflow correctly */ int DetectAsn1TestParse04(void) { int result = 0; char str[] = "bitstring_overflow"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && (ad->flags & ASN1_BITSTRING_OVF)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1TestParse05 check that we parse double_overflow correctly */ int DetectAsn1TestParse05(void) { int result = 0; char str[] = "double_overflow"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && (ad->flags & ASN1_DOUBLE_OVF)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1TestParse06 check that we fail if a needed arg is not given */ int DetectAsn1TestParse06(void) { int result = 1; char str[] = "absolute_offset"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL) { DetectAsn1Free(ad); result = 0; } return result; } /** * \test DetectAsn1TestParse07 check that we fail if a needed arg is not given */ int DetectAsn1TestParse07(void) { int result = 1; char str[] = "relative_offset"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL) { DetectAsn1Free(ad); result = 0; } return result; } /** * \test DetectAsn1TestParse08 check that we fail if a needed arg is not given */ int DetectAsn1TestParse08(void) { int result = 1; char str[] = "oversize_length"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL) { DetectAsn1Free(ad); result = 0; } return result; } /** * \test DetectAsn1TestParse09 test that we break on invalid options */ int DetectAsn1TestParse09(void) { int result = 1; DetectAsn1Data *fd = NULL; char str[] = "oversize_length 1024, lalala 360"; fd = DetectAsn1Parse(str); if (fd != NULL) { result = 0; DetectAsn1Free(fd); } return result; } /** * \test DetectAsn1TestParse10 test that we break with a empty string */ int DetectAsn1TestParse10(void) { int result = 1; DetectAsn1Data *fd = NULL; char str[] = ""; fd = DetectAsn1Parse(str); if (fd != NULL) { result = 0; DetectAsn1Free(fd); } return result; } /** * \test DetectAsn1TestParse11 check for combinations of keywords */ int DetectAsn1TestParse11(void) { int result = 0; char str[] = "oversize_length 1024, relative_offset 10"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && ad->oversize_length == 1024 && (ad->flags & ASN1_OVERSIZE_LEN) && ad->relative_offset == 10 && (ad->flags & ASN1_RELATIVE_OFFSET)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1TestParse12 check for combinations of keywords */ int DetectAsn1TestParse12(void) { int result = 0; char str[] = "oversize_length 1024 absolute_offset 10"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && ad->oversize_length == 1024 && (ad->flags & ASN1_OVERSIZE_LEN) && ad->absolute_offset == 10 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1TestParse13 check for combinations of keywords */ int DetectAsn1TestParse13(void) { int result = 0; char str[] = "oversize_length 1024 absolute_offset 10, bitstring_overflow"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && ad->oversize_length == 1024 && (ad->flags & ASN1_OVERSIZE_LEN) && (ad->flags & ASN1_BITSTRING_OVF) && ad->absolute_offset == 10 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1TestParse14 check for combinations of keywords */ int DetectAsn1TestParse14(void) { int result = 0; char str[] = "double_overflow, oversize_length 1024 absolute_offset 10," " bitstring_overflow"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && ad->oversize_length == 1024 && (ad->flags & ASN1_OVERSIZE_LEN) && (ad->flags & ASN1_BITSTRING_OVF) && (ad->flags & ASN1_DOUBLE_OVF) && ad->absolute_offset == 10 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1TestParse15 check for combinations of keywords */ int DetectAsn1TestParse15(void) { int result = 0; char str[] = "double_overflow, oversize_length 1024 relative_offset 10," " bitstring_overflow"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && ad->oversize_length == 1024 && (ad->flags & ASN1_OVERSIZE_LEN) && (ad->flags & ASN1_BITSTRING_OVF) && (ad->flags & ASN1_DOUBLE_OVF) && ad->relative_offset == 10 && (ad->flags & ASN1_RELATIVE_OFFSET)) { DetectAsn1Free(ad); result = 1; } return result; } /** * \test DetectAsn1Test01 Ensure that the checks work when they should */ int DetectAsn1Test01(void) { int result = 0; /* Match if any of the nodes after offset 0 has greater length than 10 */ char str[] = "oversize_length 132 absolute_offset 0"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && ad->oversize_length == 132 && (ad->flags & ASN1_OVERSIZE_LEN) && ad->absolute_offset == 0 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { // Example from the specification X.690-0207 Appendix A.3 uint8_t *str = (uint8_t*) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint16_t len = strlen((char *)str)-1; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); /* The first node has length 133, so it should match the oversize */ if (ac->cur_frame > 0) { /* We spect at least one node */ uint16_t n_iter = 0; for (; n_iter <= ac->cur_frame; n_iter++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); if (node == NULL || node->id.ptr == NULL) continue; /* Should not happen */ result = DetectAsn1Checks(node, ad); /* Got a match? */ if (result == 1) break; } } SCAsn1CtxDestroy(ac); DetectAsn1Free(ad); } if (result == 0) { printf("Error, oversize_length should match the first node: "); } return result; } /** * \test DetectAsn1Test02 Ensure that the checks work when they should */ int DetectAsn1Test02(void) { int result = 0; /* Match if any of the nodes has the bitstring overflow condition */ char str[] = "oversize_length 133, absolute_offset 0"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && ad->oversize_length == 133 && (ad->flags & ASN1_OVERSIZE_LEN) && ad->absolute_offset == 0 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { // Example from the specification X.690-0207 Appendix A.3 uint8_t *str = (uint8_t*) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint16_t len = strlen((char *)str)-1; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); /* The first node has length 133, so it should match the oversize */ if (ac->cur_frame > 0) { /* We spect at least one node */ uint16_t n_iter = 0; for (; n_iter <= ac->cur_frame; n_iter++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); if (node == NULL || node->id.ptr == NULL) continue; /* Should not happen */ result |= DetectAsn1Checks(node, ad); } } /* Got a match? We don't have nodes greater than 133, it should not */ if (result == 1) { printf("Error, oversize_length should not match" " any of the nodes: "); result = 0; } else { result = 1; } SCAsn1CtxDestroy(ac); DetectAsn1Free(ad); } return result; } /** * \test DetectAsn1Test03 Ensure that the checks work when they should */ int DetectAsn1Test03(void) { int result = 0; /* Match if any of the nodes after offset 0 has a bitstring overflow */ char str[] = "bitstring_overflow, absolute_offset 0"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && (ad->flags & ASN1_BITSTRING_OVF) && ad->absolute_offset == 0 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { /* Let's say tagnum bitstring, primitive, and as universal tag, * and then length = 1 octet, but the next octet specify to ignore * the last 256 bits... (let's match!) */ uint8_t *str = (uint8_t*) "\x03\x01\xFF"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint16_t len = 3; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); if (ac->cur_frame > 0 || ac->asn1_stack[0]->id.ptr != NULL) { /* We spect at least one node */ uint16_t n_iter = 0; for (; n_iter <= ac->cur_frame; n_iter++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); if (node == NULL || node->id.ptr == NULL) continue; /* Should not happen */ result = DetectAsn1Checks(node, ad); /* Got a match? */ if (result == 1) break; } } SCAsn1CtxDestroy(ac); DetectAsn1Free(ad); } if (result == 0) { printf("Error, bitstring_overflow should match the first node: "); } return result; } /** * \test DetectAsn1Test04 Ensure that the checks work when they should */ int DetectAsn1Test04(void) { int result = 0; /* Match if any of the nodes after offset 0 has a bitstring overflow */ char str[] = "bitstring_overflow, absolute_offset 0"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && (ad->flags & ASN1_BITSTRING_OVF) && ad->absolute_offset == 0 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { /* Let's say tagnum bitstring, primitive, and as universal tag, * and then length = 1 octet, but the next octet specify to ignore * the last 7 bits... (should not match) */ uint8_t *str = (uint8_t*) "\x03\x01\x07"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint16_t len = 3; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); if (ac->cur_frame > 0 || ac->asn1_stack[0]->id.ptr != NULL) { /* We spect at least one node */ uint16_t n_iter = 0; for (; n_iter <= ac->cur_frame; n_iter++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); if (node == NULL || node->id.ptr == NULL) continue; /* Should not happen */ result = DetectAsn1Checks(node, ad); /* Got a match? */ if (result == 1) break; } } SCAsn1CtxDestroy(ac); DetectAsn1Free(ad); } if (result == 1) { printf("Error, bitstring_overflog should not match any node: "); result = 0; } else { result = 1; } return result; } /** * \test DetectAsn1Test05 Ensure that the checks work when they should */ int DetectAsn1Test05(void) { int result = 0; /* Match if any of the nodes after offset 0 has a double overflow */ char str[] = "double_overflow, absolute_offset 0"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && (ad->flags & ASN1_DOUBLE_OVF) && ad->absolute_offset == 0 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { /* Let's say tag num 9 (type Real), and encoded as ASCII, with length * 257, then we must match */ uint8_t str[261]; /* universal class, primitive type, tag_num = 9 (Data type Real) */ str[0] = '\x09'; /* length, definite form, 2 octets */ str[1] = '\x82'; /* length is the sum of the following octets (257): */ str[2] = '\xFE'; str[3] = '\x03'; /* Fill the content of the number */ uint16_t i = 4; for (; i < 257;i++) str[i] = '\x05'; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint16_t len = 261; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); if (ac->cur_frame > 0 || ac->asn1_stack[0]->id.ptr != NULL) { /* We spect at least one node */ uint16_t n_iter = 0; for (; n_iter <= ac->cur_frame; n_iter++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); if (node == NULL || node->id.ptr == NULL) continue; /* Should not happen */ result = DetectAsn1Checks(node, ad); /* Got a match? */ if (result == 1) break; } } SCAsn1CtxDestroy(ac); DetectAsn1Free(ad); } if (result == 0) { printf("Error, double_overflow should match the first node: "); } return result; } /** * \test DetectAsn1Test06 Ensure that the checks work when they should */ int DetectAsn1Test06(void) { int result = 0; /* Match if any of the nodes after offset 0 has a double overflow */ char str[] = "double_overflow, absolute_offset 0"; DetectAsn1Data *ad = NULL; ad = DetectAsn1Parse(str); if (ad != NULL && (ad->flags & ASN1_DOUBLE_OVF) && ad->absolute_offset == 0 && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { /* Let's say tag num 9 (type Real), and encoded as ASCII, with length * 256, which fit in the buffer, so it should not match */ uint8_t str[260]; /* universal class, primitive type, tag_num = 9 (Data type Real) */ str[0] = '\x09'; /* length, definite form, 2 octets */ str[1] = '\x82'; /* length is the sum of the following octets (256): */ str[2] = '\xFE'; str[3] = '\x02'; /* Fill the content of the number */ uint16_t i = 4; for (; i < 256;i++) str[i] = '\x05'; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint16_t len = 260; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); if (ac->cur_frame > 0 || ac->asn1_stack[0]->id.ptr != NULL) { /* We spect at least one node */ uint16_t n_iter = 0; for (; n_iter <= ac->cur_frame; n_iter++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); if (node == NULL || node->id.ptr == NULL) continue; /* Should not happen */ result = DetectAsn1Checks(node, ad); /* Got a match? */ if (result == 1) break; } } SCAsn1CtxDestroy(ac); DetectAsn1Free(ad); } if (result == 1) { printf("Error, double_overflow should not match any node: "); result = 0 ; } else { result = 1; } return result; } /** * \test DetectAsn1TestReal01 Ensure that all works together */ int DetectAsn1TestReal01(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717" "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones" "\xA0\x0A\x43\x08""19590717"; uint16_t buflen = strlen((char *)buf) - 1; /* Check the start with AA (this is to test the relative_offset keyword) */ uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717" "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones" "\xA0\x0A\x43\x08""19590717"; uint16_t buflen2 = strlen((char *)buf2) - 1; Packet *p[2]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf2, buflen2, IPPROTO_TCP); if (p[0] == NULL || p[1] == NULL) goto end; char *sigs[3]; sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; " "content:\"Pablo\"; asn1:absolute_offset 0, " "oversize_length 130; sid:1;)"; sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; " "content:\"AA\"; asn1:relative_offset 2, " "oversize_length 130; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; " "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[2][3] = { /* packet 0 match sid 1 */ {1, 0, 0}, /* packet 1 match sid 2 */ {0, 1, 0}}; /* None of the packets should match sid 3 */ result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3); UTHFreePackets(p, 2); end: return result; } /** * \test DetectAsn1TestReal02 Ensure that all works together */ int DetectAsn1TestReal02(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717" "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones" "\xA0\x0A\x43\x08""19590717"; uint16_t buflen = strlen((char *)buf) - 1; /* Check the start with AA (this is to test the relative_offset keyword) */ uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717" "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones" "\xA0\x0A\x43\x08""19590717"; uint16_t buflen2 = strlen((char *)buf2) - 1; Packet *p[2]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf2, buflen2, IPPROTO_TCP); if (p[0] == NULL || p[1] == NULL) goto end; char *sigs[3]; sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; " "content:\"Pablo\"; asn1:absolute_offset 0, " "oversize_length 140; sid:1;)"; sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; " "content:\"AA\"; asn1:relative_offset 2, " "oversize_length 140; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; " "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[2][3] = { {0, 0, 0}, {0, 0, 0}}; /* None of the packets should match */ result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3); UTHFreePackets(p, 2); end: return result; } /** * \test DetectAsn1TestReal03 Ensure that all works together */ int DetectAsn1TestReal03(void) { int result = 0; uint8_t buf[261] = ""; /* universal class, primitive type, tag_num = 9 (Data type Real) */ buf[0] = '\x09'; /* length, definite form, 2 octets */ buf[1] = '\x82'; /* length is the sum of the following octets (257): */ buf[2] = '\xFE'; buf[3] = '\x03'; /* Fill the content of the number */ uint16_t i = 4; for (; i < 257;i++) buf[i] = '\x05'; uint16_t buflen = 261; /* Check the start with AA (this is to test the relative_offset keyword) */ uint8_t *buf2 = (uint8_t *) "AA\x03\x01\xFF"; uint16_t buflen2 = 5; Packet *p[2] = { NULL, NULL }; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf2, buflen2, IPPROTO_TCP); if (p[0] == NULL || p[1] == NULL) goto end; char *sigs[3]; /* This should match the first packet */ sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; " "asn1:absolute_offset 0, double_overflow; sid:1;)"; /* This should match the second packet */ sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; " "asn1:relative_offset 2, bitstring_overflow," "oversize_length 140; sid:2;)"; /* This should match no packet */ sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; " "asn1: oversize_length 2000; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[2][3] = {{1, 0, 0}, {0, 1, 0}}; result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3); UTHFreePackets(p, 2); end: return result; } /** * \test DetectAsn1TestReal04 like the real test 02, but modified the * relative offset to check negative offset values, in this case * start decoding from -7 bytes respect the content match "John" */ int DetectAsn1TestReal04(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717" "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones" "\xA0\x0A\x43\x08""19590717"; uint16_t buflen = strlen((char *)buf) - 1; /* Check the start with AA (this is to test the relative_offset keyword) */ uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717" "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones" "\xA0\x0A\x43\x08""19590717"; uint16_t buflen2 = strlen((char *)buf2) - 1; Packet *p[2]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf2, buflen2, IPPROTO_TCP); if (p[0] == NULL || p[1] == NULL) goto end; char *sigs[3]; sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; " "content:\"Pablo\"; asn1:absolute_offset 0, " "oversize_length 140; sid:1;)"; sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; " "content:\"John\"; asn1:relative_offset -7, " "oversize_length 140; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; " "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[2][3] = { {0, 0, 0}, {0, 0, 0}}; /* None of the packets should match */ result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3); UTHFreePackets(p, 2); end: return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectAsn1 */ void DetectAsn1RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectAsn1TestParse01", DetectAsn1TestParse01, 1); UtRegisterTest("DetectAsn1TestParse02", DetectAsn1TestParse02, 1); UtRegisterTest("DetectAsn1TestParse03", DetectAsn1TestParse03, 1); UtRegisterTest("DetectAsn1TestParse04", DetectAsn1TestParse04, 1); UtRegisterTest("DetectAsn1TestParse05", DetectAsn1TestParse05, 1); UtRegisterTest("DetectAsn1TestParse06", DetectAsn1TestParse06, 1); UtRegisterTest("DetectAsn1TestParse07", DetectAsn1TestParse07, 1); UtRegisterTest("DetectAsn1TestParse08", DetectAsn1TestParse08, 1); UtRegisterTest("DetectAsn1TestParse09", DetectAsn1TestParse09, 1); UtRegisterTest("DetectAsn1TestParse10", DetectAsn1TestParse10, 1); UtRegisterTest("DetectAsn1TestParse11", DetectAsn1TestParse11, 1); UtRegisterTest("DetectAsn1TestParse12", DetectAsn1TestParse12, 1); UtRegisterTest("DetectAsn1TestParse13", DetectAsn1TestParse13, 1); UtRegisterTest("DetectAsn1TestParse14", DetectAsn1TestParse14, 1); UtRegisterTest("DetectAsn1TestParse15", DetectAsn1TestParse15, 1); UtRegisterTest("DetectAsn1Test01 - oversize_len", DetectAsn1Test01, 1); UtRegisterTest("DetectAsn1Test02 - oversize_len", DetectAsn1Test02, 1); UtRegisterTest("DetectAsn1Test03 - bitstring_ovf", DetectAsn1Test03, 1); UtRegisterTest("DetectAsn1Test04 - bitstring_ovf", DetectAsn1Test04, 1); UtRegisterTest("DetectAsn1Test05 - double_ovf", DetectAsn1Test05, 1); UtRegisterTest("DetectAsn1Test06 - double_ovf", DetectAsn1Test06, 1); UtRegisterTest("DetectAsn1TestReal01", DetectAsn1TestReal01, 1); UtRegisterTest("DetectAsn1TestReal02", DetectAsn1TestReal02, 1); UtRegisterTest("DetectAsn1TestReal03", DetectAsn1TestReal03, 1); UtRegisterTest("DetectAsn1TestReal04", DetectAsn1TestReal04, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/runmode-erf-dag.c0000644000000000000000000000720712253546156014153 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-erf-dag.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "util-runmodes.h" static const char *default_mode; static int DagConfigGetThreadCount(void *conf) { return 1; } static void *ParseDagConfig(const char *iface) { return (void *)iface; } const char *RunModeErfDagGetDefaultMode(void) { return default_mode; } void RunModeErfDagRegister(void) { default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_DAG, "autofp", "Multi threaded DAG mode. Packets from " "each flow are assigned to a single detect " "thread, unlike \"dag_auto\" where packets " "from the same flow can be processed by any " "detect thread", RunModeIdsErfDagAutoFp); RunModeRegisterNewRunMode(RUNMODE_DAG, "single", "Singled threaded DAG mode", RunModeIdsErfDagSingle); RunModeRegisterNewRunMode(RUNMODE_DAG, "workers", "Workers DAG mode, each thread does all " " tasks from acquisition to logging", RunModeIdsErfDagWorkers); return; } int RunModeIdsErfDagSingle(DetectEngineCtx *de_ctx) { int ret; SCEnter(); RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetLiveCaptureSingle(de_ctx, ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", "RxDAG", NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG single runmode failed to start"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsDagSingle initialised"); SCReturnInt(0); } int RunModeIdsErfDagAutoFp(DetectEngineCtx *de_ctx) { int ret; SCEnter(); RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetLiveCaptureAutoFp(de_ctx, ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", "RxDAG", NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG autofp runmode failed to start"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsDagAutoFp initialised"); SCReturnInt(0); } int RunModeIdsErfDagWorkers(DetectEngineCtx *de_ctx) { int ret; SCEnter(); RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetLiveCaptureWorkers(de_ctx, ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", "RxDAG", NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG workers runmode failed to start"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsErfDagWorkers initialised"); SCReturnInt(0); } suricata-1.4.7/src/util-strlcatu.c0000644000000000000000000000526212253546156014012 00000000000000/* * Copyright (c) 1998 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: strlcatu.c,v 1.4 2003/10/20 15:03:27 chrisgreen Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_STRLCAT #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcat.c,v 1.5 2001/01/13 16:17:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(initial dst) + strlen(src); if retval >= siz, * truncation occurred. */ size_t strlcat(dst, src, siz) char *dst; const char *src; size_t siz; { register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif suricata-1.4.7/src/detect-replace.c0000644000000000000000000006135512253546156014064 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond * * Replace part of the detection engine. * * If previous filter is of content type, replace can be used to change * the matched part to a new value. */ #include "suricata-common.h" #include "runmodes.h" extern int run_mode; #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-byte-extract.h" #include "detect-replace.h" #include "app-layer.h" #include "detect-engine-mpm.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "util-checksum.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "flow-var.h" #include "util-debug.h" static int DetectReplaceSetup (DetectEngineCtx *, Signature *, char *); void DetectReplaceRegisterTests(void); void DetectReplaceRegister (void) { sigmatch_table[DETECT_REPLACE].name = "replace"; sigmatch_table[DETECT_REPLACE].Match = NULL; sigmatch_table[DETECT_REPLACE].Setup = DetectReplaceSetup; sigmatch_table[DETECT_REPLACE].Free = NULL; sigmatch_table[DETECT_REPLACE].RegisterTests = DetectReplaceRegisterTests; sigmatch_table[DETECT_REPLACE].flags |= SIGMATCH_PAYLOAD; } int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) { char *str = NULL; uint16_t len = 0; int flags; SigMatch *pm = NULL; DetectContentData *ud = NULL; int ret = DetectContentDataParse("replace", replacestr, &str, &len, &flags); if (ret == -1) goto error; if (flags & DETECT_CONTENT_NEGATED) { SCLogError(SC_ERR_INVALID_VALUE, "Can't negate replacement string: %s", replacestr); goto error; } switch (run_mode) { case RUNMODE_NFQ: case RUNMODE_IPFW: break; default: SCLogWarning(SC_ERR_RUNMODE, "Can't use 'replace' keyword in non IPS mode: %s", s->sig_str); /* this is a success, having the alert is interesting */ return 0; } /* add to the latest "content" keyword from either dmatch or pmatch */ pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "replace needs" "preceding content option for raw sig"); SCFree(str); return -1; } /* we can remove this switch now with the unified structure */ ud = (DetectContentData *)pm->ctx; if (ud == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); SCFree(str); return -1; } if (ud->flags & DETECT_CONTENT_NEGATED) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a replacement"); goto error; } if (ud->content_len != len) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a content " "length different from replace length"); goto error; } ud->replace = SCMalloc(len); if (ud->replace == NULL) { goto error; } memcpy(ud->replace, str, len); ud->replace_len = len; ud->flags |= DETECT_CONTENT_REPLACE; /* want packet matching only won't be able to replace data with * a flow. */ s->flags |= SIG_FLAG_REQUIRE_PACKET; SCFree(str); return 0; error: SCFree(str); return -1; } DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t *found, DetectContentData *cd) { DetectReplaceList *newlist; if (cd->content_len != cd->replace_len) return NULL; SCLogDebug("replace: Adding match"); newlist = SCMalloc(sizeof(DetectReplaceList)); if (unlikely(newlist == NULL)) return NULL; newlist->found = found; newlist->cd = cd; newlist->next = NULL; if (replist) { replist->next = newlist; return replist; } else return newlist; } void DetectReplaceExecute(Packet *p, DetectReplaceList *replist) { DetectReplaceList *tlist = NULL; if (p == NULL) return; SCLogDebug("replace: Executing match"); while(replist) { memcpy(replist->found, replist->cd->replace, replist->cd->replace_len); SCLogDebug("replace: injecting '%s'", replist->cd->replace); p->flags |= PKT_STREAM_MODIFIED; ReCalculateChecksum(p); tlist = replist; replist = replist->next; SCFree(tlist); } } void DetectReplaceFree(DetectReplaceList *replist) { DetectReplaceList *tlist = NULL; while(replist) { SCLogDebug("replace: Freing match"); tlist = replist; replist = replist->next; SCFree(tlist); } } #ifdef UNITTESTS /* UNITTESTS */ /** * \test Test packet Matches * \param raw_eth_pkt pointer to the ethernet packet * \param pktsize size of the packet * \param sig pointer to the signature to test * \param sid sid number of the signature * \retval return 1 if match * \retval return 0 if not */ int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, uint32_t sid, uint8_t *pp, uint16_t *len) { int result = 0; Packet *p = NULL; p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; if (pp == NULL) { SCLogDebug("replace: looks like a second run"); } memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketCopyData(p, raw_eth_pkt, pktsize); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, GET_PKT_DATA(p), pktsize, NULL); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig); if (de_ctx->sig_list == NULL) { goto end; } de_ctx->sig_list->next = NULL; if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->type == DETECT_CONTENT) { DetectContentData *co = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (co->flags & DETECT_CONTENT_RELATIVE_NEXT) { printf("relative next flag set on final match which is content: "); goto end; } } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, sid) != 1) { SCLogDebug("replace: no alert on sig %d", sid); goto end; } if (pp) { memcpy(pp, GET_PKT_DATA(p), GET_PKT_LEN(p)); *len = pktsize; SCLogDebug("replace: copying %d on %p", *len, pp); } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } FlowShutdown(); SCFree(p); return result; } /** * \brief Wrapper for DetectContentLongPatternMatchTest */ int DetectReplaceLongPatternMatchTestWrp(char *sig, uint32_t sid, char *sig_rep, uint32_t sid_rep) { int ret; /** Real packet with the following tcp data: * "Hi, this is a big test to check content matches of splitted" * "patterns between multiple chunks!" * (without quotes! :) ) */ uint8_t raw_eth_pkt[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00, 0x00,0x85,0x00,0x01,0x00,0x00,0x40,0x06, 0x7c,0x70,0x7f,0x00,0x00,0x01,0x7f,0x00, 0x00,0x01,0x00,0x14,0x00,0x50,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x02, 0x20,0x00,0xc9,0xad,0x00,0x00,0x48,0x69, 0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69, 0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20, 0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20, 0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f, 0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61, 0x74,0x63,0x68,0x65,0x73,0x20,0x6f,0x66, 0x20,0x73,0x70,0x6c,0x69,0x74,0x74,0x65, 0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72, 0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65, 0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69, 0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e, 0x6b,0x73,0x21 }; /* end raw_eth_pkt */ uint8_t p[sizeof(raw_eth_pkt)]; uint16_t psize = sizeof(raw_eth_pkt); /* would be unittest */ int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), sig, sid, p, &psize); if (ret == 1) { SCLogDebug("replace: test1 phase1"); ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL); } run_mode = run_mode_backup; return ret; } /** * \brief Wrapper for DetectContentLongPatternMatchTest */ int DetectReplaceLongPatternMatchTestUDPWrp(char *sig, uint32_t sid, char *sig_rep, uint32_t sid_rep) { int ret; /** Real UDP DNS packet with a request A to a1.twimg.com */ uint8_t raw_eth_pkt[] = { 0x8c, 0xa9, 0x82, 0x75, 0x5d, 0x62, 0xb4, 0x07, 0xf9, 0xf3, 0xc7, 0x0a, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3a, 0x92, 0x4f, 0x40, 0x00, 0x40, 0x11, 0x31, 0x1a, 0xc0, 0xa8, 0x00, 0x02, 0xc1, 0xbd, 0xf4, 0xe1, 0x3b, 0x7e, 0x00, 0x35, 0x00, 0x26, 0xcb, 0x81, 0x37, 0x62, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x61, 0x31, 0x05, 0x74, 0x77, 0x69, 0x6d, 0x67, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 }; uint8_t p[sizeof(raw_eth_pkt)]; uint16_t psize = sizeof(raw_eth_pkt); int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), sig, sid, p, &psize); if (ret == 1) { SCLogDebug("replace: test1 phase1 ok: %" PRIuMAX" vs %d",(uintmax_t)sizeof(raw_eth_pkt),psize); ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL); } run_mode = run_mode_backup; return ret; } /** * \test Check if replace is working */ int DetectReplaceMatchTest01() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"this is a pig test\"; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with offset */ int DetectReplaceMatchTest02() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; offset: 4; replace:\"TH\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"THis\"; offset:4; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with offset and keyword inversion */ int DetectReplaceMatchTest03() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; offset: 4; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"THis\"; offset:4; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with second content */ int DetectReplaceMatchTest04() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; content:\"patter\"; replace:\"matter\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"THis\"; content:\"matterns\"; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is not done when second content don't match */ int DetectReplaceMatchTest05() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"TH\"; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is not done when second content match and not * first */ int DetectReplaceMatchTest06() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"commode\"; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working when nocase used */ int DetectReplaceMatchTest07() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"BiG\"; nocase; replace:\"pig\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"this is a pig test\"; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working when depth is used */ int DetectReplaceMatchTest08() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:17; replace:\"pig\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"this is a pig test\"; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working when depth block match used */ int DetectReplaceMatchTest09() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"this is a pig test\"; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working when depth block match used */ int DetectReplaceMatchTest10() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:17; replace:\"pig\"; offset: 14; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with within */ int DetectReplaceMatchTest11() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 11; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with within */ int DetectReplaceMatchTest12() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with within */ int DetectReplaceMatchTest13() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 1; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with within */ int DetectReplaceMatchTest14() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with within */ int DetectReplaceMatchTest15() { char *sig = "alert udp any any -> any any (msg:\"Nothing..\";" " content:\"com\"; replace:\"org\"; sid:1;)"; char *sig_rep = "alert udp any any -> any any (msg:\"replace worked\";" " content:\"twimg|03|org\"; sid:2;)"; return DetectReplaceLongPatternMatchTestUDPWrp(sig, 1, sig_rep, 2); } /** * \test Parsing test */ int DetectReplaceParseTest01(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"doh\"; replace:\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: run_mode = run_mode_backup; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test: non valid because of http protocol */ int DetectReplaceParseTest02(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(msg:\"test\"; content:\"doh\"; replace:\"bon\"; sid:238012;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: run_mode = run_mode_backup; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test: non valid because of http_header on same content * as replace keyword */ int DetectReplaceParseTest03(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; content:\"doh\"; replace:\"don\"; http_header; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: run_mode = run_mode_backup; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test no content */ int DetectReplaceParseTest04(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; replace:\"don\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: run_mode = run_mode_backup; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test content after replace */ int DetectReplaceParseTest05(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; replace:\"don\"; content:\"doh\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: run_mode = run_mode_backup; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test content and replace length differ */ int DetectReplaceParseTest06(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; content:\"don\"; replace:\"donut\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: run_mode = run_mode_backup; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test content and replace length differ */ int DetectReplaceParseTest07(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; content:\"don\"; replace:\"dou\"; content:\"jpg\"; http_header; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: run_mode = run_mode_backup; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectContent */ void DetectReplaceRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ /* matching */ UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01, 1); UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02, 1); UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03, 1); UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04, 1); UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05, 0); UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06, 0); UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07, 1); UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08, 1); UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09, 0); UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10, 1); UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11, 1); UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12, 0); UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13, 1); UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14, 0); UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15, 1); /* parsing */ UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01, 1); UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02, 1); UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03, 1); UtRegisterTest("DetectReplaceParseTest04", DetectReplaceParseTest04, 1); UtRegisterTest("DetectReplaceParseTest05", DetectReplaceParseTest05, 1); UtRegisterTest("DetectReplaceParseTest06", DetectReplaceParseTest06, 1); UtRegisterTest("DetectReplaceParseTest07", DetectReplaceParseTest07, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/log-file.h0000644000000000000000000000161512253546156012677 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __LOG_FILELOG_H__ #define __LOG_FILELOG_H__ void TmModuleLogFileLogRegister (void); #endif /* __LOG_FILELOG_H__ */ suricata-1.4.7/src/detect-metadata.h0000644000000000000000000000164712253546156014234 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_METADATA_H__ #define __DETECT_METADATA_H__ /* prototypes */ void DetectMetadataRegister (void); #endif /* __DETECT_METADATA_H__ */ suricata-1.4.7/src/detect-ssl-state.h0000644000000000000000000000257712253546156014376 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef DETECT_SSL_STATE_H #define DETECT_SSL_STATE_H #include "app-layer-ssl.h" /* we pick these flags flags from the parser */ #define DETECT_SSL_STATE_CLIENT_HELLO SSL_AL_FLAG_STATE_CLIENT_HELLO #define DETECT_SSL_STATE_SERVER_HELLO SSL_AL_FLAG_STATE_SERVER_HELLO #define DETECT_SSL_STATE_CLIENT_KEYX SSL_AL_FLAG_STATE_CLIENT_KEYX #define DETECT_SSL_STATE_SERVER_KEYX SSL_AL_FLAG_STATE_SERVER_KEYX #define DETECT_SSL_STATE_UNKNOWN SSL_AL_FLAG_STATE_UNKNOWN typedef struct DetectSslStateData_ { uint32_t flags; } DetectSslStateData; void DetectSslStateRegister(void); #endif /* DETECT_SSL_STATE_H */ suricata-1.4.7/src/detect-uricontent.c0000644000000000000000000020344412253546156014640 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Gurvinder Singh * * Simple uricontent match part of the detection engine. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "flow.h" #include "detect-flow.h" #include "flow-var.h" #include "flow-util.h" #include "threads.h" #include "flow-alert-sid.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-parser.h" #include "app-layer-protos.h" #include "app-layer-htp.h" #include "util-mpm.h" #include "util-print.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-binsearch.h" #include "util-spm.h" #include "util-spm-bm.h" /* prototypes */ static int DetectUricontentSetup (DetectEngineCtx *, Signature *, char *); void HttpUriRegisterTests(void); int DetectAppLayerUricontentMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t , void *, Signature *, SigMatch *); void DetectUricontentFree(void *); /** * \brief Registration function for uricontent: keyword */ void DetectUricontentRegister (void) { sigmatch_table[DETECT_URICONTENT].name = "uricontent"; sigmatch_table[DETECT_URICONTENT].AppLayerMatch = NULL; sigmatch_table[DETECT_URICONTENT].Match = NULL; sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup; sigmatch_table[DETECT_URICONTENT].Free = DetectUricontentFree; sigmatch_table[DETECT_URICONTENT].RegisterTests = HttpUriRegisterTests; sigmatch_table[DETECT_URICONTENT].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_URICONTENT].flags |= SIGMATCH_PAYLOAD; } /** * \brief pass on the uricontent_max_id * \param de_ctx pointer to the detect egine context whose max id is asked */ uint32_t DetectUricontentMaxId(DetectEngineCtx *de_ctx) { return MpmPatternIdStoreGetMaxId(de_ctx->mpm_pattern_id_store); } /** * \brief this function will Free memory associated with DetectContentData * * \param cd pointer to DetectUricotentData */ void DetectUricontentFree(void *ptr) { SCEnter(); DetectContentData *cd = (DetectContentData *)ptr; if (cd == NULL) SCReturn; BoyerMooreCtxDeInit(cd->bm_ctx); SCFree(cd); SCReturn; } /** * \brief Helper function to print a DetectContentData */ void DetectUricontentPrint(DetectContentData *cd) { int i = 0; if (cd == NULL) { SCLogDebug("Detect UricontentData \"cd\" is NULL"); return; } char *tmpstr = SCMalloc(sizeof(char) * cd->content_len + 1); if (unlikely(tmpstr == NULL)) return; if (tmpstr != NULL) { for (i = 0; i < cd->content_len; i++) { if (isprint(cd->content[i])) tmpstr[i] = cd->content[i]; else tmpstr[i] = '.'; } tmpstr[i] = '\0'; SCLogDebug("Uricontent: \"%s\"", tmpstr); SCFree(tmpstr); } else { SCLogDebug("Uricontent: "); for (i = 0; i < cd->content_len; i++) SCLogDebug("%c", cd->content[i]); } SCLogDebug("Uricontent_id: %"PRIu32, cd->id); SCLogDebug("Uricontent_len: %"PRIu16, cd->content_len); SCLogDebug("Depth: %"PRIu16, cd->depth); SCLogDebug("Offset: %"PRIu16, cd->offset); SCLogDebug("Within: %"PRIi32, cd->within); SCLogDebug("Distance: %"PRIi32, cd->distance); SCLogDebug("flags: %u ", cd->flags); SCLogDebug("negated: %s ", cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); SCLogDebug("relative match next: %s ", cd->flags & DETECT_CONTENT_RELATIVE_NEXT ? "true" : "false"); SCLogDebug("-----------"); } /** * \brief Setup the detecturicontent keyword data from the string defined in * the rule set. * \param contentstr Pointer to the string which has been defined in the rule */ DetectContentData *DoDetectUricontentSetup (char *contentstr) { DetectContentData *cd = NULL; char *str = NULL; uint16_t len; int flags; int ret; ret = DetectContentDataParse("uricontent", contentstr, &str, &len, &flags); if (ret == -1) { return NULL; } cd = SCMalloc(sizeof(DetectContentData) + len); if (unlikely(cd == NULL)) { SCFree(str); exit(EXIT_FAILURE); } memset(cd, 0, sizeof(DetectContentData) + len); if (flags == DETECT_CONTENT_NEGATED) cd->flags |= DETECT_CONTENT_NEGATED; cd->content = (uint8_t *)cd + sizeof(DetectContentData); memcpy(cd->content, str, len); cd->content_len = len; /* Prepare Boyer Moore context for searching faster */ cd->bm_ctx = BoyerMooreCtxInit(cd->content, cd->content_len); cd->depth = 0; cd->offset = 0; cd->within = 0; cd->distance = 0; SCFree(str); return cd; } /** * \brief Creates a SigMatch for the uricontent keyword being sent as argument, * and appends it to the Signature(s). * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param contentstr Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ int DetectUricontentSetup (DetectEngineCtx *de_ctx, Signature *s, char *contentstr) { SCEnter(); DetectContentData *cd = NULL; SigMatch *sm = NULL; if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting" " keywords."); goto error; } cd = DoDetectUricontentSetup(contentstr); if (cd == 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_CONTENT; sm->ctx = (void *)cd; cd->id = DetectUricontentGetId(de_ctx->mpm_pattern_id_store, cd); /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); SCReturnInt(0); error: if (cd != NULL) SCFree(cd); if (sm != NULL) SCFree(sm); SCReturnInt(-1); } /** * \brief Checks if the content sent as the argument, has a uricontent which * has been provided in the rule. This match function matches the * normalized http uri against the given rule using multi pattern * search algorithms. * * \param det_ctx Pointer to the detection engine thread context * \param content Pointer to the uri content currently being matched * \param content_len Content_len of the received uri content * * \retval 1 if the uri contents match; 0 no match */ static inline int DoDetectAppLayerUricontentMatch (DetectEngineThreadCtx *det_ctx, uint8_t *uri, uint16_t uri_len, uint8_t flags) { int ret = 0; /* run the pattern matcher against the uri */ if (det_ctx->sgh->mpm_uricontent_maxlen > uri_len) { SCLogDebug("not searching as pkt payload is smaller than the " "largest uricontent length we need to match"); } else { SCLogDebug("search: (%p, maxlen %" PRIu32 ", sgh->sig_cnt " "%" PRIu32 ")", det_ctx->sgh, det_ctx->sgh-> mpm_uricontent_maxlen, det_ctx->sgh->sig_cnt); ret += UriPatternSearch(det_ctx, uri, uri_len, flags); SCLogDebug("post search: cnt %" PRIu32, ret); } return ret; } /** * \brief Run the pattern matcher against the uri(s) * * We run against _all_ uri(s) we have as the pattern matcher will * flag each sig that has a match. We need to do this for all uri(s) * to not miss possible events. * * \param f locked flow * \param htp_state initialized htp state * * \warning Make sure the flow/state is locked * \todo what should we return? Just the fact that we matched? */ uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { SCEnter(); uint32_t cnt = 0; int idx = 0; htp_tx_t *tx = NULL; /* locking the flow, we will inspect the htp state */ FLOWLOCK_RDLOCK(f); if (htp_state == NULL || htp_state->connp == NULL) { SCLogDebug("no HTTP state / no connp"); FLOWLOCK_UNLOCK(f); SCReturnUInt(0U); } idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->request_uri_normalized == NULL) continue; cnt += DoDetectAppLayerUricontentMatch(det_ctx, (uint8_t *) bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized), flags); } end: FLOWLOCK_UNLOCK(f); SCReturnUInt(cnt); } /* * UNITTTESTS */ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** \test Test case where path traversal has been sent as a path string in the * HTTP URL and normalized path string is checked */ static int HTTPUriTest01(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "GET /../../images.gif HTTP/1.1\r\nHost: www.ExA" "mPlE.cOM\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; } HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx->request_method_number != M_GET || tx->request_protocol_number != HTTP_1_1) { goto end; } if ((tx->parsed_uri->hostname == NULL) || (bstr_cmpc(tx->parsed_uri->hostname, "www.example.com") != 0)) { goto end; } if ((tx->parsed_uri->path == NULL) || (bstr_cmpc(tx->parsed_uri->path, "/images.gif") != 0)) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** \test Test case where path traversal has been sent in special characters in * HEX encoding in the HTTP URL and normalized path string is checked */ static int HTTPUriTest02(void) { int result = 0; Flow f; HtpState *htp_state = NULL; uint8_t httpbuf1[] = "GET /%2e%2e/images.gif HTTP/1.1\r\nHost: www.ExA" "mPlE.cOM\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; } htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx->request_method_number != M_GET || tx->request_protocol_number != HTTP_1_1) { goto end; } if ((tx->parsed_uri->hostname == NULL) || (bstr_cmpc(tx->parsed_uri->hostname, "www.example.com") != 0)) { goto end; } if ((tx->parsed_uri->path == NULL) || (bstr_cmpc(tx->parsed_uri->path, "/images.gif") != 0)) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); FLOW_DESTROY(&f); return result; } /** \test Test case where NULL character has been sent in HEX encoding in the * HTTP URL and normalized path string is checked */ static int HTTPUriTest03(void) { int result = 0; Flow f; HtpState *htp_state = NULL; uint8_t httpbuf1[] = "GET%00 /images.gif HTTP/1.1\r\nHost: www.ExA" "mPlE.cOM\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; } htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx->request_method_number != M_UNKNOWN || tx->request_protocol_number != HTTP_1_1) { goto end; } if ((tx->parsed_uri->hostname == NULL) || (bstr_cmpc(tx->parsed_uri->hostname, "www.example.com") != 0)) { goto end; } if ((tx->parsed_uri->path == NULL) || (bstr_cmpc(tx->parsed_uri->path, "/images.gif") != 0)) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); FLOW_DESTROY(&f); return result; } /** \test Test case where self referencing directories request has been sent * in the HTTP URL and normalized path string is checked */ static int HTTPUriTest04(void) { int result = 0; Flow f; HtpState *htp_state = NULL; uint8_t httpbuf1[] = "GET /./././images.gif HTTP/1.1\r\nHost: www.ExA" "mPlE.cOM\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; } htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx->request_method_number != M_GET || tx->request_protocol_number != HTTP_1_1) { goto end; } if ((tx->parsed_uri->hostname == NULL) || (bstr_cmpc(tx->parsed_uri->hostname, "www.example.com") != 0)) { goto end; } if ((tx->parsed_uri->path == NULL) || (bstr_cmpc(tx->parsed_uri->path, "/images.gif") != 0)) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); FLOW_DESTROY(&f); return result; } /** * \test Checks if a uricontent is registered in a Signature */ int DetectUriSigTest01(void) { SigMatch *sm = NULL; int result = 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Signature *s = NULL; memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"me\"; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); BUG_ON(de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL); sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type == DETECT_CONTENT) { result = 1; } else { result = 0; } end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check the signature working to alert when http_cookie is matched . */ static int DetectUriSigTest02(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST /one HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:" " hellocatch\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"foo\"; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"one\"; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"oisf\"; sid:3;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sig: 1 alerted, but it should not\n"); goto end; } else if (!PacketAlertCheck(p, 2)) { printf("sig: 2 did not alerted, but it should\n"); goto end; } else if ((PacketAlertCheck(p, 3))) { printf("sig: 3 alerted, but it should not\n"); goto end; } result = 1; end: //if (http_state != NULL) HTPStateFree(http_state); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Check the working of search once per packet only in applayer * match */ static int DetectUriSigTest03(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t httpbuf1[] = "POST /one HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:" " hellocatch\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "POST /oneself HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:" " hellocatch\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"foo\"; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"one\"; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"self\"; sid:3;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sig 1 alerted, but it should not: "); goto end; } else if (!PacketAlertCheck(p, 2)) { printf("sig 2 did not alert, but it should: "); goto end; } else if ((PacketAlertCheck(p, 3))) { printf("sig 3 alerted, but it should not: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sig 1 alerted, but it should not (chunk 2): "); goto end; } else if (PacketAlertCheck(p, 2)) { printf("sig 2 alerted, but it should not (chunk 2): "); goto end; } else if (!(PacketAlertCheck(p, 3))) { printf("sig 3 did not alert, but it should (chunk 2): "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Check that modifiers of content apply only to content keywords * and the same for uricontent modifiers */ static int DetectUriSigTest04(void) { int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"foo\"; sid:1;)"); if (s == NULL || s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 1 failed to parse: "); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";sid:1;)"); if (s == NULL || s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 2 failed to parse: "); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; sid:1;)"); if (s == NULL || s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 3 failed to parse: "); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "content:\"foo\"; uricontent:\"bar\";" " depth:10; offset: 5; sid:1;)"); if (s == NULL || s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->depth != 15 || ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->offset != 5 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 4 failed to parse: "); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; within:3; sid:1;)"); if (s != NULL) { printf("sig 5 failed to parse: "); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; distance:3; sid:1;)"); if (s != NULL) { printf("sig 6 failed to parse: "); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; content:" "\"two_contents\"; within:30; sid:1;)"); if (s == NULL) { goto end; } else if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx)->within != 30 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 7 failed to parse: "); DetectContentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; uricontent:" "\"two_uricontents\"; within:30; sid:1;)"); if (s == NULL) { goto end; } else if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->within != 30 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 8 failed to parse: "); DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; content:" "\"two_contents\"; distance:30; sid:1;)"); if (s == NULL) { goto end; } else if ( s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx)->distance != 30 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 9 failed to parse: "); DetectContentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; uricontent:" "\"two_uricontents\"; distance:30; sid:1;)"); if (s == NULL) { goto end; } else if ( s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->distance != 30 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 10 failed to parse: "); DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); goto end; } s = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; uricontent:" "\"two_uricontents\"; distance:30; " "within:60; content:\"two_contents\";" " within:70; distance:45; sid:1;)"); if (s == NULL) { printf("sig 10 failed to parse: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("umatch %p or pmatch %p: ", s->sm_lists[DETECT_SM_LIST_UMATCH], s->sm_lists[DETECT_SM_LIST_PMATCH]); goto end; } if ( ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->distance != 30 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->within != 60 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx)->distance != 45 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx)->within != 70 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 10 failed to parse, content not setup properly: "); DetectContentPrint((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx); DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); DetectContentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check the modifiers for uricontent and content * match */ static int DetectUriSigTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Flow f; HtpState *http_state = NULL; uint8_t httpbuf1[] = "POST /one/two/three HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:" " hellocatch\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP); p->tcph->th_seq = htonl(1000); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; f.proto = p->proto; StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); if (stream_msg == NULL) { printf("no stream_msg: "); goto end; } memcpy(stream_msg->data.data, httpbuf1, httplen1); stream_msg->data.data_len = httplen1; ssn.toserver_smsg_head = stream_msg; ssn.toserver_smsg_tail = stream_msg; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; uricontent:\"foo\"; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; uricontent:\"one\"; content:\"two\"; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; uricontent:\"one\"; offset:1; depth:10; " "uricontent:\"two\"; distance:1; within: 4; uricontent:\"three\"; " "distance:1; within: 6; sid:3;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } if ((PacketAlertCheck(p, 1))) { printf("sig: 1 alerted, but it should not: "); goto end; } else if (! PacketAlertCheck(p, 2)) { printf("sig: 2 did not alert, but it should: "); goto end; } else if (! (PacketAlertCheck(p, 3))) { printf("sig: 3 did not alert, but it should: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Check the modifiers for uricontent and content * match */ static int DetectUriSigTest06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Flow f; HtpState *http_state = NULL; uint8_t httpbuf1[] = "POST /one/two/three HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:" " hellocatch\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; TCPHdr tcp_hdr; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); memset(&tcp_hdr, 0, sizeof(tcp_hdr)); p = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP); p->tcph->th_seq = htonl(1000); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; f.proto = p->proto; StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); if (stream_msg == NULL) { printf("no stream_msg: "); goto end; } memcpy(stream_msg->data.data, httpbuf1, httplen1); stream_msg->data.data_len = httplen1; ssn.toserver_smsg_head = stream_msg; ssn.toserver_smsg_tail = stream_msg; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"foo\"; content:\"bar\"; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"one\"; offset:1; depth:10; " "content:\"one\"; offset:1; depth:10; " "uricontent:\"two\"; distance:1; within: 4; " "content:\"two\"; distance:1; within: 4; " "uricontent:\"three\"; distance:1; within: 6; " "content:\"/three\"; distance:0; within: 7; " "sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"one\"; offset:1; depth:10; " "uricontent:\"two\"; distance:1; within: 4; " "uricontent:\"three\"; distance:1; within: 6; " "sid:3;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } if ((PacketAlertCheck(p, 1))) { printf("sig: 1 alerted, but it should not:"); goto end; } else if (! PacketAlertCheck(p, 2)) { printf("sig: 2 did not alert, but it should:"); goto end; } else if (! (PacketAlertCheck(p, 3))) { printf("sig: 3 did not alert, but it should:"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Check the modifiers for uricontent and content * match */ static int DetectUriSigTest07(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t httpbuf1[] = "POST /one/two/three HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:" " hellocatch\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(httpbuf1, httplen1, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"foo\"; content:\"bar\"; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"one\"; offset:1; depth:10; " "content:\"one\"; offset:1; depth:10; " "uricontent:\"two\"; distance:3; within: 4; " "content:\"two\"; distance:1; within: 4; " "uricontent:\"three\"; distance:1; within: 6; " "content:\"/three\"; distance:0; within: 7; " "sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:" "\" Test uricontent\"; " "uricontent:\"one\"; offset:1; depth:10; " "uricontent:\"two\"; distance:1; within: 4; " "uricontent:\"six\"; distance:1; within: 6; " "sid:3;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } if (PacketAlertCheck(p, 1)) { printf("sig: 1 alerted, but it should not:"); goto end; } else if (PacketAlertCheck(p, 2)) { printf("sig: 2 alerted, but it should not:"); goto end; } else if (PacketAlertCheck(p, 3)) { printf("sig: 3 alerted, but it should not:"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test content for dce sig. */ int DetectUriSigTest08(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DetectUriSigTest09(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DetectUriSigTest10(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"boo; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DetectUriSigTest11(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:boo\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriSigTest12(void) { DetectEngineCtx *de_ctx = NULL; DetectContentData *ud = 0; Signature *s = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent: !\"boo\"; sid:238012;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL: "); goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx == NULL) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } ud = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; result = (strncmp("boo", (char *)ud->content, ud->content_len) == 0); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest13(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"|\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"|af\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"af|\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"|af|\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"aast|\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"aast|af\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"aast|af|\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"|af|asdf\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"|af|af|\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"|af|af|af\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; uricontent:\"|af|af|af|\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectUriContentParseTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; uricontent:\"\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectUricontentSigTest08(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd->id == ud->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectUricontentSigTest09(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd->id == ud->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectUricontentSigTest10(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"one\"; content:\"one\"; http_uri; " "content:\"two\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd3 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd1->id != 1 || cd2->id != 2 || cd3->id != 1 || ud1->id != 0 || ud2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectUricontentSigTest11(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; content:\"one\"; uricontent:\"one\"; " "content:\"two\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd3 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd1->id != 1 || cd2->id != 2 || cd3->id != 1 || ud1->id != 0 || ud2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectUricontentSigTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; content:\"one\"; uricontent:\"one\"; " "content:\"two\"; content:\"one\"; http_uri; content:\"one\"; " "uricontent:\"one\"; uricontent: \"two\"; " "content:\"one\"; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->prev->prev->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->prev->prev->ctx; DetectContentData *cd3 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->prev->ctx; DetectContentData *cd4 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd5 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->prev->prev->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->prev->prev->ctx; DetectContentData *ud3 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->prev->ctx; DetectContentData *ud4 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; DetectContentData *ud5 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd1->id != 1 || cd2->id != 2 || cd3->id != 1 || cd4->id != 1 || cd5->id != 4 || ud1->id != 0 || ud2->id != 0 || ud3->id != 0 || ud4->id != 0 || ud5->id != 3) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ void HttpUriRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("HTTPUriTest01", HTTPUriTest01, 1); UtRegisterTest("HTTPUriTest02", HTTPUriTest02, 1); UtRegisterTest("HTTPUriTest03", HTTPUriTest03, 1); UtRegisterTest("HTTPUriTest04", HTTPUriTest04, 1); UtRegisterTest("DetectUriSigTest01", DetectUriSigTest01, 1); UtRegisterTest("DetectUriSigTest02", DetectUriSigTest02, 1); UtRegisterTest("DetectUriSigTest03", DetectUriSigTest03, 1); UtRegisterTest("DetectUriSigTest04 - Modifiers", DetectUriSigTest04, 1); UtRegisterTest("DetectUriSigTest05 - Inspection", DetectUriSigTest05, 1); UtRegisterTest("DetectUriSigTest06 - Inspection", DetectUriSigTest06, 1); UtRegisterTest("DetectUriSigTest07 - Inspection", DetectUriSigTest07, 1); UtRegisterTest("DetectUriSigTest08", DetectUriSigTest08, 1); UtRegisterTest("DetectUriSigTest09", DetectUriSigTest09, 1); UtRegisterTest("DetectUriSigTest10", DetectUriSigTest10, 1); UtRegisterTest("DetectUriSigTest11", DetectUriSigTest11, 1); UtRegisterTest("DetectUriSigTest12", DetectUriSigTest12, 1); UtRegisterTest("DetectUriContentParseTest13", DetectUriContentParseTest13, 1); UtRegisterTest("DetectUriContentParseTest14", DetectUriContentParseTest14, 1); UtRegisterTest("DetectUriContentParseTest15", DetectUriContentParseTest15, 1); UtRegisterTest("DetectUriContentParseTest16", DetectUriContentParseTest16, 1); UtRegisterTest("DetectUriContentParseTest17", DetectUriContentParseTest17, 1); UtRegisterTest("DetectUriContentParseTest18", DetectUriContentParseTest18, 1); UtRegisterTest("DetectUriContentParseTest19", DetectUriContentParseTest19, 1); UtRegisterTest("DetectUriContentParseTest20", DetectUriContentParseTest20, 1); UtRegisterTest("DetectUriContentParseTest21", DetectUriContentParseTest21, 1); UtRegisterTest("DetectUriContentParseTest22", DetectUriContentParseTest22, 1); UtRegisterTest("DetectUriContentParseTest23", DetectUriContentParseTest23, 1); UtRegisterTest("DetectUriContentParseTest24", DetectUriContentParseTest24, 1); UtRegisterTest("DetectUricontentSigTest08", DetectUricontentSigTest08, 1); UtRegisterTest("DetectUricontentSigTest09", DetectUricontentSigTest09, 1); UtRegisterTest("DetectUricontentSigTest10", DetectUricontentSigTest10, 1); UtRegisterTest("DetectUricontentSigTest11", DetectUricontentSigTest11, 1); UtRegisterTest("DetectUricontentSigTest12", DetectUricontentSigTest12, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/alert-fastlog.c0000644000000000000000000003757312253546156013754 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Logs alerts in a line based text format compatible to Snort's * alert_fast format. * * \todo Support classifications * \todo Support more than just IPv4/IPv6 TCP/UDP. */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "conf.h" #include "threads.h" #include "tm-threads.h" #include "threadvars.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-reference.h" #include "util-classification-config.h" #include "output.h" #include "alert-fastlog.h" #include "util-mpm-b2g-cuda.h" #include "util-cuda-handlers.h" #include "util-privs.h" #include "util-print.h" #include "util-proto-name.h" #include "util-optimize.h" #include "util-logopenfile.h" #define DEFAULT_LOG_FILENAME "fast.log" #define MODULE_NAME "AlertFastLog" TmEcode AlertFastLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertFastLogIPv4(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertFastLogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertFastLogThreadInit(ThreadVars *, void *, void **); TmEcode AlertFastLogThreadDeinit(ThreadVars *, void *); void AlertFastLogExitPrintStats(ThreadVars *, void *); void AlertFastLogRegisterTests(void); static void AlertFastLogDeInitCtx(OutputCtx *); void TmModuleAlertFastLogRegister (void) { tmm_modules[TMM_ALERTFASTLOG].name = MODULE_NAME; tmm_modules[TMM_ALERTFASTLOG].ThreadInit = AlertFastLogThreadInit; tmm_modules[TMM_ALERTFASTLOG].Func = AlertFastLog; tmm_modules[TMM_ALERTFASTLOG].ThreadExitPrintStats = AlertFastLogExitPrintStats; tmm_modules[TMM_ALERTFASTLOG].ThreadDeinit = AlertFastLogThreadDeinit; tmm_modules[TMM_ALERTFASTLOG].RegisterTests = AlertFastLogRegisterTests; tmm_modules[TMM_ALERTFASTLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "fast", AlertFastLogInitCtx); } void TmModuleAlertFastLogIPv4Register (void) { tmm_modules[TMM_ALERTFASTLOG4].name = "AlertFastLogIPv4"; tmm_modules[TMM_ALERTFASTLOG4].ThreadInit = AlertFastLogThreadInit; tmm_modules[TMM_ALERTFASTLOG4].Func = AlertFastLogIPv4; tmm_modules[TMM_ALERTFASTLOG4].ThreadExitPrintStats = AlertFastLogExitPrintStats; tmm_modules[TMM_ALERTFASTLOG4].ThreadDeinit = AlertFastLogThreadDeinit; tmm_modules[TMM_ALERTFASTLOG4].RegisterTests = NULL; } void TmModuleAlertFastLogIPv6Register (void) { tmm_modules[TMM_ALERTFASTLOG6].name = "AlertFastLogIPv6"; tmm_modules[TMM_ALERTFASTLOG6].ThreadInit = AlertFastLogThreadInit; tmm_modules[TMM_ALERTFASTLOG6].Func = AlertFastLogIPv6; tmm_modules[TMM_ALERTFASTLOG6].ThreadExitPrintStats = AlertFastLogExitPrintStats; tmm_modules[TMM_ALERTFASTLOG6].ThreadDeinit = AlertFastLogThreadDeinit; tmm_modules[TMM_ALERTFASTLOG6].RegisterTests = NULL; } typedef struct AlertFastLogThread_ { /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ LogFileCtx* file_ctx; } AlertFastLogThread; static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); } TmEcode AlertFastLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertFastLogThread *aft = (AlertFastLogThread *)data; int i; char timebuf[64]; char *action = ""; extern uint8_t engine_mode; if (p->alerts.cnt == 0) return TM_ECODE_OK; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); char srcip[16], dstip[16]; PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; } if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { action = "[Drop] "; } else if (pa->action & ACTION_DROP) { action = "[wDrop] "; } char proto[16] = ""; if (SCProtoNameValid(IPV4_GET_IPPROTO(p)) == TRUE) { strlcpy(proto, known_proto[IPV4_GET_IPPROTO(p)], sizeof(proto)); } else { snprintf(proto, sizeof(proto), "PROTO:%03" PRIu32, IPV4_GET_IPPROTO(p)); } SCMutexLock(&aft->file_ctx->fp_mutex); fprintf(aft->file_ctx->fp, "%s %s[**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %"PRIu32"]" " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "\n", timebuf, action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio, proto, srcip, p->sp, dstip, p->dp); fflush(aft->file_ctx->fp); aft->file_ctx->alerts++; SCMutexUnlock(&aft->file_ctx->fp_mutex); } return TM_ECODE_OK; } TmEcode AlertFastLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertFastLogThread *aft = (AlertFastLogThread *)data; int i; char timebuf[64]; char *action = ""; extern uint8_t engine_mode; if (p->alerts.cnt == 0) return TM_ECODE_OK; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); char srcip[46], dstip[46]; PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; } if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { action = "[Drop] "; } else if (pa->action & ACTION_DROP) { action = "[wDrop] "; } char proto[16] = ""; if (SCProtoNameValid(IP_GET_IPPROTO(p)) == TRUE) { strlcpy(proto, known_proto[IP_GET_IPPROTO(p)], sizeof(proto)); } else { snprintf(proto, sizeof(proto), "PROTO:%03" PRIu32, IP_GET_IPPROTO(p)); } SCMutexLock(&aft->file_ctx->fp_mutex); fprintf(aft->file_ctx->fp, "%s %s[**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %" PRIu32 "] {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "\n", timebuf, action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio, proto, srcip, p->sp, dstip, p->dp); fflush(aft->file_ctx->fp); aft->file_ctx->alerts++; SCMutexUnlock(&aft->file_ctx->fp_mutex); } return TM_ECODE_OK; } TmEcode AlertFastLogDecoderEvent(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertFastLogThread *aft = (AlertFastLogThread *)data; int i; char timebuf[64]; char *action = ""; extern uint8_t engine_mode; if (p->alerts.cnt == 0) return TM_ECODE_OK; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; } if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { action = "[Drop] "; } else if (pa->action & ACTION_DROP) { action = "[wDrop] "; } SCMutexLock(&aft->file_ctx->fp_mutex); fprintf(aft->file_ctx->fp, "%s %s[**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: " "%" PRIu32 "] [**] [Raw pkt: ", timebuf, action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio); PrintRawLineHexFp(aft->file_ctx->fp, GET_PKT_DATA(p), GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32); if (p->pcap_cnt != 0) { fprintf(aft->file_ctx->fp, "] [pcap file packet: %"PRIu64"]\n", p->pcap_cnt); } else { fprintf(aft->file_ctx->fp, "]\n"); } fflush(aft->file_ctx->fp); aft->file_ctx->alerts++; SCMutexUnlock(&aft->file_ctx->fp_mutex); } return TM_ECODE_OK; } TmEcode AlertFastLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { if (PKT_IS_IPV4(p)) { return AlertFastLogIPv4(tv, p, data, pq, postpq); } else if (PKT_IS_IPV6(p)) { return AlertFastLogIPv6(tv, p, data, pq, postpq); } else if (p->events.cnt > 0) { return AlertFastLogDecoderEvent(tv, p, data, pq, postpq); } return TM_ECODE_OK; } TmEcode AlertFastLogThreadInit(ThreadVars *t, void *initdata, void **data) { AlertFastLogThread *aft = SCMalloc(sizeof(AlertFastLogThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(AlertFastLogThread)); if(initdata == NULL) { SCLogDebug("Error getting context for AlertFastLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } /** Use the Ouptut Context (file pointer and mutex) */ aft->file_ctx = ((OutputCtx *)initdata)->data; *data = (void *)aft; return TM_ECODE_OK; } TmEcode AlertFastLogThreadDeinit(ThreadVars *t, void *data) { AlertFastLogThread *aft = (AlertFastLogThread *)data; if (aft == NULL) { return TM_ECODE_OK; } /* clear memory */ memset(aft, 0, sizeof(AlertFastLogThread)); SCFree(aft); return TM_ECODE_OK; } void AlertFastLogExitPrintStats(ThreadVars *tv, void *data) { AlertFastLogThread *aft = (AlertFastLogThread *)data; if (aft == NULL) { return; } SCLogInfo("Fast log output wrote %" PRIu64 " alerts", aft->file_ctx->alerts); } /** * \brief Create a new LogFileCtx for "fast" output style. * \param conf The configuration node for this output. * \return A LogFileCtx pointer on success, NULL on failure. */ OutputCtx *AlertFastLogInitCtx(ConfNode *conf) { LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("AlertFastLogInitCtx2: Could not create new LogFileCtx"); return NULL; } if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; output_ctx->data = logfile_ctx; output_ctx->DeInit = AlertFastLogDeInitCtx; return output_ctx; } static void AlertFastLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; LogFileFreeCtx(logfile_ctx); SCFree(output_ctx); } /*------------------------------Unittests-------------------------------------*/ #ifdef UNITTESTS int AlertFastLogTest01() { int result = 0; uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { return result; } de_ctx->flags |= DE_QUIET; SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"FastLog test\"; content:\"GET\"; " "Classtype:unknown; sid:1;)"); result = (de_ctx->sig_list != NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1) result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); else result = 0; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadRC(); if (SCCudaHlPushCudaContextFromModule("SC_RULES_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); return result; } int AlertFastLogTest02() { int result = 0; uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { return result; } de_ctx->flags |= DE_QUIET; SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"FastLog test\"; content:\"GET\"; " "Classtype:unknown; sid:1;)"); result = (de_ctx->sig_list != NULL); if (result == 0) printf("sig parse failed: "); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1) { result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown Traffic") != 0); if (result == 0) printf("p->alerts.alerts[0].class_msg %s: ", p->alerts.alerts[0].s->class_msg); result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); if (result == 0) printf("p->alerts.alerts[0].class_msg %s: ", p->alerts.alerts[0].s->class_msg); } else { result = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadRC(); if (SCCudaHlPushCudaContextFromModule("SC_RULES_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief This function registers unit tests for AlertFastLog API. */ void AlertFastLogRegisterTests(void) { #ifdef UNITTESTS #ifdef __SC_CUDA_SUPPORT__ UtRegisterTest("AlertFastLogCudaContextInit", SCCudaHlTestEnvCudaContextInit, 1); #endif UtRegisterTest("AlertFastLogTest01", AlertFastLogTest01, 1); UtRegisterTest("AlertFastLogTest02", AlertFastLogTest02, 1); #ifdef __SC_CUDA_SUPPORT__ UtRegisterTest("AlertFastLogCudaContextDeInit", SCCudaHlTestEnvCudaContextDeInit, 1); #endif #endif /* UNITTESTS */ } suricata-1.4.7/src/log-httplog.c0000644000000000000000000006554712253546156013452 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Ignacio Sanchez * * Implements http logging portion of the engine. */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "pkt-var.h" #include "conf.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "util-print.h" #include "util-unittest.h" #include "util-debug.h" #include "output.h" #include "log-httplog.h" #include "app-layer-htp.h" #include "app-layer.h" #include "util-privs.h" #include "util-buffer.h" #include "util-logopenfile.h" #define DEFAULT_LOG_FILENAME "http.log" #define MODULE_NAME "LogHttpLog" #define OUTPUT_BUFFER_SIZE 65535 TmEcode LogHttpLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogHttpLogIPv4(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogHttpLogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogHttpLogThreadInit(ThreadVars *, void *, void **); TmEcode LogHttpLogThreadDeinit(ThreadVars *, void *); void LogHttpLogExitPrintStats(ThreadVars *, void *); static void LogHttpLogDeInitCtx(OutputCtx *); void TmModuleLogHttpLogRegister (void) { tmm_modules[TMM_LOGHTTPLOG].name = MODULE_NAME; tmm_modules[TMM_LOGHTTPLOG].ThreadInit = LogHttpLogThreadInit; tmm_modules[TMM_LOGHTTPLOG].Func = LogHttpLog; tmm_modules[TMM_LOGHTTPLOG].ThreadExitPrintStats = LogHttpLogExitPrintStats; tmm_modules[TMM_LOGHTTPLOG].ThreadDeinit = LogHttpLogThreadDeinit; tmm_modules[TMM_LOGHTTPLOG].RegisterTests = NULL; tmm_modules[TMM_LOGHTTPLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "http-log", LogHttpLogInitCtx); /* enable the logger for the app layer */ AppLayerRegisterLogger(ALPROTO_HTTP); } void TmModuleLogHttpLogIPv4Register (void) { tmm_modules[TMM_LOGHTTPLOG4].name = "LogHttpLogIPv4"; tmm_modules[TMM_LOGHTTPLOG4].ThreadInit = LogHttpLogThreadInit; tmm_modules[TMM_LOGHTTPLOG4].Func = LogHttpLogIPv4; tmm_modules[TMM_LOGHTTPLOG4].ThreadExitPrintStats = LogHttpLogExitPrintStats; tmm_modules[TMM_LOGHTTPLOG4].ThreadDeinit = LogHttpLogThreadDeinit; tmm_modules[TMM_LOGHTTPLOG4].RegisterTests = NULL; } void TmModuleLogHttpLogIPv6Register (void) { tmm_modules[TMM_LOGHTTPLOG6].name = "LogHttpLogIPv6"; tmm_modules[TMM_LOGHTTPLOG6].ThreadInit = LogHttpLogThreadInit; tmm_modules[TMM_LOGHTTPLOG6].Func = LogHttpLogIPv6; tmm_modules[TMM_LOGHTTPLOG6].ThreadExitPrintStats = LogHttpLogExitPrintStats; tmm_modules[TMM_LOGHTTPLOG6].ThreadDeinit = LogHttpLogThreadDeinit; tmm_modules[TMM_LOGHTTPLOG6].RegisterTests = NULL; } #define LOG_HTTP_MAXN_NODES 64 #define LOG_HTTP_NODE_STRLEN 256 #define TIMESTAMP_DEFAULT_FORMAT "%b %d, %Y; %H:%M:%S" #define LOG_HTTP_CF_NONE "-" #define LOG_HTTP_CF_LITERAL '%' #define LOG_HTTP_CF_REQUEST_HOST 'h' #define LOG_HTTP_CF_REQUEST_PROTOCOL 'H' #define LOG_HTTP_CF_REQUEST_METHOD 'm' #define LOG_HTTP_CF_REQUEST_URI 'u' #define LOG_HTTP_CF_REQUEST_TIME 't' #define LOG_HTTP_CF_REQUEST_HEADER 'i' #define LOG_HTTP_CF_REQUEST_COOKIE 'C' #define LOG_HTTP_CF_RESPONSE_STATUS 's' #define LOG_HTTP_CF_RESPONSE_HEADER 'o' #define LOG_HTTP_CF_RESPONSE_LEN 'B' #define LOG_HTTP_CF_TIMESTAMP 't' #define LOG_HTTP_CF_TIMESTAMP_U 'z' #define LOG_HTTP_CF_CLIENT_IP 'a' #define LOG_HTTP_CF_SERVER_IP 'A' #define LOG_HTTP_CF_CLIENT_PORT 'p' #define LOG_HTTP_CF_SERVER_PORT 'P' typedef struct LogHttpCustomFormatNode_ { uint32_t type; /** Node format type. ie: LOG_HTTP_CF_LITERAL, LOG_HTTP_CF_REQUEST_HEADER */ char data[LOG_HTTP_NODE_STRLEN]; /** optional data. ie: http header name */ } LogHttpCustomFormatNode; typedef struct LogHttpFileCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ uint32_t cf_n; /** Total number of custom string format nodes */ LogHttpCustomFormatNode *cf_nodes[LOG_HTTP_MAXN_NODES]; /** Custom format string nodes */ } LogHttpFileCtx; #define LOG_HTTP_DEFAULT 0 #define LOG_HTTP_EXTENDED 1 #define LOG_HTTP_CUSTOM 2 typedef struct LogHttpLogThread_ { LogHttpFileCtx *httplog_ctx; /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ uint32_t uri_cnt; MemBuffer *buffer; } LogHttpLogThread; static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); } /* Custom format logging */ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct timeval *ts, char *srcip, Port sp, char *dstip, Port dp) { LogHttpFileCtx *httplog_ctx = aft->httplog_ctx; uint32_t i; char buf[128]; htp_header_t *h_request_hdr = NULL; htp_header_t *h_response_hdr = NULL; time_t time = ts->tv_sec; struct tm local_tm; struct tm *timestamp = (struct tm *)SCLocalTime(time, &local_tm); for (i = 0; i < httplog_ctx->cf_n; i++) { switch (httplog_ctx->cf_nodes[i]->type){ case LOG_HTTP_CF_LITERAL: /* LITERAL */ PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)httplog_ctx->cf_nodes[i]->data, strlen(httplog_ctx->cf_nodes[i]->data)); break; case LOG_HTTP_CF_TIMESTAMP: /* TIMESTAMP */ if (httplog_ctx->cf_nodes[i]->data[0] == '\0') { strftime(buf, 62, TIMESTAMP_DEFAULT_FORMAT, timestamp); } else { strftime(buf, 62, httplog_ctx->cf_nodes[i]->data, timestamp); } PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)buf,strlen(buf)); break; case LOG_HTTP_CF_TIMESTAMP_U: /* TIMESTAMP USECONDS */ snprintf(buf, 62, "%06u", (unsigned int) ts->tv_usec); PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)buf,strlen(buf)); break; case LOG_HTTP_CF_CLIENT_IP: /* CLIENT IP ADDRESS */ PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)srcip,strlen(srcip)); break; case LOG_HTTP_CF_SERVER_IP: /* SERVER IP ADDRESS */ PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)dstip,strlen(dstip)); break; case LOG_HTTP_CF_CLIENT_PORT: /* CLIENT PORT */ MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); break; case LOG_HTTP_CF_SERVER_PORT: /* SERVER PORT */ MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); break; case LOG_HTTP_CF_REQUEST_METHOD: /* METHOD */ if (tx->request_method != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); } else { MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_URI: /* URI */ if (tx->request_uri != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); } else { MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_HOST: /* HOSTNAME */ if (tx->parsed_uri != NULL && tx->parsed_uri->hostname != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->parsed_uri->hostname), bstr_len(tx->parsed_uri->hostname)); } else { MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_PROTOCOL: /* PROTOCOL */ if (tx->request_protocol != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); } else { MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_HEADER: /* REQUEST HEADER */ if (tx->request_headers != NULL) { h_request_hdr = table_getc(tx->request_headers, httplog_ctx->cf_nodes[i]->data); } if (h_request_hdr != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(h_request_hdr->value), bstr_len(h_request_hdr->value)); } else { MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); } break; case LOG_HTTP_CF_RESPONSE_STATUS: /* RESPONSE STATUS */ if (tx->response_status != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status)); /* Redirect? */ if (tx->response_headers != NULL && tx->response_status_number > 300 && tx->response_status_number < 303) { htp_header_t *h_location = table_getc(tx->response_headers, "location"); if (h_location != NULL) { MemBufferWriteString(aft->buffer, "("); PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(h_location->value), bstr_len(h_location->value)); MemBufferWriteString(aft->buffer, ")"); } } } else { MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); } break; case LOG_HTTP_CF_RESPONSE_HEADER: /* RESPONSE HEADER */ if (tx->response_headers != NULL) { h_response_hdr = table_getc(tx->response_headers, httplog_ctx->cf_nodes[i]->data); } if (h_response_hdr != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(h_response_hdr->value), bstr_len(h_response_hdr->value)); } else { MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); } break; case LOG_HTTP_CF_RESPONSE_LEN: /* RESPONSE LEN */ MemBufferWriteString(aft->buffer, "%"PRIuMAX"", (uintmax_t)tx->response_message_len); break; } } MemBufferWriteString(aft->buffer, "\n"); } static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) { MemBufferWriteString(aft->buffer, " [**] "); /* referer */ htp_header_t *h_referer = NULL; if (tx->request_headers != NULL) { h_referer = table_getc(tx->request_headers, "referer"); } if (h_referer != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(h_referer->value), bstr_len(h_referer->value)); } else { MemBufferWriteString(aft->buffer, ""); } MemBufferWriteString(aft->buffer, " [**] "); /* method */ if (tx->request_method != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); } MemBufferWriteString(aft->buffer, " [**] "); /* protocol */ if (tx->request_protocol != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); } else { MemBufferWriteString(aft->buffer, ""); } MemBufferWriteString(aft->buffer, " [**] "); /* response status */ if (tx->response_status != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status)); /* Redirect? */ if ((tx->response_status_number > 300) && ((tx->response_status_number) < 303)) { htp_header_t *h_location = table_getc(tx->response_headers, "location"); if (h_location != NULL) { MemBufferWriteString(aft->buffer, " => "); PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(h_location->value), bstr_len(h_location->value)); } } } else { MemBufferWriteString(aft->buffer, ""); } /* length */ MemBufferWriteString(aft->buffer, " [**] %"PRIuMAX" bytes", (uintmax_t)tx->response_message_len); } static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq, int ipproto) { SCEnter(); LogHttpLogThread *aft = (LogHttpLogThread *)data; LogHttpFileCtx *hlog = aft->httplog_ctx; char timebuf[64]; size_t idx = 0; /* no flow, no htp state */ if (p->flow == NULL) { SCReturnInt(TM_ECODE_OK); } /* check if we have HTTP state or not */ FLOWLOCK_WRLOCK(p->flow); /* WRITE lock before we updated flow logged id */ uint16_t proto = AppLayerGetProtoFromPacket(p); if (proto != ALPROTO_HTTP) goto end; int r = AppLayerTransactionGetLoggedId(p->flow); if (r < 0) { goto end; } size_t logged = (size_t)r; r = HtpTransactionGetLoggableId(p->flow); if (r < 0) { goto end; } size_t loggable = (size_t)r; /* nothing to do */ if (logged >= loggable) { goto end; } HtpState *htp_state = (HtpState *)AppLayerGetProtoStateFromPacket(p); if (htp_state == NULL) { SCLogDebug("no http state, so no request logging"); goto end; } if (htp_state->connp == NULL || htp_state->connp->conn == NULL) goto end; htp_tx_t *tx = NULL; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); char srcip[46], dstip[46]; Port sp, dp; if ((PKT_IS_TOSERVER(p))) { switch (ipproto) { case AF_INET: PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); break; case AF_INET6: PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); break; default: goto end; } sp = p->sp; dp = p->dp; } else { switch (ipproto) { case AF_INET: PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), srcip, sizeof(srcip)); PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), dstip, sizeof(dstip)); break; case AF_INET6: PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), srcip, sizeof(srcip)); PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), dstip, sizeof(dstip)); break; default: goto end; } sp = p->dp; dp = p->sp; } for (idx = logged; idx < loggable; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL) { SCLogDebug("tx is NULL not logging !!"); continue; } SCLogDebug("got a HTTP request and now logging !!"); /* reset */ MemBufferReset(aft->buffer); if (hlog->flags & LOG_HTTP_CUSTOM) { LogHttpLogCustom(aft, tx, &p->ts, srcip, sp, dstip, dp); } else { /* time */ MemBufferWriteString(aft->buffer, "%s ", timebuf); /* hostname */ if (tx->parsed_uri != NULL && tx->parsed_uri->hostname != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->parsed_uri->hostname), bstr_len(tx->parsed_uri->hostname)); } else { MemBufferWriteString(aft->buffer, ""); } MemBufferWriteString(aft->buffer, " [**] "); /* uri */ if (tx->request_uri != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); } MemBufferWriteString(aft->buffer, " [**] "); /* user agent */ htp_header_t *h_user_agent = NULL; if (tx->request_headers != NULL) { h_user_agent = table_getc(tx->request_headers, "user-agent"); } if (h_user_agent != NULL) { PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)bstr_ptr(h_user_agent->value), bstr_len(h_user_agent->value)); } else { MemBufferWriteString(aft->buffer, ""); } if (hlog->flags & LOG_HTTP_EXTENDED) { LogHttpLogExtended(aft, tx); } /* ip/tcp header info */ MemBufferWriteString(aft->buffer, " [**] %s:%" PRIu16 " -> %s:%" PRIu16 "\n", srcip, sp, dstip, dp); } aft->uri_cnt ++; SCMutexLock(&hlog->file_ctx->fp_mutex); (void)MemBufferPrintToFPAsString(aft->buffer, hlog->file_ctx->fp); fflush(hlog->file_ctx->fp); SCMutexUnlock(&hlog->file_ctx->fp_mutex); AppLayerTransactionUpdateLoggedId(p->flow); } end: FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_OK); } TmEcode LogHttpLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return LogHttpLogIPWrapper(tv, p, data, pq, postpq, AF_INET); } TmEcode LogHttpLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return LogHttpLogIPWrapper(tv, p, data, pq, postpq, AF_INET6); } TmEcode LogHttpLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); /* no flow, no htp state */ if (p->flow == NULL) { SCReturnInt(TM_ECODE_OK); } if (!(PKT_IS_TCP(p))) { SCReturnInt(TM_ECODE_OK); } if (PKT_IS_IPV4(p)) { SCReturnInt(LogHttpLogIPv4(tv, p, data, pq, postpq)); } else if (PKT_IS_IPV6(p)) { SCReturnInt(LogHttpLogIPv6(tv, p, data, pq, postpq)); } SCReturnInt(TM_ECODE_OK); } TmEcode LogHttpLogThreadInit(ThreadVars *t, void *initdata, void **data) { LogHttpLogThread *aft = SCMalloc(sizeof(LogHttpLogThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(LogHttpLogThread)); if(initdata == NULL) { SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); if (aft->buffer == NULL) { SCFree(aft); return TM_ECODE_FAILED; } /* Use the Ouptut Context (file pointer and mutex) */ aft->httplog_ctx= ((OutputCtx *)initdata)->data; *data = (void *)aft; return TM_ECODE_OK; } TmEcode LogHttpLogThreadDeinit(ThreadVars *t, void *data) { LogHttpLogThread *aft = (LogHttpLogThread *)data; if (aft == NULL) { return TM_ECODE_OK; } MemBufferFree(aft->buffer); /* clear memory */ memset(aft, 0, sizeof(LogHttpLogThread)); SCFree(aft); return TM_ECODE_OK; } void LogHttpLogExitPrintStats(ThreadVars *tv, void *data) { LogHttpLogThread *aft = (LogHttpLogThread *)data; if (aft == NULL) { return; } SCLogInfo("HTTP logger logged %" PRIu32 " requests", aft->uri_cnt); } /** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful * */ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) { LogFileCtx* file_ctx = LogFileNewCtx(); const char *p, *np; uint32_t n; if(file_ctx == NULL) { SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { LogFileFreeCtx(file_ctx); return NULL; } LogHttpFileCtx *httplog_ctx = SCMalloc(sizeof(LogHttpFileCtx)); if (unlikely(httplog_ctx == NULL)) { LogFileFreeCtx(file_ctx); return NULL; } memset(httplog_ctx, 0x00, sizeof(LogHttpFileCtx)); httplog_ctx->file_ctx = file_ctx; httplog_ctx->cf_n=0; const char *extended = ConfNodeLookupChildValue(conf, "extended"); const char *custom = ConfNodeLookupChildValue(conf, "custom"); const char *customformat = ConfNodeLookupChildValue(conf, "customformat"); /* If custom logging format is selected, lets parse it */ if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { p=customformat; httplog_ctx->flags |= LOG_HTTP_CUSTOM; for (httplog_ctx->cf_n = 0; httplog_ctx->cf_n < LOG_HTTP_MAXN_NODES-1 && p && *p != '\0'; httplog_ctx->cf_n++){ httplog_ctx->cf_nodes[httplog_ctx->cf_n] = SCMalloc(sizeof(LogHttpCustomFormatNode)); if (httplog_ctx->cf_nodes[httplog_ctx->cf_n] == NULL) { for (n = 0; n < httplog_ctx->cf_n; n++) { SCFree(httplog_ctx->cf_nodes[n]); } LogFileFreeCtx(file_ctx); SCFree(httplog_ctx); return NULL; } if (*p != '%'){ /* Literal found in format string */ httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = LOG_HTTP_CF_LITERAL; np = strchr(p, '%'); if (np == NULL){ n = LOG_HTTP_NODE_STRLEN-2; np = NULL; /* End */ }else{ n = np-p; } strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data,p,n+1); p = np; } else { /* Non Literal found in format string */ p++; if (*p == '{') { /* Simple format char */ np = strchr(p, '}'); if (np != NULL && np-p > 1 && np-p < LOG_HTTP_NODE_STRLEN-2) { p++; n = np-p; strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data, p, n+1); p = np; } p++; } else { httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data[0] = '\0'; } httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = *p; if (*p == '%'){ httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = LOG_HTTP_CF_LITERAL; strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data, "%", 2); } p++; } } } else { if (extended == NULL) { httplog_ctx->flags |= LOG_HTTP_DEFAULT; } else { if (ConfValIsTrue(extended)) { httplog_ctx->flags |= LOG_HTTP_EXTENDED; } } } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { for (n = 0;n < httplog_ctx->cf_n;n++) { SCFree(httplog_ctx->cf_nodes[n]); } LogFileFreeCtx(file_ctx); SCFree(httplog_ctx); return NULL; } output_ctx->data = httplog_ctx; output_ctx->DeInit = LogHttpLogDeInitCtx; SCLogDebug("HTTP log output initialized"); return output_ctx; } static void LogHttpLogDeInitCtx(OutputCtx *output_ctx) { LogHttpFileCtx *httplog_ctx = (LogHttpFileCtx *)output_ctx->data; uint32_t i; for (i = 0; i < httplog_ctx->cf_n; i++) { SCFree(httplog_ctx->cf_nodes[i]); } LogFileFreeCtx(httplog_ctx->file_ctx); SCFree(httplog_ctx); SCFree(output_ctx); } suricata-1.4.7/src/util-pool.c0000644000000000000000000004134412253546156013123 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \defgroup utilpool Pool * * ::Pool are an effective way to maintain a set of ready to use * structures. * * To create a ::Pool, you need to use PoolInit(). You can * get an item from the ::Pool by using PoolGet(). When you're * done with it call PoolReturn(). * To destroy the ::Pool, call PoolFree(), it will free all used * memory. * * @{ */ /** * \file * * \author Victor Julien * * Pool utility functions */ #include "suricata-common.h" #include "util-pool.h" #include "util-unittest.h" #include "util-debug.h" static int PoolMemset(void *pitem, void *initdata) { Pool *p = (Pool *) initdata; memset(pitem, 0, p->elt_size); return 1; } /** * \brief Check if data is preallocated * \retval 0 or -1 if not inside */ static int PoolDataPreAllocated(Pool *p, void *data) { int delta = data - p->data_buffer; if ((delta < 0) || (delta > p->data_buffer_size)) { return 0; } return 1; } /** \brief Init a Pool * * PoolInit() creates a ::Pool. The Alloc function must only do * allocation stuff. The Cleanup function must not try to free * the PoolBucket::data. This is done by the ::Pool management * system. * * \param size * \param prealloc_size * \param elt_size Memory size of an element * \param Alloc An allocation function or NULL to use a standard SCMalloc * \param Init An init function or NULL to use a standard memset to 0 * \param InitData Init data * \param Cleanup a free function or NULL if no special treatment is needed * \param Free free func * \retval the allocated Pool */ Pool *PoolInit(uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(), int (*Init)(void *, void *), void *InitData, void (*Cleanup)(void *), void (*Free)(void *)) { Pool *p = NULL; if (size != 0 && prealloc_size > size) goto error; if (size != 0 && elt_size == 0) goto error; if (elt_size && Free) goto error; /* setup the filter */ p = SCMalloc(sizeof(Pool)); if (unlikely(p == NULL)) goto error; memset(p,0,sizeof(Pool)); p->max_buckets = size; p->preallocated = prealloc_size; p->elt_size = elt_size; p->data_buffer_size = prealloc_size * elt_size; p->Alloc = Alloc; p->Init = Init; p->InitData = InitData; p->Cleanup = Cleanup; p->Free = Free; if (p->Init == NULL) { p->Init = PoolMemset; p->InitData = p; } /* alloc the buckets and place them in the empty list */ uint32_t u32 = 0; if (size > 0) { PoolBucket *pb = SCCalloc(size, sizeof(PoolBucket)); if (unlikely(pb == NULL)) goto error; p->pb_buffer = pb; memset(pb, 0, size * sizeof(PoolBucket)); for (u32 = 0; u32 < size; u32++) { /* populate pool */ pb->next = p->empty_list; pb->flags |= POOL_BUCKET_PREALLOCATED; p->empty_list = pb; p->empty_list_size++; pb++; } } if (size > 0) { p->data_buffer = SCCalloc(prealloc_size, elt_size); /* FIXME better goto */ if (p->data_buffer == NULL) goto error; } /* prealloc the buckets and requeue them to the alloc list */ for (u32 = 0; u32 < prealloc_size; u32++) { if (size == 0) { /* unlimited */ PoolBucket *pb = SCMalloc(sizeof(PoolBucket)); if (unlikely(pb == NULL)) goto error; memset(pb, 0, sizeof(PoolBucket)); if (p->Alloc) { pb->data = p->Alloc(); } else { pb->data = SCMalloc(p->elt_size); } if (pb->data == NULL) { SCFree(pb); goto error; } if (p->Init(pb->data, p->InitData) != 1) { if (p->Cleanup) p->Cleanup(pb->data); if (p->Free) p->Free(pb->data); else SCFree(pb->data); SCFree(pb); goto error; } p->allocated++; pb->next = p->alloc_list; p->alloc_list = pb; p->alloc_list_size++; } else { PoolBucket *pb = p->empty_list; if (pb == NULL) goto error; pb->data = (char *)p->data_buffer + u32 * elt_size; if (p->Init(pb->data, p->InitData) != 1) { if (p->Cleanup) p->Cleanup(pb->data); goto error; } p->empty_list = pb->next; p->empty_list_size--; p->allocated++; pb->next = p->alloc_list; p->alloc_list = pb; p->alloc_list_size++; } } return p; error: if (p != NULL) { PoolFree(p); } return NULL; } void PoolFree(Pool *p) { if (p == NULL) return; while (p->alloc_list != NULL) { PoolBucket *pb = p->alloc_list; p->alloc_list = pb->next; if (p->Cleanup) p->Cleanup(pb->data); if (PoolDataPreAllocated(p, pb->data) == 0) { if (p->Free) p->Free(pb->data); else SCFree(pb->data); } pb->data = NULL; if (! pb->flags & POOL_BUCKET_PREALLOCATED) { SCFree(pb); } } while (p->empty_list != NULL) { PoolBucket *pb = p->empty_list; p->empty_list = pb->next; if (pb->data!= NULL) { if (p->Cleanup) p->Cleanup(pb->data); if (PoolDataPreAllocated(p, pb->data) == 0) { if (p->Free) p->Free(pb->data); else SCFree(pb->data); } pb->data = NULL; } if (! pb->flags & POOL_BUCKET_PREALLOCATED) { SCFree(pb); } } if (p->pb_buffer) SCFree(p->pb_buffer); if (p->data_buffer) SCFree(p->data_buffer); SCFree(p); } void PoolPrint(Pool *p) { printf("\n----------- Hash Table Stats ------------\n"); printf("Buckets: %" PRIu32 "\n", p->empty_list_size + p->alloc_list_size); printf("-----------------------------------------\n"); } void *PoolGet(Pool *p) { SCEnter(); PoolBucket *pb = p->alloc_list; if (pb != NULL) { /* pull from the alloc list */ p->alloc_list = pb->next; p->alloc_list_size--; /* put in the empty list */ pb->next = p->empty_list; p->empty_list = pb; p->empty_list_size++; } else { if (p->max_buckets == 0 || p->allocated < p->max_buckets) { void *pitem; SCLogDebug("max_buckets %"PRIu32"", p->max_buckets); p->allocated++; p->outstanding++; if (p->outstanding > p->max_outstanding) p->max_outstanding = p->outstanding; if (p->Alloc != NULL) { pitem = p->Alloc(); } else { pitem = SCMalloc(p->elt_size); } if (pitem != NULL) { if (p->Init(pitem, p->InitData) != 1) SCReturnPtr(NULL, "void"); } SCReturnPtr(pitem, "void"); } else { SCReturnPtr(NULL, "void"); } } void *ptr = pb->data; pb->data = NULL; p->outstanding++; if (p->outstanding > p->max_outstanding) p->max_outstanding = p->outstanding; SCReturnPtr(ptr,"void"); } void PoolReturn(Pool *p, void *data) { SCEnter(); PoolBucket *pb = p->empty_list; SCLogDebug("pb %p", pb); if (pb == NULL) { p->allocated--; p->outstanding--; if (p->Cleanup != NULL) { p->Cleanup(data); } if (PoolDataPreAllocated(p, data) == 0) { if (p->Free) p->Free(data); else SCFree(data); } SCLogDebug("tried to return data %p to the pool %p, but no more " "buckets available. Just freeing the data.", data, p); SCReturn; } /* pull from the alloc list */ p->empty_list = pb->next; p->empty_list_size--; /* put in the alloc list */ pb->next = p->alloc_list; p->alloc_list = pb; p->alloc_list_size++; pb->data = data; p->outstanding--; SCReturn; } void PoolPrintSaturation(Pool *p) { SCLogDebug("pool %p is using %"PRIu32" out of %"PRIu32" items (%02.1f%%), max %"PRIu32" (%02.1f%%): pool struct memory %"PRIu64".", p, p->outstanding, p->max_buckets, (float)(p->outstanding/(float)(p->max_buckets))*100, p->max_outstanding, (float)(p->max_outstanding/(float)(p->max_buckets))*100, (uint64_t)(p->max_buckets * sizeof(PoolBucket))); } /* * ONLY TESTS BELOW THIS COMMENT */ void *PoolTestAlloc() { void *ptr = SCMalloc(10); if (unlikely(ptr == NULL)) return NULL; return ptr; } int PoolTestInitArg(void *data, void *allocdata) { size_t len = strlen((char *)allocdata) + 1; char *str = data; if (str != NULL) strlcpy(str,(char *)allocdata,len); return 1; } void PoolTestFree(void *ptr) { return; } #ifdef UNITTESTS static int PoolTestInit01 (void) { Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); if (p == NULL) return 0; PoolFree(p); return 1; } static int PoolTestInit02 (void) { int retval = 0; Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); if (p == NULL) goto end; if (p->alloc_list == NULL || p->empty_list == NULL) { printf("list(s) not properly initialized (a:%p e:%p): ", p->alloc_list, p->empty_list); retval = 0; goto end; } if (p->Alloc != PoolTestAlloc) { printf("Alloc func ptr %p != %p: ", p->Alloc, PoolTestAlloc); retval = 0; goto end; } if (p->Cleanup != PoolTestFree) { printf("Free func ptr %p != %p: ", p->Cleanup, PoolTestFree); retval = 0; goto end; } retval = 1; end: if (p != NULL) PoolFree(p); return retval; } static int PoolTestInit03 (void) { int retval = 0; void *data = NULL; Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); if (p == NULL) goto end; data = PoolGet(p); if (data == NULL) { printf("PoolGet returned NULL: "); retval = 0; goto end; } if (p->alloc_list_size != 4) { printf("p->alloc_list_size 4 != %" PRIu32 ": ", p->alloc_list_size); retval = 0; goto end; } if (p->empty_list_size != 6) { printf("p->empty_list_size 6 != %" PRIu32 ": ", p->empty_list_size); retval = 0; goto end; } retval = 1; end: if (p != NULL) PoolFree(p); return retval; } static int PoolTestInit04 (void) { int retval = 0; char *str = NULL; Pool *p = PoolInit(10,5,strlen("test") + 1,NULL, PoolTestInitArg,(void *)"test",PoolTestFree, NULL); if (p == NULL) goto end; str = PoolGet(p); if (str == NULL) { printf("PoolGet returned NULL: "); retval = 0; goto end; } if (strcmp(str, "test") != 0) { printf("Memory not properly initialized: "); retval = 0; goto end; } if (p->alloc_list_size != 4) { printf("p->alloc_list_size 4 != %" PRIu32 ": ", p->alloc_list_size); retval = 0; goto end; } if (p->empty_list_size != 6) { printf("p->empty_list_size 6 != %" PRIu32 ": ", p->empty_list_size); retval = 0; goto end; } retval = 1; end: if (p != NULL) PoolFree(p); return retval; } static int PoolTestInit05 (void) { int retval = 0; void *data = NULL; Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL, NULL,PoolTestFree, NULL); if (p == NULL) goto end; data = PoolGet(p); if (data == NULL) { printf("PoolGet returned NULL: "); retval = 0; goto end; } if (p->alloc_list_size != 4) { printf("p->alloc_list_size 4 != %" PRIu32 ": ", p->alloc_list_size); retval = 0; goto end; } if (p->empty_list_size != 6) { printf("p->empty_list_size 6 != %" PRIu32 ": ", p->empty_list_size); retval = 0; goto end; } PoolReturn(p, data); data = NULL; if (p->alloc_list_size != 5) { printf("p->alloc_list_size 5 != %" PRIu32 ": ", p->alloc_list_size); retval = 0; goto end; } if (p->empty_list_size != 5) { printf("p->empty_list_size 5 != %" PRIu32 ": ", p->empty_list_size); retval = 0; goto end; } retval = 1; end: if (p != NULL) PoolFree(p); return retval; } static int PoolTestInit06 (void) { int retval = 0; void *data = NULL; void *data2 = NULL; Pool *p = PoolInit(1,0,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); if (p == NULL) goto end; if (p->allocated != 0) { printf("p->allocated 0 != %" PRIu32 ": ", p->allocated); retval = 0; goto end; } data = PoolGet(p); if (data == NULL) { printf("PoolGet returned NULL: "); retval = 0; goto end; } if (p->allocated != 1) { printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); retval = 0; goto end; } data2 = PoolGet(p); if (data2 != NULL) { printf("PoolGet returned %p, expected NULL: ", data2); retval = 0; goto end; } PoolReturn(p,data); data = NULL; if (p->allocated != 1) { printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); retval = 0; goto end; } if (p->alloc_list_size != 1) { printf("p->alloc_list_size 1 != %" PRIu32 ": ", p->alloc_list_size); retval = 0; goto end; } retval = 1; end: if (p != NULL) PoolFree(p); return retval; } /** \test pool with unlimited size */ static int PoolTestInit07 (void) { int retval = 0; void *data = NULL; void *data2 = NULL; Pool *p = PoolInit(0,1,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); if (p == NULL) goto end; if (p->max_buckets != 0) { printf("p->max_buckets 0 != %" PRIu32 ": ", p->max_buckets); retval = 0; goto end; } if (p->allocated != 1) { printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); retval = 0; goto end; } data = PoolGet(p); if (data == NULL) { printf("PoolGet returned NULL: "); retval = 0; goto end; } if (p->allocated != 1) { printf("(2) p->allocated 1 != %" PRIu32 ": ", p->allocated); retval = 0; goto end; } data2 = PoolGet(p); if (data2 == NULL) { printf("PoolGet returned NULL: "); retval = 0; goto end; } if (p->allocated != 2) { printf("(3) p->allocated 2 != %" PRIu32 ": ", p->allocated); retval = 0; goto end; } PoolReturn(p,data); data = NULL; if (p->allocated != 2) { printf("(4) p->allocated 2 != %" PRIu32 ": ", p->allocated); retval = 0; goto end; } if (p->alloc_list_size != 1) { printf("p->alloc_list_size 1 != %" PRIu32 ": ", p->alloc_list_size); retval = 0; goto end; } PoolReturn(p,data2); data2 = NULL; if (p->allocated != 1) { printf("(5) p->allocated 1 != %" PRIu32 ": ", p->allocated); retval = 0; goto end; } retval = 1; end: if (p != NULL) PoolFree(p); return retval; } #endif /* UNITTESTS */ void PoolRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("PoolTestInit01", PoolTestInit01, 1); UtRegisterTest("PoolTestInit02", PoolTestInit02, 1); UtRegisterTest("PoolTestInit03", PoolTestInit03, 1); UtRegisterTest("PoolTestInit04", PoolTestInit04, 1); UtRegisterTest("PoolTestInit05", PoolTestInit05, 1); UtRegisterTest("PoolTestInit06", PoolTestInit06, 1); UtRegisterTest("PoolTestInit07", PoolTestInit07, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/detect-flowbits.h0000644000000000000000000000251112253546156014274 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Breno Silva */ #ifndef __DETECT_FLOWBITS_H__ #define __DETECT_FLOWBITS_H__ #define DETECT_FLOWBITS_CMD_SET 0 #define DETECT_FLOWBITS_CMD_TOGGLE 1 #define DETECT_FLOWBITS_CMD_UNSET 2 #define DETECT_FLOWBITS_CMD_ISNOTSET 3 #define DETECT_FLOWBITS_CMD_ISSET 4 #define DETECT_FLOWBITS_CMD_NOALERT 5 #define DETECT_FLOWBITS_CMD_MAX 6 typedef struct DetectFlowbitsData_ { uint16_t idx; uint8_t cmd; } DetectFlowbitsData; /* prototypes */ void DetectFlowbitsRegister (void); #endif /* __DETECT_FLOWBITS_H__ */ suricata-1.4.7/src/conf-yaml-loader.h0000644000000000000000000000200212253546156014321 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited - Jason Ish */ #ifndef __CONF_YAML_LOADER_H__ #define __CONF_YAML_LOADER_H__ int ConfYamlLoadFile(const char *); int ConfYamlLoadString(const char *, size_t); void ConfYamlRegisterTests(void); #endif /* !__CONF_YAML_LOADER_H__ */ suricata-1.4.7/src/util-affinity.h0000644000000000000000000000501412253546156013762 00000000000000/* Copyright (C) 2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #ifndef __UTIL_AFFINITY_H__ #define __UTIL_AFFINITY_H__ #include "suricata-common.h" #if defined OS_FREEBSD #include #include #include #include #include #define cpu_set_t cpuset_t #elif defined __OpenBSD__ #include #include #include #elif defined OS_DARWIN #include #include #include #define cpu_set_t thread_affinity_policy_data_t #define CPU_SET(cpu_id, new_mask) (*(new_mask)).affinity_tag = (cpu_id + 1) #define CPU_ISSET(cpu_id, new_mask) ((*(new_mask)).affinity_tag == (cpu_id + 1)) #define CPU_ZERO(new_mask) (*(new_mask)).affinity_tag = THREAD_AFFINITY_TAG_NULL #endif enum { RECEIVE_CPU_SET, DECODE_CPU_SET, STREAM_CPU_SET, DETECT_CPU_SET, VERDICT_CPU_SET, REJECT_CPU_SET, OUTPUT_CPU_SET, MANAGEMENT_CPU_SET, MAX_CPU_SET }; enum { BALANCED_AFFINITY, EXCLUSIVE_AFFINITY, MAX_AFFINITY }; typedef struct ThreadsAffinityType_ { char *name; #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ cpu_set_t cpu_set; #endif uint8_t mode_flag; int prio; int nb_threads; #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ cpu_set_t lowprio_cpu; cpu_set_t medprio_cpu; cpu_set_t hiprio_cpu; #endif SCMutex taf_mutex; uint16_t lcpu; /* use by exclusive mode */ } ThreadsAffinityType; /** store thread affinity mode for all type of threads */ #ifndef _THREAD_AFFINITY ThreadsAffinityType thread_affinity[MAX_CPU_SET]; #endif void AffinitySetupLoadFromConfig(); ThreadsAffinityType * GetAffinityTypeFromName(const char *name); int AffinityGetNextCPU(ThreadsAffinityType *taf); #endif /* __UTIL_AFFINITY_H__ */ suricata-1.4.7/src/util-unittest.h0000644000000000000000000000250512253546156014032 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Breno Silva * * Unit test framework */ #ifndef __UTIL_UNITTEST_H__ #define __UTIL_UNITTEST_H__ #ifdef UNITTESTS typedef struct UtTest_ { char *name; int(*TestFn)(void); int evalue; struct UtTest_ *next; } UtTest; void UtRegisterTest(char *name, int(*TestFn)(void), int evalue); uint32_t UtRunTests(char *regex_arg); void UtInitialize(void); void UtCleanup(void); int UtRunSelftest (char *regex_arg); void UtListTests(char *regex_arg); void UtRunModeRegister(void); #endif #endif /* __UTIL_UNITTEST_H__ */ suricata-1.4.7/src/detect-engine-uri.h0000644000000000000000000000226612253546156014514 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien * \author Pablo Rincon Crespo */ #ifndef __DETECT_ENGINE_URICONTENT_H__ #define __DETECT_ENGINE_URICONTENT_H__ int DetectEngineInspectPacketUris(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); void UriRegisterTests(void); #endif /* __DETECT_ENGINE_URICONTENT_H__ */ suricata-1.4.7/src/util-fix_checksum.c0000644000000000000000000000403512253546156014616 00000000000000/* * Reference: OpenBSD's pf.c. * * Copyright (c) 2001 Daniel Hartmeier * Copyright (c) 2002 - 2008 Henning Brauer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Effort sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F30602-01-2-0537. */ #include /** * \brief Fix-up an IP checksum. * * \param sum The current checksum. * \param old Value of old header parameter. * \param new Value of new header parameter. * * \retval New checksum. */ uint16_t FixChecksum(uint16_t sum, uint16_t old, uint16_t new) { uint32_t l; l = sum + old - new; l = (l >> 16) + (l & 65535); l = l & 65535; return l; } suricata-1.4.7/src/packet-queue.c0000644000000000000000000001225612253546156013570 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Packet Queue portion of the engine. */ #include "suricata-common.h" #include "decode.h" #include "packet-queue.h" #include "threads.h" #include "suricata.h" #include "util-var.h" #include "pkt-var.h" #ifdef DEBUG void PacketQueueValidateDebug(PacketQueue *q) { SCLogDebug("q->len %u, q->top %p, q->bot %p", q->len, q->top, q->bot); if (q->len == 0) { BUG_ON(q->top != NULL); BUG_ON(q->bot != NULL); } else if(q->len == 1) { SCLogDebug("q->top->next %p, q->top->prev %p", q->top->next, q->top->prev); SCLogDebug("q->bot->next %p, q->bot->prev %p", q->bot->next, q->bot->prev); BUG_ON(q->top != q->bot); BUG_ON(q->top->next != NULL); BUG_ON(q->bot->next != NULL); BUG_ON(q->top->prev != NULL); BUG_ON(q->bot->prev != NULL); } else if (q->len == 2) { SCLogDebug("q->top->next %p, q->top->prev %p", q->top->next, q->top->prev); SCLogDebug("q->bot->next %p, q->bot->prev %p", q->bot->next, q->bot->prev); BUG_ON(q->top == NULL); BUG_ON(q->bot == NULL); BUG_ON(q->top == q->bot); BUG_ON(q->top->prev != NULL); BUG_ON(q->top->next != q->bot); BUG_ON(q->bot->prev != q->top); BUG_ON(q->bot->next != NULL); } else { BUG_ON(q->top == NULL); BUG_ON(q->bot == NULL); SCLogDebug("q->top->next %p, q->top->prev %p", q->top->next, q->top->prev); SCLogDebug("q->bot->next %p, q->bot->prev %p", q->bot->next, q->bot->prev); BUG_ON(q->top == q->bot); BUG_ON(q->top->prev != NULL); BUG_ON(q->bot->next != NULL); BUG_ON(q->top->next == q->bot); BUG_ON(q->bot->prev == q->top); Packet *p, *pp; for (p = q->top, pp = p->prev; p != NULL; pp = p, p = p->next) { SCLogDebug("p %p, pp %p, p->next %p, p->prev %p", p, pp, p->next, p->prev); BUG_ON(pp != p->prev); } } } #define BUGGER_ON(cond) { \ if ((cond)) { \ PacketQueueValidateDebug(q); \ } \ } void PacketQueueValidate(PacketQueue *q) { if (q->len == 0) { BUGGER_ON(q->top != NULL); BUGGER_ON(q->bot != NULL); } else if(q->len == 1) { BUGGER_ON(q->top != q->bot); BUGGER_ON(q->top->next != NULL); BUGGER_ON(q->bot->next != NULL); BUGGER_ON(q->top->prev != NULL); BUGGER_ON(q->bot->prev != NULL); } else if (q->len == 2) { BUGGER_ON(q->top == NULL); BUGGER_ON(q->bot == NULL); BUGGER_ON(q->top == q->bot); BUGGER_ON(q->top->prev != NULL); BUGGER_ON(q->top->next != q->bot); BUGGER_ON(q->bot->prev != q->top); BUGGER_ON(q->bot->next != NULL); } else { BUGGER_ON(q->top == NULL); BUGGER_ON(q->bot == NULL); BUGGER_ON(q->top == q->bot); BUGGER_ON(q->top->prev != NULL); BUGGER_ON(q->bot->next != NULL); BUGGER_ON(q->top->next == q->bot); BUGGER_ON(q->bot->prev == q->top); Packet *p, *pp; for (p = q->top, pp = p->prev; p != NULL; pp = p, p = p->next) { BUGGER_ON(pp != p->prev); } } } #endif /* DEBUG */ void PacketEnqueue (PacketQueue *q, Packet *p) { //PacketQueueValidateDebug(q); if (p == NULL) return; /* more packets in queue */ if (q->top != NULL) { p->prev = NULL; p->next = q->top; q->top->prev = p; q->top = p; /* only packet */ } else { p->prev = NULL; p->next = NULL; q->top = p; q->bot = p; } q->len++; #ifdef DBG_PERF if (q->len > q->dbg_maxlen) q->dbg_maxlen = q->len; #endif /* DBG_PERF */ //PacketQueueValidateDebug(q); } Packet *PacketDequeue (PacketQueue *q) { Packet *p = NULL; //PacketQueueValidateDebug(q); /* if the queue is empty there are no packets left. */ if (q->len == 0) { return NULL; } q->len--; /* pull the bottom packet from the queue */ p = q->bot; /* Weird issue: sometimes it looks that two thread arrive * here at the same time so the bot ptr is NULL (only on OS X?) */ if (p == NULL) { return NULL; } /* more packets in queue */ if (q->bot->prev != NULL) { q->bot = q->bot->prev; q->bot->next = NULL; /* just the one we remove, so now empty */ } else { q->top = NULL; q->bot = NULL; } //PacketQueueValidateDebug(q); return p; } suricata-1.4.7/src/counters.c0000644000000000000000000023753512253546156013052 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Performance counters */ #include "suricata-common.h" #include "suricata.h" #include "counters.h" #include "threadvars.h" #include "tm-threads.h" #include "conf.h" #include "util-time.h" #include "util-unittest.h" #include "util-debug.h" #include "util-privs.h" #include "util-signal.h" #include "unix-manager.h" /** \todo Get the default log directory from some global resource. */ #define SC_PERF_DEFAULT_LOG_FILENAME "stats.log" /* Used to parse the interval for Timebased counters */ #define SC_PERF_PCRE_TIMEBASED_INTERVAL "^(?:(\\d+)([shm]))(?:(\\d+)([shm]))?(?:(\\d+)([shm]))?$" static SCPerfOPIfaceContext *sc_perf_op_ctx = NULL; static time_t sc_start_time; /** refresh interval in seconds */ static uint32_t sc_counter_tts = SC_PERF_MGMTT_TTS; /** is the stats counter enabled? */ static char sc_counter_enabled = TRUE; /** append or overwrite? 1: append, 0: overwrite */ static char sc_counter_append = TRUE; /** * \brief Adds a value of type uint64_t to the local counter. * * \param id ID of the counter as set by the API * \param pca Counter array that holds the local counter for this TM * \param x Value to add to this local counter */ void SCPerfCounterAddUI64(uint16_t id, SCPerfCounterArray *pca, uint64_t x) { if (!pca) { SCLogDebug("counterarray is NULL"); return; } if ((id < 1) || (id > pca->size)) { SCLogDebug("counter doesn't exist"); return; } switch (pca->head[id].pc->value->type) { case SC_PERF_TYPE_UINT64: pca->head[id].ui64_cnt += x; break; case SC_PERF_TYPE_DOUBLE: pca->head[id].d_cnt += x; break; } if (pca->head[id].syncs == ULONG_MAX) { pca->head[id].syncs = 0; pca->head[id].wrapped_syncs++; } pca->head[id].syncs++; return; } /** * \brief Adds a value of type double to the local counter * * \param id ID of the counter as set by the API * \param pca Counter array that holds the local counter for this TM * \param x Value to add to this local counter */ void SCPerfCounterAddDouble(uint16_t id, SCPerfCounterArray *pca, double x) { if (!pca) { SCLogDebug("counterarray is NULL"); return; } if ((id < 1) || (id > pca->size)) { SCLogDebug("counter doesn't exist"); return; } /* incase you are trying to add a double to a counter of type SC_PERF_TYPE_UINT64 * it will be truncated */ switch (pca->head[id].pc->value->type) { case SC_PERF_TYPE_UINT64: pca->head[id].ui64_cnt += x; break; case SC_PERF_TYPE_DOUBLE: pca->head[id].d_cnt += x; break; } if (pca->head[id].syncs == ULONG_MAX) { pca->head[id].syncs = 0; pca->head[id].wrapped_syncs++; } pca->head[id].syncs++; return; } /** * \brief Increments the local counter * * \param id Index of the counter in the counter array * \param pca Counter array that holds the local counters for this TM */ void SCPerfCounterIncr(uint16_t id, SCPerfCounterArray *pca) { if (pca == NULL) { SCLogDebug("counterarray is NULL"); return; } if ((id < 1) || (id > pca->size)) { SCLogDebug("counter doesn't exist"); return; } switch (pca->head[id].pc->value->type) { case SC_PERF_TYPE_UINT64: pca->head[id].ui64_cnt++; break; case SC_PERF_TYPE_DOUBLE: pca->head[id].d_cnt++; break; } if (pca->head[id].syncs == ULONG_MAX) { pca->head[id].syncs = 0; pca->head[id].wrapped_syncs++; } pca->head[id].syncs++; return; } /** * \brief Sets a value of type double to the local counter * * \param id Index of the local counter in the counter array * \param pca Pointer to the SCPerfCounterArray * \param x The value to set for the counter */ void SCPerfCounterSetUI64(uint16_t id, SCPerfCounterArray *pca, uint64_t x) { if (!pca) { SCLogDebug("counterarray is NULL"); return; } if ((id < 1) || (id > pca->size)) { SCLogDebug("counter doesn't exist"); return; } switch (pca->head[id].pc->value->type) { case SC_PERF_TYPE_UINT64: if ( (pca->head[id].pc->type_q->type & SC_PERF_TYPE_Q_MAXIMUM) && (x > pca->head[id].ui64_cnt)) { pca->head[id].ui64_cnt = x; } else if (pca->head[id].pc->type_q->type & SC_PERF_TYPE_Q_NORMAL) { pca->head[id].ui64_cnt = x; } break; case SC_PERF_TYPE_DOUBLE: if ( (pca->head[id].pc->type_q->type & SC_PERF_TYPE_Q_MAXIMUM) && (x > pca->head[id].d_cnt)) { pca->head[id].d_cnt = x; } else if (pca->head[id].pc->type_q->type & SC_PERF_TYPE_Q_NORMAL) { pca->head[id].d_cnt = x; } break; } if (pca->head[id].syncs == ULONG_MAX) { pca->head[id].syncs = 0; pca->head[id].wrapped_syncs++; } pca->head[id].syncs++; return; } /** * \brief Sets a local counter to an arg of type double * * \param id Index of the local counter in the counter array * \param pca Pointer to the SCPerfCounterArray * \param x The value to set for the counter */ void SCPerfCounterSetDouble(uint16_t id, SCPerfCounterArray *pca, double x) { if (!pca) { SCLogDebug("counterarray is NULL"); return; } if ((id < 1) || (id > pca->size)) { SCLogDebug("counter doesn't exist"); return; } switch (pca->head[id].pc->value->type) { case SC_PERF_TYPE_UINT64: if ( (pca->head[id].pc->type_q->type & SC_PERF_TYPE_Q_MAXIMUM) && (x > pca->head[id].ui64_cnt)) { pca->head[id].ui64_cnt = x; } else if (pca->head[id].pc->type_q->type & SC_PERF_TYPE_Q_NORMAL) { pca->head[id].ui64_cnt = x; } break; case SC_PERF_TYPE_DOUBLE: if ( (pca->head[id].pc->type_q->type & SC_PERF_TYPE_Q_MAXIMUM) && (x > pca->head[id].d_cnt)) { pca->head[id].d_cnt = x; } else if (pca->head[id].pc->type_q->type & SC_PERF_TYPE_Q_NORMAL) { pca->head[id].d_cnt = x; } break; } if (pca->head[id].syncs == ULONG_MAX) { pca->head[id].syncs = 0; pca->head[id].wrapped_syncs++; } pca->head[id].syncs++; return; } /** * \brief Get the filename with path to the stats log file. * * This function returns a string containing the log filename. It uses * allocated memory simply to drop into the existing code a little better * where a SCStrdup was used. So as before, it is up to the caller to free * the memory. * * \retval An allocated string containing the log filename on success or NULL on * failure. */ static char *SCPerfGetLogFilename(ConfNode *stats) { char *log_dir = NULL; char *log_filename = NULL; const char* filename = NULL; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; if ( (log_filename = SCMalloc(PATH_MAX)) == NULL) { return NULL; } if (stats != NULL) { filename = ConfNodeLookupChildValue(stats, "filename"); if (filename == NULL) { filename = SC_PERF_DEFAULT_LOG_FILENAME; } } else { filename = SC_PERF_DEFAULT_LOG_FILENAME; } if (snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, filename) < 0) { SCLogError(SC_ERR_SPRINTF, "Sprintf Error"); SCFree(log_filename); return NULL; } return log_filename; } /** * \brief Initializes the output interface context * * \todo Support multiple interfaces */ static void SCPerfInitOPCtx(void) { SCEnter(); ConfNode *root = ConfGetNode("outputs"); ConfNode *node = NULL; ConfNode *stats = NULL; if (root != NULL) { TAILQ_FOREACH(node, &root->head, next) { if (strncmp(node->val, "stats", 5) == 0) { stats = node->head.tqh_first; } } } /* Check if the stats module is enabled or not */ if (stats != NULL) { const char *enabled = ConfNodeLookupChildValue(stats, "enabled"); if (enabled != NULL && ConfValIsFalse(enabled)) { sc_counter_enabled = FALSE; SCLogDebug("Stats module has been disabled"); SCReturn; } const char *interval = ConfNodeLookupChildValue(stats, "interval"); if (interval != NULL) sc_counter_tts = (uint32_t) atoi(interval); const char *append = ConfNodeLookupChildValue(stats, "append"); if (append != NULL) sc_counter_append = ConfValIsTrue(append); } /* Store the engine start time */ time(&sc_start_time); if ( (sc_perf_op_ctx = SCMalloc(sizeof(SCPerfOPIfaceContext))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCPerfInitOPCtx. Exiting..."); exit(EXIT_FAILURE); } memset(sc_perf_op_ctx, 0, sizeof(SCPerfOPIfaceContext)); sc_perf_op_ctx->iface = SC_PERF_IFACE_FILE; if ( (sc_perf_op_ctx->file = SCPerfGetLogFilename(stats)) == NULL) { SCLogInfo("Error retrieving Perf Counter API output file path"); } char *mode; if (sc_counter_append) mode = "a+"; else mode = "w+"; if ( (sc_perf_op_ctx->fp = fopen(sc_perf_op_ctx->file, mode)) == NULL) { SCLogError(SC_ERR_FOPEN, "fopen error opening file \"%s\". Resorting " "to using the standard output for output", sc_perf_op_ctx->file); SCFree(sc_perf_op_ctx->file); /* Let us use the standard output for output */ sc_perf_op_ctx->fp = stdout; if ( (sc_perf_op_ctx->file = SCStrdup("stdout")) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } } /* club the counter from multiple instances of the tm before o/p */ sc_perf_op_ctx->club_tm = 1; /* init the lock used by SCPerfClubTMInst */ if (SCMutexInit(&sc_perf_op_ctx->pctmi_lock, NULL) != 0) { SCLogError(SC_ERR_INITIALIZATION, "error initializing pctmi mutex"); exit(EXIT_FAILURE); } SCReturn; } /** * \brief Releases the resources alloted to the output context of the Perf * Counter API */ static void SCPerfReleaseOPCtx() { if (sc_perf_op_ctx == NULL) { SCLogDebug("Counter module has been disabled"); return; } SCPerfClubTMInst *pctmi = NULL; SCPerfClubTMInst *temp = NULL; pctmi = sc_perf_op_ctx->pctmi; if (sc_perf_op_ctx->fp != NULL) fclose(sc_perf_op_ctx->fp); if (sc_perf_op_ctx->file != NULL) SCFree(sc_perf_op_ctx->file); while (pctmi != NULL) { if (pctmi->tm_name != NULL) SCFree(pctmi->tm_name); if (pctmi->head != NULL) SCFree(pctmi->head); temp = pctmi->next; SCFree(pctmi); pctmi = temp; } SCFree(sc_perf_op_ctx); sc_perf_op_ctx = NULL; return; } /** * \brief The management thread. This thread is responsible for writing the * performance stats information. * * \param arg is NULL always * * \retval NULL This is the value that is always returned */ static void *SCPerfMgmtThread(void *arg) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *tv_local = (ThreadVars *)arg; uint8_t run = 1; struct timespec cond_time; /* Set the thread name */ if (SCSetThreadName(tv_local->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } if (tv_local->thread_setup_flags != 0) TmThreadSetupOptions(tv_local); /* Set the threads capability */ tv_local->cap_flags = 0; SCDropCaps(tv_local); if (sc_perf_op_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" "SCPerfInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; } TmThreadsSetFlag(tv_local, THV_INIT_DONE); while (run) { if (TmThreadsCheckFlag(tv_local, THV_PAUSE)) { TmThreadsSetFlag(tv_local, THV_PAUSED); TmThreadTestThreadUnPaused(tv_local); TmThreadsUnsetFlag(tv_local, THV_PAUSED); } cond_time.tv_sec = time(NULL) + sc_counter_tts; cond_time.tv_nsec = 0; SCMutexLock(tv_local->m); SCCondTimedwait(tv_local->cond, tv_local->m, &cond_time); SCMutexUnlock(tv_local->m); SCPerfOutputCounters(); if (TmThreadsCheckFlag(tv_local, THV_KILL)) { run = 0; } } TmThreadsSetFlag(tv_local, THV_RUNNING_DONE); TmThreadWaitForFlag(tv_local, THV_DEINIT); TmThreadsSetFlag(tv_local, THV_CLOSED); return NULL; } /** * \brief Wake up thread. This thread wakes up every TTS(time to sleep) seconds * and sets the flag for every ThreadVars' SCPerfContext * * \param arg is NULL always * * \retval NULL This is the value that is always returned */ static void *SCPerfWakeupThread(void *arg) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *tv_local = (ThreadVars *)arg; uint8_t run = 1; ThreadVars *tv = NULL; PacketQueue *q = NULL; struct timespec cond_time; /* Set the thread name */ if (SCSetThreadName(tv_local->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } if (tv_local->thread_setup_flags != 0) TmThreadSetupOptions(tv_local); /* Set the threads capability */ tv_local->cap_flags = 0; SCDropCaps(tv_local); if (sc_perf_op_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" "SCPerfInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; } TmThreadsSetFlag(tv_local, THV_INIT_DONE); while (run) { if (TmThreadsCheckFlag(tv_local, THV_PAUSE)) { TmThreadsSetFlag(tv_local, THV_PAUSED); TmThreadTestThreadUnPaused(tv_local); TmThreadsUnsetFlag(tv_local, THV_PAUSED); } cond_time.tv_sec = time(NULL) + SC_PERF_WUT_TTS; cond_time.tv_nsec = 0; SCMutexLock(tv_local->m); SCCondTimedwait(tv_local->cond, tv_local->m, &cond_time); SCMutexUnlock(tv_local->m); tv = tv_root[TVT_PPT]; while (tv != NULL) { if (tv->sc_perf_pctx.head == NULL) { tv = tv->next; continue; } /* assuming the assignment of an int to be atomic, and even if it's * not, it should be okay */ tv->sc_perf_pctx.perf_flag = 1; if (tv->inq != NULL) { q = &trans_q[tv->inq->id]; SCCondSignal(&q->cond_q); } tv = tv->next; } /* mgt threads for flow manager */ tv = tv_root[TVT_MGMT]; while (tv != NULL) { if (tv->sc_perf_pctx.head == NULL) { tv = tv->next; continue; } /* assuming the assignment of an int to be atomic, and even if it's * not, it should be okay */ tv->sc_perf_pctx.perf_flag = 1; tv = tv->next; } if (TmThreadsCheckFlag(tv_local, THV_KILL)) { run = 0; } } TmThreadsSetFlag(tv_local, THV_RUNNING_DONE); TmThreadWaitForFlag(tv_local, THV_DEINIT); TmThreadsSetFlag(tv_local, THV_CLOSED); return NULL; } /** * \brief Parses a time based counter interval * * \param pc Pointer to the PerfCounter that has to be updated with the * interval * \param interval Pointer to a character string that holds the time interval * * \retval 0 on successfully parsing the time_interval * \retval -1 on error */ static int SCPerfParseTBCounterInterval(SCPerfCounter *pc, char *interval) { pcre *regex = NULL; pcre_extra *regex_study = NULL; int opts = 0; const char *ep = NULL; const char *str_ptr1 = NULL; const char *str_ptr2 = NULL; int eo = 0; int ret = 0; int res = 0; int ov[30]; int temp_value = 0; int i = 0; regex = pcre_compile(SC_PERF_PCRE_TIMEBASED_INTERVAL, opts, &ep, &eo, NULL); if (regex == NULL) { SCLogInfo("pcre compile of \"%s\" failed at offset %d: %s", interval, eo, ep); goto error; } regex_study = pcre_study(regex, 0, &ep); if (ep != NULL) { SCLogInfo("pcre study failed: %s", ep); goto error; } ret = pcre_exec(regex, regex_study, interval, strlen(interval), 0, 0, ov, 30); if (ret < 0) { SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "Invalid Timebased interval"); goto error; } for (i = 1; i < ret; i += 2) { res = pcre_get_substring((char *)interval, ov, 30, i, &str_ptr1); if (res < 0) { SCLogInfo("SCPerfParseTBCounterInterval:pcre_get_substring failed"); goto error; } temp_value = atoi(str_ptr1); res = pcre_get_substring((char *)interval, ov, 30, i + 1, &str_ptr2); if (res < 0) { SCLogInfo("SCPerfParseTBCounterInterval:pcre_get_substring failed"); goto error; } switch (*str_ptr2) { case 'h': if (temp_value < 0 || temp_value > 24) { SCLogInfo("Invalid timebased counter interval"); goto error; } pc->type_q->hours = temp_value; break; case 'm': if (temp_value < 0 || temp_value >= 60) { SCLogInfo("Invalid timebased counter interval"); goto error; } pc->type_q->minutes = temp_value; break; case 's': if (temp_value < 0 || temp_value >= 60) { SCLogInfo("Invalid timebased counter interval"); goto error; } pc->type_q->seconds = temp_value; break; } } if ( !(pc->type_q->hours | pc->type_q->minutes | pc->type_q->seconds)) { SCLogInfo("Invalid timebased counter interval"); goto error; } pc->type_q->total_secs = ((pc->type_q->hours * 60 * 60) + (pc->type_q->minutes * 60) + pc->type_q->seconds); if (str_ptr1 != NULL) SCFree((char *)str_ptr1); if (str_ptr2 != NULL) SCFree((char *)str_ptr2); SCFree(regex); return 0; error: if (str_ptr1 != NULL) SCFree((char *)str_ptr1); if (str_ptr2 != NULL) SCFree((char *)str_ptr2); return -1; } /** * \brief Releases a perf counter. Used internally by * SCPerfReleasePerfCounterS() * * \param pc Pointer to the SCPerfCounter to be freed */ static void SCPerfReleaseCounter(SCPerfCounter *pc) { if (pc != NULL) { if (pc->name != NULL) { if (pc->name->cname != NULL) SCFree(pc->name->cname); if (pc->name->tm_name != NULL) SCFree(pc->name->tm_name); SCFree(pc->name); } if (pc->value != NULL) { if (pc->value->cvalue != NULL) SCFree(pc->value->cvalue); SCFree(pc->value); } if (pc->desc != NULL) SCFree(pc->desc); if (pc->type_q != NULL) SCFree(pc->type_q); SCFree(pc); } return; } /** * \brief Registers a counter. Used internally by the Perf Counter API * * \param cname Name of the counter, to be registered * \param tm_name Thread module to which this counter belongs * \param type Datatype of this counter variable * \param desc Description of this counter * \param pctx SCPerfContext for this tm-tv instance * \param type_q Qualifier describing the type of counter to be registered * \param interval Time interval required by a SC_PERF_TYPE_Q_TIMEBASED counter * * \retval the counter id for the newly registered counter, or the already * present counter on success * \retval 0 on failure */ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, int type, char *desc, SCPerfContext *pctx, int type_q, char *interval) { SCPerfCounter **head = &pctx->head; SCPerfCounter *temp = NULL; SCPerfCounter *prev = NULL; SCPerfCounter *pc = NULL; if (cname == NULL || tm_name == NULL || pctx == NULL) { SCLogDebug("Counter name, tm name null or SCPerfContext NULL"); return 0; } /* (SC_PERF_TYPE_MAX - 1) because we haven't implemented SC_PERF_TYPE_STR */ if ((type >= (SC_PERF_TYPE_MAX - 1)) || (type < 0)) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Counters of type %" PRId32 " can't " "be registered", type); return 0; } temp = prev = *head; while (temp != NULL) { prev = temp; if (strcmp(cname, temp->name->cname) == 0 && strcmp(tm_name, temp->name->tm_name) == 0) { break; } temp = temp->next; } /* We already have a counter registered by this name */ if (temp != NULL) return(temp->id); /* if we reach this point we don't have a counter registered by this cname */ if ( (pc = SCMalloc(sizeof(SCPerfCounter))) == NULL) return 0; memset(pc, 0, sizeof(SCPerfCounter)); if ( (pc->name = SCMalloc(sizeof(SCPerfCounterName))) == NULL) { SCFree(pc); return 0; } memset(pc->name, 0, sizeof(SCPerfCounterName)); if ( (pc->value = SCMalloc(sizeof(SCPerfCounterValue))) == NULL) { SCFree(pc->name); SCFree(pc); return 0; } memset(pc->value, 0, sizeof(SCPerfCounterValue)); if ( (pc->name->cname = SCStrdup(cname)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } if ( (pc->name->tm_name = SCStrdup(tm_name)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } /* assign a unique id to this SCPerfCounter. The id is local to this * PerfContext. Please note that the id start from 1, and not 0 */ pc->id = ++(pctx->curr_id); if (desc != NULL && (pc->desc = SCStrdup(desc)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } if ( (pc->type_q = SCMalloc(sizeof(SCPerfCounterTypeQ))) == NULL) return 0; memset(pc->type_q, 0, sizeof(SCPerfCounterTypeQ)); pc->type_q->type = type_q; /* handle timebased counters */ if (pc->type_q->type & SC_PERF_TYPE_Q_TIMEBASED) { /* override for all timebased counters */ type = SC_PERF_TYPE_DOUBLE; if (SCPerfParseTBCounterInterval(pc, interval) == -1) { SCPerfReleaseCounter(pc); return 0; } } /* allocate memory to hold this counter value */ pc->value->type = type; switch (pc->value->type) { case SC_PERF_TYPE_UINT64: pc->value->size = sizeof(uint64_t); break; case SC_PERF_TYPE_DOUBLE: pc->value->size = sizeof(double); break; } if ( (pc->value->cvalue = SCMalloc(pc->value->size)) == NULL) return 0; memset(pc->value->cvalue, 0, pc->value->size); /* display flag which specifies if the counter should be displayed or not */ pc->disp = 1; /* we now add the counter to the list */ if (prev == NULL) *head = pc; else prev->next = pc; return pc->id; } /** * \brief Copies the SCPerfCounter value from the local counter present in the * SCPerfCounterArray to its corresponding global counterpart. Used * internally by SCPerfUpdateCounterArray() * * \param pcae Pointer to the SCPerfCounterArray which holds the local * versions of the counters * \param reset_lc Flag which indicates if the values of the local counters * in the SCPerfCounterArray has to be reset or not */ static void SCPerfCopyCounterValue(SCPCAElem *pcae, int reset_lc) { SCPerfCounter *pc = NULL; double d_temp = 0; uint64_t ui64_temp = 0; struct timeval curr_ts; uint64_t u = 0; pc = pcae->pc; switch (pc->value->type) { case SC_PERF_TYPE_UINT64: ui64_temp = pcae->ui64_cnt; if (pc->type_q->type & SC_PERF_TYPE_Q_AVERAGE) { for (u = 0; u < pcae->wrapped_syncs; u++) ui64_temp /= ULONG_MAX; if (pcae->syncs != 0) ui64_temp /= pcae->syncs; *((uint64_t *)pc->value->cvalue) = ui64_temp; } else if (pc->type_q->type & SC_PERF_TYPE_Q_TIMEBASED) { /* we have a timebased counter. Awesome. Time for some more processing */ TimeGet(&curr_ts); pc->type_q->tbc_secs += ((curr_ts.tv_sec + curr_ts.tv_usec / 1000000.0) - (pcae->ts.tv_sec + pcae->ts.tv_usec / 1000000.0)); /* special treatment for timebased counters. We add instead of * copying to the global counters. The job of resetting the * global counters is done by the output function */ *((uint64_t *)pc->value->cvalue) += ui64_temp; pcae->ui64_cnt = 0; /* reset it to the current time */ TimeGet(&pcae->ts); } else { *((uint64_t *)pc->value->cvalue) = ui64_temp; } if (reset_lc) pcae->ui64_cnt = 0; break; case SC_PERF_TYPE_DOUBLE: d_temp = pcae->d_cnt; if (pc->type_q->type & SC_PERF_TYPE_Q_AVERAGE) { for (u = 0; u < pcae->wrapped_syncs; u++) d_temp /= ULONG_MAX; if (pcae->syncs != 0) d_temp /= pcae->syncs; *((double *)pc->value->cvalue) = d_temp; } else if (pc->type_q->type & SC_PERF_TYPE_Q_TIMEBASED) { /* we have a timebased counter. Awesome. Time for some more processing */ TimeGet(&curr_ts); pc->type_q->tbc_secs += ((curr_ts.tv_sec + curr_ts.tv_usec / 1000000.0) - (pcae->ts.tv_sec + pcae->ts.tv_usec / 1000000.0)); /* special treatment for timebased counters. We add instead of * copying to the global counters. The job of resetting the * global counters is done by the output function */ *((double *)pc->value->cvalue) += d_temp; pcae->d_cnt = 0; /* reset it to the current time */ TimeGet(&pcae->ts); } else { *((double *)pc->value->cvalue) = d_temp; } if (reset_lc) pcae->d_cnt = 0; break; } return; } /** * \brief Calculates counter value that should be sent as output * * If we aren't dealing with timebased counters, we just return the * the counter value. In case of Timebased counters, if we haven't * crossed the interval, we display the current value without any * modifications. If we have crossed the limit, we calculate the counter * value for the time period and also return 1, to indicate that the * counter value can be reset after use * * \param pc Pointer to the PerfCounter for which the timebased counter has to * be calculated */ static void SCPerfOutputCalculateCounterValue(SCPerfCounter *pc, void *cvalue_op) { double divisor = 0; switch (pc->value->type) { case SC_PERF_TYPE_UINT64: *((uint64_t *)cvalue_op) = *((uint64_t *)pc->value->cvalue); break; case SC_PERF_TYPE_DOUBLE: *((double *)cvalue_op) = *((double *)pc->value->cvalue); break; } /* if we don't have a Timebased counter, we are out of here */ if ( !(pc->type_q->type & SC_PERF_TYPE_Q_TIMEBASED)) return; //if (pc->type_q->tbc_secs < pc->type_q->total_secs) // return; divisor = pc->type_q->tbc_secs/pc->type_q->total_secs; divisor += ((double)(pc->type_q->tbc_secs % pc->type_q->total_secs)/ pc->type_q->total_secs); switch (pc->value->type) { case SC_PERF_TYPE_UINT64: *((uint64_t *)cvalue_op) /= divisor; break; case SC_PERF_TYPE_DOUBLE: *((double *)cvalue_op) /= divisor; break; } pc->type_q->tbc_secs = 0; /* reset the local counter back to 0 */ memset(pc->value->cvalue, 0, pc->value->size); return; } /** * \brief The file output interface for the Perf Counter api */ static int SCPerfOutputCounterFileIface() { ThreadVars *tv = NULL; SCPerfClubTMInst *pctmi = NULL; SCPerfCounter *pc = NULL; SCPerfCounter **pc_heads = NULL; uint64_t ui64_temp = 0; uint64_t ui64_result = 0; double double_temp = 0; double double_result = 0; struct timeval tval; struct tm *tms; uint32_t u = 0; int flag = 0; if (sc_perf_op_ctx->fp == NULL) { SCLogDebug("perf_op_ctx->fp is NULL"); return 0; } memset(&tval, 0, sizeof(struct timeval)); gettimeofday(&tval, NULL); struct tm local_tm; tms = (struct tm *)SCLocalTime(tval.tv_sec, &local_tm); /* Calculate the Engine uptime */ int up_time = (int)difftime(tval.tv_sec, sc_start_time); int sec = up_time % 60; // Seconds in a minute int in_min = up_time / 60; int min = in_min % 60; // Minutes in a hour int in_hours = in_min / 60; int hours = in_hours % 24; // Hours in a day int days = in_hours / 24; fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" "---------------------\n"); fprintf(sc_perf_op_ctx->fp, "Date: %" PRId32 "/%" PRId32 "/%04d -- " "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec, days, hours, min, sec); fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" "---------------------\n"); fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s | %-s\n", "Counter", "TM Name", "Value"); fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" "---------------------\n"); if (sc_perf_op_ctx->club_tm == 0) { for (u = 0; u < TVT_MAX; u++) { tv = tv_root[u]; //if (pc_heads == NULL || pc_heads[u] == NULL) // continue; while (tv != NULL) { SCMutexLock(&tv->sc_perf_pctx.m); pc = tv->sc_perf_pctx.head; while (pc != NULL) { if (pc->disp == 0 || pc->value == NULL) { pc = pc->next; continue; } switch (pc->value->type) { case SC_PERF_TYPE_UINT64: SCPerfOutputCalculateCounterValue(pc, &ui64_temp); fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s | " "%-" PRIu64 "\n", pc->name->cname, pc->name->tm_name, ui64_temp); break; case SC_PERF_TYPE_DOUBLE: SCPerfOutputCalculateCounterValue(pc, &double_temp); fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s |" " %-lf\n", pc->name->cname, pc->name->tm_name, double_temp); break; } pc = pc->next; } SCMutexUnlock(&tv->sc_perf_pctx.m); tv = tv->next; } fflush(sc_perf_op_ctx->fp); } return 1; } pctmi = sc_perf_op_ctx->pctmi; while (pctmi != NULL) { if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) return 0; memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); for (u = 0; u < pctmi->size; u++) { pc_heads[u] = pctmi->head[u]->head; SCMutexLock(&pctmi->head[u]->m); while(pc_heads[u] != NULL && strcmp(pctmi->tm_name, pc_heads[u]->name->tm_name)) { pc_heads[u] = pc_heads[u]->next; } } flag = 1; while(flag) { ui64_result = 0; double_result = 0; if (pc_heads[0] == NULL) break; pc = pc_heads[0]; for (u = 0; u < pctmi->size; u++) { switch (pc->value->type) { case SC_PERF_TYPE_UINT64: SCPerfOutputCalculateCounterValue(pc_heads[u], &ui64_temp); ui64_result += ui64_temp; break; case SC_PERF_TYPE_DOUBLE: SCPerfOutputCalculateCounterValue(pc_heads[u], &double_temp); double_result += double_temp; break; } if (pc_heads[u] != NULL) pc_heads[u] = pc_heads[u]->next; if (pc_heads[u] == NULL || (pc_heads[0] != NULL && strcmp(pctmi->tm_name, pc_heads[0]->name->tm_name))) { flag = 0; } } if (pc->disp == 0 || pc->value == NULL) continue; switch (pc->value->type) { case SC_PERF_TYPE_UINT64: fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s | %-" PRIu64 "\n", pc->name->cname, pctmi->tm_name, ui64_result); break; case SC_PERF_TYPE_DOUBLE: fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s | %0.0lf\n", pc->name->cname, pctmi->tm_name, double_result); break; } } for (u = 0; u < pctmi->size; u++) SCMutexUnlock(&pctmi->head[u]->m); pctmi = pctmi->next; SCFree(pc_heads); fflush(sc_perf_op_ctx->fp); } return 1; } #ifdef BUILD_UNIX_SOCKET /** * \brief The file output interface for the Perf Counter api */ TmEcode SCPerfOutputCounterSocket(json_t *cmd, json_t *answer, void *data) { ThreadVars *tv = NULL; SCPerfClubTMInst *pctmi = NULL; SCPerfCounter *pc = NULL; SCPerfCounter **pc_heads = NULL; uint64_t ui64_temp = 0; uint64_t ui64_result = 0; double double_temp = 0; double double_result = 0; uint32_t u = 0; int flag = 0; if (sc_perf_op_ctx == NULL) { json_object_set_new(answer, "message", json_string("No performance counter context")); return TM_ECODE_FAILED; } if (sc_perf_op_ctx->club_tm == 0) { json_t *tm_array; tm_array = json_object(); if (tm_array == NULL) { json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } for (u = 0; u < TVT_MAX; u++) { tv = tv_root[u]; //if (pc_heads == NULL || pc_heads[u] == NULL) // continue; while (tv != NULL) { SCMutexLock(&tv->sc_perf_pctx.m); pc = tv->sc_perf_pctx.head; json_t *jdata; int filled = 0; jdata = json_object(); if (jdata == NULL) { json_decref(tm_array); json_object_set_new(answer, "message", json_string("internal error at json object creation")); SCMutexUnlock(&tv->sc_perf_pctx.m); return TM_ECODE_FAILED; } while (pc != NULL) { if (pc->disp == 0 || pc->value == NULL) { pc = pc->next; continue; } switch (pc->value->type) { case SC_PERF_TYPE_UINT64: SCPerfOutputCalculateCounterValue(pc, &ui64_temp); json_object_set_new(jdata, pc->name->cname, json_integer(ui64_temp)); filled = 1; break; case SC_PERF_TYPE_DOUBLE: SCPerfOutputCalculateCounterValue(pc, &double_temp); json_object_set_new(jdata, pc->name->cname, json_real(double_temp)); filled = 1; break; } pc = pc->next; } SCMutexUnlock(&tv->sc_perf_pctx.m); if (filled == 1) { json_object_set_new(tm_array, tv->name, jdata); } tv = tv->next; } } json_object_set_new(answer, "message", tm_array); return TM_ECODE_OK; } json_t *tm_array; tm_array = json_object(); if (tm_array == NULL) { json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } pctmi = sc_perf_op_ctx->pctmi; while (pctmi != NULL) { json_t *jdata; int filled = 0; jdata = json_object(); if (jdata == NULL) { json_decref(tm_array); json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) { json_decref(tm_array); json_object_set_new(answer, "message", json_string("internal memory error")); return TM_ECODE_FAILED; } memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); for (u = 0; u < pctmi->size; u++) { pc_heads[u] = pctmi->head[u]->head; SCMutexLock(&pctmi->head[u]->m); while(pc_heads[u] != NULL && strcmp(pctmi->tm_name, pc_heads[u]->name->tm_name)) { pc_heads[u] = pc_heads[u]->next; } } flag = 1; while(flag) { ui64_result = 0; double_result = 0; if (pc_heads[0] == NULL) break; pc = pc_heads[0]; for (u = 0; u < pctmi->size; u++) { switch (pc->value->type) { case SC_PERF_TYPE_UINT64: SCPerfOutputCalculateCounterValue(pc_heads[u], &ui64_temp); ui64_result += ui64_temp; break; case SC_PERF_TYPE_DOUBLE: SCPerfOutputCalculateCounterValue(pc_heads[u], &double_temp); double_result += double_temp; break; } if (pc_heads[u] != NULL) pc_heads[u] = pc_heads[u]->next; if (pc_heads[u] == NULL || (pc_heads[0] != NULL && strcmp(pctmi->tm_name, pc_heads[0]->name->tm_name))) { flag = 0; } } if (pc->disp == 0 || pc->value == NULL) continue; switch (pc->value->type) { case SC_PERF_TYPE_UINT64: filled = 1; json_object_set_new(jdata, pc->name->cname, json_integer(ui64_result)); break; case SC_PERF_TYPE_DOUBLE: filled = 1; json_object_set_new(jdata, pc->name->cname, json_real(double_result)); break; } } for (u = 0; u < pctmi->size; u++) SCMutexUnlock(&pctmi->head[u]->m); if (filled == 1) { json_object_set_new(tm_array, pctmi->tm_name, jdata); } pctmi = pctmi->next; SCFree(pc_heads); } json_object_set_new(answer, "message", tm_array); return TM_ECODE_OK; } #endif /* BUILD_UNIX_SOCKET */ /** * \brief Initializes the perf counter api. Things are hard coded currently. * More work to be done when we implement multiple interfaces */ void SCPerfInitCounterApi(void) { SCPerfInitOPCtx(); return; } /** * \brief Spawns the wakeup, and the management thread used by the perf * counter api */ void SCPerfSpawnThreads(void) { SCEnter(); if (!sc_counter_enabled) { SCReturn; } ThreadVars *tv_wakeup = NULL; ThreadVars *tv_mgmt = NULL; /* spawn the stats wakeup thread */ tv_wakeup = TmThreadCreateMgmtThread("SCPerfWakeupThread", SCPerfWakeupThread, 1); if (tv_wakeup == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadCreateMgmtThread " "failed"); exit(EXIT_FAILURE); } if (TmThreadSpawn(tv_wakeup) != 0) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " "SCPerfWakeupThread"); exit(EXIT_FAILURE); } /* spawn the stats mgmt thread */ tv_mgmt = TmThreadCreateMgmtThread("SCPerfMgmtThread", SCPerfMgmtThread, 1); if (tv_mgmt == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadCreateMgmtThread failed"); exit(EXIT_FAILURE); } if (TmThreadSpawn(tv_mgmt) != 0) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " "SCPerfWakeupThread"); exit(EXIT_FAILURE); } SCReturn; } /** * \brief Registers a normal, unqualified counter * * \param cname Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * \param type Datatype of this counter variable * \param desc Description of this counter * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type, char *desc) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, desc, &tv->sc_perf_pctx, SC_PERF_TYPE_Q_NORMAL, NULL); return id; } /** * \brief Registers a counter, whose value holds the average of all the values * assigned to it. * * \param cname Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * \param type Datatype of this counter variable * \param desc Description of this counter * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, int type, char *desc) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, desc, &tv->sc_perf_pctx, SC_PERF_TYPE_Q_AVERAGE, NULL); return id; } /** * \brief Registers a counter, whose value holds the maximum of all the values * assigned to it. * * \param cname Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered * \param type Datatype of this counter variable * \param desc Description of this counter * * \retval the counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, int type, char *desc) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, desc, &tv->sc_perf_pctx, SC_PERF_TYPE_Q_MAXIMUM, NULL); return id; } /** * \brief Registers a counter, whose value holds the value taken held the * counter in a specified time interval * * \param cname Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter * would be registered * \param type Datatype of this counter variable * \param desc Description of this counter * \param interval The time interval over which the counter value has to be * calculated. The format for the time interval is * "", where number > 0, and modifier can * be "s" for seconds, "m" for minutes, "h" for hours * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfTVRegisterIntervalCounter(char *cname, struct ThreadVars_ *tv, int type, char *desc, char *time_interval) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, type, desc, &tv->sc_perf_pctx, SC_PERF_TYPE_Q_TIMEBASED | SC_PERF_TYPE_Q_NORMAL, time_interval); return id; } /** * \brief Registers a normal, unqualified counter * * \param cname Name of the counter, to be registered * \param tm_name Name of the engine module under which the counter has to be * registered * \param type Datatype of this counter variable * \param desc Description of this counter * \param pctx SCPerfContext corresponding to the tm_name key under which the * key has to be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char *desc, SCPerfContext *pctx) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, pctx, SC_PERF_TYPE_Q_NORMAL, NULL); return id; } /** * \brief Registers a counter, whose value holds the average of all the values * assigned to it. * * \param cname Name of the counter, to be registered * \param tm_name Name of the engine module under which the counter has to be * registered * \param type Datatype of this counter variable * \param desc Description of this counter * \param pctx SCPerfContext corresponding to the tm_name key under which the * key has to be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfRegisterAvgCounter(char *cname, char *tm_name, int type, char *desc, SCPerfContext *pctx) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, pctx, SC_PERF_TYPE_Q_AVERAGE, NULL); return id; } /** * \brief Registers a counter, whose value holds the maximum of all the values * assigned to it. * * \param cname Name of the counter, to be registered * \param tm_name Name of the engine module under which the counter has to be * registered * \param type Datatype of this counter variable * \param desc Description of this counter * \param pctx SCPerfContext corresponding to the tm_name key under which the * key has to be registered * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfRegisterMaxCounter(char *cname, char *tm_name, int type, char *desc, SCPerfContext *pctx) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, pctx, SC_PERF_TYPE_Q_MAXIMUM, NULL); return id; } /** * \brief Registers a counter, whose value holds the value taken held the * counter in a specified time interval * * \param cname Name of the counter, to be registered * \param tm_name Name of the engine module under which the counter has to be * registered * \param type Datatype of this counter variable * \param desc Description of this counter * \param pctx SCPerfContext corresponding to the tm_name key under which the * key has to be registered * \param interval The time interval over which the counter value has to be * calculated. The format for the time interval is * "", where number > 0, and modifier can * be "s" for seconds, "m" for minutes, "h" for hours * * \retval id Counter id for the newly registered counter, or the already * present counter */ uint16_t SCPerfRegisterIntervalCounter(char *cname, char *tm_name, int type, char *desc, SCPerfContext *pctx, char *time_interval) { uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, pctx, SC_PERF_TYPE_Q_TIMEBASED | SC_PERF_TYPE_Q_NORMAL, time_interval); return id; } /** * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM * are stacked together in a PCTMI container. * * \param tm_name Name of the tm to be added to the table * \param pctx SCPerfContext associated with the TM tm_name * * \retval 1 on success, 0 on failure */ int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfContext *pctx) { if (sc_perf_op_ctx == NULL) { SCLogDebug("Counter module has been disabled"); return 0; } SCPerfClubTMInst *pctmi = NULL; SCPerfClubTMInst *prev = NULL; SCPerfClubTMInst *temp = NULL; SCPerfContext **hpctx = NULL; uint32_t u = 0; if (tm_name == NULL || pctx == NULL) { SCLogDebug("supplied argument(s) to SCPerfAddToClubbedTMTable NULL"); return 0; } SCMutexLock(&sc_perf_op_ctx->pctmi_lock); pctmi = sc_perf_op_ctx->pctmi; SCLogDebug("pctmi %p", pctmi); prev = pctmi; while (pctmi != NULL) { prev = pctmi; if (strcmp(tm_name, pctmi->tm_name) != 0) { pctmi = pctmi->next; continue; } break; } /* get me the bugger who wrote this junk of a code :P */ if (pctmi == NULL) { if ( (temp = SCMalloc(sizeof(SCPerfClubTMInst))) == NULL) { SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 0; } memset(temp, 0, sizeof(SCPerfClubTMInst)); temp->size = 1; temp->head = SCMalloc(sizeof(SCPerfContext **)); if (temp->head == NULL) { SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 0; } temp->head[0] = pctx; temp->tm_name = SCStrdup(tm_name); if (prev == NULL) sc_perf_op_ctx->pctmi = temp; else prev->next = temp; SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 1; } /* see if the pctx is already part of this pctmi */ hpctx = pctmi->head; for (u = 0; u < pctmi->size; u++) { if (hpctx[u] != pctx) continue; SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 1; } pctmi->head = SCRealloc(pctmi->head, (pctmi->size + 1) * sizeof(SCPerfContext **)); if (pctmi->head == NULL) { SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 0; } hpctx = pctmi->head; hpctx[pctmi->size] = pctx; for (u = pctmi->size - 1; u > 0; u--) { if (pctx->curr_id <= hpctx[u]->curr_id) { hpctx[u + 1] = hpctx[u]; hpctx[u] = pctx; continue; } break; } pctmi->size++; SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); return 1; } /** * \brief Returns a counter array for counters in this id range(s_id - e_id) * * \param s_id Counter id of the first counter to be added to the array * \param e_id Counter id of the last counter to be added to the array * \param pctx Pointer to the tv's SCPerfContext * * \retval a counter-array in this(s_id-e_id) range for this TM instance */ SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, SCPerfContext *pctx) { SCPerfCounter *pc = NULL; SCPerfCounterArray *pca = NULL; uint32_t i = 0; if (pctx == NULL) { SCLogDebug("pctx is NULL"); return NULL; } if (s_id < 1 || e_id < 1 || s_id > e_id) { SCLogDebug("error with the counter ids"); return NULL; } if (e_id > pctx->curr_id) { SCLogDebug("end id is greater than the max id for this tv"); return NULL; } if ( (pca = SCMalloc(sizeof(SCPerfCounterArray))) == NULL) return NULL; memset(pca, 0, sizeof(SCPerfCounterArray)); if ( (pca->head = SCMalloc(sizeof(SCPCAElem) * (e_id - s_id + 2))) == NULL) return NULL; memset(pca->head, 0, sizeof(SCPCAElem) * (e_id - s_id + 2)); pc = pctx->head; while (pc->id != s_id) pc = pc->next; i = 1; while ((pc != NULL) && (pc->id <= e_id)) { pca->head[i].pc = pc; pca->head[i].id = pc->id; if (pc->type_q->type & SC_PERF_TYPE_Q_TIMEBASED) TimeGet(&pca->head[i].ts); pc = pc->next; i++; } pca->size = i - 1; return pca; } /** * \brief Returns a counter array for all counters registered for this tm * instance * * \param pctx Pointer to the tv's SCPerfContext * * \retval pca Pointer to a counter-array for all counter of this tm instance * on success; NULL on failure */ SCPerfCounterArray *SCPerfGetAllCountersArray(SCPerfContext *pctx) { SCPerfCounterArray *pca = ((pctx)? SCPerfGetCounterArrayRange(1, pctx->curr_id, pctx): NULL); return pca; } /** * \brief Allows the user the set whether the counter identified with the id * should be displayed or not in the output * * \param id Id of the counter * \param pctx Pointer to the SCPerfContext in which the counter exists * \param disp Holds a 0 or a non-zero value, based on whether the counter * should be displayed or not, in the output * * \retval 1 on success * \retval 0 on failure */ int SCPerfCounterDisplay(uint16_t id, SCPerfContext *pctx, int disp) { SCPerfCounter *pc = NULL; if (pctx == NULL) { SCLogDebug("pctx null inside SCPerfCounterDisplay"); return 0; } if ( (id < 1) || (id > pctx->curr_id) ) { SCLogDebug("counter with the id %d doesn't exist in this tm instance", id); return 0; } pc = pctx->head; while(pc->id != id) pc = pc->next; pc->disp = (disp != 0); return 1; } /** * \brief Syncs the counter array with the global counter variables * * \param pca Pointer to the SCPerfCounterArray * \param pctx Pointer the the tv's SCPerfContext * \param reset_lc Indicates whether the local counter has to be reset or not * * \retval 0 on success * \retval -1 on error */ int SCPerfUpdateCounterArray(SCPerfCounterArray *pca, SCPerfContext *pctx, int reset_lc) { SCPerfCounter *pc = NULL; SCPCAElem *pcae = NULL; uint32_t i = 0; if (pca == NULL || pctx == NULL) { SCLogDebug("pca or pctx is NULL inside SCPerfUpdateCounterArray"); return -1; } pcae = pca->head; SCMutexLock(&pctx->m); pc = pctx->head; for (i = 1; i <= pca->size; i++) { while (pc != NULL) { if (pc->id != pcae[i].id) { pc = pc->next; continue; } SCPerfCopyCounterValue(&pcae[i], reset_lc); pc->updated++; pc = pc->next; break; } } SCMutexUnlock(&pctx->m); pctx->perf_flag = 0; return 1; } /* * \brief Get the value of the local copy of the counter that hold this id. * * \param id The counter id. * \param pca Pointer to the SCPerfCounterArray. * * \retval 0 on success. * \retval -1 on error. */ double SCPerfGetLocalCounterValue(uint16_t id, SCPerfCounterArray *pca) { if (pca == NULL) { SCLogDebug("pca NULL inside SCPerfUpdateCounterArray"); return -1; } if ((id < 1) || (id > pca->size)) { SCLogDebug("counter doesn't exist"); return -1; } /* we check the type of the counter. Whether it's a counter that holds an * unsigned_int_64 value or double value */ switch (pca->head[id].pc->value->type) { /* the counter holds an unsigned_int_64 value */ case SC_PERF_TYPE_UINT64: return pca->head[id].ui64_cnt; /* the counter holds a double */ case SC_PERF_TYPE_DOUBLE: return pca->head[id].d_cnt; default: /* this can never happen */ return -1; } } /** * \brief The output interface dispatcher for the counter api */ void SCPerfOutputCounters() { switch (sc_perf_op_ctx->iface) { case SC_PERF_IFACE_FILE: SCPerfOutputCounterFileIface(); break; case SC_PERF_IFACE_CONSOLE: /* yet to be implemented */ break; case SC_PERF_IFACE_SYSLOG: /* yet to be implemented */ break; } return; } /** * \brief Releases the resources alloted by the Perf Counter API */ void SCPerfReleaseResources() { SCPerfReleaseOPCtx(); return; } /** * \brief Releases a list of perf counters * * \param head Pointer to the head of the list of perf counters that have to * be freed */ void SCPerfReleasePerfCounterS(SCPerfCounter *head) { SCPerfCounter *pc = NULL; while (head != NULL) { pc = head; head = head->next; SCPerfReleaseCounter(pc); } return; } /** * \brief Releases the SCPerfCounterArray allocated by the user, for storing and * updating local counter values * * \param pca Pointer to the SCPerfCounterArray */ void SCPerfReleasePCA(SCPerfCounterArray *pca) { if (pca != NULL) { if (pca->head != NULL) SCFree(pca->head); SCFree(pca); } return; } /*----------------------------------Unit_Tests--------------------------------*/ #ifdef UNITTESTS static int SCPerfTestCounterReg01() { SCPerfContext pctx; memset(&pctx, 0, sizeof(SCPerfContext)); return SCPerfRegisterCounter("t1", "c1", 5, NULL, &pctx); } static int SCPerfTestCounterReg02() { SCPerfContext pctx; memset(&pctx, 0, sizeof(SCPerfContext)); return SCPerfRegisterCounter(NULL, NULL, SC_PERF_TYPE_UINT64, NULL, &pctx); } static int SCPerfTestCounterReg03() { SCPerfContext pctx; int result; memset(&pctx, 0, sizeof(SCPerfContext)); result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); SCPerfReleasePerfCounterS(pctx.head); return result; } static int SCPerfTestCounterReg04() { SCPerfContext pctx; int result; memset(&pctx, 0, sizeof(SCPerfContext)); SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &pctx); SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, &pctx); result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); SCPerfReleasePerfCounterS(pctx.head); return result; } static int SCPerfTestGetCntArray05() { ThreadVars tv; int id; memset(&tv, 0, sizeof(ThreadVars)); id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); if (id != 1) { printf("id %d: ", id); return 0; } tv.sc_perf_pca = SCPerfGetAllCountersArray(NULL); return (!tv.sc_perf_pca)?1:0; } static int SCPerfTestGetCntArray06() { ThreadVars tv; int id; int result; memset(&tv, 0, sizeof(ThreadVars)); id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); if (id != 1) return 0; tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); result = (tv.sc_perf_pca)?1:0; SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); SCPerfReleasePCA(tv.sc_perf_pca); return result; } static int SCPerfTestCntArraySize07() { ThreadVars tv; SCPerfCounterArray *pca = NULL; int result; memset(&tv, 0, sizeof(ThreadVars)); //pca = (SCPerfCounterArray *)&tv.sc_perf_pca; SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterIncr(1, pca); SCPerfCounterIncr(2, pca); result = pca->size; SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); SCPerfReleasePCA(pca); return result; } static int SCPerfTestUpdateCounter08() { ThreadVars tv; SCPerfCounterArray *pca = NULL; int id; int result; memset(&tv, 0, sizeof(ThreadVars)); id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterIncr(id, pca); SCPerfCounterAddUI64(id, pca, 100); result = pca->head[id].ui64_cnt; SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); SCPerfReleasePCA(pca); return result; } static int SCPerfTestUpdateCounter09() { ThreadVars tv; SCPerfCounterArray *pca = NULL; uint16_t id1, id2; int result; memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); id2 = SCPerfRegisterCounter("t5", "c5", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterIncr(id2, pca); SCPerfCounterAddUI64(id2, pca, 100); result = (pca->head[id1].ui64_cnt == 0) && (pca->head[id2].ui64_cnt == 101); SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); SCPerfReleasePCA(pca); return result; } static int SCPerfTestUpdateGlobalCounter10() { ThreadVars tv; SCPerfCounterArray *pca = NULL; int result = 1; uint16_t id1, id2, id3; memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterIncr(id1, pca); SCPerfCounterAddUI64(id2, pca, 100); SCPerfCounterIncr(id3, pca); SCPerfCounterAddUI64(id3, pca, 100); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); result = (1 == *((uint64_t *)tv.sc_perf_pctx.head->value->cvalue) ); result &= (100 == *((uint64_t *)tv.sc_perf_pctx.head->next->value->cvalue) ); result &= (101 == *((uint64_t *)tv.sc_perf_pctx.head->next->next->value->cvalue) ); SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); SCPerfReleasePCA(pca); return result; } static int SCPerfTestCounterValues11() { ThreadVars tv; SCPerfCounterArray *pca = NULL; int result = 1; uint16_t id1, id2, id3, id4; memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); id4 = SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterIncr(id1, pca); SCPerfCounterAddUI64(id2, pca, 256); SCPerfCounterAddUI64(id3, pca, 257); SCPerfCounterAddUI64(id4, pca, 16843024); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); uint64_t *u64p = (uint64_t *)tv.sc_perf_pctx.head->value->cvalue; result &= (1 == *u64p); u64p = (uint64_t *)tv.sc_perf_pctx.head->next->value->cvalue; result &= (256 == *u64p); u64p = (uint64_t *)tv.sc_perf_pctx.head->next->next->value->cvalue; result &= (257 == *u64p); u64p = (uint64_t *)tv.sc_perf_pctx.head->next->next->next->value->cvalue; result &= (16843024 == *u64p); SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); SCPerfReleasePCA(pca); return result; } static int SCPerfTestAverageQual12() { ThreadVars tv; SCPerfCounterArray *pca = NULL; int result = 1; uint16_t id1, id2; memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterAvgCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx); id2 = SCPerfRegisterAvgCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &tv.sc_perf_pctx); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterAddDouble(id1, pca, 1); SCPerfCounterAddDouble(id1, pca, 2); SCPerfCounterAddDouble(id1, pca, 3); SCPerfCounterAddDouble(id1, pca, 4); SCPerfCounterAddDouble(id1, pca, 5); SCPerfCounterAddDouble(id1, pca, 6); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); result &= (21 == pca->head[1].d_cnt); result &= (6 == pca->head[1].syncs); result &= (0 == pca->head[1].wrapped_syncs); result &= (3.5 == *((double *)tv.sc_perf_pctx.head->value->cvalue) ); SCPerfCounterAddUI64(id2, pca, (uint64_t)1.635); SCPerfCounterAddUI64(id2, pca, (uint64_t)2.12); SCPerfCounterAddUI64(id2, pca, (uint64_t)3.74); SCPerfCounterAddUI64(id2, pca, (uint64_t)4.23); SCPerfCounterAddUI64(id2, pca, (uint64_t)5.76); SCPerfCounterAddDouble(id2, pca, 6.99999); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); result &= (21 == pca->head[2].ui64_cnt); result &= (6 == pca->head[2].syncs); result &= (0 == pca->head[2].wrapped_syncs); result &= (3 == *((uint64_t *)tv.sc_perf_pctx.head->next->value->cvalue)); return result; } static int SCPerfTestMaxQual13() { ThreadVars tv; SCPerfCounterArray *pca = NULL; int result = 1; uint16_t id1; memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterMaxCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterSetDouble(id1, pca, 1.352); SCPerfCounterSetDouble(id1, pca, 5.12412); SCPerfCounterSetDouble(id1, pca, 4.1234); SCPerfCounterSetDouble(id1, pca, 5.13562); SCPerfCounterSetDouble(id1, pca, 1.2342); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); result &= (5.13562 == *((double *)tv.sc_perf_pctx.head->value->cvalue)); SCPerfCounterSetDouble(id1, pca, 8); SCPerfCounterSetDouble(id1, pca, 7); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); result &= (8 == *((double *)tv.sc_perf_pctx.head->value->cvalue)); SCPerfCounterSetDouble(id1, pca, 6); SCPerfCounterSetUI64(id1, pca, 10); SCPerfCounterSetDouble(id1, pca, 9.562); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); result &= (10 == *((double *)tv.sc_perf_pctx.head->value->cvalue)); return result; } static int SCPerfTestIntervalQual14() { ThreadVars tv; int result = 1; memset(&tv, 0, sizeof(ThreadVars)); SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "10s"); result &= (tv.sc_perf_pctx.head->type_q->hours == 0); result &= (tv.sc_perf_pctx.head->type_q->minutes == 0); result &= (tv.sc_perf_pctx.head->type_q->seconds == 10); SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); memset(&tv, 0, sizeof(ThreadVars)); SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "20h10s"); result &= (tv.sc_perf_pctx.head->type_q->hours == 20); result &= (tv.sc_perf_pctx.head->type_q->minutes == 0); result &= (tv.sc_perf_pctx.head->type_q->seconds == 10); SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); memset(&tv, 0, sizeof(ThreadVars)); SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "20h30m10s"); result &= (tv.sc_perf_pctx.head->type_q->hours == 20); result &= (tv.sc_perf_pctx.head->type_q->minutes == 30); result &= (tv.sc_perf_pctx.head->type_q->seconds == 10); SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); memset(&tv, 0, sizeof(ThreadVars)); SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "30m10s"); result &= (tv.sc_perf_pctx.head->type_q->hours == 0); result &= (tv.sc_perf_pctx.head->type_q->minutes == 30); result &= (tv.sc_perf_pctx.head->type_q->seconds == 10); SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); return result; } static int SCPerfTestIntervalQual15() { ThreadVars tv; int result = 1; memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "25h") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "24h61m") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "24h60m") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "24h58m61s") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "24h61m60s") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "24h61ms") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "236m") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "67s") == 0); result &= (tv.sc_perf_pctx.head == NULL); memset(&tv, 0, sizeof(ThreadVars)); result &= (SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "0h0m0s") == 0); result &= (tv.sc_perf_pctx.head == NULL); return result; } static int SCPerfTestIntervalQual16() { ThreadVars tv; SCPerfCounterArray *pca = NULL; double d_temp = 0; int result = 1; uint16_t id1; memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "3s"); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterAddDouble(id1, pca, 1); SCPerfCounterAddDouble(id1, pca, 2); SCPerfCounterAddDouble(id1, pca, 3); SCPerfCounterAddDouble(id1, pca, 4); SCPerfCounterAddDouble(id1, pca, 5); SCPerfCounterAddDouble(id1, pca, 6); /* forward the time 6 seconds */ TimeSetIncrementTime(6); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); SCPerfOutputCalculateCounterValue(tv.sc_perf_pctx.head, &d_temp); result &= (d_temp > 10 && d_temp < 11); return result; } static int SCPerfTestIntervalQual17() { ThreadVars tv; SCPerfCounterArray *pca = NULL; double d_temp = 0; uint16_t id1; memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "2m30s"); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterAddDouble(id1, pca, 1); SCPerfCounterAddDouble(id1, pca, 2); SCPerfCounterAddDouble(id1, pca, 3); SCPerfCounterAddDouble(id1, pca, 4); SCPerfCounterAddDouble(id1, pca, 5); SCPerfCounterAddDouble(id1, pca, 6); /* forward the time 3 seconds */ TimeSetIncrementTime(3); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); SCPerfOutputCalculateCounterValue(tv.sc_perf_pctx.head, &d_temp); return (d_temp == 1050.0); } static int SCPerfTestIntervalQual18() { ThreadVars tv; SCPerfCounterArray *pca = NULL; double d_temp = 0; int result = 1; uint16_t id1; memset(&tv, 0, sizeof(ThreadVars)); id1 = SCPerfRegisterIntervalCounter("t1", "c1", SC_PERF_TYPE_DOUBLE, NULL, &tv.sc_perf_pctx, "3s"); pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); SCPerfCounterAddDouble(id1, pca, 1); SCPerfCounterAddDouble(id1, pca, 2); SCPerfCounterAddDouble(id1, pca, 3); SCPerfCounterAddDouble(id1, pca, 4); SCPerfCounterAddDouble(id1, pca, 5); SCPerfCounterAddDouble(id1, pca, 6); /* forward the time 3 seconds */ TimeSetIncrementTime(3); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); SCPerfCounterAddDouble(id1, pca, 1); SCPerfCounterAddDouble(id1, pca, 2); SCPerfCounterAddDouble(id1, pca, 3); /* forward the time 3 seconds */ TimeSetIncrementTime(3); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); SCPerfCounterAddDouble(id1, pca, 3); SCPerfCounterAddDouble(id1, pca, 3); /* forward the time 3 seconds */ TimeSetIncrementTime(3); SCPerfOutputCalculateCounterValue(tv.sc_perf_pctx.head, &d_temp); result &= (d_temp == 13.5); SCPerfCounterAddDouble(id1, pca, 1); SCPerfCounterAddDouble(id1, pca, 2); SCPerfCounterAddDouble(id1, pca, 3); /* forward the time 3 seconds */ TimeSetIncrementTime(3); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); SCPerfCounterAddDouble(id1, pca, 1); SCPerfCounterAddDouble(id1, pca, 2); SCPerfCounterAddDouble(id1, pca, 3); /* forward the time 1 second */ TimeSetIncrementTime(1); SCPerfOutputCalculateCounterValue(tv.sc_perf_pctx.head, &d_temp); result &= (d_temp == 6); SCPerfCounterAddDouble(id1, pca, 2); /* forward the time 1 second */ TimeSetIncrementTime(1); SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx, 0); SCPerfOutputCalculateCounterValue(tv.sc_perf_pctx.head, &d_temp); result &= (d_temp == 12.0); return result; } #endif void SCPerfRegisterTests() { #ifdef UNITTESTS UtRegisterTest("SCPerfTestCounterReg01", SCPerfTestCounterReg01, 0); UtRegisterTest("SCPerfTestCounterReg02", SCPerfTestCounterReg02, 0); UtRegisterTest("SCPerfTestCounterReg03", SCPerfTestCounterReg03, 1); UtRegisterTest("SCPerfTestCounterReg04", SCPerfTestCounterReg04, 1); UtRegisterTest("SCPerfTestGetCntArray05", SCPerfTestGetCntArray05, 1); UtRegisterTest("SCPerfTestGetCntArray06", SCPerfTestGetCntArray06, 1); UtRegisterTest("SCPerfTestCntArraySize07", SCPerfTestCntArraySize07, 2); UtRegisterTest("SCPerfTestUpdateCounter08", SCPerfTestUpdateCounter08, 101); UtRegisterTest("SCPerfTestUpdateCounter09", SCPerfTestUpdateCounter09, 1); UtRegisterTest("SCPerfTestUpdateGlobalCounter10", SCPerfTestUpdateGlobalCounter10, 1); UtRegisterTest("SCPerfTestCounterValues11", SCPerfTestCounterValues11, 1); UtRegisterTest("SCPerfTestAverageQual12", SCPerfTestAverageQual12, 1); UtRegisterTest("SCPerfTestMaxQual13", SCPerfTestMaxQual13, 1); UtRegisterTest("SCPerfTestIntervalQual14", SCPerfTestIntervalQual14, 1); UtRegisterTest("SCPerfTestIntervalQual15", SCPerfTestIntervalQual15, 1); UtRegisterTest("SCPerfTestIntervalQual16", SCPerfTestIntervalQual16, 1); UtRegisterTest("SCPerfTestIntervalQual17", SCPerfTestIntervalQual17, 1); UtRegisterTest("SCPerfTestIntervalQual18", SCPerfTestIntervalQual18, 1); #endif } suricata-1.4.7/src/util-memcmp.c0000644000000000000000000002323412253546156013426 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Memcmp implementations. */ #include "suricata-common.h" #include "util-memcmp.h" #include "util-unittest.h" /* code is implemented in util-memcmp.h as it's all inlined */ /* UNITTESTS */ #ifdef UNITTESTS static int MemcmpTest01 (void) { uint8_t a[] = "abcd"; uint8_t b[] = "abcd"; if (SCMemcmp(a, b, sizeof(a)-1) != 0) return 0; return 1; } static int MemcmpTest02 (void) { uint8_t a[] = "abcdabcdabcdabcd"; uint8_t b[] = "abcdabcdabcdabcd"; if (SCMemcmp(a, b, sizeof(a)-1) != 0) return 0; return 1; } static int MemcmpTest03 (void) { uint8_t a[] = "abcdabcd"; uint8_t b[] = "abcdabcd"; if (SCMemcmp(a, b, sizeof(a)-1) != 0) return 0; return 1; } static int MemcmpTest04 (void) { uint8_t a[] = "abcd"; uint8_t b[] = "abcD"; int r = SCMemcmp(a, b, sizeof(a)-1); if (r != 1) { printf("%s != %s, but memcmp returned %d: ", a, b, r); return 0; } return 1; } static int MemcmpTest05 (void) { uint8_t a[] = "abcdabcdabcdabcd"; uint8_t b[] = "abcDabcdabcdabcd"; if (SCMemcmp(a, b, sizeof(a)-1) != 1) return 0; return 1; } static int MemcmpTest06 (void) { uint8_t a[] = "abcdabcd"; uint8_t b[] = "abcDabcd"; if (SCMemcmp(a, b, sizeof(a)-1) != 1) return 0; return 1; } static int MemcmpTest07 (void) { uint8_t a[] = "abcd"; uint8_t b[] = "abcde"; if (SCMemcmp(a, b, sizeof(a)-1) != 0) return 0; return 1; } static int MemcmpTest08 (void) { uint8_t a[] = "abcdabcdabcdabcd"; uint8_t b[] = "abcdabcdabcdabcde"; if (SCMemcmp(a, b, sizeof(a)-1) != 0) return 0; return 1; } static int MemcmpTest09 (void) { uint8_t a[] = "abcdabcd"; uint8_t b[] = "abcdabcde"; if (SCMemcmp(a, b, sizeof(a)-1) != 0) return 0; return 1; } static int MemcmpTest10 (void) { uint8_t a[] = "abcd"; uint8_t b[] = "Zbcde"; if (SCMemcmp(a, b, sizeof(a)-1) != 1) return 0; return 1; } static int MemcmpTest11 (void) { uint8_t a[] = "abcdabcdabcdabcd"; uint8_t b[] = "Zbcdabcdabcdabcde"; if (SCMemcmp(a, b, sizeof(a)-1) != 1) return 0; return 1; } static int MemcmpTest12 (void) { uint8_t a[] = "abcdabcd"; uint8_t b[] = "Zbcdabcde"; if (SCMemcmp(a, b, sizeof(a)-1) != 1) return 0; return 1; } static int MemcmpTest13 (void) { uint8_t a[] = "abcdefgh"; uint8_t b[] = "AbCdEfGhIjK"; if (SCMemcmpLowercase(a, b, sizeof(a)-1) != 0) return 0; return 1; } #include "util-cpu.h" #define TEST_RUNS 1000000 static int MemcmpTest14 (void) { #ifdef PROFILING uint64_t ticks_start = 0; uint64_t ticks_end = 0; char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; int t = 0; int i, j; int r1 = 0; printf("\n"); ticks_start = UtilCpuGetTicks(); for (t = 0; t < TEST_RUNS; t++) { for (i = 0; a[i] != NULL; i++) { // printf("a[%d] = %s\n", i, a[i]); size_t alen = strlen(a[i]) - 1; for (j = 0; b[j] != NULL; j++) { // printf("b[%d] = %s\n", j, b[j]); size_t blen = strlen(b[j]) - 1; r1 += (memcmp((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen) ? 1 : 0); } } } ticks_end = UtilCpuGetTicks(); printf("memcmp(%d) \t\t\t%"PRIu64"\n", TEST_RUNS, ((uint64_t)(ticks_end - ticks_start))/TEST_RUNS); SCLogInfo("ticks passed %"PRIu64, ticks_end - ticks_start); printf("r1 %d\n", r1); if (r1 != (51 * TEST_RUNS)) return 0; #endif return 1; } static int MemcmpTest15 (void) { #ifdef PROFILING uint64_t ticks_start = 0; uint64_t ticks_end = 0; char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; int t = 0; int i, j; int r2 = 0; printf("\n"); ticks_start = UtilCpuGetTicks(); for (t = 0; t < TEST_RUNS; t++) { for (i = 0; a[i] != NULL; i++) { // printf("a[%d] = %s\n", i, a[i]); size_t alen = strlen(a[i]) - 1; for (j = 0; b[j] != NULL; j++) { // printf("b[%d] = %s\n", j, b[j]); size_t blen = strlen(b[j]) - 1; r2 += MemcmpLowercase((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); } } } ticks_end = UtilCpuGetTicks(); printf("MemcmpLowercase(%d) \t\t%"PRIu64"\n", TEST_RUNS, ((uint64_t)(ticks_end - ticks_start))/TEST_RUNS); SCLogInfo("ticks passed %"PRIu64, ticks_end - ticks_start); printf("r2 %d\n", r2); if (r2 != (51 * TEST_RUNS)) return 0; #endif return 1; } static int MemcmpTest16 (void) { #ifdef PROFILING uint64_t ticks_start = 0; uint64_t ticks_end = 0; char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; int t = 0; int i, j; int r3 = 0; printf("\n"); ticks_start = UtilCpuGetTicks(); for (t = 0; t < TEST_RUNS; t++) { for (i = 0; a[i] != NULL; i++) { // printf("a[%d] = %s\n", i, a[i]); size_t alen = strlen(a[i]) - 1; for (j = 0; b[j] != NULL; j++) { // printf("b[%d] = %s\n", j, b[j]); size_t blen = strlen(b[j]) - 1; r3 += SCMemcmp((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); } } } ticks_end = UtilCpuGetTicks(); printf("SCMemcmp(%d) \t\t\t%"PRIu64"\n", TEST_RUNS, ((uint64_t)(ticks_end - ticks_start))/TEST_RUNS); SCLogInfo("ticks passed %"PRIu64, ticks_end - ticks_start); printf("r3 %d\n", r3); if (r3 != (51 * TEST_RUNS)) return 0; #endif return 1; } static int MemcmpTest17 (void) { #ifdef PROFILING uint64_t ticks_start = 0; uint64_t ticks_end = 0; char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; int t = 0; int i, j; int r4 = 0; printf("\n"); ticks_start = UtilCpuGetTicks(); for (t = 0; t < TEST_RUNS; t++) { for (i = 0; a[i] != NULL; i++) { // printf("a[%d] = %s\n", i, a[i]); size_t alen = strlen(a[i]) - 1; for (j = 0; b[j] != NULL; j++) { // printf("b[%d] = %s\n", j, b[j]); size_t blen = strlen(b[j]) - 1; r4 += SCMemcmpLowercase((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); } } } ticks_end = UtilCpuGetTicks(); printf("SCMemcmpLowercase(%d) \t\t%"PRIu64"\n", TEST_RUNS, ((uint64_t)(ticks_end - ticks_start))/TEST_RUNS); SCLogInfo("ticks passed %"PRIu64, ticks_end - ticks_start); printf("r4 %d\n", r4); if (r4 != (51 * TEST_RUNS)) return 0; #endif return 1; } #endif /* UNITTESTS */ void MemcmpRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("MemcmpTest01", MemcmpTest01, 1); UtRegisterTest("MemcmpTest02", MemcmpTest02, 1); UtRegisterTest("MemcmpTest03", MemcmpTest03, 1); UtRegisterTest("MemcmpTest04", MemcmpTest04, 1); UtRegisterTest("MemcmpTest05", MemcmpTest05, 1); UtRegisterTest("MemcmpTest06", MemcmpTest06, 1); UtRegisterTest("MemcmpTest07", MemcmpTest07, 1); UtRegisterTest("MemcmpTest08", MemcmpTest08, 1); UtRegisterTest("MemcmpTest09", MemcmpTest09, 1); UtRegisterTest("MemcmpTest10", MemcmpTest10, 1); UtRegisterTest("MemcmpTest11", MemcmpTest11, 1); UtRegisterTest("MemcmpTest12", MemcmpTest12, 1); UtRegisterTest("MemcmpTest13", MemcmpTest13, 1); UtRegisterTest("MemcmpTest14", MemcmpTest14, 1); UtRegisterTest("MemcmpTest15", MemcmpTest15, 1); UtRegisterTest("MemcmpTest16", MemcmpTest16, 1); UtRegisterTest("MemcmpTest17", MemcmpTest17, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-dsize.h0000644000000000000000000000216112253546156013562 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_DSIZE_H__ #define __DETECT_DSIZE_H__ #define DETECTDSIZE_LT 0 #define DETECTDSIZE_EQ 1 #define DETECTDSIZE_GT 2 #define DETECTDSIZE_RA 3 typedef struct DetectDsizeData_ { uint16_t dsize; uint16_t dsize2; uint8_t mode; } DetectDsizeData; /* prototypes */ void DetectDsizeRegister (void); #endif /* __DETECT_DSIZE_H__ */ suricata-1.4.7/src/detect-flags.h0000644000000000000000000000274512253546156013550 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DETECT_FLAGS_H__ #define __DETECT_FLAGS_H__ #include "decode-events.h" #include "decode-ipv4.h" #include "decode-tcp.h" /** * \struct DetectFlagsData_ * DetectFlagsData_ is used to store flags: input value */ /** * \typedef DetectFlagsData * A typedef for DetectFlagsData_ */ typedef struct DetectFlagsData_ { uint8_t flags; /**< TCP flags */ uint8_t modifier; /**< !(1) +(2) *(3) modifiers */ uint8_t ignored_flags; /**< Ignored TCP flags defined by modifer , */ } DetectFlagsData; /** * Registration function for flags: keyword */ void DetectFlagsRegister (void); /** * This function registers unit tests for Flags */ void FlagsRegisterTests(void); #endif /*__DETECT_FLAGS_H__ */ suricata-1.4.7/src/detect-dce-opnum.h0000644000000000000000000000241512253546156014335 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_DCE_OPNUM_H__ #define __DETECT_DCE_OPNUM_H__ #define DCE_OPNUM_RANGE_MAX 65535 #define DCE_OPNUM_RANGE_UNINITIALIZED 100000 typedef struct DetectDceOpnumRange_ { uint32_t range1; uint32_t range2; struct DetectDceOpnumRange_ *next; } DetectDceOpnumRange; typedef struct DetectDceOpnumData_ { DetectDceOpnumRange *range; } DetectDceOpnumData; void DetectDceOpnumRegister(void); void DetectDceOpnumRegisterTests(void); #endif /* __DETECT_DCE_OPNUM_H__ */ suricata-1.4.7/src/detect-rev.h0000644000000000000000000000162312253546156013242 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_REV_H__ #define __DETECT_REV_H__ /* prototypes */ void DetectRevRegister (void); #endif /* __DETECT_REV_H__ */ suricata-1.4.7/src/app-layer-dcerpc-udp.h0000644000000000000000000000133212253546156015113 00000000000000/* * Copyright (c) 2009,2010 Open Information Security Foundation * * \author Kirby Kuehl */ #ifndef __APP_LAYER_DCERPC_UDP_H__ #define __APP_LAYER_DCERPC_UDP_H__ #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-dcerpc-common.h" #include "flow.h" #include "queue.h" #include "util-byte.h" typedef struct DCERPCUDPState_ { DCERPCUDP dcerpc; uint16_t bytesprocessed; uint16_t fraglenleft; uint8_t *frag_data; DCERPCUuidEntry *uuid_entry; TAILQ_HEAD(, DCERPCUuidEntry_) uuid_list; } DCERPCUDPState; void RegisterDCERPCUDPParsers(void); void DCERPCUDPParserTests(void); void DCERPCUDPParserRegisterTests(void); #endif /* __APP_LAYER_DCERPC_UDP_H__ */ suricata-1.4.7/src/packet-queue.h0000644000000000000000000000175012253546156013572 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __PACKET_QUEUE_H__ #define __PACKET_QUEUE_H__ #include "threads.h" #include "decode.h" void PacketEnqueue (PacketQueue *, Packet *); Packet *PacketDequeue (PacketQueue *); #endif /* __PACKET_QUEUE_H__ */ suricata-1.4.7/src/detect-http-hrh.h0000644000000000000000000000163012253546156014202 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_HTTP_HRH_H__ #define __DETECT_HTTP_HRH_H__ void DetectHttpHRHRegister(void); #endif /* __DETECT_HTTP_HRH_H__ */ suricata-1.4.7/src/detect-engine-address-ipv4.h0000644000000000000000000000253712253546156016223 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_ADDRESS_IPV4_H__ #define __DETECT_ENGINE_ADDRESS_IPV4_H__ int DetectAddressCutNotIPv4(DetectAddress *, DetectAddress **); int DetectAddressCmpIPv4(DetectAddress *a, DetectAddress *b); int DetectAddressCutIPv4(DetectEngineCtx *, DetectAddress *, DetectAddress *, DetectAddress **); int DetectAddressJoinIPv4(DetectEngineCtx *, DetectAddress *target, DetectAddress *source); int DetectAddressIsCompleteIPSpaceIPv4(DetectAddress *); void DetectAddressIPv4Tests(void); #endif /* __DETECT_ENGINE_ADDRESS_IPV4_H__ */ suricata-1.4.7/src/app-layer-parser.c0000644000000000000000000053606612253546156014375 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Generic App-layer parsing functions. */ #include "suricata-common.h" #include "debug.h" #include "util-unittest.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "flow-util.h" #include "detect-engine-state.h" #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream.h" #include "stream-tcp-reassemble.h" #include "app-layer.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-smb.h" #include "app-layer-dcerpc.h" #include "app-layer-dcerpc-udp.h" #include "app-layer-htp.h" #include "app-layer-ftp.h" #include "app-layer-ssl.h" #include "app-layer-ssh.h" #include "app-layer-smtp.h" #include "util-spm.h" #include "util-debug.h" #include "decode-events.h" #include "util-unittest-helper.h" #include "util-validate.h" AppLayerProto al_proto_table[ALPROTO_MAX]; /**< Application layer protocol table mapped to their corresponding parsers */ #define MAX_PARSERS 100 static AppLayerParserTableElement al_parser_table[MAX_PARSERS]; static uint16_t al_max_parsers = 0; /* incremented for every registered parser */ static Pool *al_result_pool = NULL; static SCMutex al_result_pool_mutex = PTHREAD_MUTEX_INITIALIZER; #ifdef DEBUG static uint32_t al_result_pool_elmts = 0; #endif /* DEBUG */ /** \brief Get the file container flow * \param f flow pointer to a LOCKED flow * \retval files void pointer to the state * \retval direction flow direction, either STREAM_TOCLIENT or STREAM_TOSERVER * \retval NULL in case we have no state */ FileContainer *AppLayerGetFilesFromFlow(Flow *f, uint8_t direction) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); uint16_t alproto = f->alproto; if (alproto == ALPROTO_UNKNOWN) SCReturnPtr(NULL, "FileContainer"); if (al_proto_table[alproto].StateGetFiles != NULL) { FileContainer *ptr = al_proto_table[alproto].StateGetFiles(AppLayerGetProtoStateFromFlow(f), direction); SCReturnPtr(ptr, "FileContainer"); } else { SCReturnPtr(NULL, "FileContainer"); } } /** \brief Alloc a AppLayerParserResultElmt func for the pool */ static void *AlpResultElmtPoolAlloc() { AppLayerParserResultElmt *e = NULL; e = (AppLayerParserResultElmt *)SCMalloc (sizeof(AppLayerParserResultElmt)); if (e == NULL) return NULL; #ifdef DEBUG al_result_pool_elmts++; SCLogDebug("al_result_pool_elmts %"PRIu32"", al_result_pool_elmts); #endif /* DEBUG */ return e; } static void AlpResultElmtPoolCleanup(void *e) { AppLayerParserResultElmt *re = (AppLayerParserResultElmt *)e; if (re->flags & ALP_RESULT_ELMT_ALLOC) { if (re->data_ptr != NULL) SCFree(re->data_ptr); } #ifdef DEBUG al_result_pool_elmts--; SCLogDebug("al_result_pool_elmts %"PRIu32"", al_result_pool_elmts); #endif /* DEBUG */ } static AppLayerParserResultElmt *AlpGetResultElmt(void) { SCMutexLock(&al_result_pool_mutex); AppLayerParserResultElmt *e = (AppLayerParserResultElmt *)PoolGet(al_result_pool); SCMutexUnlock(&al_result_pool_mutex); if (e == NULL) { return NULL; } e->next = NULL; return e; } static void AlpReturnResultElmt(AppLayerParserResultElmt *e) { if (e->flags & ALP_RESULT_ELMT_ALLOC) { if (e->data_ptr != NULL) SCFree(e->data_ptr); } e->flags = 0; e->data_ptr = NULL; e->data_len = 0; e->next = NULL; SCMutexLock(&al_result_pool_mutex); PoolReturn(al_result_pool, (void *)e); SCMutexUnlock(&al_result_pool_mutex); } static void AlpAppendResultElmt(AppLayerParserResult *r, AppLayerParserResultElmt *e) { if (r->head == NULL) { r->head = e; r->tail = e; r->cnt = 1; } else { r->tail->next = e; r->tail = e; r->cnt++; } } /** * \param alloc Is ptr alloc'd (1) or a ptr to static mem (0). * \retval -1 error * \retval 0 ok */ static int AlpStoreField(AppLayerParserResult *output, uint16_t idx, uint8_t *ptr, uint32_t len, uint8_t alloc) { SCEnter(); AppLayerParserResultElmt *e = AlpGetResultElmt(); if (e == NULL) { SCLogError(SC_ERR_POOL_EMPTY, "App layer \"al_result_pool\" is empty"); SCReturnInt(-1); } if (alloc == 1) e->flags |= ALP_RESULT_ELMT_ALLOC; e->name_idx = idx; e->data_ptr = ptr; e->data_len = len; AlpAppendResultElmt(output, e); SCReturnInt(0); } void AppLayerSetEOF(Flow *f) { if (f == NULL) return; AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store != NULL) { parser_state_store->id_flags |= APP_LAYER_TRANSACTION_EOF; parser_state_store->to_client.flags |= APP_LAYER_PARSER_EOF; parser_state_store->to_server.flags |= APP_LAYER_PARSER_EOF; /* increase version so we will inspect it one more time * with the EOF flags now set */ parser_state_store->version++; } } /** \brief Parse a field up to we reach the size limit * * \retval 1 Field found and stored. * \retval 0 Field parsing in progress. * \retval -1 error */ int AlpParseFieldBySize(AppLayerParserResult *output, AppLayerParserState *pstate, uint16_t field_idx, uint32_t size, uint8_t *input, uint32_t input_len, uint32_t *offset) { SCEnter(); if ((pstate->store_len + input_len) < size) { if (pstate->store_len == 0) { pstate->store = SCMalloc(input_len); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store, input, input_len); pstate->store_len = input_len; } else { pstate->store = SCRealloc(pstate->store, (input_len + pstate->store_len)); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store+pstate->store_len, input, input_len); pstate->store_len += input_len; } } else { if (pstate->store_len == 0) { int r = AlpStoreField(output, field_idx, input, size, /* static mem */0); if (r == -1) { SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); SCReturnInt(-1); } (*offset) += size; SCReturnInt(1); } else { uint32_t diff = size - pstate->store_len; pstate->store = SCRealloc(pstate->store, (diff + pstate->store_len)); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store+pstate->store_len, input, diff); pstate->store_len += diff; int r = AlpStoreField(output, field_idx, pstate->store, pstate->store_len, /* alloc mem */1); if (r == -1) { SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); SCReturnInt(-1); } (*offset) += diff; pstate->store = NULL; pstate->store_len = 0; SCReturnInt(1); } } SCReturnInt(0); } /** \brief Parse a field up to the EOF * * \retval 1 Field found and stored. * \retval 0 Field parsing in progress. * \retval -1 error */ int AlpParseFieldByEOF(AppLayerParserResult *output, AppLayerParserState *pstate, uint16_t field_idx, uint8_t *input, uint32_t input_len) { SCEnter(); if (pstate->store_len == 0) { if (pstate->flags & APP_LAYER_PARSER_EOF) { SCLogDebug("store_len 0 and EOF"); int r = AlpStoreField(output, field_idx, input, input_len, 0); if (r == -1) { SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); SCReturnInt(-1); } SCReturnInt(1); } else { SCLogDebug("store_len 0 but no EOF"); /* delimiter field not found, so store the result for the next run */ pstate->store = SCMalloc(input_len); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store, input, input_len); pstate->store_len = input_len; } } else { if (pstate->flags & APP_LAYER_PARSER_EOF) { SCLogDebug("store_len %" PRIu32 " and EOF", pstate->store_len); pstate->store = SCRealloc(pstate->store, (input_len + pstate->store_len)); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store+pstate->store_len, input, input_len); pstate->store_len += input_len; int r = AlpStoreField(output, field_idx, pstate->store, pstate->store_len, 1); if (r == -1) { SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); SCReturnInt(-1); } pstate->store = NULL; pstate->store_len = 0; SCReturnInt(1); } else { SCLogDebug("store_len %" PRIu32 " but no EOF", pstate->store_len); /* delimiter field not found, so store the result for the next run */ pstate->store = SCRealloc(pstate->store, (input_len + pstate->store_len)); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store+pstate->store_len, input, input_len); pstate->store_len += input_len; } } SCReturnInt(0); } /** \brief Parse a field up to a delimeter. * * \retval 1 Field found and stored. * \retval 0 Field parsing in progress. * \retval -1 error */ int AlpParseFieldByDelimiter(AppLayerParserResult *output, AppLayerParserState *pstate, uint16_t field_idx, const uint8_t *delim, uint8_t delim_len, uint8_t *input, uint32_t input_len, uint32_t *offset) { SCEnter(); SCLogDebug("pstate->store_len %" PRIu32 ", delim_len %" PRIu32 "", pstate->store_len, delim_len); if (pstate->store_len == 0) { uint8_t *ptr = SpmSearch(input, input_len, (uint8_t*)delim, delim_len); if (ptr != NULL) { uint32_t len = ptr - input; SCLogDebug(" len %" PRIu32 "", len); int r = AlpStoreField(output, field_idx, input, len, 0); if (r == -1) { SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); SCReturnInt(-1); } (*offset) += (len + delim_len); SCReturnInt(1); } else { if (pstate->flags & APP_LAYER_PARSER_EOF) { SCLogDebug("delim not found and EOF"); SCReturnInt(0); } SCLogDebug("delim not found, continue"); /* delimiter field not found, so store the result for the next run */ pstate->store = SCMalloc(input_len); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store, input, input_len); pstate->store_len = input_len; } } else { uint8_t *ptr = SpmSearch(input, input_len, (uint8_t*)delim, delim_len); if (ptr != NULL) { uint32_t len = ptr - input; SCLogDebug("len %" PRIu32 " + %" PRIu32 " = %" PRIu32 "", len, pstate->store_len, len + pstate->store_len); pstate->store = SCRealloc(pstate->store, (len + pstate->store_len)); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store+pstate->store_len, input, len); pstate->store_len += len; int r = AlpStoreField(output, field_idx, pstate->store, pstate->store_len, 1); if (r == -1) { SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); SCReturnInt(-1); } pstate->store = NULL; pstate->store_len = 0; (*offset) += (len + delim_len); SCReturnInt(1); } else { if (pstate->flags & APP_LAYER_PARSER_EOF) { /* if the input len is smaller than the delim len we search the * pstate->store since we may match there. */ if (delim_len > input_len) { /* delimiter field not found, so store the result for the * next run */ pstate->store = SCRealloc(pstate->store, (input_len + pstate->store_len)); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store+pstate->store_len, input, input_len); pstate->store_len += input_len; SCLogDebug("input_len < delim_len, checking pstate->store"); if (pstate->store_len >= delim_len) { ptr = SpmSearch(pstate->store, pstate->store_len, (uint8_t*)delim, delim_len); if (ptr != NULL) { SCLogDebug("now we found the delim"); uint32_t len = ptr - pstate->store; int r = AlpStoreField(output, field_idx, pstate->store, len, 1); if (r == -1) { SCLogError(SC_ERR_ALPARSER, "Failed to store " "field value"); SCReturnInt(-1); } pstate->store = NULL; pstate->store_len = 0; (*offset) += (input_len); SCLogDebug("offset %" PRIu32 "", (*offset)); SCReturnInt(1); } goto free_and_return; } goto free_and_return; } free_and_return: SCLogDebug("not found and EOF, so free what we have so far."); SCFree(pstate->store); pstate->store = NULL; pstate->store_len = 0; SCReturnInt(0); } /* delimiter field not found, so store the result for the next run */ pstate->store = SCRealloc(pstate->store, (input_len + pstate->store_len)); if (pstate->store == NULL) SCReturnInt(-1); memcpy(pstate->store+pstate->store_len, input, input_len); pstate->store_len += input_len; /* if the input len is smaller than the delim len we search the * pstate->store since we may match there. */ if (delim_len > input_len && delim_len <= pstate->store_len) { SCLogDebug("input_len < delim_len, checking pstate->store"); ptr = SpmSearch(pstate->store, pstate->store_len, (uint8_t*)delim, delim_len); if (ptr != NULL) { SCLogDebug("now we found the delim"); uint32_t len = ptr - pstate->store; int r = AlpStoreField(output, field_idx, pstate->store, len, 1); if (r == -1) { SCLogError(SC_ERR_ALPARSER, "Failed to store field value"); SCReturnInt(-1); } pstate->store = NULL; pstate->store_len = 0; (*offset) += (input_len); SCLogDebug("ffset %" PRIu32 "", (*offset)); SCReturnInt(1); } } } } SCReturnInt(0); } uint16_t AppLayerGetProtoByName(const char *name) { uint8_t u = 1; SCLogDebug("looking for name %s", name); for ( ; u < ALPROTO_MAX; u++) { if (al_proto_table[u].name == NULL) continue; SCLogDebug("name %s proto %"PRIu16"", al_proto_table[u].name, u); if (strcasecmp(name,al_proto_table[u].name) == 0) { SCLogDebug("match, returning %"PRIu16"", u); return u; } } return ALPROTO_UNKNOWN; } const char *AppLayerGetProtoString(int proto) { if ((proto >= ALPROTO_MAX) || (proto < 0)) { return "Undefined"; } if (al_proto_table[proto].name == NULL) { return "Unset"; } else { return al_proto_table[proto].name; } } /** \brief Description: register a parser. * * \param name full parser name, e.g. "http.request_line" * \todo do we need recursive, so a "http" and a "request_line" where the engine * knows it's actually "http.request_line"... same difference maybe. * \param AppLayerParser pointer to the parser function * * \retval 0 on success * \retval -1 on error */ int AppLayerRegisterParser(char *name, uint16_t proto, uint16_t parser_id, int (*AppLayerParser)(Flow *f, void *protocol_state, AppLayerParserState *parser_state, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output), char *dependency) { al_max_parsers++; if(al_max_parsers >= MAX_PARSERS){ SCLogInfo("Failed to register %s al_parser_table array full",name); exit(EXIT_FAILURE); } al_parser_table[al_max_parsers].name = name; al_parser_table[al_max_parsers].proto = proto; al_parser_table[al_max_parsers].parser_local_id = parser_id; al_parser_table[al_max_parsers].AppLayerParser = AppLayerParser; SCLogDebug("registered %p at proto %" PRIu32 ", al_proto_table idx " "%" PRIu32 ", parser_local_id %" PRIu32 "", AppLayerParser, proto, al_max_parsers, parser_id); return 0; } /** \brief Description: register a protocol parser. * * \param name full parser name, e.g. "http.request_line" * \todo do we need recursive, so a "http" and a "request_line" where the engine * knows it's actually "http.request_line"... same difference maybe. * \param AppLayerParser pointer to the parser function * * \retval 0 on success * \retval -1 on error */ int AppLayerRegisterProto(char *name, uint8_t proto, uint8_t flags, int (*AppLayerParser)(Flow *f, void *protocol_state, AppLayerParserState *parser_state, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output)) { al_max_parsers++; if(al_max_parsers >= MAX_PARSERS){ SCLogInfo("Failed to register %s al_parser_table array full",name); exit(EXIT_FAILURE); } al_parser_table[al_max_parsers].name = name; al_parser_table[al_max_parsers].AppLayerParser = AppLayerParser; /* create proto, direction -- parser mapping */ if (flags & STREAM_TOSERVER) { al_proto_table[proto].to_server = al_max_parsers; } else if (flags & STREAM_TOCLIENT) { al_proto_table[proto].to_client = al_max_parsers; } SCLogDebug("registered %p at proto %" PRIu32 " flags %02X, al_proto_table " "idx %" PRIu32 ", %s", AppLayerParser, proto, flags, al_max_parsers, name); return 0; } void AppLayerRegisterStateFuncs(uint16_t proto, void *(*StateAlloc)(void), void (*StateFree)(void *)) { al_proto_table[proto].StateAlloc = StateAlloc; al_proto_table[proto].StateFree = StateFree; } void AppLayerRegisterTransactionIdFuncs(uint16_t proto, void (*StateUpdateTransactionId)(void *state, uint16_t *), void (*StateTransactionFree)(void *, uint16_t)) { al_proto_table[proto].StateUpdateTransactionId = StateUpdateTransactionId; al_proto_table[proto].StateTransactionFree = StateTransactionFree; } void AppLayerRegisterLocalStorageFunc(uint16_t proto, void *(*LocalStorageAlloc)(void), void (*LocalStorageFree)(void *)) { al_proto_table[proto].LocalStorageAlloc = LocalStorageAlloc; al_proto_table[proto].LocalStorageFree = LocalStorageFree; return; } void AppLayerRegisterTruncateFunc(uint16_t proto, void (*Truncate)(void *, uint8_t)) { al_proto_table[proto].Truncate = Truncate; return; } void AppLayerStreamTruncated(uint16_t proto, void *state, uint8_t flags) { if (al_proto_table[proto].Truncate != NULL) { al_proto_table[proto].Truncate(state, flags); } } void *AppLayerGetProtocolParserLocalStorage(uint16_t proto) { if (al_proto_table[proto].LocalStorageAlloc != NULL) { return al_proto_table[proto].LocalStorageAlloc(); } return NULL; } void AppLayerRegisterGetFilesFunc(uint16_t proto, FileContainer *(*StateGetFiles)(void *, uint8_t)) { al_proto_table[proto].StateGetFiles = StateGetFiles; } /** \brief Indicate to the app layer parser that a logger is active * for this protocol. */ void AppLayerRegisterLogger(uint16_t proto) { al_proto_table[proto].logger = TRUE; } AppLayerParserStateStore *AppLayerParserStateStoreAlloc(void) { AppLayerParserStateStore *s = (AppLayerParserStateStore *)SCMalloc (sizeof(AppLayerParserStateStore)); if (s == NULL) return NULL; memset(s, 0, sizeof(AppLayerParserStateStore)); /* when we start, we're working with transaction id 1 */ s->avail_id = 1; return s; } /** \brief free a AppLayerParserStateStore structure * \param s AppLayerParserStateStore structure to free */ void AppLayerParserStateStoreFree(AppLayerParserStateStore *s) { if (s->to_server.store != NULL) SCFree(s->to_server.store); if (s->to_client.store != NULL) SCFree(s->to_client.store); if (s->decoder_events != NULL) AppLayerDecoderEventsFreeEvents(s->decoder_events); s->decoder_events = NULL; SCFree(s); } static void AppLayerParserResultCleanup(AppLayerParserResult *result) { AppLayerParserResultElmt *e = result->head; while (e != NULL) { AppLayerParserResultElmt *next_e = e->next; result->head = next_e; if (next_e == NULL) result->tail = NULL; result->cnt--; AlpReturnResultElmt(e); e = next_e; } } static int AppLayerDoParse(void *local_data, Flow *f, void *app_layer_state, AppLayerParserState *parser_state, uint8_t *input, uint32_t input_len, uint16_t parser_idx, uint16_t proto) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); int retval = 0; AppLayerParserResult result = { NULL, NULL, 0 }; SCLogDebug("parser_idx %" PRIu32 "", parser_idx); //printf("--- (%u)\n", input_len); //PrintRawDataFp(stdout, input,input_len); //printf("---\n"); /* invoke the parser */ int r = al_parser_table[parser_idx]. AppLayerParser(f, app_layer_state, parser_state, input, input_len, local_data, &result); if (r < 0) { if (r == -1) { AppLayerParserResultCleanup(&result); SCReturnInt(-1); #ifdef DEBUG } else { BUG_ON(r); /* this is not supposed to happen!! */ #else SCReturnInt(-1); #endif } } /* process the result elements */ AppLayerParserResultElmt *e = result.head; for (; e != NULL; e = e->next) { SCLogDebug("e %p e->name_idx %" PRIu32 ", e->data_ptr %p, e->data_len " "%" PRIu32 ", map_size %" PRIu32 "", e, e->name_idx, e->data_ptr, e->data_len, al_proto_table[proto].map_size); /* no parser defined for this field. */ if (e->name_idx >= al_proto_table[proto].map_size || al_proto_table[proto].map[e->name_idx] == NULL) { SCLogDebug("no parser for proto %" PRIu32 ", parser_local_id " "%" PRIu32 "", proto, e->name_idx); continue; } uint16_t idx = al_proto_table[proto].map[e->name_idx]->parser_id; /* prepare */ uint16_t tmp = parser_state->parse_field; parser_state->parse_field = 0; parser_state->flags |= APP_LAYER_PARSER_EOF; r = AppLayerDoParse(local_data, f, app_layer_state, parser_state, e->data_ptr, e->data_len, idx, proto); /* restore */ parser_state->flags &= ~APP_LAYER_PARSER_EOF; parser_state->parse_field = tmp; /* bail out on a serious error */ if (r < 0) { if (r == -1) { retval = -1; break; #ifdef DEBUG } else { BUG_ON(r); /* this is not supposed to happen!! */ #else SCReturnInt(-1); #endif } } } AppLayerParserResultCleanup(&result); SCReturnInt(retval); } /** \brief remove obsolete (inspected and logged) transactions */ static int AppLayerTransactionsCleanup(AppLayerProto *p, AppLayerParserStateStore *parser_state_store, void *app_layer_state) { SCEnter(); uint16_t obsolete = 0; if (p->StateTransactionFree == NULL) { SCLogDebug("no StateTransactionFree function"); goto end; } if (p->logger == TRUE) { uint16_t low = (parser_state_store->logged_id < parser_state_store->inspect_id) ? parser_state_store->logged_id : parser_state_store->inspect_id; obsolete = low - parser_state_store->base_id; SCLogDebug("low %"PRIu16" (logged %"PRIu16", inspect %"PRIu16"), base_id %"PRIu16", obsolete %"PRIu16", avail_id %"PRIu16, low, parser_state_store->logged_id, parser_state_store->inspect_id, parser_state_store->base_id, obsolete, parser_state_store->avail_id); } else { obsolete = parser_state_store->inspect_id - parser_state_store->base_id; } SCLogDebug("obsolete transactions: %"PRIu16, obsolete); /* call the callback on the obsolete transactions */ while ((obsolete--)) { p->StateTransactionFree(app_layer_state, parser_state_store->base_id); parser_state_store->base_id++; } SCLogDebug("base_id %"PRIu16, parser_state_store->base_id); end: SCReturnInt(0); } #ifdef DEBUG uint32_t applayererrors = 0; uint32_t applayerhttperrors = 0; #endif /** * \brief Layer 7 Parsing main entry point. * * \param f Properly initialized and locked flow. * \param proto L7 proto, e.g. ALPROTO_HTTP * \param flags Stream flags * \param input Input L7 data * \param input_len Length of the input data. * * \retval -1 error * \retval 0 ok */ int AppLayerParse(void *local_data, Flow *f, uint8_t proto, uint8_t flags, uint8_t *input, uint32_t input_len) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); uint16_t parser_idx = 0; AppLayerProto *p = &al_proto_table[proto]; TcpSession *ssn = NULL; /* Used only if it's TCP */ ssn = f->protoctx; /* Do this check before calling AppLayerParse */ if (flags & STREAM_GAP) { SCLogDebug("stream gap detected (missing packets), this is not yet supported."); if (f->alstate != NULL) AppLayerStreamTruncated(proto, f->alstate, flags); goto error; } /* Get the parser state (if any) */ AppLayerParserStateStore *parser_state_store = f->alparser; if (parser_state_store == NULL) { parser_state_store = AppLayerParserStateStoreAlloc(); if (parser_state_store == NULL) goto error; f->alparser = (void *)parser_state_store; } parser_state_store->version++; SCLogDebug("app layer state version incremented to %"PRIu16, parser_state_store->version); AppLayerParserState *parser_state = NULL; if (flags & STREAM_TOSERVER) { SCLogDebug("to_server msg (flow %p)", f); parser_state = &parser_state_store->to_server; if (!(parser_state->flags & APP_LAYER_PARSER_USE)) { parser_idx = p->to_server; parser_state->cur_parser = parser_idx; parser_state->flags |= APP_LAYER_PARSER_USE; } else { SCLogDebug("using parser %" PRIu32 " we stored before (to_server)", parser_state->cur_parser); parser_idx = parser_state->cur_parser; } } else { SCLogDebug("to_client msg (flow %p)", f); parser_state = &parser_state_store->to_client; if (!(parser_state->flags & APP_LAYER_PARSER_USE)) { parser_idx = p->to_client; parser_state->cur_parser = parser_idx; parser_state->flags |= APP_LAYER_PARSER_USE; } else { SCLogDebug("using parser %" PRIu32 " we stored before (to_client)", parser_state->cur_parser); parser_idx = parser_state->cur_parser; } } if (parser_idx == 0 || (parser_state->flags & APP_LAYER_PARSER_DONE)) { SCLogDebug("no parser for protocol %" PRIu32 "", proto); SCReturnInt(0); } if (flags & STREAM_EOF) parser_state->flags |= APP_LAYER_PARSER_EOF; /* See if we already have a 'app layer' state */ void *app_layer_state = f->alstate; if (app_layer_state == NULL) { /* lock the allocation of state as we may * alloc more than one otherwise */ app_layer_state = p->StateAlloc(); if (app_layer_state == NULL) { goto error; } f->alstate = app_layer_state; SCLogDebug("alloced new app layer state %p (name %s)", app_layer_state, al_proto_table[f->alproto].name); } else { SCLogDebug("using existing app layer state %p (name %s))", app_layer_state, al_proto_table[f->alproto].name); } /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */ if (input_len > 0) { int r = AppLayerDoParse(local_data, f, app_layer_state, parser_state, input, input_len, parser_idx, proto); if (r < 0) goto error; } /* set the packets to no inspection and reassembly if required */ if (parser_state->flags & APP_LAYER_PARSER_NO_INSPECTION) { AppLayerSetEOF(f); FlowSetNoPayloadInspectionFlag(f); FlowSetSessionNoApplayerInspectionFlag(f); /* Set the no reassembly flag for both the stream in this TcpSession */ if (parser_state->flags & APP_LAYER_PARSER_NO_REASSEMBLY) { if (ssn != NULL) { StreamTcpSetSessionNoReassemblyFlag(ssn, flags & STREAM_TOCLIENT ? 1 : 0); StreamTcpSetSessionNoReassemblyFlag(ssn, flags & STREAM_TOSERVER ? 1 : 0); } } } /* update the transaction id */ if (p->StateUpdateTransactionId != NULL) { p->StateUpdateTransactionId(app_layer_state, &parser_state_store->avail_id); /* next, see if we can get rid of transactions now */ AppLayerTransactionsCleanup(p, parser_state_store, app_layer_state); } if (parser_state->flags & APP_LAYER_PARSER_EOF) { SCLogDebug("eof, flag Transaction id's"); parser_state_store->id_flags |= APP_LAYER_TRANSACTION_EOF; } /* stream truncated, inform app layer */ if (flags & STREAM_DEPTH) { AppLayerStreamTruncated(proto, app_layer_state, flags); } SCReturnInt(0); error: if (ssn != NULL) { #ifdef DEBUG if (FLOW_IS_IPV4(f)) { char src[16]; char dst[16]; PrintInet(AF_INET, (const void*)&f->src.addr_data32[0], src, sizeof (src)); PrintInet(AF_INET, (const void*)&f->dst.addr_data32[0], dst, sizeof (dst)); SCLogDebug("Error occured in parsing \"%s\" app layer " "protocol, using network protocol %"PRIu8", source IP " "address %s, destination IP address %s, src port %"PRIu16" and " "dst port %"PRIu16"", al_proto_table[f->alproto].name, f->proto, src, dst, f->sp, f->dp); fflush(stdout); } else if (FLOW_IS_IPV6(f)) { char dst6[46]; char src6[46]; PrintInet(AF_INET6, (const void*)&f->src.addr_data32, src6, sizeof (src6)); PrintInet(AF_INET6, (const void*)&f->dst.addr_data32, dst6, sizeof (dst6)); SCLogDebug("Error occured in parsing \"%s\" app layer " "protocol, using network protocol %"PRIu8", source IPv6 " "address %s, destination IPv6 address %s, src port %"PRIu16" and " "dst port %"PRIu16"", al_proto_table[f->alproto].name, f->proto, src6, dst6, f->sp, f->dp); fflush(stdout); } applayererrors++; if (f->alproto == ALPROTO_HTTP) applayerhttperrors++; #endif /* Set the no app layer inspection flag for both * the stream in this Flow */ FlowSetSessionNoApplayerInspectionFlag(f); AppLayerSetEOF(f); } SCReturnInt(-1); } /** \brief get the base transaction id */ int AppLayerTransactionGetBaseId(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store == NULL) { SCLogDebug("no state store"); goto error; } SCReturnInt((int)parser_state_store->base_id); error: SCReturnInt(-1); } /** \brief get the base transaction id * * \retval txid or -1 on error */ int AppLayerTransactionGetInspectId(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store == NULL) { SCLogDebug("no state store"); goto error; } SCReturnInt((int)parser_state_store->inspect_id); error: SCReturnInt(-1); } uint16_t AppLayerTransactionGetAvailId(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store == NULL) { SCLogDebug("no state store"); SCReturnUInt(0); } SCReturnUInt(parser_state_store->avail_id); } /** \brief get the highest loggable transaction id */ int AppLayerTransactionGetLoggableId(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store == NULL) { SCLogDebug("no state store"); goto error; } int id = 0; if (parser_state_store->id_flags & APP_LAYER_TRANSACTION_EOF) { SCLogDebug("eof, return current transaction as well"); id = (int)(parser_state_store->avail_id); } else { id = (int)(parser_state_store->avail_id - 1); } SCReturnInt(id); error: SCReturnInt(-1); } /** \brief get the highest loggable transaction id */ void AppLayerTransactionUpdateLoggedId(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store == NULL) { SCLogDebug("no state store"); goto error; } parser_state_store->logged_id++; SCReturn; error: SCReturn; } /** \brief get the highest loggable transaction id */ int AppLayerTransactionGetLoggedId(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store == NULL) { SCLogDebug("no state store"); goto error; } SCReturnInt((int)parser_state_store->logged_id); error: SCReturnInt(-1); } /** * \brief get the version of the state in a direction * * \param f LOCKED flow * \param direction STREAM_TOSERVER or STREAM_TOCLIENT */ uint16_t AppLayerGetStateVersion(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); uint16_t version = 0; AppLayerParserStateStore *parser_state_store = NULL; parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store != NULL) { version = parser_state_store->version; } SCReturnUInt(version); } /** * \param f LOCKED flow * \param direction STREAM_TOSERVER or STREAM_TOCLIENT * * \retval 2 current transaction done, new available * \retval 1 current transaction done, no new (yet) * \retval 0 current transaction is not done yet */ int AppLayerTransactionUpdateInspectId(Flow *f, char direction) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); int r = 0; AppLayerParserStateStore *parser_state_store = NULL; parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store != NULL) { /* update inspect_id and see if it there are other transactions * as well */ SCLogDebug("avail_id %"PRIu16", inspect_id %"PRIu16, parser_state_store->avail_id, parser_state_store->inspect_id); if (direction == STREAM_TOSERVER) { SCLogDebug("toserver"); parser_state_store->id_flags |= APP_LAYER_TRANSACTION_TOSERVER; } else { SCLogDebug("toclient"); parser_state_store->id_flags |= APP_LAYER_TRANSACTION_TOCLIENT; } if ((parser_state_store->inspect_id+1) < parser_state_store->avail_id && (parser_state_store->id_flags & APP_LAYER_TRANSACTION_TOCLIENT) && (parser_state_store->id_flags & APP_LAYER_TRANSACTION_TOSERVER)) { parser_state_store->id_flags &=~ APP_LAYER_TRANSACTION_TOCLIENT; parser_state_store->id_flags &=~ APP_LAYER_TRANSACTION_TOSERVER; parser_state_store->inspect_id = parser_state_store->avail_id - 1; if (parser_state_store->inspect_id < parser_state_store->avail_id) { /* done and more transactions available */ r = 2; SCLogDebug("inspect_id %"PRIu16", avail_id %"PRIu16, parser_state_store->inspect_id, parser_state_store->avail_id); } else { /* done but no more transactions available */ r = 1; SCLogDebug("inspect_id %"PRIu16", avail_id %"PRIu16, parser_state_store->inspect_id, parser_state_store->avail_id); } } } SCReturnInt(r); } void AppLayerListSupportedProtocols(void) { uint32_t i; uint32_t temp_alprotos_buf[ALPROTO_MAX]; memset(temp_alprotos_buf, 0, sizeof(temp_alprotos_buf)); printf("=========Supported App Layer Protocols=========\n"); /* for each proto, alloc the map array */ for (i = 0; i < ALPROTO_MAX; i++) { if (al_proto_table[i].name == NULL) continue; temp_alprotos_buf[i] = 1; printf("%s\n", al_proto_table[i].name); } AppLayerProbingParserInfo *pinfo = alp_proto_ctx.probing_parsers_info; while (pinfo != NULL) { if (temp_alprotos_buf[pinfo->al_proto] == 1) { pinfo = pinfo->next; continue; } printf("%s\n", pinfo->al_proto_name); temp_alprotos_buf[pinfo->al_proto] = 1; pinfo = pinfo->next; } printf("=====\n"); return; } AppLayerDecoderEvents *AppLayerGetDecoderEventsForFlow(Flow *f) { DEBUG_ASSERT_FLOW_LOCKED(f); /* Get the parser state (if any) */ AppLayerParserStateStore *parser_state_store = NULL; if (f == NULL || f->alparser == NULL) { return NULL; } parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store != NULL) { return parser_state_store->decoder_events; } return NULL; } /** * \brief Trigger "raw" stream reassembly from the app layer. * * This way HTTP for example, can trigger raw stream inspection right * when the full request body is received. This is often smaller than * our raw reassembly size limit. * * \param f flow, for access the stream state */ void AppLayerTriggerRawStreamReassembly(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); #ifdef DEBUG BUG_ON(f == NULL); #endif if (f != NULL && f->protoctx != NULL) { TcpSession *ssn = (TcpSession *)f->protoctx; StreamTcpReassembleTriggerRawReassembly(ssn); } SCReturn; } void RegisterAppLayerParsers(void) { /** \todo move to general init function */ memset(&al_proto_table, 0, sizeof(al_proto_table)); memset(&al_parser_table, 0, sizeof(al_parser_table)); /** setup result pool * \todo Per thread pool */ al_result_pool = PoolInit(1000, 250, sizeof(AppLayerParserResultElmt), AlpResultElmtPoolAlloc, NULL, NULL, AlpResultElmtPoolCleanup, NULL); RegisterHTPParsers(); RegisterSSLParsers(); RegisterSMBParsers(); RegisterDCERPCParsers(); RegisterDCERPCUDPParsers(); RegisterFTPParsers(); RegisterSSHParsers(); RegisterSMTPParsers(); /** IMAP */ //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_IMAP, "|2A 20|OK|20|", 5, 0, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, "imap", IPPROTO_TCP, ALPROTO_IMAP, "1|20|capability", 12, 0, STREAM_TOSERVER); /** MSN Messenger */ //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_MSN, "MSNP", 10, 6, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, "msn", IPPROTO_TCP, ALPROTO_MSN, "MSNP", 10, 6, STREAM_TOSERVER); /** Jabber */ //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_JABBER, "xmlns='jabber|3A|client'", 74, 53, STREAM_TOCLIENT); //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_JABBER, "xmlns='jabber|3A|client'", 74, 53, STREAM_TOSERVER); return; } void AppLayerParserCleanupState(Flow *f) { if (f == NULL) { SCLogDebug("no flow"); return; } if (f->alproto >= ALPROTO_MAX) { SCLogDebug("app layer proto unknown"); return; } /* free the parser protocol state */ AppLayerProto *p = &al_proto_table[f->alproto]; if (p->StateFree != NULL && f->alstate != NULL) { SCLogDebug("calling StateFree"); p->StateFree(f->alstate); f->alstate = NULL; } /* free the app layer parser api state */ if (f->alparser != NULL) { SCLogDebug("calling AppLayerParserStateStoreFree"); AppLayerParserStateStoreFree(f->alparser); f->alparser = NULL; } } /** \brief Create a mapping between the individual parsers local field id's * and the global field parser id's. * */ void AppLayerParsersInitPostProcess(void) { uint16_t u16 = 0; /* build local->global mapping */ for (u16 = 1; u16 <= al_max_parsers; u16++) { /* no local parser */ if (al_parser_table[u16].parser_local_id == 0) continue; if (al_parser_table[u16].parser_local_id > al_proto_table[al_parser_table[u16].proto].map_size) { al_proto_table[al_parser_table[u16].proto].map_size = al_parser_table[u16].parser_local_id; } SCLogDebug("map_size %" PRIu32 "", al_proto_table [al_parser_table[u16].proto].map_size); } /* for each proto, alloc the map array */ for (u16 = 0; u16 < ALPROTO_MAX; u16++) { if (al_proto_table[u16].map_size == 0) continue; al_proto_table[u16].map_size++; al_proto_table[u16].map = (AppLayerLocalMap **)SCMalloc (al_proto_table[u16].map_size * sizeof(AppLayerLocalMap *)); if (al_proto_table[u16].map == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in AppLayerParsersInitPostProcess. Exiting..."); exit(EXIT_FAILURE); } memset(al_proto_table[u16].map, 0, al_proto_table[u16].map_size * sizeof(AppLayerLocalMap *)); uint16_t u = 0; for (u = 1; u <= al_max_parsers; u++) { /* no local parser */ if (al_parser_table[u].parser_local_id == 0) continue; if (al_parser_table[u].proto != u16) continue; uint16_t parser_local_id = al_parser_table[u].parser_local_id; SCLogDebug("parser_local_id: %" PRIu32 "", parser_local_id); if (parser_local_id < al_proto_table[u16].map_size) { al_proto_table[u16].map[parser_local_id] = SCMalloc(sizeof(AppLayerLocalMap)); if (al_proto_table[u16].map[parser_local_id] == NULL) { exit(EXIT_FAILURE); } al_proto_table[u16].map[parser_local_id]->parser_id = u; } } } for (u16 = 0; u16 < ALPROTO_MAX; u16++) { if (al_proto_table[u16].map_size == 0) continue; if (al_proto_table[u16].map == NULL) continue; uint16_t x = 0; for (x = 0; x < al_proto_table[u16].map_size; x++) { if (al_proto_table[u16].map[x] == NULL) continue; SCLogDebug("al_proto_table[%" PRIu32 "].map[%" PRIu32 "]->parser_id:" " %" PRIu32 "", u16, x, al_proto_table[u16].map[x]->parser_id); } } } /********************************Probing Parsers*******************************/ static uint32_t AppLayerProbingParserGetMask(uint16_t al_proto) { if (al_proto > ALPROTO_UNKNOWN && al_proto < ALPROTO_FAILED) { return (1 << al_proto); } else { SCLogError(SC_ERR_ALPARSER, "Unknown protocol detected - %"PRIu16, al_proto); exit(EXIT_FAILURE); } } static AppLayerProbingParserElement * AppLayerCreateAppLayerProbingParserElement(const char *al_proto_name, uint16_t ip_proto, uint16_t al_proto, uint16_t min_depth, uint16_t max_depth, uint16_t port, uint8_t priority, uint8_t top, uint16_t (*AppLayerProbingParser) (uint8_t *input, uint32_t input_len)) { AppLayerProbingParserElement *pe = SCMalloc(sizeof(AppLayerProbingParserElement)); if (unlikely(pe == NULL)) { return NULL; } pe->al_proto_name = al_proto_name; pe->ip_proto = ip_proto; pe->al_proto = al_proto; pe->al_proto_mask = AppLayerProbingParserGetMask(al_proto); pe->min_depth = min_depth; pe->max_depth = max_depth; pe->port = port; pe->priority = priority; pe->top = top; pe->ProbingParser = AppLayerProbingParser; pe->next = NULL; if (max_depth != 0 && min_depth > max_depth) { SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to " "register the probing parser. min_depth > max_depth"); goto error; } if (al_proto <= ALPROTO_UNKNOWN || al_proto >= ALPROTO_MAX) { SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to register " "the probing parser. Invalid alproto - %d", al_proto); goto error; } if (AppLayerProbingParser == NULL) { SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to " "register the probing parser. Probing parser func NULL"); goto error; } return pe; error: SCFree(pe); return NULL; } static AppLayerProbingParserElement * AppLayerDuplicateAppLayerProbingParserElement(AppLayerProbingParserElement *pe) { AppLayerProbingParserElement *new_pe = SCMalloc(sizeof(AppLayerProbingParserElement)); if (unlikely(new_pe == NULL)) { return NULL; } new_pe->al_proto_name = pe->al_proto_name; new_pe->ip_proto = pe->ip_proto; new_pe->al_proto = pe->al_proto; new_pe->al_proto_mask = pe->al_proto_mask; new_pe->min_depth = pe->min_depth; new_pe->max_depth = pe->max_depth; new_pe->port = pe->port; new_pe->priority = pe->priority; new_pe->top = pe->top; new_pe->ProbingParser = pe->ProbingParser; new_pe->next = NULL; return new_pe; } static void AppLayerFreeAppLayerProbingParserElement(AppLayerProbingParserElement *pe) { SCFree(pe); return; } static void AppLayerInsertNewProbingParserSingleElement(AppLayerProbingParser *pp, AppLayerProbingParser **probing_parsers, AppLayerProbingParserElement *new_pe, uint8_t flags) { if (pp == NULL) { AppLayerProbingParser *new_pp = SCMalloc(sizeof(AppLayerProbingParser)); if (unlikely(new_pp == NULL)) return; memset(new_pp, 0, sizeof(AppLayerProbingParser)); new_pp->port = new_pe->port; if (probing_parsers[0] == NULL) { probing_parsers[0] = new_pp; } else { AppLayerProbingParser *pp = probing_parsers[0]; if (pp->port == 0) { new_pp->next = probing_parsers[0]; probing_parsers[0] = new_pp; } else { /* port 0 based pp is always the last one. Hence the * premature exit condition if port is 0 */ while (pp->next != NULL && pp->next->port != 0) { pp = pp->next; } new_pp->next = pp->next; pp->next = new_pp; } } pp = new_pp; } AppLayerProbingParserElement *pe = NULL; if (flags & STREAM_TOSERVER) { pe = pp->toserver; } else { pe = pp->toclient; } if (pe == NULL) { if (flags & STREAM_TOSERVER) { pp->toserver = new_pe; pp->toserver_max_depth = new_pe->max_depth; } else { pp->toclient = new_pe; pp->toclient_max_depth = new_pe->max_depth; } } else { uint8_t break_priority; if (new_pe->top) { break_priority = new_pe->priority; } else { break_priority = new_pe->priority + 1; } AppLayerProbingParserElement *prev_pe = pe; while (pe != NULL) { if (pe->priority < break_priority) { prev_pe = pe; pe = pe->next; continue; } break; } if (prev_pe == pe) { if (flags & STREAM_TOSERVER) { new_pe->next = pp->toserver; pp->toserver = new_pe; } else { new_pe->next = pp->toclient; pp->toclient = new_pe; } } else { new_pe->next = prev_pe->next; prev_pe->next = new_pe; } if (flags & STREAM_TOSERVER) { if (new_pe->max_depth == 0) { pp->toserver_max_depth = 0; } else { if (pp->toserver_max_depth != 0 && pp->toserver_max_depth < new_pe->max_depth) { pp->toserver_max_depth = new_pe->max_depth; } } } else { if (new_pe->max_depth == 0) { pp->toclient_max_depth = 0; } else { if (pp->toclient_max_depth != 0 && pp->toclient_max_depth < new_pe->max_depth) { pp->toclient_max_depth = new_pe->max_depth; } } } /* else - if (flags & STREAM_TOSERVER) */ } /* else - if (pe == NULL) */ if (flags & STREAM_TOSERVER) pp->toserver_al_proto_mask |= new_pe->al_proto_mask; else pp->toclient_al_proto_mask |= new_pe->al_proto_mask; return; } static void AppLayerInsertNewProbingParserElement(AppLayerProbingParser **probing_parsers, AppLayerProbingParserElement *new_pe, uint8_t flags) { AppLayerProbingParser *pp = probing_parsers[0]; if (new_pe->port != 0) { AppLayerProbingParser *zero_pp = NULL; while (pp != NULL) { if (pp->port == new_pe->port) { break; } if (pp->port == 0) zero_pp = pp; pp = pp->next; } AppLayerInsertNewProbingParserSingleElement(pp, probing_parsers, new_pe, flags); if (zero_pp != NULL) { pp = probing_parsers[0]; while (pp != NULL) { if (pp->port == new_pe->port) break; pp = pp->next; } BUG_ON(pp == NULL); AppLayerProbingParserElement *temp_pe; if (flags & STREAM_TOSERVER) { temp_pe = zero_pp->toserver; } else { temp_pe = zero_pp->toclient; } while (temp_pe != NULL) { AppLayerProbingParserElement *dup_pe = AppLayerDuplicateAppLayerProbingParserElement(temp_pe); AppLayerInsertNewProbingParserSingleElement(pp, probing_parsers, dup_pe, flags); temp_pe = temp_pe->next; } } } else { int zero_port_present = 0; while (pp != NULL) { AppLayerProbingParserElement *dup_pe = AppLayerDuplicateAppLayerProbingParserElement(new_pe); AppLayerInsertNewProbingParserSingleElement(pp, probing_parsers, dup_pe, flags); if (pp->port == 0) zero_port_present = 1; pp = pp->next; } if (zero_port_present == 0) { AppLayerInsertNewProbingParserSingleElement(NULL, probing_parsers, new_pe, flags); } else { SCFree(new_pe); } } return; } void AppLayerPrintProbingParsers(AppLayerProbingParser *pp) { AppLayerProbingParserElement *pe = NULL; printf("\n"); while (pp != NULL) { printf("Port: %"PRIu16 "\n", pp->port); printf(" to_server: max-depth: %"PRIu16 ", " "mask - %"PRIu32"\n", pp->toserver_max_depth, pp->toserver_al_proto_mask); pe = pp->toserver; while (pe != NULL) { printf(" name: %s\n", pe->al_proto_name); if (pe->al_proto == ALPROTO_HTTP) printf(" alproto: ALPROTO_HTTP\n"); else if (pe->al_proto == ALPROTO_FTP) printf(" alproto: ALPROTO_FTP\n"); else if (pe->al_proto == ALPROTO_SMTP) printf(" alproto: ALPROTO_SMTP\n"); else if (pe->al_proto == ALPROTO_TLS) printf(" alproto: ALPROTO_TLS\n"); else if (pe->al_proto == ALPROTO_SSH) printf(" alproto: ALPROTO_SSH\n"); else if (pe->al_proto == ALPROTO_IMAP) printf(" alproto: ALPROTO_IMAP\n"); else if (pe->al_proto == ALPROTO_MSN) printf(" alproto: ALPROTO_MSN\n"); else if (pe->al_proto == ALPROTO_JABBER) printf(" alproto: ALPROTO_JABBER\n"); else if (pe->al_proto == ALPROTO_SMB) printf(" alproto: ALPROTO_SMB\n"); else if (pe->al_proto == ALPROTO_SMB2) printf(" alproto: ALPROTO_SMB2\n"); else if (pe->al_proto == ALPROTO_DCERPC) printf(" alproto: ALPROTO_DCERPC\n"); else if (pe->al_proto == ALPROTO_DCERPC_UDP) printf(" alproto: ALPROTO_DCERPC_UDP\n"); else if (pe->al_proto == ALPROTO_IRC) printf(" alproto: ALPROTO_IRC\n"); else printf("impossible\n"); printf(" port: %"PRIu16 "\n", pe->port); if (pe->priority == APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) printf(" priority: HIGH\n"); else if (pe->priority == APP_LAYER_PROBING_PARSER_PRIORITY_MEDIUM) printf(" priority: MEDIUM\n"); else if (pe->priority == APP_LAYER_PROBING_PARSER_PRIORITY_LOW) printf(" priority: LOW\n"); else printf(" priority: impossible\n"); printf(" top: %"PRIu8 "\n", pe->top); printf(" min_depth: %"PRIu32 "\n", pe->min_depth); printf(" max_depth: %"PRIu32 "\n", pe->max_depth); printf(" mask: %"PRIu32 "\n", pe->al_proto_mask); printf("\n"); pe = pe->next; } pp = pp->next; } return; } int AppLayerProbingParserInfoAdd(AlpProtoDetectCtx *ctx, const char *al_proto_name, uint16_t ip_proto, uint16_t al_proto, uint16_t (*ProbingParser) (uint8_t *input, uint32_t input_len)) { AppLayerProbingParserInfo *new_ppi = NULL; AppLayerProbingParserInfo *ppi = ctx->probing_parsers_info; while (ppi != NULL) { if (strcmp(ppi->al_proto_name, al_proto_name) == 0) break; ppi = ppi->next; } if (ppi == NULL) { new_ppi = SCMalloc(sizeof(AppLayerProbingParserInfo)); if (unlikely(new_ppi == NULL)) { return -1; } memset(new_ppi, 0, sizeof(AppLayerProbingParserInfo)); new_ppi->al_proto_name = al_proto_name; new_ppi->ip_proto = ip_proto; new_ppi->al_proto = al_proto; new_ppi->ProbingParser = ProbingParser; if (ctx->probing_parsers_info == NULL) { ctx->probing_parsers_info = new_ppi; } else { new_ppi->next = ctx->probing_parsers_info; ctx->probing_parsers_info = new_ppi; } return 0; } if (ppi->ip_proto != ip_proto) { SCLogError(SC_ERR_ALPARSER, "New probing parser \"%s\" being registered " "already exists in the database of registered parsers, " "except that the new one registers with a different ip_proto" " %"PRIu16" compared to the existing entry of %"PRIu16, ppi->al_proto_name, ppi->ip_proto, ip_proto); return -1; } if (ppi->al_proto != al_proto) { SCLogError(SC_ERR_ALPARSER, "New probing parser \"%s\" being registered " "already exists in the database of registered parsers, " "except that the new one registers with a different alproto " "%"PRIu16" compared to the existing entry of %"PRIu16, ppi->al_proto_name, ppi->al_proto, al_proto); return -1; } if (ppi->ProbingParser != ProbingParser) { SCLogError(SC_ERR_ALPARSER, "New probing parser \"%s\" being registered " "already exists in the database of registered parsers, " "except that the new one registers with a differnt " "ProbingParser function compared to the existing entry " "in the database", ppi->al_proto_name); return -1; } return 0; } void AppLayerRegisterProbingParser(AlpProtoDetectCtx *ctx, uint16_t port, uint16_t ip_proto, const char *al_proto_name, uint16_t al_proto, uint16_t min_depth, uint16_t max_depth, uint8_t flags, uint8_t priority, uint8_t top, uint16_t (*ProbingParser) (uint8_t *input, uint32_t input_len)) { AppLayerProbingParser **probing_parsers = &ctx->probing_parsers; AppLayerProbingParserElement *pe = NULL; AppLayerProbingParserElement *new_pe = NULL; AppLayerProbingParser *pp = NULL; /* Add info about this probing parser to our database. Also detects any * duplicate existance of this parser but with conflicting parameters */ if (AppLayerProbingParserInfoAdd(ctx, al_proto_name, ip_proto, al_proto, ProbingParser) < 0) { goto error; } /* \todo introduce parsing port range here */ /* Get a new parser element */ new_pe = AppLayerCreateAppLayerProbingParserElement(al_proto_name, ip_proto, al_proto, min_depth, max_depth, port, priority, top, ProbingParser); if (new_pe == NULL) goto error; pp = AppLayerGetProbingParsers(probing_parsers[0], ip_proto, port); if (pp != NULL) { if (flags & STREAM_TOSERVER) { pe = pp->toserver; } else { pe = pp->toclient; } } /* check if this parser has already been registered for this port + dir */ if (pe != NULL) { AppLayerProbingParserElement *tmp_pe = pe; while (tmp_pe != NULL) { if (pe->al_proto == al_proto || strcmp(pe->al_proto_name, al_proto_name) == 0) { /* looks like we have it registered for this port + dir */ SCLogWarning(SC_ERR_ALPARSER, "App layer probing parser already " "registered for this port, direction"); goto error; } tmp_pe = tmp_pe->next; } } AppLayerInsertNewProbingParserElement(probing_parsers, new_pe, flags); return; error: if (new_pe != NULL) SCFree(new_pe); return; } void AppLayerFreeProbingParsersInfo(AppLayerProbingParserInfo *probing_parsers_info) { AppLayerProbingParserInfo *ppi = probing_parsers_info; AppLayerProbingParserInfo *next_ppi = NULL; while (ppi != NULL) { next_ppi = ppi->next; SCFree(ppi); ppi = next_ppi; } return; } void AppLayerFreeProbingParsers(AppLayerProbingParser *probing_parsers) { while (probing_parsers != NULL) { AppLayerProbingParserElement *pe; AppLayerProbingParserElement *next_pe; pe = probing_parsers->toserver; while (pe != NULL) { next_pe = pe->next; AppLayerFreeAppLayerProbingParserElement(pe); pe = next_pe; } pe = probing_parsers->toclient; while (pe != NULL) { next_pe = pe->next; AppLayerFreeAppLayerProbingParserElement(pe); pe = next_pe; } probing_parsers = probing_parsers->next; } return; } /**************************************Unittests*******************************/ #ifdef UNITTESTS typedef struct TestState_ { uint8_t test; }TestState; /** * \brief Test parser function to test the memory deallocation of app layer * parser of occurence of an error. */ static int TestProtocolParser(Flow *f, void *test_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { return -1; } /** \brief Function to allocates the Test protocol state memory */ static void *TestProtocolStateAlloc(void) { void *s = SCMalloc(sizeof(TestState)); if (unlikely(s == NULL)) return NULL; memset(s, 0, sizeof(TestState)); return s; } /** \brief Function to free the Test Protocol state memory */ static void TestProtocolStateFree(void *s) { SCFree(s); } /** \test Test the deallocation of app layer parser memory on occurance of * error in the parsing process. */ static int AppLayerParserTest01 (void) { int result = 0; Flow *f = NULL; uint8_t testbuf[] = { 0x11 }; uint32_t testlen = sizeof(testbuf); TcpSession ssn; memset(&ssn, 0, sizeof(ssn)); /* Register the Test protocol state and parser functions */ AppLayerRegisterProto("test", ALPROTO_TEST, STREAM_TOSERVER, TestProtocolParser); AppLayerRegisterStateFuncs(ALPROTO_TEST, TestProtocolStateAlloc, TestProtocolStateFree); f = UTHBuildFlow(AF_INET, "1.2.3.4", "4.3.2.1", 20, 40); if (f == NULL) goto end; f->protoctx = &ssn; f->alproto = ALPROTO_TEST; f->proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, testbuf, testlen); if (r != -1) { printf("returned %" PRId32 ", expected -1: ", r); goto end; } if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { printf("flag should have been set, but is not: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); UTHFreeFlow(f); return result; } /** \test Test the deallocation of app layer parser memory on occurance of * error in the parsing process for UDP. */ static int AppLayerParserTest02 (void) { int result = 1; Flow *f = NULL; uint8_t testbuf[] = { 0x11 }; uint32_t testlen = sizeof(testbuf); /* Register the Test protocol state and parser functions */ AppLayerRegisterProto("test", ALPROTO_TEST, STREAM_TOSERVER, TestProtocolParser); AppLayerRegisterStateFuncs(ALPROTO_TEST, TestProtocolStateAlloc, TestProtocolStateFree); f = UTHBuildFlow(AF_INET, "1.2.3.4", "4.3.2.1", 20, 40); if (f == NULL) goto end; f->alproto = ALPROTO_TEST; f->proto = IPPROTO_UDP; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, testbuf, testlen); if (r != -1) { printf("returned %" PRId32 ", expected -1: \n", r); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); UTHFreeFlow(f); return result; } uint16_t ProbingParserDummyForTesting(uint8_t *input, uint32_t input_len) { return 0; } static int AppLayerProbingParserTest01(void) { AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); if (ctx.probing_parsers == NULL) return 0; AlpProtoTestDestroy(&ctx); return 1; } static int AppLayerProbingParserTest02(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; if (pp->toserver_al_proto_mask != 1 << ALPROTO_HTTP) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; if (pp->toserver_al_proto_mask != (1 << ALPROTO_HTTP | 1 << ALPROTO_SMB)) { goto end; } /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_SMB) { goto end; } /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) { goto end; } AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; if (pp->toserver_al_proto_mask != (1 << ALPROTO_HTTP | 1 << ALPROTO_SMB | 1 << ALPROTO_DCERPC)) { goto end; } /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_DCERPC) { goto end; } /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_SMB) { goto end; } /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) { goto end; } result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest03(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; if (pp->toserver_al_proto_mask != (1 << ALPROTO_HTTP)) { goto end; } /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) { goto end; } AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; if (pp->toserver_al_proto_mask != (1 << ALPROTO_HTTP | 1 << ALPROTO_SMB)) { goto end; } /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) { goto end; } /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_SMB) { goto end; } AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; if (pp->toserver_al_proto_mask != (1 << ALPROTO_HTTP | 1 << ALPROTO_DCERPC | 1 << ALPROTO_SMB)) { goto end; } /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) { goto end; } /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_SMB) { goto end; } /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_DCERPC) { goto end; } result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest04(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; if (pp->toserver_al_proto_mask != (1 << ALPROTO_HTTP)) { goto end; } /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) { goto end; } AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; if (pp->toserver_al_proto_mask != (1 << ALPROTO_HTTP | 1 << ALPROTO_SMB)) { goto end; } /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_SMB) { goto end; } /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) { goto end; } AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; if (pp->toserver_al_proto_mask != (1 << ALPROTO_HTTP | 1 << ALPROTO_DCERPC | 1 << ALPROTO_SMB)) { goto end; } /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_SMB) { goto end; } /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_HTTP) { goto end; } /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; if (pe->al_proto_mask != 1 << ALPROTO_DCERPC) { goto end; } result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest05(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest06(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest07(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest08(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest09(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest10(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 10) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* third one */ pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest11(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 81, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } /* first pp */ if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp */ if (pp->next->next != NULL) goto end; if (pp->next->toclient != NULL) goto end; if (pp->next->port != 81) goto end; if (pp->next->toserver_max_depth != 10) goto end; if (pp->next->toclient_max_depth != 0) goto end; if (pp->next->toserver == NULL) goto end; if (pp->next->toserver->next != NULL) goto end; /* second pp - first one */ pe = pp->next->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 81, IPPROTO_TCP, "ftp", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } /* first pp */ if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp */ if (pp->next->next != NULL) goto end; if (pp->next->toclient != NULL) goto end; if (pp->next->port != 81) goto end; if (pp->next->toserver_max_depth != 15) goto end; if (pp->next->toclient_max_depth != 0) goto end; if (pp->next->toserver == NULL) goto end; if (pp->next->toserver->next == NULL) goto end; if (pp->next->toserver->next->next != NULL) goto end; /* second pp - first one */ pe = pp->next->toserver; if (strcmp(pe->al_proto_name, "ftp") != 0) goto end; if (pe->al_proto != ALPROTO_FTP) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 7) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp - second one */ pe = pp->next->toserver->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest12(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 81, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } /* first pp */ if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp */ if (pp->next->next != NULL) goto end; if (pp->next->toclient != NULL) goto end; if (pp->next->port != 81) goto end; if (pp->next->toserver_max_depth != 10) goto end; if (pp->next->toclient_max_depth != 0) goto end; if (pp->next->toserver == NULL) goto end; if (pp->next->toserver->next != NULL) goto end; /* second pp - first one */ pe = pp->next->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp */ if (pp->next->next != NULL) goto end; if (pp->next->toclient != NULL) goto end; if (pp->next->port != 81) goto end; if (pp->next->toserver_max_depth != 10) goto end; if (pp->next->toclient_max_depth != 0) goto end; if (pp->next->toserver == NULL) goto end; if (pp->next->toserver->next != NULL) goto end; /* second pp - first one */ pe = pp->next->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 81, IPPROTO_TCP, "ftp", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } /* first pp */ if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp */ if (pp->next->next != NULL) goto end; if (pp->next->toclient != NULL) goto end; if (pp->next->port != 81) goto end; if (pp->next->toserver_max_depth != 15) goto end; if (pp->next->toclient_max_depth != 0) goto end; if (pp->next->toserver == NULL) goto end; if (pp->next->toserver->next == NULL) goto end; if (pp->next->toserver->next->next != NULL) goto end; /* second pp - first one */ pe = pp->next->toserver; if (strcmp(pe->al_proto_name, "ftp") != 0) goto end; if (pe->al_proto != ALPROTO_FTP) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 7) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp - second one */ pe = pp->next->toserver->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest13(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 81, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_LOW, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } /* first pp */ if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp */ if (pp->next->next != NULL) goto end; if (pp->next->toclient != NULL) goto end; if (pp->next->port != 81) goto end; if (pp->next->toserver_max_depth != 10) goto end; if (pp->next->toclient_max_depth != 0) goto end; if (pp->next->toserver == NULL) goto end; if (pp->next->toserver->next != NULL) goto end; /* second pp - first one */ pe = pp->next->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 5, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp */ if (pp->next->next != NULL) goto end; if (pp->next->toclient != NULL) goto end; if (pp->next->port != 81) goto end; if (pp->next->toserver_max_depth != 10) goto end; if (pp->next->toclient_max_depth != 0) goto end; if (pp->next->toserver == NULL) goto end; if (pp->next->toserver->next != NULL) goto end; /* second pp - first one */ pe = pp->next->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 81, IPPROTO_TCP, "ftp", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } /* first pp */ if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 5) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp */ if (pp->next->next != NULL) goto end; if (pp->next->toclient != NULL) goto end; if (pp->next->port != 81) goto end; if (pp->next->toserver_max_depth != 15) goto end; if (pp->next->toclient_max_depth != 0) goto end; if (pp->next->toserver == NULL) goto end; if (pp->next->toserver->next == NULL) goto end; if (pp->next->toserver->next->next != NULL) goto end; /* second pp - first one */ pe = pp->next->toserver; if (strcmp(pe->al_proto_name, "ftp") != 0) goto end; if (pe->al_proto != ALPROTO_FTP) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 7) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second pp - second one */ pe = pp->next->toserver->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_LOW) goto end; if (pe->min_depth != 9) goto end; if (pe->max_depth != 10) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerPrintProbingParsers(ctx.probing_parsers); result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest14(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 15, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 15) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 0, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 5, 25, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->next->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second probing parser */ pp = pp->next; if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 0) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 81, IPPROTO_TCP, "ftp", ALPROTO_FTP, 7, 50, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->next->next == NULL) goto end; if (pp->next->next->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second probing parser */ pp = pp->next; if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->next->next != NULL) goto end; if (pp->port != 81) goto end; if (pp->toserver_max_depth != 50) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "ftp") != 0) goto end; if (pe->al_proto != ALPROTO_FTP) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 7) goto end; if (pe->max_depth != 50) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* third probing parser */ pp = pp->next; if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 0) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerPrintProbingParsers(ctx.probing_parsers); result = 1; end: AlpProtoTestDestroy(&ctx); return result; } static int AppLayerProbingParserTest15(void) { int result = 0; AppLayerProbingParser *pp; AppLayerProbingParserElement *pe; AlpProtoDetectCtx ctx; AlpProtoInit(&ctx); AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "http", ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 8) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 80, IPPROTO_TCP, "smb", ALPROTO_SMB, 5, 15, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 15) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 0, IPPROTO_TCP, "dcerpc", ALPROTO_DCERPC, 5, 25, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 0, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->next->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second probing parser */ pp = pp->next; if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 0) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerRegisterProbingParser(&ctx, 81, IPPROTO_TCP, "ftp", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, ProbingParserDummyForTesting); pp = ctx.probing_parsers; if (ctx.probing_parsers == NULL) { goto end; } if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->next->next == NULL) goto end; if (pp->next->next->next != NULL) goto end; if (pp->port != 80) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next == NULL) goto end; if (pp->toserver->next->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "http") != 0) goto end; if (pe->al_proto != ALPROTO_HTTP) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 8) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "smb") != 0) goto end; if (pe->al_proto != ALPROTO_SMB) goto end; if (pe->port != 80) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; pe = pp->toserver->next->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second probing parser */ pp = pp->next; if (pp->toclient != NULL) goto end; if (pp->next == NULL) goto end; if (pp->next->next != NULL) goto end; if (pp->port != 81) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next == NULL) goto end; if (pp->toserver->next->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "ftp") != 0) goto end; if (pe->al_proto != ALPROTO_FTP) goto end; if (pe->port != 81) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 7) goto end; if (pe->max_depth != 15) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* second one */ pe = pp->toserver->next; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; /* third probing parser */ pp = pp->next; if (pp->toclient != NULL) goto end; if (pp->next != NULL) goto end; if (pp->port != 0) goto end; if (pp->toserver_max_depth != 25) goto end; if (pp->toclient_max_depth != 0) goto end; if (pp->toserver == NULL) goto end; if (pp->toserver->next != NULL) goto end; /* first one */ pe = pp->toserver; if (strcmp(pe->al_proto_name, "dcerpc") != 0) goto end; if (pe->al_proto != ALPROTO_DCERPC) goto end; if (pe->port != 0) goto end; if (pe->priority != APP_LAYER_PROBING_PARSER_PRIORITY_HIGH) goto end; if (pe->min_depth != 5) goto end; if (pe->max_depth != 25) goto end; if (pe->ProbingParser != ProbingParserDummyForTesting) goto end; AppLayerPrintProbingParsers(ctx.probing_parsers); result = 1; end: AlpProtoTestDestroy(&ctx); return result; } #endif /* UNITESTS */ void AppLayerParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("AppLayerParserTest01", AppLayerParserTest01, 1); UtRegisterTest("AppLayerParserTest02", AppLayerParserTest02, 1); UtRegisterTest("AppLayerProbingParserTest01", AppLayerProbingParserTest01, 1); UtRegisterTest("AppLayerProbingParserTest02", AppLayerProbingParserTest02, 1); UtRegisterTest("AppLayerProbingParserTest03", AppLayerProbingParserTest03, 1); UtRegisterTest("AppLayerProbingParserTest04", AppLayerProbingParserTest04, 1); UtRegisterTest("AppLayerProbingParserTest05", AppLayerProbingParserTest05, 1); UtRegisterTest("AppLayerProbingParserTest06", AppLayerProbingParserTest06, 1); UtRegisterTest("AppLayerProbingParserTest07", AppLayerProbingParserTest07, 1); UtRegisterTest("AppLayerProbingParserTest08", AppLayerProbingParserTest08, 1); UtRegisterTest("AppLayerProbingParserTest09", AppLayerProbingParserTest09, 1); UtRegisterTest("AppLayerProbingParserTest10", AppLayerProbingParserTest10, 1); UtRegisterTest("AppLayerProbingParserTest11", AppLayerProbingParserTest11, 1); UtRegisterTest("AppLayerProbingParserTest12", AppLayerProbingParserTest12, 1); UtRegisterTest("AppLayerProbingParserTest13", AppLayerProbingParserTest13, 1); UtRegisterTest("AppLayerProbingParserTest14", AppLayerProbingParserTest14, 1); UtRegisterTest("AppLayerProbingParserTest15", AppLayerProbingParserTest15, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/detect-icmp-seq.h0000644000000000000000000000203312253546156014160 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DETECT_ICMP_SEQ_H__ #define __DETECT_ICMP_SEQ_H__ typedef struct DetectIcmpSeqData_ { uint16_t seq; /**< sequence value in network byte order */ } DetectIcmpSeqData; /* prototypes */ void DetectIcmpSeqRegister(void); #endif /* __DETECT_ICMP_SEQ__ */ suricata-1.4.7/src/util-optimize.h0000644000000000000000000000246012253546156014013 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef __UTIL_OPTIMIZE_H__ #define __UTIL_OPTIMIZE_H__ /** * \file * * \author Victor Julien */ #ifndef likely #define likely(expr) __builtin_expect(!!(expr), 1) #endif #ifndef unlikely #define unlikely(expr) __builtin_expect(!!(expr), 0) #endif /** from http://en.wikipedia.org/wiki/Memory_ordering * * C Compiler memory barrier */ #define cc_barrier() __asm__ __volatile__("": : :"memory") /** from http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html * * Hardware memory barrier */ #define hw_barrier() __sync_synchronize() #endif /* __UTIL_OPTIMIZE_H__ */ suricata-1.4.7/src/util-rohash.h0000644000000000000000000000264412253546156013443 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_ROHASH_H__ #define __UTIL_ROHASH_H__ #include "queue.h" typedef struct ROHashTable_ { uint8_t locked; uint8_t hash_bits; uint16_t item_size; uint32_t items; void *data; TAILQ_HEAD(, ROHashTableItem_) head; } ROHashTable; /* init time */ ROHashTable *ROHashInit(uint8_t hash_bits, uint16_t item_size); int ROHashInitFinalize(ROHashTable *table); void ROHashFree(ROHashTable *table); int ROHashInitQueueValue(ROHashTable *table, void *value, uint16_t size); uint32_t ROHashMemorySize(ROHashTable *table); /* run time */ void *ROHashLookup(ROHashTable *table, void *data, uint16_t size); #endif /* __UTIL_ROHASH_H__ */ suricata-1.4.7/src/util-cpu.c0000644000000000000000000001540212253546156012735 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * Retrieve CPU information (configured CPUs, online CPUs) */ #include "util-error.h" #include "util-debug.h" #include "suricata-common.h" /** * Ok, if they should use sysconf, check that they have the macro's * (syscalls) defined; * * Note: For windows it's different; Check the following: * SYSTEM_INFO info; * GetSystemInfo(&info); * -> info.dwNumberOfProcessors; */ #ifdef _SC_NPROCESSORS_CONF #define SYSCONF_NPROCESSORS_CONF_COMPAT #endif #ifdef _SC_NPROCESSORS_ONLN #define SYSCONF_NPROCESSORS_ONLN_COMPAT #endif /* This one is available on Solaris 10 */ #ifdef _SC_NPROCESSORS_MAX #define SYSCONF_NPROCESSORS_MAX_COMPAT #endif /** * \brief Get the number of cpus configured in the system * \retval 0 if the syscall is not available or we have an error; * otherwise it will return the number of cpus configured */ uint16_t UtilCpuGetNumProcessorsConfigured() { #ifdef SYSCONF_NPROCESSORS_CONF_COMPAT long nprocs = -1; nprocs = sysconf(_SC_NPROCESSORS_CONF); if (nprocs < 1) { SCLogError(SC_ERR_SYSCALL, "Couldn't retrieve the number of cpus " "configured (%s)", strerror(errno)); return 0; } if (nprocs > UINT16_MAX) { SCLogDebug("It seems that there are more than %"PRIu16" CPUs " "configured on this system. You can modify util-cpu.{c,h} " "to use uint32_t to support it", UINT16_MAX); return UINT16_MAX; } return (uint16_t)nprocs; #elif OS_WIN32 long nprocs = -1; const char* envvar = getenv("NUMBER_OF_PROCESSORS"); nprocs = (NULL != envvar) ? atoi(envvar) : 0; if (nprocs < 1) { SCLogError(SC_ERR_SYSCALL, "Couldn't retrieve the number of cpus " "configured from the NUMBER_OF_PROCESSORS environment variable"); return 0; } return (uint16_t)nprocs; #else SCLogError(SC_ERR_SYSCONF, "Couldn't retrieve the number of cpus " "configured, sysconf macro unavailable"); return 0; #endif } /** * \brief Get the number of cpus online in the system * \retval 0 if the syscall is not available or we have an error; * otherwise it will return the number of cpus online */ uint16_t UtilCpuGetNumProcessorsOnline() { #ifdef SYSCONF_NPROCESSORS_ONLN_COMPAT long nprocs = -1; nprocs = sysconf(_SC_NPROCESSORS_ONLN); if (nprocs < 1) { SCLogError(SC_ERR_SYSCALL, "Couldn't retrieve the number of cpus " "online (%s)", strerror(errno)); return 0; } if (nprocs > UINT16_MAX) { SCLogDebug("It seems that there are more than %"PRIu16" CPUs online. " "You can modify util-cpu.{c,h} to use uint32_t to " "support it", UINT16_MAX); return UINT16_MAX; } return nprocs; #elif OS_WIN32 return UtilCpuGetNumProcessorsConfigured(); #else SCLogError(SC_ERR_SYSCONF, "Couldn't retrieve the number of cpus online, " "synconf macro unavailable"); return 0; #endif } /** * \brief Get the maximum number of cpus allowed in the system * This syscall is present on Solaris, but it's not on linux * or macosx. Maybe you should look at UtilCpuGetNumProcessorsConfigured() * \retval 0 if the syscall is not available or we have an error; * otherwise it will return the number of cpus allowed */ uint16_t UtilCpuGetNumProcessorsMax() { #ifdef SYSCONF_NPROCESSORS_MAX_COMPAT long nprocs = -1; nprocs = sysconf(_SC_NPROCESSORS_MAX); if (nprocs < 1) { SCLogError(SC_ERR_SYSCALL, "Couldn't retrieve the maximum number of cpus " "allowed by the system (%s)", strerror(errno)); return 0; } if (nprocs > UINT16_MAX) { SCLogDebug("It seems that the system support more that %"PRIu16" CPUs. You " "can modify util-cpu.{c,h} to use uint32_t to support it", UINT16_MAX); return UINT16_MAX; } return (uint16_t)nprocs; #else SCLogError(SC_ERR_SYSCONF, "Couldn't retrieve the maximum number of cpus allowed by " "the system, synconf macro unavailable"); return 0; #endif } /** * \brief Print a summary of CPUs detected (configured and online) */ void UtilCpuPrintSummary() { uint16_t cpus_conf = UtilCpuGetNumProcessorsConfigured(); uint16_t cpus_online = UtilCpuGetNumProcessorsOnline(); SCLogDebug("CPUs Summary: "); if (cpus_conf > 0) SCLogDebug("CPUs configured: %"PRIu16, cpus_conf); if (cpus_online > 0) SCLogInfo("CPUs/cores online: %"PRIu16, cpus_online); if (cpus_online == 0 && cpus_conf == 0) SCLogInfo("Couldn't retireve any information of CPU's, please, send your operating " "system info and check util-cpu.{c,h}"); } /** * Get the current number of ticks from the CPU. * * \todo We'll have to deal with removig ticks from the extra cpuids inbetween * 2 calls. */ uint64_t UtilCpuGetTicks(void) { uint64_t val; #if defined(__GNUC__) && (defined(__x86_64) || defined(_X86_64_) || defined(ia_64) || defined(__i386__)) #if defined(__x86_64) || defined(_X86_64_) || defined(ia_64) __asm__ __volatile__ ( "xorl %%eax,%%eax\n\t" "cpuid\n\t" ::: "%rax", "%rbx", "%rcx", "%rdx"); #else __asm__ __volatile__ ( "xorl %%eax,%%eax\n\t" "pushl %%ebx\n\t" "cpuid\n\t" "popl %%ebx\n\t" ::: "%eax", "%ecx", "%edx"); #endif uint32_t a, d; __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d)); val = ((uint64_t)a) | (((uint64_t)d) << 32); #if defined(__x86_64) || defined(_X86_64_) || defined(ia_64) __asm__ __volatile__ ( "xorl %%eax,%%eax\n\t" "cpuid\n\t" ::: "%rax", "%rbx", "%rcx", "%rdx"); #else __asm__ __volatile__ ( "xorl %%eax,%%eax\n\t" "pushl %%ebx\n\t" "cpuid\n\t" "popl %%ebx\n\t" ::: "%eax", "%ecx", "%edx"); #endif #else /* #if defined(__GNU__) */ #warning Using inferior version of UtilCpuGetTicks struct timeval now; gettimeofday(&now, NULL); val = (now.tv_sec * 1000000) + now.tv_usec; #endif return val; } suricata-1.4.7/src/unix-manager.c0000644000000000000000000006561612253546156013602 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #include "suricata-common.h" #include "suricata.h" #include "unix-manager.h" #include "detect-engine.h" #include "tm-threads.h" #include "runmodes.h" #include "conf.h" #include "util-privs.h" #include "util-debug.h" #include "util-signal.h" #include #include #include #ifdef BUILD_UNIX_SOCKET #include // MSG_NOSIGNAL does not exists on OS X #ifdef OS_DARWIN # ifndef MSG_NOSIGNAL # define MSG_NOSIGNAL SO_NOSIGPIPE # endif #endif #define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/" #define SOCKET_FILENAME "suricata-command.socket" #define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME typedef struct Command_ { char *name; TmEcode (*Func)(json_t *, json_t *, void *); void *data; int flags; TAILQ_ENTRY(Command_) next; } Command; typedef struct Task_ { TmEcode (*Func)(void *); void *data; TAILQ_ENTRY(Task_) next; } Task; typedef struct UnixClient_ { int fd; TAILQ_ENTRY(UnixClient_) next; } UnixClient; typedef struct UnixCommand_ { time_t start_timestamp; int socket; struct sockaddr_un client_addr; int select_max; TAILQ_HEAD(, Command_) commands; TAILQ_HEAD(, Task_) tasks; TAILQ_HEAD(, UnixClient_) clients; } UnixCommand; /** * \brief Create a command unix socket on system * * \retval 0 in case of error, 1 in case of success */ int UnixNew(UnixCommand * this) { struct sockaddr_un addr; int len; int ret; int on = 1; char *sockettarget = NULL; char *socketname; this->start_timestamp = time(NULL); this->socket = -1; this->select_max = 0; TAILQ_INIT(&this->commands); TAILQ_INIT(&this->tasks); TAILQ_INIT(&this->clients); /* Create socket dir */ ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); if ( ret != 0 ) { int err = errno; if (err != EEXIST) { SCLogError(SC_ERR_OPENING_FILE, "Cannot create socket directory %s: %s", SOCKET_PATH, strerror(err)); return 0; } } if (ConfGet("unix-command.filename", &socketname) == 1) { int socketlen = strlen(SOCKET_PATH) + strlen(socketname) + 2; sockettarget = SCMalloc(socketlen); if (unlikely(sockettarget == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); return 0; } snprintf(sockettarget, socketlen, "%s/%s", SOCKET_PATH, socketname); SCLogInfo("Use unix socket file '%s'.", sockettarget); } if (sockettarget == NULL) { sockettarget = SCStrdup(SOCKET_TARGET); if (unlikely(sockettarget == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); return 0; } } /* Remove socket file */ (void) unlink(sockettarget); /* set address */ addr.sun_family = AF_UNIX; strlcpy(addr.sun_path, sockettarget, sizeof(addr.sun_path)); addr.sun_path[sizeof(addr.sun_path) - 1] = 0; len = strlen(addr.sun_path) + sizeof(addr.sun_family); /* create socket */ this->socket = socket(AF_UNIX, SOCK_STREAM, 0); if (this->socket == -1) { SCLogWarning(SC_ERR_OPENING_FILE, "Unix Socket: unable to create UNIX socket %s: %s", addr.sun_path, strerror(errno)); SCFree(sockettarget); return 0; } this->select_max = this->socket + 1; /* Set file mode: will not fully work on most system, the group * permission is not changed on some Linux and *BSD won't do the * chmod. */ ret = fchmod(this->socket, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (ret == -1) { int err = errno; SCLogWarning(SC_ERR_INITIALIZATION, "Unable to change permission on socket: %s (%d)", strerror(err), err); } /* set reuse option */ ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); if ( ret != 0 ) { SCLogWarning(SC_ERR_INITIALIZATION, "Cannot set sockets options: %s.", strerror(errno)); } /* bind socket */ ret = bind(this->socket, (struct sockaddr *) &addr, len); if (ret == -1) { SCLogWarning(SC_ERR_INITIALIZATION, "Unix socket: UNIX socket bind(%s) error: %s", sockettarget, strerror(errno)); SCFree(sockettarget); return 0; } /* listen */ if (listen(this->socket, 1) == -1) { SCLogWarning(SC_ERR_INITIALIZATION, "Command server: UNIX socket listen() error: %s", strerror(errno)); SCFree(sockettarget); return 0; } SCFree(sockettarget); return 1; } void UnixCommandSetMaxFD(UnixCommand *this) { UnixClient *item; if (this == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Unix command is NULL, warn devel"); return; } this->select_max = this->socket + 1; TAILQ_FOREACH(item, &this->clients, next) { if (item->fd >= this->select_max) { this->select_max = item->fd + 1; } } } /** * \brief Close the unix socket */ void UnixCommandClose(UnixCommand *this, int fd) { UnixClient *item; int found = 0; TAILQ_FOREACH(item, &this->clients, next) { if (item->fd == fd) { found = 1; break; } } if (found == 0) { SCLogError(SC_ERR_INVALID_VALUE, "No fd found in client list"); return; } TAILQ_REMOVE(&this->clients, item, next); close(item->fd); UnixCommandSetMaxFD(this); SCFree(item); } /** * \brief Callback function used to send message to socket */ int UnixCommandSendCallback(const char *buffer, size_t size, void *data) { int fd = *(int *) data; if (send(fd, buffer, size, MSG_NOSIGNAL) == -1) { SCLogInfo("Unable to send block: %s", strerror(errno)); return -1; } return 0; } #define UNIX_PROTO_VERSION_LENGTH 200 #define UNIX_PROTO_VERSION "0.1" /** * \brief Accept a new client on unix socket * * The function is called when a new user is detected * in UnixMain(). It does the initial protocol negotiation * with client. * * \retval 0 in case of error, 1 in case of success */ int UnixCommandAccept(UnixCommand *this) { char buffer[UNIX_PROTO_VERSION_LENGTH + 1]; json_t *client_msg; json_t *server_msg; json_t *version; json_error_t jerror; int client; int ret; UnixClient *uclient = NULL; /* accept client socket */ socklen_t len = sizeof(this->client_addr); client = accept(this->socket, (struct sockaddr *) &this->client_addr, &len); if (client < 0) { SCLogInfo("Unix socket: accept() error: %s", strerror(errno)); return 0; } SCLogDebug("Unix socket: client connection"); /* read client version */ buffer[sizeof(buffer)-1] = 0; ret = recv(client, buffer, sizeof(buffer)-1, 0); if (ret < 0) { SCLogInfo("Command server: client doesn't send version"); close(client); return 0; } if (ret >= (int)(sizeof(buffer)-1)) { SCLogInfo("Command server: client message is too long, " "disconnect him."); close(client); } buffer[ret] = 0; client_msg = json_loads(buffer, 0, &jerror); if (client_msg == NULL) { SCLogInfo("Invalid command, error on line %d: %s\n", jerror.line, jerror.text); close(client); return 0; } version = json_object_get(client_msg, "version"); if (!json_is_string(version)) { SCLogInfo("error: version is not a string"); close(client); json_decref(client_msg); return 0; } /* check client version */ if (strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0) { SCLogInfo("Unix socket: invalid client version: \"%s\"", json_string_value(version)); json_decref(client_msg); close(client); return 0; } else { SCLogInfo("Unix socket: client version: \"%s\"", json_string_value(version)); } json_decref(client_msg); /* send answer */ server_msg = json_object(); if (server_msg == NULL) { close(client); return 0; } json_object_set_new(server_msg, "return", json_string("OK")); if (json_dump_callback(server_msg, UnixCommandSendCallback, &client, 0) == -1) { SCLogWarning(SC_ERR_SOCKET, "Unable to send command"); json_decref(server_msg); close(client); return 0; } json_decref(server_msg); /* client connected */ SCLogInfo("Unix socket: client connected"); uclient = SCMalloc(sizeof(UnixClient)); if (unlikely(uclient == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new cient"); return 0; } uclient->fd = client; TAILQ_INSERT_TAIL(&this->clients, uclient, next); UnixCommandSetMaxFD(this); return 1; } int UnixCommandBackgroundTasks(UnixCommand* this) { int ret = 1; Task *ltask; TAILQ_FOREACH(ltask, &this->tasks, next) { int fret = ltask->Func(ltask->data); if (fret != TM_ECODE_OK) { ret = 0; } } return ret; } /** * \brief Command dispatcher * * \param this a UnixCommand:: structure * \param command a string containing a json formatted * command * * \retval 0 in case of error, 1 in case of success */ int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *client) { int ret = 1; json_error_t error; json_t *jsoncmd = NULL; json_t *cmd = NULL; json_t *server_msg = json_object(); const char * value; int found = 0; Command *lcmd; if (server_msg == NULL) { return 0; } jsoncmd = json_loads(command, 0, &error); if (jsoncmd == NULL) { SCLogInfo("Invalid command, error on line %d: %s\n", error.line, error.text); goto error; } cmd = json_object_get(jsoncmd, "command"); if(!json_is_string(cmd)) { SCLogInfo("error: command is not a string"); goto error_cmd; } value = json_string_value(cmd); TAILQ_FOREACH(lcmd, &this->commands, next) { if (!strcmp(value, lcmd->name)) { int fret = TM_ECODE_OK; found = 1; if (lcmd->flags & UNIX_CMD_TAKE_ARGS) { cmd = json_object_get(jsoncmd, "arguments"); if(!json_is_object(cmd)) { SCLogInfo("error: argument is not an object"); goto error_cmd; } } fret = lcmd->Func(cmd, server_msg, lcmd->data); if (fret != TM_ECODE_OK) { ret = 0; } break; } } if (found == 0) { json_object_set_new(server_msg, "message", json_string("Unknown command")); ret = 0; } switch (ret) { case 0: json_object_set_new(server_msg, "return", json_string("NOK")); break; case 1: json_object_set_new(server_msg, "return", json_string("OK")); break; } /* send answer */ if (json_dump_callback(server_msg, UnixCommandSendCallback, &client->fd, 0) == -1) { SCLogWarning(SC_ERR_SOCKET, "Unable to send command"); goto error_cmd; } json_decref(jsoncmd); json_decref(server_msg); return ret; error_cmd: json_decref(jsoncmd); error: json_decref(server_msg); UnixCommandClose(this, client->fd); return 0; } void UnixCommandRun(UnixCommand * this, UnixClient *client) { char buffer[4096]; int ret; ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0); if (ret <= 0) { if (ret == 0) { SCLogInfo("Unix socket: lost connection with client"); } else { SCLogInfo("Unix socket: error on recv() from client: %s", strerror(errno)); } UnixCommandClose(this, client->fd); return; } if (ret >= (int)(sizeof(buffer)-1)) { SCLogInfo("Command server: client command is too long, " "disconnect him."); UnixCommandClose(this, client->fd); } buffer[ret] = 0; UnixCommandExecute(this, buffer, client); } /** * \brief Select function * * \retval 0 in case of error, 1 in case of success */ int UnixMain(UnixCommand * this) { struct timeval tv; int ret; fd_set select_set; UnixClient *uclient; /* Wait activity on the socket */ FD_ZERO(&select_set); FD_SET(this->socket, &select_set); TAILQ_FOREACH(uclient, &this->clients, next) { FD_SET(uclient->fd, &select_set); } tv.tv_sec = 0; tv.tv_usec = 200 * 1000; ret = select(this->select_max, &select_set, NULL, NULL, &tv); /* catch select() error */ if (ret == -1) { /* Signal was catched: just ignore it */ if (errno == EINTR) { return 1; } SCLogInfo("Command server: select() fatal error: %s", strerror(errno)); return 0; } if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { return 1; } /* timeout: continue */ if (ret == 0) { return 1; } TAILQ_FOREACH(uclient, &this->clients, next) { if (FD_ISSET(uclient->fd, &select_set)) { UnixCommandRun(this, uclient); } } if (FD_ISSET(this->socket, &select_set)) { if (!UnixCommandAccept(this)) return 1; } return 1; } /** * \brief Used to kill unix manager thread(s). * * \todo Kinda hackish since it uses the tv name to identify unix manager * thread. We need an all weather identification scheme. */ void UnixKillUnixManagerThread(void) { ThreadVars *tv = NULL; int cnt = 0; SCCondSignal(&unix_manager_cond); SCMutexLock(&tv_root_lock); /* flow manager thread(s) is/are a part of mgmt threads */ tv = tv_root[TVT_CMD]; while (tv != NULL) { if (strcasecmp(tv->name, "UnixManagerThread") == 0) { TmThreadsSetFlag(tv, THV_KILL); TmThreadsSetFlag(tv, THV_DEINIT); /* be sure it has shut down */ while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { usleep(100); } cnt++; } tv = tv->next; } /* not possible, unless someone decides to rename UnixManagerThread */ if (cnt == 0) { SCMutexUnlock(&tv_root_lock); abort(); } SCMutexUnlock(&tv_root_lock); return; } TmEcode UnixManagerShutdownCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); json_object_set_new(server_msg, "message", json_string("Closing Suricata")); EngineStop(); SCReturnInt(TM_ECODE_OK); } TmEcode UnixManagerVersionCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); json_object_set_new(server_msg, "message", json_string( #ifdef REVISION PROG_VER xstr(REVISION) #elif defined RELEASE PROG_VER " RELEASE" #else PROG_VER #endif )); SCReturnInt(TM_ECODE_OK); } TmEcode UnixManagerUptimeCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); int uptime; UnixCommand *ucmd = (UnixCommand *)data; uptime = time(NULL) - ucmd->start_timestamp; json_object_set_new(server_msg, "message", json_integer(uptime)); SCReturnInt(TM_ECODE_OK); } TmEcode UnixManagerRunningModeCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); json_object_set_new(server_msg, "message", json_string(RunmodeGetActive())); SCReturnInt(TM_ECODE_OK); } TmEcode UnixManagerCaptureModeCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); json_object_set_new(server_msg, "message", json_string(RunModeGetMainMode())); SCReturnInt(TM_ECODE_OK); } TmEcode UnixManagerConfGetCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); char *confval = NULL; char *variable = NULL; json_t *jarg = json_object_get(cmd, "variable"); if(!json_is_string(jarg)) { SCLogInfo("error: variable is not a string"); json_object_set_new(server_msg, "message", json_string("variable is not a string")); SCReturnInt(TM_ECODE_FAILED); } variable = (char *)json_string_value(jarg); if (ConfGet(variable, &confval) != 1) { json_object_set_new(server_msg, "message", json_string("Unable to get value")); SCReturnInt(TM_ECODE_FAILED); } if (confval) { json_object_set_new(server_msg, "message", json_string(confval)); SCReturnInt(TM_ECODE_OK); } json_object_set_new(server_msg, "message", json_string("No string value")); SCReturnInt(TM_ECODE_FAILED); } TmEcode UnixManagerListCommand(json_t *cmd, json_t *answer, void *data) { SCEnter(); json_t *jdata; json_t *jarray; Command *lcmd = NULL; UnixCommand *gcmd = (UnixCommand *) data; int i = 0; jdata = json_object(); if (jdata == NULL) { json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } jarray = json_array(); if (jarray == NULL) { json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } TAILQ_FOREACH(lcmd, &gcmd->commands, next) { json_array_append(jarray, json_string(lcmd->name)); i++; } json_object_set_new(jdata, "count", json_integer(i)); json_object_set_new(jdata, "commands", jarray); json_object_set_new(answer, "message", jdata); SCReturnInt(TM_ECODE_OK); } #if 0 TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); if (suricata_ctl_flags != 0) { json_object_set_new(server_msg, "message", json_string("Live rule swap no longer possible. Engine in shutdown mode.")); SCReturn(TM_ECODE_FAILED); } else { /* FIXME : need to check option value */ UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle); DetectEngineSpawnLiveRuleSwapMgmtThread(); json_object_set_new(server_msg, "message", json_string("Reloading rules")); } SCReturn(TM_ECODE_OK); } #endif static UnixCommand command; /** * \brief Add a command to the list of commands * * This function adds a command to the list of commands available * through the unix socket. * * When a command is received from user through the unix socket, the content * of 'Command' field in the JSON message is match against keyword, then the * Func is called. See UnixSocketAddPcapFile() for an example. * * \param keyword name of the command * \param Func function to run when command is received * \param data a pointer to data that are pass to Func when runned * \param flags a flag now used to tune the command type * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure */ TmEcode UnixManagerRegisterCommand(const char * keyword, TmEcode (*Func)(json_t *, json_t *, void *), void *data, int flags) { SCEnter(); Command *cmd = NULL; Command *lcmd = NULL; if (Func == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function"); SCReturnInt(TM_ECODE_FAILED); } if (keyword == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Null keyword"); SCReturnInt(TM_ECODE_FAILED); } TAILQ_FOREACH(lcmd, &command.commands, next) { if (!strcmp(keyword, lcmd->name)) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Null keyword"); SCReturnInt(TM_ECODE_FAILED); } } cmd = SCMalloc(sizeof(Command)); if (unlikely(cmd == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd"); SCReturnInt(TM_ECODE_FAILED); } cmd->name = SCStrdup(keyword); if (unlikely(cmd->name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd name"); SCFree(cmd); SCReturnInt(TM_ECODE_FAILED); } cmd->Func = Func; cmd->data = data; cmd->flags = flags; /* Add it to the list */ TAILQ_INSERT_TAIL(&command.commands, cmd, next); SCReturnInt(TM_ECODE_OK); } /** * \brief Add a task to the list of tasks * * This function adds a task to run in background. The task is runned * each time the UnixMain() function exit from select. * * \param Func function to run when command is received * \param data a pointer to data that are pass to Func when runned * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure */ TmEcode UnixManagerRegisterBackgroundTask( TmEcode (*Func)(void *), void *data) { SCEnter(); Task *task = NULL; if (Func == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function"); SCReturnInt(TM_ECODE_FAILED); } task = SCMalloc(sizeof(Task)); if (unlikely(task == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc task"); SCReturnInt(TM_ECODE_FAILED); } task->Func = Func; task->data = data; /* Add it to the list */ TAILQ_INSERT_TAIL(&command.tasks, task, next); SCReturnInt(TM_ECODE_OK); } void *UnixManagerThread(void *td) { ThreadVars *th_v = (ThreadVars *)td; int ret; /* set the thread name */ (void) SCSetThreadName(th_v->name); SCLogDebug("%s started...", th_v->name); th_v->sc_perf_pca = SCPerfGetAllCountersArray(&th_v->sc_perf_pctx); SCPerfAddToClubbedTMTable(th_v->name, &th_v->sc_perf_pctx); if (UnixNew(&command) == 0) { int failure_fatal = 0; SCLogError(SC_ERR_INITIALIZATION, "Unable to create unix command socket"); if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) { SCLogDebug("ConfGetBool could not load the value."); } if (failure_fatal) { exit(EXIT_FAILURE); } else { TmThreadsSetFlag(th_v, THV_INIT_DONE|THV_RUNNING_DONE); pthread_exit((void *) 0); } } /* Set the threads capability */ th_v->cap_flags = 0; SCDropCaps(th_v); /* Init Unix socket */ UnixManagerRegisterCommand("shutdown", UnixManagerShutdownCommand, NULL, 0); UnixManagerRegisterCommand("command-list", UnixManagerListCommand, &command, 0); UnixManagerRegisterCommand("help", UnixManagerListCommand, &command, 0); UnixManagerRegisterCommand("version", UnixManagerVersionCommand, &command, 0); UnixManagerRegisterCommand("uptime", UnixManagerUptimeCommand, &command, 0); UnixManagerRegisterCommand("running-mode", UnixManagerRunningModeCommand, &command, 0); UnixManagerRegisterCommand("capture-mode", UnixManagerCaptureModeCommand, &command, 0); UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("dump-counters", SCPerfOutputCounterSocket, NULL, 0); #if 0 UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0); #endif TmThreadsSetFlag(th_v, THV_INIT_DONE); while (1) { ret = UnixMain(&command); if (ret == 0) { SCLogError(SC_ERR_FATAL, "Fatal error on unix socket"); } if ((ret == 0) || (TmThreadsCheckFlag(th_v, THV_KILL))) { UnixClient *item; UnixClient *titem; TAILQ_FOREACH_SAFE(item, &(&command)->clients, next, titem) { close(item->fd); SCFree(item); } SCPerfSyncCounters(th_v, 0); break; } UnixCommandBackgroundTasks(&command); } TmThreadWaitForFlag(th_v, THV_DEINIT); TmThreadsSetFlag(th_v, THV_CLOSED); pthread_exit((void *) 0); } /** \brief spawn the unix socket manager thread * * \param de_ctx context for detection engine * \param mode if set to 1, init failure cause suricata exit * */ void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode) { ThreadVars *tv_unixmgr = NULL; SCCondInit(&unix_manager_cond, NULL); tv_unixmgr = TmThreadCreateCmdThread("UnixManagerThread", UnixManagerThread, 0); if (tv_unixmgr == NULL) { SCLogError(SC_ERR_INITIALIZATION, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } if (TmThreadSpawn(tv_unixmgr) != TM_ECODE_OK) { SCLogError(SC_ERR_INITIALIZATION, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } if (mode == 1) { if (TmThreadsCheckFlag(tv_unixmgr, THV_RUNNING_DONE)) { SCLogError(SC_ERR_INITIALIZATION, "Unix socket init failed"); exit(EXIT_FAILURE); } } return; } /** * \brief Used to kill unix manager thread(s). * * \todo Kinda hackish since it uses the tv name to identify unix manager * thread. We need an all weather identification scheme. */ void UnixSocketKillSocketThread(void) { ThreadVars *tv = NULL; SCMutexLock(&tv_root_lock); /* unix manager thread(s) is/are a part of command threads */ tv = tv_root[TVT_CMD]; while (tv != NULL) { if (strcasecmp(tv->name, "UnixManagerThread") == 0) { /* If thread die during init it will have THV_RUNNING_DONE * set. So we can set the correct flag and exit. */ if (TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { TmThreadsSetFlag(tv, THV_KILL); TmThreadsSetFlag(tv, THV_DEINIT); TmThreadsSetFlag(tv, THV_CLOSED); break; } TmThreadsSetFlag(tv, THV_KILL); TmThreadsSetFlag(tv, THV_DEINIT); /* be sure it has shut down */ while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { usleep(100); } } tv = tv->next; } SCMutexUnlock(&tv_root_lock); return; } #else /* BUILD_UNIX_SOCKET */ void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode) { SCLogError(SC_ERR_UNIMPLEMENTED, "Unix socket is not compiled"); return; } void UnixSocketKillSocketThread(void) { return; } #endif /* BUILD_UNIX_SOCKET */ suricata-1.4.7/src/util-vector.h0000644000000000000000000000234512253546156013457 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_VECTOR_H__ #define __UTIL_VECTOR_H__ #if defined(__SSE3__) #include typedef struct Vector_ { union { __m128i v; /**< vector */ uint8_t c[16]; /**< character */ uint16_t w[8]; /**< word */ uint32_t dw[4]; /**< double word */ uint64_t qw[2]; /**< quad word */ }; } Vector __attribute((aligned(16))); #endif /* defined(__SSE3__) */ #endif /* __UTIL_VECTOR_H__ */ suricata-1.4.7/src/tmqh-packetpool.h0000644000000000000000000000243712253546156014314 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __TMQH_PACKETPOOL_H__ #define __TMQH_PACKETPOOL_H__ Packet *TmqhInputPacketpool(ThreadVars *); void TmqhOutputPacketpool(ThreadVars *, Packet *); void TmqhReleasePacketsToPacketPool(PacketQueue *); void TmqhPacketpoolRegister (void); void TmqhPacketpoolDestroy (void); Packet *PacketPoolGetPacket(void); uint16_t PacketPoolSize(void); void PacketPoolStorePacket(Packet *); void PacketPoolWait(void); void PacketPoolInit(intmax_t max_pending_packets); void PacketPoolDestroy(void); #endif /* __TMQH_PACKETPOOL_H__ */ suricata-1.4.7/src/detect-within.c0000644000000000000000000003607212253546156013751 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * * Implements the within keyword */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-bytejump.h" #include "detect-byte-extract.h" #include "app-layer.h" #include "detect-parse.h" #include "flow-var.h" #include "util-debug.h" #include "detect-pcre.h" #include "util-unittest.h" static int DetectWithinSetup (DetectEngineCtx *, Signature *, char *); void DetectWithinRegisterTests(void); void DetectWithinRegister (void) { sigmatch_table[DETECT_WITHIN].name = "within"; sigmatch_table[DETECT_WITHIN].desc = "indicate that this content match has to be within a certain distance of the previous content keyword match"; sigmatch_table[DETECT_WITHIN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Within"; sigmatch_table[DETECT_WITHIN].Match = NULL; sigmatch_table[DETECT_WITHIN].Setup = DetectWithinSetup; sigmatch_table[DETECT_WITHIN].Free = NULL; sigmatch_table[DETECT_WITHIN].RegisterTests = DetectWithinRegisterTests; sigmatch_table[DETECT_WITHIN].flags |= SIGMATCH_PAYLOAD; } /** \brief Setup within pattern (content/uricontent) modifier. * * \todo apply to uricontent * * \retval 0 ok * \retval -1 error, sig needs to be invalidated */ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withinstr) { char *str = withinstr; char dubbed = 0; SigMatch *pm = NULL; /* strip "'s */ if (withinstr[0] == '\"' && withinstr[strlen(withinstr)-1] == '\"') { str = SCStrdup(withinstr+1); if (unlikely(str == NULL)) goto error; str[strlen(withinstr)-2] = '\0'; dubbed = 1; } /* if we still haven't found that the sig is related to DCERPC, * it's a direct entry into Signature->[DETECT_SM_LIST_PMATCH] */ if (s->alproto == ALPROTO_DCERPC) { SigMatch *dcem = NULL; SigMatch *dm = NULL; SigMatch *pm1 = NULL; SigMatch *pm1_ots = NULL; SigMatch *pm2_ots = NULL; dcem = SigMatchGetLastSMFromLists(s, 6, DETECT_DCE_IFACE, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_DCE_OPNUM, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_DCE_STUB_DATA, s->sm_lists_tail[DETECT_SM_LIST_AMATCH]); pm1_ots = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm1_ots != NULL && pm1_ots->prev != NULL) { pm2_ots = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, pm1_ots->prev, DETECT_PCRE, pm1_ots->prev, DETECT_BYTEJUMP, pm1_ots->prev); } dm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm1 = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (dm == NULL && pm1 == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"within\" requires a " "preceding content keyword"); goto error; } if (dm == NULL) { if (pm2_ots == NULL) { if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ pm = pm1; } } else if (pm2_ots->idx > dcem->idx) { /* within is against pm1, pm = pm1; */ pm = pm1; } else if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ pm = pm1; } } else { if (pm1 == NULL) { /* within is against dm and continue this way */ pm = dm; } else if (dm->idx > pm1->idx) { /* within is against dm */ pm = dm; } else if (pm2_ots == NULL || pm2_ots->idx < dcem->idx) { /* trasnfer pm1 to dmatch list and pm = pm1 */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1, pm = pm1 */ pm = pm1; } } } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "\"within\" requires " "preceding content, uricontent, http_client_body, " "http_server_body, http_header, http_raw_header, " "http_method, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code, http_user_agent, " "http_host or http_raw_host option"); if (dubbed) SCFree(str); return -1; } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (pm->type) { case DETECT_CONTENT: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "content error"); goto error; } if (cd->flags & DETECT_CONTENT_NEGATED) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a fast_pattern"); goto error; } } else { if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "keyword set along with a fast_pattern:only"); goto error; } } if ((cd->flags & DETECT_CONTENT_DEPTH) || (cd->flags & DETECT_CONTENT_OFFSET)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative keyword " "with a non-relative keyword for the same content" ); goto error; } if (str[0] != '-' && isalpha((unsigned char)str[0])) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var " "seen in within - %s\n", str); goto error; } cd->within = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_WITHIN_BE; } else { cd->within = strtol(str, NULL, 10); if (cd->within < (int32_t)cd->content_len) { SCLogError(SC_ERR_WITHIN_INVALID, "within argument \"%"PRIi32"\" is " "less than the content length \"%"PRIu32"\" which is invalid, since " "this will never match. Invalidating signature", cd->within, cd->content_len); goto error; } } cd->flags |= DETECT_CONTENT_WITHIN; pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, pm->prev, DETECT_PCRE, pm->prev, DETECT_BYTEJUMP, pm->prev); if (pm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("content relative without a previous content based " "keyword. Holds good only in the case of DCERPC " "alproto like now."); } else { //SCLogError(SC_ERR_INVALID_SIGNATURE, "No related " // "previous-previous content or pcre keyword"); //goto error; ; } } else { switch (pm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "content error"); goto error; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "previous keyword " "has a fast_pattern:only; set. Can't " "have relative keywords around a fast_pattern " "only content"); goto error; } break; case DETECT_PCRE: pe = (DetectPcreData *) pm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre error"); goto error; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: SCLogDebug("no setting relative_next for bytejump. We " "have no use for it"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "unsupported type %d", pm->type); break; } } break; default: SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs two " "preceding content or uricontent options"); goto error; } if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; } /***********************************Unittests**********************************/ #ifdef UNITTESTS #include "util-unittest-helper.h" /** * \test DetectWithinTestPacket01 is a test to check matches of * within, if the previous keyword is pcre (bug 145) */ int DetectWithinTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" "User-Agent: Wget/1.11.4" "Accept: */*" "Host: www.google.com" "Connection: Keep-Alive" "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"pcre with within " "modifier\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\";" " content:\"HTTP\"; within:5; sid:49; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } int DetectWithinTestPacket02 (void) { int result = 0; uint8_t *buf = (uint8_t *)"Zero Five Ten Fourteen"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"pcre with within " "modifier\"; content:\"Five\"; content:\"Ten\"; within:3; distance:1; sid:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } #endif /* UNITTESTS */ void DetectWithinRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectWithinTestPacket01", DetectWithinTestPacket01, 1); UtRegisterTest("DetectWithinTestPacket02", DetectWithinTestPacket02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-rawbytes.c0000644000000000000000000000557612253546156014314 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements rawbytes keyword support * * \todo Provide un-normalized telnet dce/rpc buffers to match on */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "flow-var.h" #include "detect-content.h" #include "detect-pcre.h" #include "util-debug.h" static int DetectRawbytesSetup (DetectEngineCtx *, Signature *, char *); 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; sigmatch_table[DETECT_RAWBYTES].flags |= SIGMATCH_PAYLOAD; } static int DetectRawbytesSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr) { SCEnter(); if (nullstr != NULL) { SCLogError(SC_ERR_INVALID_VALUE, "rawbytes has no value"); return -1; } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { SCLogError(SC_ERR_RAWBYTES_FILE_DATA, "\"rawbytes\" cannot be combined with \"file_data\""); SCReturnInt(-1); } SigMatch *pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_RAWBYTES_MISSING_CONTENT, "\"rawbytes\" needs a preceding content option"); SCReturnInt(-1); } switch (pm->type) { case DETECT_CONTENT: { DetectContentData *cd = (DetectContentData *)pm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple rawbytes modifiers for the same content. "); SCReturnInt(-1); } cd->flags |= DETECT_CONTENT_RAWBYTES; break; } default: SCLogError(SC_ERR_RAWBYTES_MISSING_CONTENT, "\"rawbytes\" needs a preceding content option"); SCReturnInt(-1); } SCReturnInt(0); } suricata-1.4.7/src/detect-engine-dcepayload.h0000644000000000000000000000205612253546156016017 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_DCEPAYLOAD_H__ #define __DETECT_ENGINE_DCEPAYLOAD_H__ int DetectEngineInspectDcePayload(DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *); void DcePayloadRegisterTests(void); #endif /* __DETECT_ENGINE_DCEPAYLOAD_H__ */ suricata-1.4.7/src/detect-http-method.h0000644000000000000000000000206512253546156014704 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus */ #ifndef __DETECT_HTTP_METHOD_H__ #define __DETECT_HTTP_METHOD_H__ /* prototypes */ void DetectHttpMethodRegister(void); int DetectHttpMethodDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Flow *, uint8_t, void *); #endif /* __DETECT_HTTP_METHOD_H__ */ suricata-1.4.7/src/source-ipfw.h0000644000000000000000000000334712253546156013450 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Nick Rogness * \author Eric Leblond */ #ifndef __SOURCE_IPFW_H__ #define __SOURCE_IPFW_H__ #define IPFW_MAX_QUEUE 16 /* per packet IPFW vars (Not used) */ typedef struct IPFWPacketVars_ { int ipfw_index; } IPFWPacketVars; typedef struct IPFWQueueVars_ { int fd; SCMutex socket_lock; uint8_t use_mutex; /* this one should be not changing after init */ uint16_t port_num; /* position into the ipfw queue var array */ uint16_t ipfw_index; struct sockaddr_in ipfw_sin; socklen_t ipfw_sinlen; #ifdef DBG_PERF int dbg_maxreadsize; #endif /* DBG_PERF */ /* counters */ uint32_t pkts; uint64_t bytes; uint32_t errs; uint32_t accepted; uint32_t dropped; uint32_t replaced; } IPFWQueueVars; void *IPFWGetThread(int number); int IPFWRegisterQueue(char *queue); void TmModuleReceiveIPFWRegister (void); void TmModuleVerdictIPFWRegister (void); void TmModuleDecodeIPFWRegister (void); #endif /* __SOURCE_IPFW_H__ */ suricata-1.4.7/src/detect-tls-version.h0000644000000000000000000000204012253546156014725 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_TLS_VERSION_H__ #define __DETECT_TLS_VERSION_H__ typedef struct DetectTlsVersionData_ { uint16_t ver; /** tls version to match */ } DetectTlsVersionData; /* prototypes */ void DetectTlsVersionRegister (void); #endif /* __DETECT_TLS_VERSION_H__ */ suricata-1.4.7/src/detect-msg.h0000644000000000000000000000162312253546156013234 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_MSG_H__ #define __DETECT_MSG_H__ /* prototypes */ void DetectMsgRegister (void); #endif /* __DETECT_MSG_H__ */ suricata-1.4.7/src/util-cidr.h0000644000000000000000000000162512253546156013076 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_NETMASK_H__ #define __UTIL_NETMASK_H__ void CIDRInit(void); uint32_t CIDRGet(int); #endif /* __UTIL_NETMASK_H__ */ suricata-1.4.7/src/detect-engine-alert.h0000644000000000000000000000237512253546156015025 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_ALERT_H__ #define __DETECT_ENGINE_ALERT_H__ #include "suricata-common.h" #include "decode.h" #include "detect.h" void PacketAlertFinalize(DetectEngineCtx *, DetectEngineThreadCtx *, Packet *); int PacketAlertAppend(DetectEngineThreadCtx *, Signature *, Packet *, uint8_t); int PacketAlertCheck(Packet *, uint32_t); int PacketAlertRemove(Packet *, uint16_t); void PacketAlertTagInit(void); PacketAlert *PacketAlertGetTag(void); #endif /* __DETECT_ENGINE_ALERT_H__ */ suricata-1.4.7/src/util-runmodes.c0000644000000000000000000012612712253546156014011 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond * * Helper function for runmode. * */ #include "suricata-common.h" #include "config.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-af-packet.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "util-device.h" #include "util-runmodes.h" int RunModeSetLiveCaptureAuto(DetectEngineCtx *de_ctx, ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev) { /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); int nlive = LiveGetDeviceCount(); TmModule *tm_module; char tname[16]; int thread; if ((nlive <= 1) && (live_dev != NULL)) { void *aconf; SCLogDebug("live_dev %s", live_dev); aconf = ConfigParser(live_dev); if (aconf == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Single dev: Failed to allocate config"); exit(EXIT_FAILURE); } if (ModThreadsCount(aconf) > 1) { SCLogWarning(SC_ERR_UNIMPLEMENTED, "'Auto' running mode does not honor 'threads'" " variable (set on '%s'). Please use another mode as" " 'autofp' or 'worker'", live_dev); } /* create the threads */ ThreadVars *tv_receive = TmThreadCreatePacketHandler(recv_mod_name, "packetpool", "packetpool", "pickup-queue", "simple", "pktacqloop"); if (tv_receive == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receive, tm_module, aconf); TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } else { SCLogInfo("Using %d live device(s).", nlive); for (thread = 0; thread < nlive; thread++) { char *live_dev = LiveGetDeviceName(thread); char *tnamec = NULL; void *aconf; if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Multidev: Failed to lookup live dev %d", thread); exit(EXIT_FAILURE); } SCLogDebug("live_dev %s", live_dev); aconf = ConfigParser(live_dev); if (aconf == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate config for %s (%d)", live_dev, thread); exit(EXIT_FAILURE); } if (ModThreadsCount(aconf) > 1) { SCLogWarning(SC_ERR_UNIMPLEMENTED, "'Auto' running mode does not honor 'threads'" " variable (set on '%s'). Please use another mode as" " 'autofp' or 'worker'", live_dev); } snprintf(tname, sizeof(tname),"%s-%s", thread_name, live_dev); tnamec = SCStrdup(tname); if (unlikely(tnamec == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); exit(EXIT_FAILURE); } /* create the threads */ ThreadVars *tv_receive = TmThreadCreatePacketHandler(tnamec, "packetpool", "packetpool", "pickup-queue", "simple", "pktacqloop"); if (tv_receive == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receive, tm_module, (void *)aconf); TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { SCLogError(SC_ERR_INVALID_VALUE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } } #if defined(__SC_CUDA_SUPPORT__) if (PatternMatchDefaultMatcher() == MPM_B2G_CUDA) { ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode", "pickup-queue", "simple", "decode-queue1", "simple", "1slot"); if (tv_decode1 == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for Decode1"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); TmThreadSetCPU(tv_decode1, DECODE_CPU_SET); if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } ThreadVars *tv_cuda_PB = TmThreadCreate("CUDA_PB", "decode-queue1", "simple", "cuda-pb-queue1", "simple", "custom", SCCudaPBTmThreadsSlot1, 0); if (tv_cuda_PB == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for CUDA_PB"); exit(EXIT_FAILURE); } tv_cuda_PB->type = TVT_PPT; tm_module = TmModuleGetByName("CudaPacketBatcher"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName CudaPacketBatcher failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_cuda_PB, tm_module, (void *)de_ctx); TmThreadSetCPU(tv_cuda_PB, DETECT_CPU_SET); if (TmThreadSpawn(tv_cuda_PB) != TM_ECODE_OK) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } ThreadVars *tv_stream1 = TmThreadCreatePacketHandler("Stream1", "cuda-pb-queue1", "simple", "stream-queue1", "simple", "1slot"); if (tv_stream1 == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for Stream1"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_stream1, tm_module, NULL); TmThreadSetCPU(tv_stream1, STREAM_CPU_SET); if (TmThreadSpawn(tv_stream1) != TM_ECODE_OK) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } else { ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode & Stream", "pickup-queue", "simple", "stream-queue1", "simple", "varslot"); if (tv_decode1 == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for Decode1"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); TmThreadSetCPU(tv_decode1, DECODE_CPU_SET); if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } #else ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode & Stream", "pickup-queue", "simple", "stream-queue1", "simple", "varslot"); if (tv_decode1 == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for Decode1"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); TmThreadSetCPU(tv_decode1, DECODE_CPU_SET); if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } #endif /* always create at least one thread */ int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) thread_max = 1; for (thread = 0; thread < thread_max; thread++) { snprintf(tname, sizeof(tname),"Detect%"PRIu16, thread+1); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); exit(EXIT_FAILURE); } ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name, "stream-queue1", "simple", "verdict-queue", "simple", "1slot"); if (tv_detect_ncpu == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, (void *)de_ctx, de_ctx->delayed_detect); TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); char *thread_group_name = SCStrdup("Detect"); if (unlikely(thread_group_name == NULL)) { SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); exit(EXIT_FAILURE); } tv_detect_ncpu->thread_group_name = thread_group_name; if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } ThreadVars *tv_rreject = TmThreadCreatePacketHandler("RespondReject", "verdict-queue", "simple", "alert-queue", "simple", "1slot"); if (tv_rreject == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for RespondReject failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_rreject, tm_module, NULL); TmThreadSetCPU(tv_rreject, REJECT_CPU_SET); if (TmThreadSpawn(tv_rreject) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs", "alert-queue", "simple", "packetpool", "packetpool", "varslot"); if (tv_outputs == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadCreatePacketHandler for Outputs failed"); exit(EXIT_FAILURE); } SetupOutputs(tv_outputs); TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } return 0; } int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev) { char tname[12]; char qname[12]; char queues[2048] = ""; int thread; /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); int nlive = LiveGetDeviceCount(); int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); /* always create at least one thread */ if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) thread_max = 1; for (thread = 0; thread < thread_max; thread++) { if (strlen(queues) > 0) strlcat(queues, ",", sizeof(queues)); snprintf(qname, sizeof(qname),"pickup%"PRIu16, thread+1); strlcat(queues, qname, sizeof(queues)); } SCLogDebug("queues %s", queues); if ((nlive <= 1) && (live_dev != NULL)) { void *aconf; int threads_count; SCLogDebug("live_dev %s", live_dev); aconf = ConfigParser(live_dev); if (aconf == NULL) { SCLogError(SC_ERR_RUNMODE, "Failed to allocate config for %s (%d)", live_dev, thread); exit(EXIT_FAILURE); } threads_count = ModThreadsCount(aconf); SCLogInfo("Going to use %" PRId32 " %s receive thread(s)", threads_count, recv_mod_name); /* create the threads */ for (thread = 0; thread < threads_count; thread++) { snprintf(tname, sizeof(tname), "%s%"PRIu16, thread_name, thread+1); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); exit(EXIT_FAILURE); } ThreadVars *tv_receive = TmThreadCreatePacketHandler(thread_name, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receive, tm_module, aconf); tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receive, tm_module, NULL); TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } } else { /* Multiple input device */ SCLogInfo("Using %d live device(s).", nlive); int lthread; for (lthread = 0; lthread < nlive; lthread++) { char *live_dev = LiveGetDeviceName(lthread); void *aconf; int threads_count; if (live_dev == NULL) { SCLogError(SC_ERR_RUNMODE, "Failed to lookup live dev %d", lthread); exit(EXIT_FAILURE); } SCLogDebug("live_dev %s", live_dev); aconf = ConfigParser(live_dev); if (aconf == NULL) { SCLogError(SC_ERR_RUNMODE, "Multidev: Failed to allocate config for %s (%d)", live_dev, lthread); exit(EXIT_FAILURE); } threads_count = ModThreadsCount(aconf); for (thread = 0; thread < threads_count; thread++) { snprintf(tname, sizeof(tname), "%s%s%"PRIu16, thread_name, live_dev, thread+1); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); exit(EXIT_FAILURE); } ThreadVars *tv_receive = TmThreadCreatePacketHandler(thread_name, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receive, tm_module, aconf); tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receive, tm_module, NULL); TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } } } for (thread = 0; thread < thread_max; thread++) { snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); SCLogDebug("tname %s, qname %s", tname, qname); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); exit(EXIT_FAILURE); } ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name, qname, "flow", "packetpool", "packetpool", "varslot"); if (tv_detect_ncpu == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, (void *)de_ctx, de_ctx->delayed_detect); TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); char *thread_group_name = SCStrdup("Detect"); if (unlikely(thread_group_name == NULL)) { SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); exit(EXIT_FAILURE); } tv_detect_ncpu->thread_group_name = thread_group_name; tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName RespondReject failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); /* add outputs as well */ SetupOutputs(tv_detect_ncpu); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } return 0; } static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev, void *aconf, unsigned char single_mode) { int thread; int threads_count; if (single_mode) { threads_count = 1; } else { threads_count = ModThreadsCount(aconf); SCLogInfo("Going to use %" PRId32 " thread(s)", threads_count); } /* create the threads */ for (thread = 0; thread < threads_count; thread++) { char tname[20]; char *n_thread_name = NULL; ThreadVars *tv = NULL; TmModule *tm_module = NULL; if (single_mode) { snprintf(tname, sizeof(tname), "%s", thread_name); } else { snprintf(tname, sizeof(tname), "%s%s%"PRIu16, thread_name, live_dev, thread+1); } n_thread_name = SCStrdup(tname); if (unlikely(n_thread_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); exit(EXIT_FAILURE); } tv = TmThreadCreatePacketHandler(n_thread_name, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); if (tv == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, aconf); tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppendDelayed(tv, tm_module, (void *)de_ctx, de_ctx->delayed_detect); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName RespondReject failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); SetupOutputs(tv); TmThreadSetCPU(tv, DETECT_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } return 0; } int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev) { int nlive = LiveGetDeviceCount(); void *aconf; int ldev; for (ldev = 0; ldev < nlive; ldev++) { char *live_dev_c = NULL; if (live_dev != NULL) { aconf = ConfigParser(live_dev); live_dev_c = SCStrdup(live_dev); if (unlikely(live_dev_c == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate interface name"); exit(EXIT_FAILURE); } } else { live_dev_c = LiveGetDeviceName(ldev); aconf = ConfigParser(live_dev_c); } RunModeSetLiveCaptureWorkersForDevice(de_ctx, ModThreadsCount, recv_mod_name, decode_mod_name, thread_name, live_dev_c, aconf, 0); } return 0; } int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev) { int nlive = LiveGetDeviceCount(); void *aconf; if (nlive > 1) { SCLogError(SC_ERR_RUNMODE, "Can't use single runmode with multiple device"); exit(EXIT_FAILURE); } if (live_dev != NULL) { aconf = ConfigParser(live_dev); } else { char *live_dev_c = LiveGetDeviceName(0); aconf = ConfigParser(live_dev_c); /* \todo Set threads number in config to 1 */ } return RunModeSetLiveCaptureWorkersForDevice(de_ctx, ModThreadsCount, recv_mod_name, decode_mod_name, thread_name, live_dev, aconf, 1); } int RunModeSetIPSAuto(DetectEngineCtx *de_ctx, ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name) { SCEnter(); char tname[16]; TmModule *tm_module ; char *cur_queue = NULL; /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); int nqueue = LiveGetDeviceCount(); for (int i = 0; i < nqueue; i++) { /* create the threads */ cur_queue = LiveGetDeviceName(i); if (cur_queue == NULL) { printf("ERROR: Invalid queue number\n"); exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Recv-Q%s", cur_queue); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { printf("ERROR: Can't create thread name failed\n"); exit(EXIT_FAILURE); } ThreadVars *tv_receivenfq = TmThreadCreatePacketHandler(thread_name, "packetpool", "packetpool", "pickup-queue", "simple", "1slot_noinout"); if (tv_receivenfq == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName failed for %s\n", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receivenfq, tm_module, (void *) ConfigParser(i)); TmThreadSetCPU(tv_receivenfq, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receivenfq) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } } /* decode and stream */ ThreadVars *tv_decode = TmThreadCreatePacketHandler("Decode1", "pickup-queue", "simple", "decode-queue", "simple", "varslot"); if (tv_decode == NULL) { printf("ERROR: TmThreadsCreate failed for Decode1\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName %s failed\n", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_decode,tm_module,NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName StreamTcp failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_decode, tm_module, NULL); TmThreadSetCPU(tv_decode, DECODE_CPU_SET); if (TmThreadSpawn(tv_decode) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } /* always create at least one thread */ int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) thread_max = 1; int thread; for (thread = 0; thread < thread_max; thread++) { memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { printf("ERROR: thead name creation failed\n"); exit(EXIT_FAILURE); } SCLogDebug("Assigning %s affinity", thread_name); ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name, "decode-queue", "simple", "verdict-queue", "simple", "1slot"); if (tv_detect_ncpu == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, (void *)de_ctx, de_ctx->delayed_detect); TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); char *thread_group_name = SCStrdup("Detect"); if (unlikely(thread_group_name == NULL)) { printf("Error allocating memory\n"); exit(EXIT_FAILURE); } tv_detect_ncpu->thread_group_name = thread_group_name; if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } } /* create the threads */ for (int i = 0; i < nqueue; i++) { memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Verdict%"PRIu16, i); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { printf("ERROR: thead name creation failed\n"); exit(EXIT_FAILURE); } ThreadVars *tv_verdict = TmThreadCreatePacketHandler(thread_name, "verdict-queue", "simple", "alert-queue", "simple", "varslot"); if (tv_verdict == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(verdict_mod_name); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName %s failed\n", verdict_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_verdict, tm_module, (void *)ConfigParser(i)); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName for RespondReject failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_verdict, tm_module, NULL); TmThreadSetCPU(tv_verdict, VERDICT_CPU_SET); if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } }; ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs", "alert-queue", "simple", "packetpool", "packetpool", "varslot"); if (tv_outputs == NULL) { printf("ERROR: TmThreadCreatePacketHandler for Outputs failed\n"); exit(EXIT_FAILURE); } TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); SetupOutputs(tv_outputs); if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } return 0; } int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name) { SCEnter(); char tname[16]; char qname[16]; TmModule *tm_module ; char *cur_queue = NULL; char queues[2048] = ""; int thread; /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); int nqueue = LiveGetDeviceCount(); int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); /* always create at least one thread */ if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) thread_max = 1; for (thread = 0; thread < thread_max; thread++) { if (strlen(queues) > 0) strlcat(queues, ",", sizeof(queues)); snprintf(qname, sizeof(qname),"pickup%"PRIu16, thread+1); strlcat(queues, qname, sizeof(queues)); } SCLogDebug("queues %s", queues); for (int i = 0; i < nqueue; i++) { /* create the threads */ cur_queue = LiveGetDeviceName(i); if (cur_queue == NULL) { printf("ERROR: Invalid queue number\n"); exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Recv-Q%s", cur_queue); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { printf("ERROR: thead name creation failed\n"); exit(EXIT_FAILURE); } ThreadVars *tv_receive = TmThreadCreatePacketHandler(thread_name, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receive, tm_module, (void *) ConfigParser(i)); tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receive, tm_module, NULL); TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } for (thread = 0; thread < thread_max; thread++) { snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); SCLogDebug("tname %s, qname %s", tname, qname); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); exit(EXIT_FAILURE); } ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name, qname, "flow", "verdict-queue", "simple", "varslot"); if (tv_detect_ncpu == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, (void *)de_ctx, de_ctx->delayed_detect); TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); SetupOutputs(tv_detect_ncpu); char *thread_group_name = SCStrdup("Detect"); if (unlikely(thread_group_name == NULL)) { SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); exit(EXIT_FAILURE); } tv_detect_ncpu->thread_group_name = thread_group_name; if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } /* create the threads */ for (int i = 0; i < nqueue; i++) { memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Verdict%"PRIu16, i); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); exit(EXIT_FAILURE); } ThreadVars *tv_verdict = TmThreadCreatePacketHandler(thread_name, "verdict-queue", "simple", "packetpool", "packetpool", "varslot"); if (tv_verdict == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(verdict_mod_name); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName %s failed\n", verdict_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_verdict, tm_module, (void *)ConfigParser(i)); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName for RespondReject failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_verdict, tm_module, NULL); TmThreadSetCPU(tv_verdict, VERDICT_CPU_SET); if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } }; return 0; } int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name) { char tname[16]; ThreadVars *tv = NULL; TmModule *tm_module = NULL; char *cur_queue = NULL; int nqueue = LiveGetDeviceCount(); for (int i = 0; i < nqueue; i++) { /* create the threads */ cur_queue = LiveGetDeviceName(i); if (cur_queue == NULL) { printf("ERROR: Invalid queue number\n"); exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); snprintf(tname, sizeof(tname), "Worker-Q%s", cur_queue); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); exit(EXIT_FAILURE); } tv = TmThreadCreatePacketHandler(thread_name, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); if (tv == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, (void *) ConfigParser(i)); tm_module = TmModuleGetByName(decode_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppendDelayed(tv, tm_module, (void *)de_ctx, de_ctx->delayed_detect); tm_module = TmModuleGetByName(verdict_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", verdict_mod_name); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName for RespondReject failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); SetupOutputs(tv); TmThreadSetCPU(tv, DETECT_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } } return 0; } suricata-1.4.7/src/detect-filesize.h0000644000000000000000000000277412253546156014270 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_FILESIZE_H__ #define __DETECT_FILESIZE_H__ #define DETECT_FILESIZE_LT 0 /**< "less than" operator */ #define DETECT_FILESIZE_GT 1 /**< "greater than" operator */ #define DETECT_FILESIZE_RA 2 /**< range operator */ #define DETECT_FILESIZE_EQ 3 /**< equal operator */ typedef struct DetectFilesizeData_ { uint64_t size1; /**< 1st value in the signature*/ uint64_t size2; /**< 2nd value in the signature*/ uint8_t mode; /**< operator used in the signature */ } DetectFilesizeData; //int DetectFilesizeMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, // uint8_t, void *, Signature *, SigMatch *); void DetectFilesizeRegister(void); #endif /* _DETECT_URILEN_H */ suricata-1.4.7/src/util-syslog.c0000644000000000000000000000457112253546156013473 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * Syslog utility file * */ #include "suricata-common.h" /* holds the string-enum mapping for the syslog facility in SCLogOPIfaceCtx */ SCEnumCharMap sc_syslog_facility_map[] = { { "auth", LOG_AUTH }, { "authpriv", LOG_AUTHPRIV }, { "cron", LOG_CRON }, { "daemon", LOG_DAEMON }, { "ftp", LOG_FTP }, { "kern", LOG_KERN }, { "lpr", LOG_LPR }, { "mail", LOG_MAIL }, { "news", LOG_NEWS }, { "security", LOG_AUTH }, { "syslog", LOG_SYSLOG }, { "user", LOG_USER }, { "uucp", LOG_UUCP }, { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, { NULL, -1 } }; /** \brief returns the syslog facility enum map */ SCEnumCharMap *SCSyslogGetFacilityMap() { return sc_syslog_facility_map; } SCEnumCharMap sc_syslog_level_map[ ] = { { "Emergency", LOG_EMERG }, { "Alert", LOG_ALERT }, { "Critical", LOG_CRIT }, { "Error", LOG_ERR }, { "Warning", LOG_WARNING }, { "Notice", LOG_NOTICE }, { "Info", LOG_INFO }, { "Debug", LOG_DEBUG }, { NULL, -1 } }; /** \brief returns the syslog facility enum map */ SCEnumCharMap *SCSyslogGetLogLevelMap() { return sc_syslog_level_map; } suricata-1.4.7/src/util-privs.h0000644000000000000000000000741612253546156013324 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh */ #ifndef _UTIL_PRIVS_H #define _UTIL_PRIVS_H #define SC_CAP_NONE 0x01 #define SC_CAP_SYS_ADMIN 0x02 #define SC_CAP_SYS_RAW_IO 0x04 #define SC_CAP_IPC_LOCK 0x08 #define SC_CAP_NET_ADMIN 0x10 #define SC_CAP_NET_RAW 0x20 #define SC_CAP_NET_BIND_SERVICE 0x40 #define SC_CAP_NET_BROADCAST 0x80 #ifndef HAVE_LIBCAP_NG #define SCDropCaps(...) #define SCDropMainThreadCaps(...) #else #include "threadvars.h" #include "util-debug.h" #include /**Drop the previliges of the given thread tv, based on the thread cap_flags * which implies the capability requirement of the given thread. Initially all * caps are dropped and later, the required caps are set for the given thread */ void SCDropCaps(ThreadVars *tv); /* #define SCDropCaps(tv) ({ \ capng_clear(CAPNG_SELECT_BOTH); \ capng_apply(CAPNG_SELECT_BOTH); \ if (tv->cap_flags & SC_CAP_IPC_LOCK) { \ capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); \ capng_apply(CAPNG_SELECT_CAPS); \ SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); \ } \ if (tv->cap_flags & SC_CAP_NET_ADMIN) { \ capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); \ capng_apply(CAPNG_SELECT_CAPS); \ SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); \ } \ if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { \ capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE); \ capng_apply(CAPNG_SELECT_CAPS); \ SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); \ } \ if (tv->cap_flags & SC_CAP_NET_BROADCAST) { \ capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST); \ capng_apply(CAPNG_SELECT_CAPS); \ SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); \ } \ if (tv->cap_flags & SC_CAP_NET_RAW) { \ capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); \ capng_apply(CAPNG_SELECT_CAPS); \ SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); \ } \ if (tv->cap_flags & SC_CAP_SYS_ADMIN) { \ capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); \ capng_apply(CAPNG_SELECT_CAPS); \ SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); \ } \ if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { \ capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); \ capng_apply(CAPNG_SELECT_CAPS); \ SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); \ } \ }) */ void SCDropMainThreadCaps(uint32_t , uint32_t ); #endif /* HAVE_LIBCAP_NG */ int SCGetUserID(char *, char *, uint32_t *, uint32_t *); int SCGetGroupID(char *, uint32_t *); #endif /* _UTIL_PRIVS_H */ suricata-1.4.7/src/util-mpm.h0000644000000000000000000002065412253546156012751 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_MPM_H__ #define __UTIL_MPM_H__ #include "suricata-common.h" #define MPM_ENDMATCH_SINGLE 0x01 /**< A single match is sufficient. No depth, offset, etc settings. */ #define MPM_ENDMATCH_OFFSET 0x02 /**< has offset setting */ #define MPM_ENDMATCH_DEPTH 0x04 /**< has depth setting */ #define MPM_ENDMATCH_NOSEARCH 0x08 /**< if this matches, no search is required (for this pattern) */ #define HASHSIZE_LOWEST 2048 /**< Lowest hash size for the multi pattern matcher algorithms */ #define HASHSIZE_LOW 4096 /**< Low hash size for the multi pattern matcher algorithms */ #define HASHSIZE_MEDIUM 8192 /**< Medium hash size for the multi pattern matcher algorithms */ #define HASHSIZE_HIGH 16384 /**< High hash size for the multi pattern matcher algorithms */ #define HASHSIZE_HIGHER 32768 /**< Higher hash size for the multi pattern matcher algorithms */ #define HASHSIZE_MAX 65536 /**< Max hash size for the multi pattern matcher algorithms */ #define BLOOMSIZE_LOW 512 /*<* Low bloomfilter size for the multi pattern matcher algorithms */ #define BLOOMSIZE_MEDIUM 1024 /**< Medium bloomfilter size for the multi pattern matcher algorithms */ #define BLOOMSIZE_HIGH 2048 /**< High bloomfilter size for the multi pattern matcher algorithms */ #define MPM_PACKET_BUFFER_LIMIT 2400 #define MPM_PACKET_SIZE_LIMIT 1500 #define MPM_PACKET_BUFFERS 10 #define MPM_BATCHING_TIMEOUT 1 #define MPM_PAGE_LOCKED 1 #define MPM_CUDA_STREAMS 2 enum { MPM_NOTSET = 0, /* wumanber as the name suggests */ MPM_WUMANBER, /* bndmq 2 gram */ MPM_B2G, #ifdef __SC_CUDA_SUPPORT__ MPM_B2G_CUDA, #endif /* bndmq 3 gram */ MPM_B3G, MPM_B2GC, MPM_B2GM, /* aho-corasick */ MPM_AC, /* aho-corasick-goto-failure state based */ MPM_AC_GFBS, MPM_AC_BS, /* table size */ MPM_TABLE_SIZE, }; typedef struct MpmMatchBucket_ { uint32_t len; } MpmMatchBucket; typedef struct MpmThreadCtx_ { void *ctx; uint32_t memory_cnt; uint32_t memory_size; } MpmThreadCtx; /** \brief helper structure for the pattern matcher engine. The Pattern Matcher * thread has this and passes a pointer to it to the pattern matcher. * The actual pattern matcher will fill the structure. */ typedef struct PatternMatcherQueue_ { uint32_t *pattern_id_array; /** array with pattern id's that had a pattern match. These will be inspected futher by the detection engine. */ uint32_t pattern_id_array_cnt; uint32_t pattern_id_array_size; /**< size in bytes */ uint8_t *pattern_id_bitarray; /** bitarray with pattern id matches */ uint32_t pattern_id_bitarray_size; /**< size in bytes */ } PatternMatcherQueue; typedef struct MpmCtx_ { void *ctx; uint16_t mpm_type; /* used uint16_t here to avoiding using a pad. You can use a uint8_t * here as well */ uint16_t global; uint32_t pattern_cnt; /* unique patterns */ uint16_t minlen; uint16_t maxlen; uint32_t memory_cnt; uint32_t memory_size; } MpmCtx; /* if we want to retrieve an unique mpm context from the mpm context factory * we should supply this as the key */ #define MPM_CTX_FACTORY_UNIQUE_CONTEXT -1 #define MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD 0x01 typedef struct MpmCtxFactoryItem_ { char *name; MpmCtx *mpm_ctx_ts; MpmCtx *mpm_ctx_tc; int32_t id; uint8_t flags; } MpmCtxFactoryItem; typedef struct MpmCtxFactoryContainer_ { MpmCtxFactoryItem *items; int32_t no_of_items; } MpmCtxFactoryContainer; /** pattern is case insensitive */ #define MPM_PATTERN_FLAG_NOCASE 0x01 /** pattern is negated */ #define MPM_PATTERN_FLAG_NEGATED 0x02 /** pattern has a depth setting */ #define MPM_PATTERN_FLAG_DEPTH 0x04 /** pattern has an offset setting */ #define MPM_PATTERN_FLAG_OFFSET 0x08 /** one byte pattern (used in b2g) */ #define MPM_PATTERN_ONE_BYTE 0x10 typedef struct MpmTableElmt_ { char *name; uint8_t max_pattern_length; void (*InitCtx)(struct MpmCtx_ *, int); void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *, uint32_t); void (*DestroyCtx)(struct MpmCtx_ *); void (*DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); /** function pointers for adding patterns to the mpm ctx. * * \param mpm_ctx Mpm context to add the pattern to * \param pattern pointer to the pattern * \param pattern_len length of the pattern in bytes * \param offset pattern offset setting * \param depth pattern depth setting * \param pid pattern id * \param sid signature _internal_ id * \param flags pattern flags */ int (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int (*Prepare)(struct MpmCtx_ *); uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); void (*Cleanup)(struct MpmThreadCtx_ *); void (*PrintCtx)(struct MpmCtx_ *); void (*PrintThreadCtx)(struct MpmThreadCtx_ *); void (*RegisterUnittests)(void); uint8_t flags; } MpmTableElmt; MpmTableElmt mpm_table[MPM_TABLE_SIZE]; struct DetectEngineCtx_; int32_t MpmFactoryRegisterMpmCtxProfile(struct DetectEngineCtx_ *, const char *, uint8_t); void MpmFactoryReClaimMpmCtx(struct DetectEngineCtx_ *, MpmCtx *); MpmCtx *MpmFactoryGetMpmCtxForProfile(struct DetectEngineCtx_ *, int32_t, int); void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); int32_t MpmFactoryIsMpmCtxAvailable(struct DetectEngineCtx_ *, MpmCtx *); /* macros decides if cuda is enabled for the platform or not */ #ifdef __SC_CUDA_SUPPORT__ /** * \brief Cuda configuration for "mpm" profile. We can further extend this * to have conf for specific mpms. For now its common for all mpms. */ typedef struct MpmCudaConf_ { int32_t packet_buffer_limit; uint16_t packet_size_limit; int8_t packet_buffers; double batching_timeout; int8_t page_locked; int8_t device_id; int8_t cuda_streams; } MpmCudaConf; #endif /* __SC_CUDA_SUPPORT__ */ int PmqSetup(PatternMatcherQueue *, uint32_t, uint32_t); void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst); void PmqReset(PatternMatcherQueue *); void PmqCleanup(PatternMatcherQueue *); void PmqFree(PatternMatcherQueue *); #ifdef __SC_CUDA_SUPPORT__ MpmCudaConf *MpmCudaConfParse(void); void MpmCudaConfCleanup(MpmCudaConf *); #endif /* __SC_CUDA_SUPPORT */ void MpmTableSetup(void); void MpmRegisterTests(void); /** Return the max pattern length of a Matcher type given as arg */ int32_t MpmMatcherGetMaxPatternLength(uint16_t); int MpmVerifyMatch(MpmThreadCtx *, PatternMatcherQueue *, uint32_t); void MpmInitCtx (MpmCtx *mpm_ctx, uint16_t matcher, int module_handle); void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t, uint32_t); uint32_t MpmGetHashSize(const char *); uint32_t MpmGetBloomSize(const char *); #endif /* __UTIL_MPM_H__ */ suricata-1.4.7/src/source-pfring.h0000644000000000000000000000331612253546156013764 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author William Metcalf */ #ifndef __SOURCE_PFRING_H__ #define __SOURCE_PFRING_H__ #define PFRING_IFACE_NAME_LENGTH 48 #include #ifdef HAVE_PFRING #include #endif typedef struct PfringIfaceConfig_ { /* cluster param */ int cluster_id; #ifdef HAVE_PFRING_CLUSTER_TYPE cluster_type ctype; #endif /* HAVE_PFRING_CLUSTER_TYPE */ char iface[PFRING_IFACE_NAME_LENGTH]; /* number of threads */ int threads; #ifdef HAVE_PFRING_SET_BPF_FILTER char *bpf_filter; #endif /* HAVE_PFRING_SET_BPF_FILTER */ ChecksumValidationMode checksum_mode; SC_ATOMIC_DECLARE(unsigned int, ref); void (*DerefFunc)(void *); } PfringIfaceConfig; void TmModuleReceivePfringRegister (void); void TmModuleDecodePfringRegister (void); int PfringConfGetThreads(void); void PfringLoadConfig(void); /* We don't have to use an enum that sucks in our code */ #define CLUSTER_FLOW 0 #define CLUSTER_ROUND_ROBIN 1 #endif /* __SOURCE_PFRING_H__ */ suricata-1.4.7/src/app-layer-htp.h0000644000000000000000000002374512253546156013674 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \defgroup httplayer HTTP layer support * * @{ */ /** * \file * * \author Gurvinder Singh * \author Pablo Rincon * * This file provides a HTTP protocol support for the engine using HTP library. */ #ifndef __APP_LAYER_HTP_H__ #define __APP_LAYER_HTP_H__ #include "util-radix-tree.h" #include "util-file.h" #include /* default request body limit */ #define HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT 4096U #define HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT 4096U #define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE 32768U #define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW 4096U #define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE 32768U #define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW 4096U /** a boundary should be smaller in size */ #define HTP_BOUNDARY_MAX 200U #define HTP_FLAG_STATE_OPEN 0x0001 /**< Flag to indicate that HTTP connection is open */ #define HTP_FLAG_STATE_CLOSED_TS 0x0002 /**< Flag to indicate that HTTP connection is closed */ #define HTP_FLAG_STATE_CLOSED_TC 0x0004 /**< Flag to indicate that HTTP connection is closed */ #define HTP_FLAG_STATE_DATA 0x0008 /**< Flag to indicate that HTTP connection needs more data */ #define HTP_FLAG_STATE_ERROR 0x0010 /**< Flag to indicate that an error has been occured on HTTP connection */ #define HTP_FLAG_NEW_BODY_SET 0x0020 /**< Flag to indicate that HTTP has parsed a new body (for pcre) */ #define HTP_FLAG_STORE_FILES_TS 0x0040 #define HTP_FLAG_STORE_FILES_TC 0x0080 #define HTP_FLAG_STORE_FILES_TX_TS 0x0100 #define HTP_FLAG_STORE_FILES_TX_TC 0x0200 /** flag the state that a new file has been set in this tx */ #define HTP_FLAG_NEW_FILE_TX_TS 0x0400 /** flag the state that a new file has been set in this tx */ #define HTP_FLAG_NEW_FILE_TX_TC 0x0800 enum { HTP_BODY_NONE = 0, /**< Flag to indicate the current operation */ HTP_BODY_REQUEST, /**< Flag to indicate that the current operation is a request */ HTP_BODY_RESPONSE /**< Flag to indicate that the current * operation is a response */ }; enum { HTP_BODY_REQUEST_NONE = 0, HTP_BODY_REQUEST_MULTIPART, /* POST, MP */ HTP_BODY_REQUEST_POST, /* POST, no MP */ HTP_BODY_REQUEST_PUT, }; enum { /* libhtp errors/warnings */ HTTP_DECODER_EVENT_UNKNOWN_ERROR, HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED, HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON, HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON, HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN, HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN, HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST, HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE, HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST, HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE, HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN, HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST, HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST, HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT, HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID, HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID, HTTP_DECODER_EVENT_MISSING_HOST_HEADER, HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS, HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING, HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING, HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG, HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG, HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH, /* suricata errors/warnings */ HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR, HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA, HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER, }; #define HTP_PCRE_NONE 0x00 /**< No pcre executed yet */ #define HTP_PCRE_DONE 0x01 /**< Flag to indicate that pcre has done some inspection in the chunks */ #define HTP_PCRE_HAS_MATCH 0x02 /**< Flag to indicate that the chunks matched on some rule */ /** Need a linked list in order to keep track of these */ typedef struct HTPCfgRec_ { htp_cfg_t *cfg; struct HTPCfgRec_ *next; /** max size of the client body we inspect */ uint32_t request_body_limit; uint32_t response_body_limit; uint32_t request_inspect_min_size; uint32_t request_inspect_window; uint32_t response_inspect_min_size; uint32_t response_inspect_window; } HTPCfgRec; /** Struct used to hold chunks of a body on a request */ struct HtpBodyChunk_ { uint8_t *data; /**< Pointer to the data of the chunk */ struct HtpBodyChunk_ *next; /**< Pointer to the next chunk */ uint64_t stream_offset; uint32_t len; /**< Length of the chunk */ } __attribute__((__packed__)); typedef struct HtpBodyChunk_ HtpBodyChunk; /** Struct used to hold all the chunks of a body on a request */ typedef struct HtpBody_ { HtpBodyChunk *first; /**< Pointer to the first chunk */ HtpBodyChunk *last; /**< Pointer to the last chunk */ /* Holds the length of the htp request body */ uint64_t content_len; /* Holds the length of the htp request body seen so far */ uint64_t content_len_so_far; /* parser tracker */ uint64_t body_parsed; /* inspection tracker */ uint64_t body_inspected; } HtpBody; #define HTP_REQ_BODY_COMPLETE 0x01 /**< body is complete or limit is reached, either way, this is it. */ #define HTP_RES_BODY_COMPLETE 0x02 #define HTP_CONTENTTYPE_SET 0x04 /**< We have the content type */ #define HTP_BOUNDARY_SET 0x08 /**< We have a boundary string */ #define HTP_BOUNDARY_OPEN 0x10 /**< We have a boundary string */ #define HTP_FILENAME_SET 0x20 /**< filename is registered in the flow */ #define HTP_DONTSTORE 0x40 /**< not storing this file */ #define HTP_TX_HAS_FILE 0x01 #define HTP_TX_HAS_FILENAME 0x02 /**< filename is known at this time */ #define HTP_TX_HAS_TYPE 0x04 #define HTP_TX_HAS_FILECONTENT 0x08 /**< file has content so we can do type detect */ #define HTP_RULE_NEED_FILE HTP_TX_HAS_FILE #define HTP_RULE_NEED_FILENAME HTP_TX_HAS_FILENAME #define HTP_RULE_NEED_TYPE HTP_TX_HAS_TYPE #define HTP_RULE_NEED_FILECONTENT HTP_TX_HAS_FILECONTENT /** Now the Body Chunks will be stored per transaction, at * the tx user data */ typedef struct HtpTxUserData_ { /* Body of the request (if any) */ HtpBody request_body; HtpBody response_body; /** Holds the boundary identificator string if any (used on * multipart/form-data only) */ uint8_t *boundary; uint8_t boundary_len; uint8_t tsflags; uint8_t tcflags; int16_t operation; uint8_t request_body_type; uint8_t response_body_type; } HtpTxUserData; typedef struct HtpState_ { htp_connp_t *connp; /**< Connection parser structure for each connection */ Flow *f; /**< Needed to retrieve the original flow when usin HTPLib callbacks */ uint16_t flags; uint16_t transaction_cnt; uint16_t transaction_done; uint16_t store_tx_id; FileContainer *files_ts; FileContainer *files_tc; struct HTPCfgRec_ *cfg; } HtpState; /** part of the engine needs the request body (e.g. http_client_body keyword) */ #define HTP_REQUIRE_REQUEST_BODY (1 << 0) /** part of the engine needs the request body multipart header (e.g. filename * and / or fileext keywords) */ #define HTP_REQUIRE_REQUEST_MULTIPART (1 << 1) /** part of the engine needs the request file (e.g. log-file module) */ #define HTP_REQUIRE_REQUEST_FILE (1 << 2) /** part of the engine needs the request body (e.g. file_data keyword) */ #define HTP_REQUIRE_RESPONSE_BODY (1 << 3) SC_ATOMIC_DECLARE(uint32_t, htp_config_flags); void RegisterHTPParsers(void); void HTPParserRegisterTests(void); void HTPAtExitPrintStats(void); void HTPFreeConfig(void); htp_tx_t *HTPTransactionMain(const HtpState *); int HTPCallbackRequestBodyData(htp_tx_data_t *); int HtpTransactionGetLoggableId(Flow *); void HtpBodyPrint(HtpBody *); void HtpBodyFree(HtpBody *); /* To free the state from unittests using app-layer-htp */ void HTPStateFree(void *); void AppLayerHtpEnableRequestBodyCallback(void); void AppLayerHtpEnableResponseBodyCallback(void); void AppLayerHtpNeedFileInspection(void); void AppLayerHtpPrintStats(void); void HTPConfigure(void); void HtpConfigCreateBackup(void); void HtpConfigRestoreBackup(void); #endif /* __APP_LAYER_HTP_H__ */ /** * @} */ suricata-1.4.7/src/decode-ipv6.h0000644000000000000000000003074312253546156013312 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DECODE_IPV6_H__ #define __DECODE_IPV6_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_ { uint32_t ip6_un1_flow; /* 20 bits of flow-ID */ uint16_t ip6_un1_plen; /* payload length */ uint8_t ip6_un1_nxt; /* next header */ uint8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ } ip6_hdrun; union { struct { uint32_t ip6_src[4]; uint32_t ip6_dst[4]; } ip6_un2; uint16_t ip6_addrs[16]; } ip6_hdrun2; } IPV6Hdr; #define s_ip6_src ip6_hdrun2.ip6_un2.ip6_src #define s_ip6_dst ip6_hdrun2.ip6_un2.ip6_dst #define s_ip6_addrs ip6_hdrun2.ip6_addrs #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_RAW_NH(ip6h, value) ((ip6h)->s_ip6_nxt = (value)) #define IPV6_SET_L4PROTO(p,proto) (p)->ip6vars.l4proto = proto /* ONLY call these functions after making sure that: * 1. p->ip6h is set * 2. p->ip6h is valid (len is correct) */ #define IPV6_GET_VER(p) \ IPV6_GET_RAW_VER((p)->ip6h) #define IPV6_GET_CLASS(p) \ IPV6_GET_RAW_CLASS((p)->ip6h) #define IPV6_GET_FLOW(p) \ IPV6_GET_RAW_FLOW((p)->ip6h) #define IPV6_GET_NH(p) \ (IPV6_GET_RAW_NH((p)->ip6h)) #define IPV6_GET_PLEN(p) \ 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) /** \brief get the highest proto/next header field we know */ //#define IPV6_GET_UPPER_PROTO(p) (p)->ip6eh.ip6_exthdrs_cnt ? // (p)->ip6eh.ip6_exthdrs[(p)->ip6eh.ip6_exthdrs_cnt - 1].next : IPV6_GET_NH((p)) /* helper structure with parsed ipv6 info */ typedef struct IPV6Vars_ { uint8_t ip_opts_len; uint8_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; #define CLEAR_IPV6_PACKET(p) do { \ (p)->ip6h = NULL; \ (p)->ip6vars.ip_opts_len = 0; \ (p)->ip6vars.l4proto = 0; \ (p)->ip6eh.ip6fh = NULL; \ (p)->ip6eh.fh_offset = 0; \ (p)->ip6eh.ip6rh = NULL; \ (p)->ip6eh.ip6eh = NULL; \ (p)->ip6eh.ip6dh1 = NULL; \ (p)->ip6eh.ip6dh2 = NULL; \ (p)->ip6eh.ip6hh = NULL; \ (p)->ip6eh.ip6_exthdrs_cnt = 0; \ } while (0) /* Fragment header */ typedef struct IPV6FragHdr_ { uint8_t ip6fh_nxt; /* next header */ uint8_t ip6fh_reserved; /* reserved field */ uint16_t ip6fh_offlg; /* offset, reserved, and flag */ uint32_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_ { uint8_t ip6ah_nxt; /* next header */ uint8_t ip6ah_len; /* header length in units of 8 bytes, not including first 8 bytes. */ uint16_t ip6ah_reserved; /* reserved for future use */ uint32_t ip6ah_spi; /* SECURITY PARAMETERS INDEX (SPI) */ uint32_t ip6ah_seq; /* sequence number */ } IPV6AuthHdr; typedef struct IPV6EspHdr_ { uint32_t ip6esph_spi; /* SECURITY PARAMETERS INDEX (SPI) */ uint32_t ip6esph_seq; /* sequence number */ } IPV6EspHdr; typedef struct IPV6RouteHdr_ { uint8_t ip6rh_nxt; /* next header */ uint8_t ip6rh_len; /* header length in units of 8 bytes, not including first 8 bytes. */ uint8_t ip6rh_type; /* routing type */ uint8_t ip6rh_segsleft; /* segments left */ struct in6_addr ip6rh0_addr[23]; /* type 0 addresses */ uint8_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_ { uint8_t ip6hao_type; /* Option type */ uint8_t ip6hao_len; /* Option Data len (excludes type and len) */ struct in6_addr ip6hao_hoa; /* Home address. */ } IPV6OptHAO; /* Router Alert Option */ typedef struct IPV6OptRA_ { uint8_t ip6ra_type; /* Option type */ uint8_t ip6ra_len; /* Option Data len (excludes type and len) */ uint16_t ip6ra_value; /* Router Alert value */ } IPV6OptRA; /* Jumbo Option */ typedef struct IPV6OptJumbo_ { uint8_t ip6j_type; /* Option type */ uint8_t ip6j_len; /* Option Data len (excludes type and len) */ uint32_t ip6j_payload_len; /* Jumbo Payload Length */ } IPV6OptJumbo; typedef struct IPV6HopOptsHdr_ { uint8_t ip6hh_nxt; /* next header */ uint8_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_ { uint8_t ip6dh_nxt; /* next header */ uint8_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_ { uint8_t type; uint8_t next; uint8_t len; uint8_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 */ uint16_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]; uint8_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) void DecodeIPV6RegisterTests(void); #endif /* __DECODE_IPV6_H__ */ suricata-1.4.7/src/detect-engine-hrud.h0000644000000000000000000000242312253546156014652 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HRUD_H__ #define __DETECT_ENGINE_HRUD_H__ #include "app-layer-htp.h" int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *, Flow *f, HtpState *, uint8_t); int DetectEngineInspectHttpRawUri(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); void DetectEngineHttpRawUriRegisterTests(void); #endif /* __DETECT_ENGINE_HRUD_H__ */ suricata-1.4.7/src/detect-sid.c0000644000000000000000000000430212253546156013215 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the sid keyword */ #include "suricata-common.h" #include "detect.h" #include "util-debug.h" #include "util-error.h" static int DetectSidSetup (DetectEngineCtx *, Signature *, char *); void DetectSidRegister (void) { sigmatch_table[DETECT_SID].name = "sid"; sigmatch_table[DETECT_SID].desc = "set rule id"; sigmatch_table[DETECT_SID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Sid-signature-id"; sigmatch_table[DETECT_SID].Match = NULL; sigmatch_table[DETECT_SID].Setup = DetectSidSetup; sigmatch_table[DETECT_SID].Free = NULL; sigmatch_table[DETECT_SID].RegisterTests = NULL; } static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) { char *str = sidstr; char dubbed = 0; /* strip "'s */ if (sidstr[0] == '\"' && sidstr[strlen(sidstr)-1] == '\"') { str = SCStrdup(sidstr+1); if (unlikely(str == NULL)) return -1; str[strlen(sidstr)-2] = '\0'; dubbed = 1; } unsigned long id = 0; char *endptr = NULL; id = strtoul(sidstr, &endptr, 10); if (endptr == NULL || *endptr != '\0') { SCLogError(SC_ERR_INVALID_SIGNATURE, "Saw an invalid character as arg " "to sid keyword"); goto error; } s->id = (uint32_t)id; if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; } suricata-1.4.7/src/app-layer-tls-handshake.c0000644000000000000000000001545712253546156015623 00000000000000/* * Copyright (C) 2011-2012 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * \author Pierre Chifflier * * \brief Decode TLS Handshake messages, as described in RFC2246 * */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "app-layer-parser.h" #include "decode-events.h" #include "app-layer-ssl.h" #include "app-layer-tls-handshake.h" #include #include "util-decode-der.h" #include "util-decode-der-get.h" #include "util-crypt.h" #define SSLV3_RECORD_LEN 5 static void TLSCertificateErrCodeToWarning(SSLState *ssl_state, uint32_t errcode) { if (errcode == 0) return; switch (errcode) { case ERR_DER_ELEMENT_SIZE_TOO_BIG: case ERR_DER_INVALID_SIZE: AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH); break; case ERR_DER_UNSUPPORTED_STRING: AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_CERTIFICATE_INVALID_STRING); break; case ERR_DER_UNKNOWN_ELEMENT: AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT); break; case ERR_DER_MISSING_ELEMENT: AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT); break; case ERR_DER_GENERIC: default: AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_CERTIFICATE); break; }; } int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uint32_t input_len) { uint32_t certificates_length, cur_cert_length; int i; Asn1Generic *cert; char buffer[256]; int rc; int parsed; uint8_t *start_data; uint32_t errcode; if (input_len < 3) return 1; certificates_length = input[0]<<16 | input[1]<<8 | input[2]; /* check if the message is complete */ if (input_len < certificates_length + 3) return 0; start_data = input; input += 3; parsed = 3; i = 0; while (certificates_length > 0) { cur_cert_length = input[0]<<16 | input[1]<<8 | input[2]; input += 3; parsed += 3; if (input - start_data + cur_cert_length > input_len) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_CERTIFICATE); return -1; } cert = DecodeDer(input, cur_cert_length, &errcode); if (cert == NULL) { TLSCertificateErrCodeToWarning(ssl_state, errcode); } if (cert != NULL) { rc = Asn1DerGetSubjectDN(cert, buffer, sizeof(buffer), &errcode); if (rc != 0) { TLSCertificateErrCodeToWarning(ssl_state, errcode); } else { SSLCertsChain *ncert; //SCLogInfo("TLS Cert %d: %s\n", i, buffer); if (i==0) { ssl_state->server_connp.cert0_subject = SCStrdup(buffer); if (ssl_state->server_connp.cert0_subject == NULL) { DerFree(cert); return -1; } } ncert = (SSLCertsChain *)SCMalloc(sizeof(SSLCertsChain)); if (ncert == NULL) { DerFree(cert); return -1; } memset(ncert, 0, sizeof(*ncert)); ncert->cert_data = input; ncert->cert_len = cur_cert_length; TAILQ_INSERT_TAIL(&ssl_state->server_connp.certs, ncert, next); } rc = Asn1DerGetIssuerDN(cert, buffer, sizeof(buffer), &errcode); if (rc != 0) { TLSCertificateErrCodeToWarning(ssl_state, errcode); } else { //SCLogInfo("TLS IssuerDN %d: %s\n", i, buffer); if (i==0) { ssl_state->server_connp.cert0_issuerdn = SCStrdup(buffer); if (ssl_state->server_connp.cert0_issuerdn == NULL) { DerFree(cert); return -1; } } } DerFree(cert); if (i == 0 && ssl_state->server_connp.cert0_fingerprint == NULL) { int msg_len = cur_cert_length; int hash_len = 20; int out_len = 60; char out[out_len]; unsigned char* hash; hash = ComputeSHA1((unsigned char*) input, (int) msg_len); char *p = out; int j = 0; if (hash == NULL) { SCLogWarning(SC_ERR_MEM_ALLOC, "Can not allocate fingerprint string"); } else { for (j = 0; j < hash_len; j++, p += 3) { snprintf(p, 4, j == hash_len - 1 ? "%02x" : "%02x:", hash[j]); } SCFree(hash); ssl_state->server_connp.cert0_fingerprint = SCStrdup(out); if (ssl_state->server_connp.cert0_fingerprint == NULL) { SCLogWarning(SC_ERR_MEM_ALLOC, "Can not allocate fingerprint string"); } } ssl_state->server_connp.cert_input = input; ssl_state->server_connp.cert_input_len = cur_cert_length; } } i++; certificates_length -= (cur_cert_length + 3); parsed += cur_cert_length; input += cur_cert_length; } return parsed; } suricata-1.4.7/src/runmode-unix-socket.h0000644000000000000000000000210512253546156015114 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Eric Leblond */ #ifndef __RUNMODE_UNIX_SOCKET_H__ #define __RUNMODE_UNIX_SOCKET_H__ int RunModeUnixSocketSingle(DetectEngineCtx *); void RunModeUnixSocketRegister(void); const char *RunModeUnixSocketGetDefaultMode(void); int RunModeUnixSocketIsActive(void); void UnixSocketPcapFile(TmEcode tm); #endif /* __RUNMODE_UNIX_SOCKET_H__ */ suricata-1.4.7/src/defrag-hash.h0000644000000000000000000000606412253546156013355 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DEFRAG_HASH_H__ #define __DEFRAG_HASH_H__ #include "decode.h" #include "defrag.h" /** Spinlocks or Mutex for the flow buckets. */ //#define DRLOCK_SPIN #define DRLOCK_MUTEX #ifdef DRLOCK_SPIN #ifdef DRLOCK_MUTEX #error Cannot enable both DRLOCK_SPIN and DRLOCK_MUTEX #endif #endif #ifdef DRLOCK_SPIN #define DRLOCK_TYPE SCSpinlock #define DRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) #define DRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) #define DRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) #define DRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) #define DRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) #elif defined DRLOCK_MUTEX #define DRLOCK_TYPE SCMutex #define DRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) #define DRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) #define DRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) #define DRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) #define DRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) #else #error Enable DRLOCK_SPIN or DRLOCK_MUTEX #endif typedef struct DefragTrackerHashRow_ { DRLOCK_TYPE lock; DefragTracker *head; DefragTracker *tail; } DefragTrackerHashRow; /** defrag tracker hash table */ DefragTrackerHashRow *defragtracker_hash; #define DEFRAG_VERBOSE 0 #define DEFRAG_QUIET 1 typedef struct DefragConfig_ { uint64_t memcap; uint32_t hash_rand; uint32_t hash_size; uint32_t prealloc; } DefragConfig; /** \brief check if a memory alloc would fit in the memcap * * \param size memory allocation size to check * * \retval 1 it fits * \retval 0 no fit */ #define DEFRAG_CHECK_MEMCAP(size) \ ((((uint64_t)SC_ATOMIC_GET(defrag_memuse) + (uint64_t)(size)) <= defrag_config.memcap)) DefragConfig defrag_config; SC_ATOMIC_DECLARE(unsigned long long int,defrag_memuse); SC_ATOMIC_DECLARE(unsigned int,defragtracker_counter); SC_ATOMIC_DECLARE(unsigned int,defragtracker_prune_idx); void DefragInitConfig(char quiet); void DefragHashShutdown(void); DefragTracker *DefragLookupTrackerFromHash (Packet *); DefragTracker *DefragGetTrackerFromHash (Packet *); void DefragTrackerRelease(DefragTracker *); void DefragTrackerClearMemory(DefragTracker *); void DefragTrackerMoveToSpare(DefragTracker *); uint32_t DefragTrackerSpareQueueGetSize(void); #endif /* __DEFRAG_HASH_H__ */ suricata-1.4.7/src/decode.c0000644000000000000000000003506212253546156012422 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \defgroup decode Packet decoding * * \brief Code in charge of protocol decoding * * The task of decoding packets is made in different files and * as Suricata is supporting encapsulation there is a potential * recursivity in the call. * * For each protocol a DecodePROTO function is provided. For * example we have DecodeIPV4() for IPv4 and DecodePPP() for * PPP. * * These functions have all a pkt and and a len argument which * are respectively a pointer to the protocol data and the length * of this protocol data. * * \attention The pkt parameter must point to the effective data because * it will be used later to set per protocol pointer like Packet::tcph * * @{ */ /** * \file * * \author Victor Julien * * Decode the raw packet */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "util-debug.h" #include "util-mem.h" #include "app-layer-detect-proto.h" #include "tm-threads.h" #include "util-error.h" #include "util-print.h" #include "tmqh-packetpool.h" #include "util-profiling.h" void DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq, uint8_t proto) { switch (proto) { case PPP_OVER_GRE: DecodePPP(tv, dtv, p, pkt, len, pq); return; case IPPROTO_IP: DecodeIPV4(tv, dtv, p, pkt, len, pq); return; case IPPROTO_IPV6: DecodeIPV6(tv, dtv, p, pkt, len, pq); return; case VLAN_OVER_GRE: DecodeVLAN(tv, dtv, p, pkt, len, pq); return; default: SCLogInfo("FIXME: DecodeTunnel: protocol %" PRIu32 " not supported.", proto); break; } } /** * \brief Get a malloced packet. * * \retval p packet, NULL on error */ Packet *PacketGetFromAlloc(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) { return NULL; } PACKET_INITIALIZE(p); p->flags |= PKT_ALLOC; SCLogDebug("allocated a new packet only using alloc..."); PACKET_PROFILING_START(p); return p; } /** * \brief Get a packet. We try to get a packet from the packetpool first, but * if that is empty we alloc a packet that is free'd again after * processing. * * \retval p packet, NULL on error */ Packet *PacketGetFromQueueOrAlloc(void) { Packet *p = NULL; /* try the pool first */ if (PacketPoolSize() > 0) { p = PacketPoolGetPacket(); } if (p == NULL) { /* non fatal, we're just not processing a packet then */ p = PacketGetFromAlloc(); } else { PACKET_PROFILING_START(p); } return p; } /** * \brief Copy data to Packet payload at given offset * * This function copies data/payload to a Packet. It uses the * space allocated at Packet creation (pointed by Packet::pkt) * or allocate some memory (pointed by Packet::ext_pkt) if the * data size is to big to fit in initial space (of size * default_packet_size). * * \param Pointer to the Packet to modify * \param Offset of the copy relatively to payload of Packet * \param Pointer to the data to copy * \param Length of the data to copy */ inline int PacketCopyDataOffset(Packet *p, int offset, uint8_t *data, int datalen) { if (offset + datalen > MAX_PAYLOAD_SIZE) { /* too big */ return -1; } /* Do we have already an packet with allocated data */ if (! p->ext_pkt) { if (offset + datalen <= (int)default_packet_size) { /* data will fit in memory allocated with packet */ memcpy(p->pkt + offset, data, datalen); } else { /* here we need a dynamic allocation */ p->ext_pkt = SCMalloc(MAX_PAYLOAD_SIZE); if (p->ext_pkt == NULL) { SET_PKT_LEN(p, 0); return -1; } /* copy initial data */ memcpy(p->ext_pkt, GET_PKT_DIRECT_DATA(p), GET_PKT_DIRECT_MAX_SIZE(p)); /* copy data as asked */ memcpy(p->ext_pkt + offset, data, datalen); } } else { memcpy(p->ext_pkt + offset, data, datalen); } return 0; } /** * \brief Copy data to Packet payload and set packet length * * \param Pointer to the Packet to modify * \param Pointer to the data to copy * \param Length of the data to copy */ inline int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen) { SET_PKT_LEN(p, (size_t)pktlen); return PacketCopyDataOffset(p, 0, pktdata, pktlen); } /** * \brief Setup a pseudo packet (tunnel) * * \param parent parent packet for this pseudo pkt * \param pkt raw packet data * \param len packet data length * \param proto protocol of the tunneled packet * * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto) { SCEnter(); /* get us a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCReturnPtr(NULL, "Packet"); } /* set the root ptr to the lowest layer */ if (parent->root != NULL) p->root = parent->root; else p->root = parent; /* copy packet and set lenght, proto */ PacketCopyData(p, pkt, len); p->recursion_level = parent->recursion_level + 1; p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; /* set tunnel flags */ /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); /* tell parent packet it's part of a tunnel */ SET_TUNNEL_PKT(parent); /* increment tunnel packet refcnt in the root packet */ TUNNEL_INCR_PKT_TPR(p); /* disable payload (not packet) inspection on the parent, as the payload * is the packet we will now run through the system separately. We do * check it against the ip/port/other header checks though */ DecodeSetNoPayloadInspectionFlag(parent); SCReturnPtr(p, "Packet"); } /** * \brief Setup a pseudo packet (reassembled frags) * * Difference with PacketPseudoPktSetup is that this func doesn't increment * the recursion level. It needs to be on the same level as the frags because * we run the flow engine against this and we need to get the same flow. * * \param parent parent packet for this pseudo pkt * \param pkt raw packet data * \param len packet data length * \param proto protocol of the tunneled packet * * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto) { SCEnter(); /* get us a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCReturnPtr(NULL, "Packet"); } /* set the root ptr to the lowest layer */ if (parent->root != NULL) p->root = parent->root; else p->root = parent; /* copy packet and set lenght, proto */ PacketCopyData(p, pkt, len); p->recursion_level = parent->recursion_level; /* NOT incremented */ p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; /* set tunnel flags */ /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); /* tell parent packet it's part of a tunnel */ SET_TUNNEL_PKT(parent); /* increment tunnel packet refcnt in the root packet */ TUNNEL_INCR_PKT_TPR(p); /* disable payload (not packet) inspection on the parent, as the payload * is the packet we will now run through the system separately. We do * check it against the ip/port/other header checks though */ DecodeSetNoPayloadInspectionFlag(parent); SCReturnPtr(p, "Packet"); } void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) { /* register counters */ dtv->counter_pkts = SCPerfTVRegisterCounter("decoder.pkts", tv, SC_PERF_TYPE_UINT64, "NULL"); #if 0 dtv->counter_pkts_per_sec = SCPerfTVRegisterIntervalCounter("decoder.pkts_per_sec", tv, SC_PERF_TYPE_DOUBLE, "NULL", "1s"); #endif dtv->counter_bytes = SCPerfTVRegisterCounter("decoder.bytes", tv, SC_PERF_TYPE_UINT64, "NULL"); #if 0 dtv->counter_bytes_per_sec = SCPerfTVRegisterIntervalCounter("decoder.bytes_per_sec", tv, SC_PERF_TYPE_DOUBLE, "NULL", "1s"); dtv->counter_mbit_per_sec = SCPerfTVRegisterIntervalCounter("decoder.mbit_per_sec", tv, SC_PERF_TYPE_DOUBLE, "NULL", "1s"); #endif dtv->counter_ipv4 = SCPerfTVRegisterCounter("decoder.ipv4", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_ipv6 = SCPerfTVRegisterCounter("decoder.ipv6", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_eth = SCPerfTVRegisterCounter("decoder.ethernet", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_raw = SCPerfTVRegisterCounter("decoder.raw", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_sll = SCPerfTVRegisterCounter("decoder.sll", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_tcp = SCPerfTVRegisterCounter("decoder.tcp", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_udp = SCPerfTVRegisterCounter("decoder.udp", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_sctp = SCPerfTVRegisterCounter("decoder.sctp", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_icmpv4 = SCPerfTVRegisterCounter("decoder.icmpv4", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_icmpv6 = SCPerfTVRegisterCounter("decoder.icmpv6", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_ppp = SCPerfTVRegisterCounter("decoder.ppp", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_pppoe = SCPerfTVRegisterCounter("decoder.pppoe", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_gre = SCPerfTVRegisterCounter("decoder.gre", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_vlan = SCPerfTVRegisterCounter("decoder.vlan", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_teredo = SCPerfTVRegisterCounter("decoder.teredo", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_ipv4inipv6 = SCPerfTVRegisterCounter("decoder.ipv4_in_ipv6", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_ipv6inipv6 = SCPerfTVRegisterCounter("decoder.ipv6_in_ipv6", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_avg_pkt_size = SCPerfTVRegisterAvgCounter("decoder.avg_pkt_size", tv, SC_PERF_TYPE_DOUBLE, "NULL"); dtv->counter_max_pkt_size = SCPerfTVRegisterMaxCounter("decoder.max_pkt_size", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_defrag_ipv4_fragments = SCPerfTVRegisterCounter("defrag.ipv4.fragments", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_defrag_ipv4_reassembled = SCPerfTVRegisterCounter("defrag.ipv4.reassembled", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_defrag_ipv4_timeouts = SCPerfTVRegisterCounter("defrag.ipv4.timeouts", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_defrag_ipv6_fragments = SCPerfTVRegisterCounter("defrag.ipv6.fragments", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_defrag_ipv6_reassembled = SCPerfTVRegisterCounter("defrag.ipv6.reassembled", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_defrag_ipv6_timeouts = SCPerfTVRegisterCounter("defrag.ipv6.timeouts", tv, SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_defrag_max_hit = SCPerfTVRegisterCounter("defrag.max_frag_hits", tv, SC_PERF_TYPE_UINT64, "NULL"); tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); SCPerfAddToClubbedTMTable(tv->name, &tv->sc_perf_pctx); return; } /** * \brief Debug print function for printing addresses * * \param Address object * * \todo IPv6 */ void AddressDebugPrint(Address *a) { if (a == NULL) return; switch (a->family) { case AF_INET: { char s[16]; PrintInet(AF_INET, (const void *)&a->addr_data32[0], s, sizeof(s)); SCLogDebug("%s", s); break; } } } /** \brief Alloc and setup DecodeThreadVars */ DecodeThreadVars *DecodeThreadVarsAlloc() { DecodeThreadVars *dtv = NULL; if ( (dtv = SCMalloc(sizeof(DecodeThreadVars))) == NULL) return NULL; memset(dtv, 0, sizeof(DecodeThreadVars)); /* initialize UDP app layer code */ AlpProtoFinalize2Thread(&dtv->udp_dp_ctx); return dtv; } /** * \brief Set data for Packet and set length when zeo copy is used * * \param Pointer to the Packet to modify * \param Pointer to the data * \param Length of the data */ inline int PacketSetData(Packet *p, uint8_t *pktdata, int pktlen) { SET_PKT_LEN(p, (size_t)pktlen); if (!pktdata) { return -1; } p->ext_pkt = pktdata; p->flags |= PKT_ZERO_COPY; return 0; } /** * @} */ suricata-1.4.7/src/detect-iprep.h0000644000000000000000000000241312253546156013563 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_IPREP_H__ #define __DETECT_IPREP_H__ #define DETECT_IPREP_CMD_ANY 0 #define DETECT_IPREP_CMD_BOTH 1 #define DETECT_IPREP_CMD_SRC 2 #define DETECT_IPREP_CMD_DST 3 #define DETECT_IPREP_OP_LT 0 #define DETECT_IPREP_OP_GT 1 #define DETECT_IPREP_OP_EQ 2 typedef struct DetectIPRepData_ { uint8_t cmd; int8_t cat; int8_t op; uint8_t val; } DetectIPRepData; /* prototypes */ void DetectIPRepRegister (void); #endif /* __DETECT_IPREP_H__ */ suricata-1.4.7/src/runmode-nfq.c0000644000000000000000000000731112253546156013426 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * \author Eric Leblond * * Handling of NFQ runmodes. */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-nfq.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "util-runmodes.h" static const char *default_mode; const char *RunModeIpsNFQGetDefaultMode(void) { return default_mode; } void RunModeIpsNFQRegister(void) { default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_NFQ, "auto", "Multi threaded NFQ IPS mode", RunModeIpsNFQAuto); RunModeRegisterNewRunMode(RUNMODE_NFQ, "autofp", "Multi threaded NFQ IPS mode with respect to flow", RunModeIpsNFQAutoFp); RunModeRegisterNewRunMode(RUNMODE_NFQ, "workers", "Multi queue NFQ IPS mode with one thread per queue", RunModeIpsNFQWorker); return; } /** * \brief RunModeIpsNFQAuto set up the following thread packet handlers: * - Receive thread (from NFQ) * - Decode thread * - Stream thread * - Detect: If we have only 1 cpu, it will setup one Detect thread * If we have more than one, it will setup num_cpus - 1 * starting from the second cpu available. * - Veredict thread (NFQ) * - Respond/Reject thread * - Outputs thread * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * * \param de_ctx Pointer to the Detection Engine. * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ int RunModeIpsNFQAuto(DetectEngineCtx *de_ctx) { SCEnter(); int ret = 0; #ifdef NFQ RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetIPSAuto(de_ctx, NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); #endif /* NFQ */ return ret; } int RunModeIpsNFQAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); int ret = 0; #ifdef NFQ RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetIPSAutoFp(de_ctx, NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); #endif /* NFQ */ return ret; } int RunModeIpsNFQWorker(DetectEngineCtx *de_ctx) { SCEnter(); int ret = 0; #ifdef NFQ RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetIPSWorker(de_ctx, NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); #endif /* NFQ */ return ret; } suricata-1.4.7/src/util-bloomfilter-counting.c0000644000000000000000000002566412253546156016323 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Counting Bloom Filter implementation. Can be used with 8, 16, 32 bits * counters. */ #include "suricata-common.h" #include "util-bloomfilter-counting.h" #include "util-unittest.h" /* type: 1, 2 or 4 for 8, 16, or 32 bit counters * */ BloomFilterCounting *BloomFilterCountingInit(uint32_t size, uint8_t type, uint8_t iter, uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t)) { BloomFilterCounting *bf = NULL; if (iter == 0) goto error; if (Hash == NULL || size == 0) { //printf("ERROR: BloomFilterCountingInit no Hash function\n"); goto error; } if (type != 1 && type != 2 && type != 4) { //printf("ERROR: BloomFilterCountingInit only 1, 2 and 4 bytes are supported\n"); goto error; } /* setup the filter */ bf = SCMalloc(sizeof(BloomFilterCounting)); if (unlikely(bf == NULL)) goto error; memset(bf,0,sizeof(BloomFilterCounting)); bf->type = type; /* size of the type: 1, 2, 4 */ bf->array_size = size; bf->hash_iterations = iter; bf->Hash = Hash; /* setup the bitarray */ bf->array = SCMalloc(bf->array_size * bf->type); if (bf->array == NULL) goto error; memset(bf->array,0,bf->array_size * bf->type); return bf; error: if (bf != NULL) { if (bf->array != NULL) SCFree(bf->array); SCFree(bf); } return NULL; } void BloomFilterCountingFree(BloomFilterCounting *bf) { if (bf != NULL) { if (bf->array != NULL) SCFree(bf->array); SCFree(bf); } } void BloomFilterCountingPrint(BloomFilterCounting *bf) { printf("\n------ Counting Bloom Filter Stats ------\n"); printf("Buckets: %" PRIu32 "\n", bf->array_size); printf("Counter size: %" PRIu32 "\n", bf->type); printf("Memory size: %" PRIu32 " bytes\n", bf->array_size * bf->type); printf("Hash function pointer: %p\n", bf->Hash); printf("Hash functions: %" PRIu32 "\n", bf->hash_iterations); printf("-----------------------------------------\n"); } int BloomFilterCountingAdd(BloomFilterCounting *bf, void *data, uint16_t datalen) { uint8_t iter = 0; uint32_t hash = 0; if (bf == NULL || data == NULL || datalen == 0) return -1; for (iter = 0; iter < bf->hash_iterations; iter++) { hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; if (bf->type == 1) { uint8_t *u8 = (uint8_t *)&bf->array[hash]; if ((*u8) != 255) (*u8)++; } else if (bf->type == 2) { uint16_t *u16 = (uint16_t *)&bf->array[hash]; if ((*u16) != 65535) (*u16)++; } else if (bf->type == 4) { uint32_t *u32 = (uint32_t *)&bf->array[hash]; if ((*u32) != 4294967295UL) (*u32)++; } } return 0; } int BloomFilterCountingRemove(BloomFilterCounting *bf, void *data, uint16_t datalen) { uint8_t iter = 0; uint32_t hash = 0; if (bf == NULL || data == NULL || datalen == 0) return -1; /* only remove data that was actually added */ if (BloomFilterCountingTest(bf, data, datalen) == 0) { printf("ERROR: BloomFilterCountingRemove tried to remove data " "that was never added to the set or was already removed.\n"); return -1; } /* decrease counters for every iteration */ for (iter = 0; iter < bf->hash_iterations; iter++) { hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; if (bf->type == 1) { uint8_t *u8 = (uint8_t *)&bf->array[hash]; if ((*u8) > 0) (*u8)--; else { printf("ERROR: BloomFilterCountingRemove tried to decrease a " "counter below zero.\n"); return -1; } } else if (bf->type == 2) { uint16_t *u16 = (uint16_t *)&bf->array[hash]; if ((*u16) > 0) (*u16)--; else { printf("ERROR: BloomFilterCountingRemove tried to decrease a " "counter below zero.\n"); return -1; } } else if (bf->type == 4) { uint32_t *u32 = (uint32_t *)&bf->array[hash]; if ((*u32) > 0) (*u32)--; else { printf("ERROR: BloomFilterCountingRemove tried to decrease a " "counter below zero.\n"); return -1; } } } return 0; } /* Test if data matches our filter and is likely to be in the set * * returns 0: for no match * 1: match */ int BloomFilterCountingTest(BloomFilterCounting *bf, void *data, uint16_t datalen) { uint8_t iter = 0; uint32_t hash = 0; int hit = 1; /* check each hash iteration */ for (iter = 0; iter < bf->hash_iterations; iter++) { hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; if (bf->type == 1) { uint8_t *u8 = (uint8_t *)&bf->array[hash]; if ((*u8) == 0x00) { hit = 0; break; } } else if (bf->type == 2) { uint16_t *u16 = (uint16_t *)&bf->array[hash]; if ((*u16) == 0x0000) { hit = 0; break; } } else if (bf->type == 4) { uint32_t *u32 = (uint32_t *)&bf->array[hash]; if ((*u32) == 0x00000000) { hit = 0; break; } } } return hit; } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS static uint32_t BloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint32_t i; uint32_t hash = 0; for (i = 0; i < datalen; i++) { if (i == 0) hash += (((uint32_t)*d++)); else if (i == 1) hash += (((uint32_t)*d++) * datalen); else hash *= (((uint32_t)*d++) * i); } hash *= (iter + datalen); hash %= hash_size; return hash; } static int BloomFilterCountingTestInit01 (void) { BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); if (bf == NULL) return 0; BloomFilterCountingFree(bf); return 1; } /* no hash function, so it should fail */ static int BloomFilterCountingTestInit02 (void) { BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, NULL); if (bf == NULL) return 1; BloomFilterCountingFree(bf); return 0; } static int BloomFilterCountingTestInit03 (void) { int result = 0; BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); if (bf == NULL) return 0; if (bf->Hash == BloomHash) result = 1; BloomFilterCountingFree(bf); return result; } static int BloomFilterCountingTestInit04 (void) { BloomFilterCounting *bf = BloomFilterCountingInit(1024, 0, 4, BloomHash); if (bf == NULL) return 1; BloomFilterCountingFree(bf); return 0; } static int BloomFilterCountingTestInit05 (void) { BloomFilterCounting *bf = BloomFilterCountingInit(0, 4, 4, BloomHash); if (bf == NULL) return 1; BloomFilterCountingFree(bf); return 0; } static int BloomFilterCountingTestInit06 (void) { BloomFilterCounting *bf = BloomFilterCountingInit(32, 3, 4, BloomHash); if (bf == NULL) return 1; BloomFilterCountingFree(bf); return 0; } static int BloomFilterCountingTestAdd01 (void) { int result = 0; BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); if (bf == NULL) return 0; int r = BloomFilterCountingAdd(bf, "test", 0); if (r == 0) goto end; /* all is good! */ result = 1; end: if (bf != NULL) BloomFilterCountingFree(bf); return result; } static int BloomFilterCountingTestAdd02 (void) { int result = 0; BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); if (bf == NULL) return 0; int r = BloomFilterCountingAdd(bf, NULL, 4); if (r == 0) goto end; /* all is good! */ result = 1; end: if (bf != NULL) BloomFilterCountingFree(bf); return result; } static int BloomFilterCountingTestFull01 (void) { int result = 0; BloomFilterCounting *bf = BloomFilterCountingInit(32, 4, 4, BloomHash); if (bf == NULL) { printf("init failed: "); goto end; } int r = BloomFilterCountingAdd(bf, "test", 4); if (r != 0) { printf("first add: "); goto end; } r = BloomFilterCountingTest(bf, "test", 4); if (r != 1) { printf("2nd add: "); goto end; } r = BloomFilterCountingRemove(bf, "test", 4); if (r != 0) { printf("3rd add: "); goto end; } /* all is good! */ result = 1; end: if (bf != NULL) BloomFilterCountingFree(bf); return result; } static int BloomFilterCountingTestFull02 (void) { int result = 0; BloomFilterCounting *bf = BloomFilterCountingInit(32, 4, 4, BloomHash); if (bf == NULL) goto end; int r = BloomFilterCountingTest(bf, "test", 4); if (r != 0) goto end; /* all is good! */ result = 1; end: if (bf != NULL) BloomFilterCountingFree(bf); return result; } #endif void BloomFilterCountingRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("BloomFilterCountingTestInit01", BloomFilterCountingTestInit01, 1); UtRegisterTest("BloomFilterCountingTestInit02", BloomFilterCountingTestInit02, 1); UtRegisterTest("BloomFilterCountingTestInit03", BloomFilterCountingTestInit03, 1); UtRegisterTest("BloomFilterCountingTestInit04", BloomFilterCountingTestInit04, 1); UtRegisterTest("BloomFilterCountingTestInit05", BloomFilterCountingTestInit05, 1); UtRegisterTest("BloomFilterCountingTestInit06", BloomFilterCountingTestInit06, 1); UtRegisterTest("BloomFilterCountingTestAdd01", BloomFilterCountingTestAdd01, 1); UtRegisterTest("BloomFilterCountingTestAdd02", BloomFilterCountingTestAdd02, 1); UtRegisterTest("BloomFilterCountingTestFull01", BloomFilterCountingTestFull01, 1); UtRegisterTest("BloomFilterCountingTestFull02", BloomFilterCountingTestFull02, 1); #endif } suricata-1.4.7/src/detect-http-ua.c0000644000000000000000000021420612253546156014026 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Anoop Saldanha * * Implements support for the http_user_agent keyword. */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "app-layer.h" #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-ua.h" int DetectHttpUASetup(DetectEngineCtx *, Signature *, char *); void DetectHttpUARegisterTests(void); void DetectHttpUAFree(void *); /** * \brief Registers the keyword handlers for the "http_user_agent" keyword. */ void DetectHttpUARegister(void) { sigmatch_table[DETECT_AL_HTTP_USER_AGENT].name = "http_user_agent"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].desc = "content modifier to match only on the HTTP User-Agent header"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_user_agent"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Match = NULL; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Setup = DetectHttpUASetup; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Free = DetectHttpUAFree; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].RegisterTests = DetectHttpUARegisterTests; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_PAYLOAD ; return; } /** * \brief The setup function for the http_user_agent keyword for a signature. * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to the signature for the current Signature being * parsed from the rules. * \param m Pointer to the head of the SigMatch for the current rule * being parsed. * \param arg Pointer to the string holding the keyword value. * * \retval 0 On success * \retval -1 On failure */ int DetectHttpUASetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_user_agent supplied with args"); goto error; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if we still can't find any previous content keywords, it's an invalid * rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_user_agent\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_user_agent\" keyword"); goto error; } cd = (DetectContentData *)sm->ctx; /* http_user_agent should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_user_agent rule can not " "be used with the rawbytes rule keyword"); goto error; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if (s->flags & SIG_FLAG_TOCLIENT) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_user_agent can not be used " "with flow:to_client or flow:from_server. "); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_user_agent seen with a " "distance or within without a previous http_user_agent " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HUADMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to huadmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HUADMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } /** * \brief The function to free the http_user_agent data. * * \param ptr Pointer to the http_user_agent. */ void DetectHttpUAFree(void *ptr) { DetectContentData *huad = (DetectContentData *)ptr; if (huad == NULL) return; if (huad->content != NULL) SCFree(huad->content); BoyerMooreCtxDeInit(huad->bm_ctx); SCFree(huad); return; } /************************************Unittests*********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Test that a signature containting a http_user_agent is correctly parsed * and the keyword is registered. */ static int DetectHttpUATest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_user_agent\"; " "content:\"one\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a signature containing an valid http_user_agent entry is * parsed. */ static int DetectHttpUATest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_user_agent\"; " "content:\"one\"; http_user_agent:; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing no content but a * http_user_agent is invalidated. */ static int DetectHttpUATest03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_user_agent\"; " "http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_user_agent is invalidated. */ static int DetectHttpUATest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_user_agent\"; " "content:\"one\"; rawbytes; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a http_user_agent with nocase is parsed. */ static int DetectHttpUATest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_user_agent\"; " "content:\"one\"; http_user_agent; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectHttpUATest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: This is dummy message body\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"message\"; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectHttpUATest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: This is dummy message"; uint8_t http2_buf[] = "body1\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"message\"; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched on p1 but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match on p2 but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectHttpUATest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: This is dummy mess"; uint8_t http2_buf[] = "age body\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"message\"; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_user_agent content matches against a http request * which holds the content, against a cross boundary present pattern. */ static int DetectHttpUATest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"body1This\"; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_user_agent content matches against a http request * against a case insensitive pattern. */ static int DetectHttpUATest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: This is dummy bodY1"; uint8_t http2_buf[] = "This is dummy message body2\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy bodY1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"body1this\"; http_user_agent; nocase;" "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the negated http_user_agent content matches against a * http request which doesn't hold the content. */ static int DetectHttpUATest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: This is dummy message body\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:!\"message\"; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Negative test that the negated http_user_agent content matches against a * http request which holds hold the content. */ static int DetectHttpUATest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: This is dummy body\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:!\"message\"; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectHttpUATest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test multiple http transactions and body chunks of request handling */ static int DetectHttpUATest14(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "Cookie: dummy1\r\n"; uint8_t httpbuf3[] = "User-Agent: Body one!!\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf5[] = "Cookie: dummy2\r\n"; uint8_t httpbuf6[] = "User-Agent: Body two\r\n\r\n"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; http_cookie; content:\"Body one\"; http_user_agent; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"dummy2\"; http_cookie; content:\"Body two\"; http_user_agent; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) || PacketAlertCheck(p, 2)) { printf("sig 1 alerted (4): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) || !(PacketAlertCheck(p, 2))) { printf("signature 2 didn't match or sig 1 matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } int DetectHttpUATest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"one\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (cd->id == huad->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (cd->id == huad->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_user_agent; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (cd->id != 0 || huad->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (cd->id != 1 || huad->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"one\"; content:\"one\"; http_user_agent; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (cd->id != 1 || huad1->id != 0 || huad2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"one\"; content:\"one\"; http_user_agent; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (cd->id != 2 || huad1->id != 0 || huad2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; http_user_agent; " "content:\"three\"; distance:10; http_user_agent; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "two", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_DISTANCE || memcmp(huad2->content, "three", huad1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd1) || !DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(huad1) || DETECT_CONTENT_IS_SINGLE(huad2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; pcre:/two/; " "content:\"three\"; distance:10; http_user_agent; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_DISTANCE || memcmp(huad2->content, "three", huad1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(huad1) || DETECT_CONTENT_IS_SINGLE(huad2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; pcre:/two/; " "content:\"three\"; distance:10; within:15; http_user_agent; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(huad2->content, "three", huad1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(huad1) || DETECT_CONTENT_IS_SINGLE(huad2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; pcre:/two/; " "content:\"three\"; distance:10; http_user_agent; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_DISTANCE || memcmp(huad2->content, "three", huad1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(huad1) || DETECT_CONTENT_IS_SINGLE(huad2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_user_agent; pcre:/two/; " "content:\"three\"; distance:10; http_user_agent; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(huad2->content, "three", huad1->content_len) != 0) { printf ("failed: http_user_agent incorrect flags"); goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(huad1) || DETECT_CONTENT_IS_SINGLE(huad2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_user_agent; pcre:/two/; " "content:\"three\"; distance:10; http_user_agent; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; pcre:/two/; " "content:\"three\"; http_user_agent; depth:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != 0 || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_DEPTH || memcmp(huad2->content, "three", huad1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || !DETECT_CONTENT_IS_SINGLE(huad1) || DETECT_CONTENT_IS_SINGLE(huad2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; distance:0; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_DISTANCE || memcmp(huad2->content, "two", huad1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; within:5; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_WITHIN || memcmp(huad2->content, "two", huad1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/V; " "content:\"two\"; within:5; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_USER_AGENT) || huad2->flags != DETECT_CONTENT_WITHIN || memcmp(huad2->content, "two", huad2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "pcre:/one/VR; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_PCRE || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_CONTENT) { goto end; } DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_USER_AGENT) || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "two", huad1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUATest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/V; " "content:\"two\"; distance:5; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_USER_AGENT) || huad2->flags != DETECT_CONTENT_DISTANCE || memcmp(huad2->content, "two", huad2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ void DetectHttpUARegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectHttpUATest01", DetectHttpUATest01, 1); UtRegisterTest("DetectHttpUATest02", DetectHttpUATest02, 1); UtRegisterTest("DetectHttpUATest03", DetectHttpUATest03, 1); UtRegisterTest("DetectHttpUATest04", DetectHttpUATest04, 1); UtRegisterTest("DetectHttpUATest05", DetectHttpUATest05, 1); UtRegisterTest("DetectHttpUATest06", DetectHttpUATest06, 1); UtRegisterTest("DetectHttpUATest07", DetectHttpUATest07, 1); UtRegisterTest("DetectHttpUATest08", DetectHttpUATest08, 1); UtRegisterTest("DetectHttpUATest09", DetectHttpUATest09, 1); UtRegisterTest("DetectHttpUATest10", DetectHttpUATest10, 1); UtRegisterTest("DetectHttpUATest11", DetectHttpUATest11, 1); UtRegisterTest("DetectHttpUATest12", DetectHttpUATest12, 1); UtRegisterTest("DetectHttpUATest13", DetectHttpUATest13, 1); UtRegisterTest("DetectHttpUATest14", DetectHttpUATest14, 1); UtRegisterTest("DetectHttpUATest16", DetectHttpUATest16, 1); UtRegisterTest("DetectHttpUATest17", DetectHttpUATest17, 1); UtRegisterTest("DetectHttpUATest18", DetectHttpUATest18, 1); UtRegisterTest("DetectHttpUATest19", DetectHttpUATest19, 1); UtRegisterTest("DetectHttpUATest20", DetectHttpUATest20, 1); UtRegisterTest("DetectHttpUATest21", DetectHttpUATest21, 1); UtRegisterTest("DetectHttpUATest22", DetectHttpUATest22, 1); UtRegisterTest("DetectHttpUATest23", DetectHttpUATest23, 1); UtRegisterTest("DetectHttpUATest24", DetectHttpUATest24, 1); UtRegisterTest("DetectHttpUATest25", DetectHttpUATest25, 1); UtRegisterTest("DetectHttpUATest26", DetectHttpUATest26, 1); UtRegisterTest("DetectHttpUATest27", DetectHttpUATest27, 1); UtRegisterTest("DetectHttpUATest28", DetectHttpUATest28, 1); UtRegisterTest("DetectHttpUATest29", DetectHttpUATest29, 1); UtRegisterTest("DetectHttpUATest30", DetectHttpUATest30, 1); UtRegisterTest("DetectHttpUATest31", DetectHttpUATest31, 1); UtRegisterTest("DetectHttpUATest32", DetectHttpUATest32, 1); UtRegisterTest("DetectHttpUATest33", DetectHttpUATest33, 1); UtRegisterTest("DetectHttpUATest34", DetectHttpUATest34, 1); UtRegisterTest("DetectHttpUATest35", DetectHttpUATest35, 1); UtRegisterTest("DetectHttpUATest36", DetectHttpUATest36, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/util-device.h0000644000000000000000000000300312253546156013404 00000000000000/* Copyright (C) 2011-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef __UTIL_DEVICE_H__ #define __UTIL_DEVICE_H__ #include "queue.h" #include "unix-manager.h" /** storage for live device names */ typedef struct LiveDevice_ { char *dev; /**< the device (e.g. "eth0") */ int ignore_checksum; SC_ATOMIC_DECLARE(unsigned int, pkts); SC_ATOMIC_DECLARE(unsigned int, drop); SC_ATOMIC_DECLARE(unsigned int, invalid_checksums); TAILQ_ENTRY(LiveDevice_) next; } LiveDevice; int LiveRegisterDevice(char *dev); int LiveGetDeviceCount(void); char *LiveGetDeviceName(int number); LiveDevice *LiveGetDevice(char *dev); int LiveBuildDeviceList(char * base); #ifdef BUILD_UNIX_SOCKET TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *server_msg, void *data); TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *server_msg, void *data); #endif #endif /* __UTIL_DEVICE_H__ */ suricata-1.4.7/src/detect-ipproto.c0000644000000000000000000066520312253546156014147 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus * * Implements the ip_proto keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-ipproto.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-siggroup.h" #include "detect-engine-address.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" /** * \brief Regex for parsing our options */ #define PARSE_REGEX "^\\s*" \ "([!<>]?)" \ "\\s*([^\\s]+)" \ "\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectIPProtoSetup(DetectEngineCtx *, Signature *, char *); static DetectIPProtoData *DetectIPProtoParse(const char *); static void DetectIPProtoRegisterTests(void); void DetectIPProtoRegister(void) { const char *eb; int eo; int opts = 0; sigmatch_table[DETECT_IPPROTO].name = "ip_proto"; sigmatch_table[DETECT_IPPROTO].desc = "match on the IP protocol in the packet-header"; sigmatch_table[DETECT_IPPROTO].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ip_proto"; sigmatch_table[DETECT_IPPROTO].Match = NULL; sigmatch_table[DETECT_IPPROTO].Setup = DetectIPProtoSetup; sigmatch_table[DETECT_IPPROTO].Free = NULL; sigmatch_table[DETECT_IPPROTO].RegisterTests = DetectIPProtoRegisterTests; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /** * \internal * \brief Parse ip_proto options string. * * \param optstr Options string to parse * * \return New ip_proto data structure */ static DetectIPProtoData *DetectIPProtoParse(const char *optstr) { DetectIPProtoData *data = NULL; char *args[2] = { NULL, NULL }; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int i; const char *str_ptr; /* Execute the regex and populate args with captures. */ ret = pcre_exec(parse_regex, parse_regex_study, optstr, strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 3) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret" "%" PRId32 ", string %s", ret, optstr); goto error; } for (i = 0; i < (ret - 1); i++) { res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS, i + 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i] = (char *)str_ptr; } /* Initialize the data */ data = SCMalloc(sizeof(DetectIPProtoData)); if (unlikely(data == NULL)) goto error; data->op = DETECT_IPPROTO_OP_EQ; data->proto = 0; /* Operator */ if (*(args[0]) != '\0') { data->op = *(args[0]); } /* Protocol name/number */ if (!isdigit((unsigned char)*(args[1]))) { struct protoent *pent = getprotobyname(args[1]); if (pent == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed protocol name: %s", str_ptr); goto error; } data->proto = (uint8_t)pent->p_proto; } else { if (ByteExtractStringUint8(&data->proto, 10, 0, args[1]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed protocol number: %s", str_ptr); goto error; } } for (i = 0; i < (ret - 1); i++){ if (args[i] != NULL) SCFree(args[i]); } return data; error: for (i = 0; i < (ret - 1) && i < 2; i++){ if (args[i] != NULL) SCFree(args[i]); } if (data != NULL) SCFree(data); return NULL; } static int DetectIPProtoTypePresentForOP(Signature *s, uint8_t op) { SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; DetectIPProtoData *data; while (sm != NULL) { if (sm->type == DETECT_IPPROTO) { data = (DetectIPProtoData *)sm->ctx; if (data->op == op) return 1; } sm = sm->next; } return 0; } /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto * multiple uses */ #if 0 static int DetectIPProtoQSortCompare(const void *a, const void *b) { const uint8_t *one = a; const uint8_t *two = b; return ((int)*one - *two); } #endif /** * \internal * \brief Setup ip_proto keyword. * * \param de_ctx Detection engine context * \param s Signature * \param optstr Options string * * \return Non-zero on error */ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { SigMatch *sm = NULL; DetectIPProtoData *data = NULL; int i; data = DetectIPProtoParse((const char *)optstr); if (data == NULL) { goto error; } /* Reset our "any" (or "ip") state: for ipv4, ipv6 and ip cases, the bitfield * s->proto.proto have all bit set to 1 to be able to match any protocols. ipproto * will refined the protocol list and thus it needs to reset the bitfield to zero * before setting the value specified by the ip_proto keyword. */ if (s->proto.flags & (DETECT_PROTO_ANY | DETECT_PROTO_IPV6 | DETECT_PROTO_IPV4)) { s->proto.flags &= ~DETECT_PROTO_ANY; memset(s->proto.proto, 0x00, sizeof(s->proto.proto)); } int eq_set = DetectIPProtoTypePresentForOP(s, DETECT_IPPROTO_OP_EQ); int gt_set = DetectIPProtoTypePresentForOP(s, DETECT_IPPROTO_OP_GT); int lt_set = DetectIPProtoTypePresentForOP(s, DETECT_IPPROTO_OP_LT); int not_set = DetectIPProtoTypePresentForOP(s, DETECT_IPPROTO_OP_NOT); switch (data->op) { case DETECT_IPPROTO_OP_EQ: if (eq_set || gt_set || lt_set || not_set) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a eq " "ipproto without any operators attached to " "them in the same sig"); goto error; } s->proto.proto[data->proto / 8] |= 1 << (data->proto % 8); break; case DETECT_IPPROTO_OP_GT: if (eq_set || gt_set) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a eq or gt " "ipproto along with a greater than ipproto in the " "same sig "); goto error; } if (!lt_set && !not_set) { s->proto.proto[data->proto / 8] = 0xfe << (data->proto % 8); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] = 0xff; } } else if (lt_set && !not_set) { SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO) { break; } temp_sm = temp_sm->next; } if (temp_sm != NULL) { DetectIPProtoData *data_temp = temp_sm->ctx; if (data_temp->proto <= data->proto) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have " "both gt and lt ipprotos, with the lt being " "lower than gt value"); goto error; /* Updated by AS. Please do not remove this unused code. Need it * as we redo this code once we solve ipproto multiple uses */ #if 0 s->proto.proto[data->proto / 8] |= 0xfe << (data->proto % 8); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] = 0xff; } #endif } else { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] = 0; } s->proto.proto[data->proto / 8] &= 0xfe << (data->proto % 8); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] &= 0xff; } } } } else if (!lt_set && not_set) { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] = 0; } s->proto.proto[data->proto / 8] &= 0xfe << (data->proto % 8); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] &= 0xff; } } else { DetectIPProtoData *data_temp; SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_LT) { break; } temp_sm = temp_sm->next; } if (temp_sm != NULL) { data_temp = temp_sm->ctx; if (data_temp->proto <= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto * multiple uses */ SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have " "both gt and lt ipprotos, with the lt being " "lower than gt value"); goto error; #if 0 s->proto.proto[data->proto / 8] |= 0xfe << (data->proto % 8); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] = 0xff; } temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; uint8_t *not_protos = NULL; int not_protos_len = 0; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_NOT) { DetectIPProtoData *data_temp = temp_sm->ctx; not_protos = SCRealloc(not_protos, (not_protos_len + 1) * sizeof(uint8_t)); if (not_protos == NULL) goto error; not_protos[not_protos_len] = data_temp->proto; not_protos_len++; } temp_sm = temp_sm->next; } qsort(not_protos, not_protos_len, sizeof(uint8_t), DetectIPProtoQSortCompare); int j = 0; while (j < not_protos_len) { if (not_protos[j] < data->proto) { ; } else { s->proto.proto[not_protos[j] / 8] &= ~(1 << (not_protos[j] % 8)); } j++; } #endif } else { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] = 0; } s->proto.proto[data->proto / 8] &= 0xfe << (data->proto % 8); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] &= 0xff; } } } } break; case DETECT_IPPROTO_OP_LT: if (eq_set || lt_set) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a eq or lt " "ipproto along with a less than ipproto in the " "same sig "); goto error; } if (!gt_set && !not_set) { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] = 0xff; } s->proto.proto[data->proto / 8] = ~(0xff << (data->proto % 8)); } else if (gt_set && !not_set) { SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO) { break; } temp_sm = temp_sm->next; } if (temp_sm != NULL) { DetectIPProtoData *data_temp = temp_sm->ctx; if (data_temp->proto >= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto * multiple uses */ SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a have " "both gt and lt ipprotos, with the lt being " "lower than gt value"); goto error; #if 0 for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] = 0xff; } s->proto.proto[data->proto / 8] |= ~(0xff << (data->proto % 8));; #endif } else { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] &= 0xff; } s->proto.proto[data->proto / 8] &= ~(0xff << (data->proto % 8)); for (i = (data->proto / 8) + 1; i < 256 / 8; i++) { s->proto.proto[i] = 0; } } } } else if (!gt_set && not_set) { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] &= 0xFF; } s->proto.proto[data->proto / 8] &= ~(0xff << (data->proto % 8)); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] = 0; } } else { DetectIPProtoData *data_temp; SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_GT) { break; } temp_sm = temp_sm->next; } if (temp_sm != NULL) { data_temp = temp_sm->ctx; if (data_temp->proto >= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto * multiple uses */ SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have " "both gt and lt ipprotos, with the lt being " "lower than gt value"); goto error; #if 0 for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] = 0xff; } s->proto.proto[data->proto / 8] |= ~(0xff << (data->proto % 8)); temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; uint8_t *not_protos = NULL; int not_protos_len = 0; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_NOT) { DetectIPProtoData *data_temp = temp_sm->ctx; not_protos = SCRealloc(not_protos, (not_protos_len + 1) * sizeof(uint8_t)); if (not_protos == NULL) goto error; not_protos[not_protos_len] = data_temp->proto; not_protos_len++; } temp_sm = temp_sm->next; } qsort(not_protos, not_protos_len, sizeof(uint8_t), DetectIPProtoQSortCompare); int j = 0; while (j < not_protos_len) { if (not_protos[j] < data->proto) { s->proto.proto[not_protos[j] / 8] &= ~(1 << (not_protos[j] % 8)); } else { ; } j++; } #endif } else { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] &= 0xFF; } s->proto.proto[data->proto / 8] &= ~(0xff << (data->proto % 8)); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] = 0; } } } } break; case DETECT_IPPROTO_OP_NOT: if (eq_set) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a eq " "ipproto along with a not ipproto in the " "same sig "); goto error; } if (!gt_set && !lt_set && !not_set) { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] = 0xff; } s->proto.proto[data->proto / 8] = ~(1 << (data->proto % 8)); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] = 0xff; } } else { for (i = 0; i < (data->proto / 8); i++) { s->proto.proto[i] &= 0xff; } s->proto.proto[data->proto / 8] &= ~(1 << (data->proto % 8)); for (i = (data->proto / 8) + 1; i < (256 / 8); i++) { s->proto.proto[i] &= 0xff; } } break; } sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_IPPROTO; sm->ctx = (void *)data; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: return -1; } void DetectIPProtoRemoveAllSMs(Signature *s) { SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type != DETECT_IPPROTO) { sm = sm->next; continue; } SigMatch *tmp_sm = sm->next; SigMatchRemoveSMFromList(s, sm, DETECT_SM_LIST_MATCH); sm = tmp_sm; } return; } /* UNITTESTS */ #ifdef UNITTESTS #include "detect-engine.h" #include "detect-parse.h" /** * \test DetectIPProtoTestParse01 is a test for an invalid proto number */ static int DetectIPProtoTestParse01(void) { int result = 0; DetectIPProtoData *data = NULL; data = DetectIPProtoParse("999"); if (data == NULL) { result = 1; } if (data) SCFree(data); return result; } /** * \test DetectIPProtoTestParse02 is a test for an invalid proto name */ static int DetectIPProtoTestParse02(void) { int result = 0; DetectIPProtoData *data = NULL; data = DetectIPProtoParse("foobarbooeek"); if (data == NULL) { result = 1; } if (data) SCFree(data); return result; } /** * \test DetectIPProtoTestSetup01 is a test for a protocol number */ static int DetectIPProtoTestSetup01(void) { int result = 0; Signature *sig; char *value_str = "14"; int value = atoi(value_str); int i; if ((sig = SigAlloc()) == NULL) goto end; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value / 8] != 0x40) { goto end; } for (i = (value / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } /** * \test DetectIPProtoTestSetup02 is a test for a protocol name */ static int DetectIPProtoTestSetup02(void) { int result = 0; Signature *sig = NULL; char *value_str = "tcp"; struct protoent *pent = getprotobyname(value_str); if (pent == NULL) { goto end; } uint8_t value = (uint8_t)pent->p_proto; int i; if ((sig = SigAlloc()) == NULL) goto end; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value / 8] != 0x40) { goto end; } for (i = (value / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: if (sig != NULL) SigFree(sig); return result; } /** * \test DetectIPProtoTestSetup03 is a test for a < operator */ static int DetectIPProtoTestSetup03(void) { int result = 0; Signature *sig; char *value_str = "<14"; int value = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value / 8] != 0x3F) { goto end; } for (i = (value / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } /** * \test DetectIPProtoTestSetup04 is a test for a > operator */ static int DetectIPProtoTestSetup04(void) { int result = 0; Signature *sig; char *value_str = ">14"; int value = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value / 8] != 0x80) { goto end; } for (i = (value / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } /** * \test DetectIPProtoTestSetup05 is a test for a ! operator */ static int DetectIPProtoTestSetup05(void) { int result = 0; Signature *sig; char *value_str = "!14"; int value = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value / 8] != 0xBF) { goto end; } for (i = (value / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } /** * \test Negative test. */ static int DetectIPProtoTestSetup06(void) { int result = 0; Signature *sig; char *value1_str = "14"; char *value2_str = "15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } /** * \test Negative test. */ static int DetectIPProtoTestSetup07(void) { int result = 0; Signature *sig; char *value1_str = "14"; char *value2_str = "<15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } /** * \test Negative test. */ static int DetectIPProtoTestSetup08(void) { int result = 0; Signature *sig; char *value1_str = "14"; char *value2_str = ">15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } /** * \test Negative test. */ static int DetectIPProtoTestSetup09(void) { int result = 0; Signature *sig; char *value1_str = "14"; char *value2_str = "!15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } /** * \test Negative test. */ static int DetectIPProtoTestSetup10(void) { int result = 0; Signature *sig; char *value1_str = ">14"; char *value2_str = "15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } /** * \test Negative test. */ static int DetectIPProtoTestSetup11(void) { int result = 0; Signature *sig; char *value1_str = "<14"; char *value2_str = "15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } /** * \test Negative test. */ static int DetectIPProtoTestSetup12(void) { int result = 0; Signature *sig; char *value1_str = "!14"; char *value2_str = "15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } /** * \test Negative test. */ static int DetectIPProtoTestSetup13(void) { int result = 0; Signature *sig; char *value1_str = ">14"; char *value2_str = ">15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup14(void) { int result = 0; Signature *sig; char *value1_str = "<14"; char *value2_str = "<15"; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != -1) goto end; result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup15(void) { int result = 0; Signature *sig; char *value1_str = "<14"; int value1 = 14; char *value2_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x3F) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<14"; int value1 = 14; char *value2_str = ">34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x3F) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup16(void) { int result = 0; Signature *sig; char *value1_str = "<14"; char *value2_str = ">34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<14"; int value1 = 14; char *value2_str = ">34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x3F) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup17(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = ">13"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = ">13"; int value2 = 13; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0xC7) { goto end; } if (sig->proto.proto[value2 / 8] != 0xC7) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup18(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value2_str = ">13"; int value2 = 13; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xC0) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = ">13"; int value2 = 13; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0xC7) { goto end; } if (sig->proto.proto[value2 / 8] != 0xC7) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup19(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!13"; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!13"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup20(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!13"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup21(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!13"; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!13"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup22(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value2_str = "!13"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!13"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup23(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!13"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup24(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value2_str = "!13"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!13"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup25(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!18"; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!18"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup26(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!18"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup27(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!18"; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!18"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup28(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value2_str = "!18"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!18"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup29(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!18"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup30(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value2_str = "!18"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!18"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup31(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup32(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup33(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup34(void) { int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup35(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup36(void) { int result = 0; Signature *sig; char *value1_str = "<11"; char *value2_str = "!34"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<11"; int value1 = 11; char *value2_str = "!34"; char *value3_str = ">36"; int value3 = 36; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x07) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xE0) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup37(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0x0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x83) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup38(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value3_str = ">14"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x83) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup39(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value1 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x83) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup40(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0x80) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x83) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup41(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0x80) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x83) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup42(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0x80) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!12"; char *value3_str = ">14"; int value3 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x83) { goto end; } for (i = (value3 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup43(void) { int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup44(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = "<13"; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup45(void) { int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup46(void) { int result = 0; Signature *sig; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup47(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = "<13"; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup48(void) { int result = 0; Signature *sig; char *value2_str = "<13"; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup49(void) { int result = 0; Signature *sig; char *value1_str = "!11"; int value1 = 11; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x17) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!11"; int value1 = 11; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x17) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup50(void) { int result = 0; Signature *sig; char *value1_str = "!11"; char *value2_str = "<13"; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!11"; int value1 = 11; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x17) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup51(void) { int result = 0; Signature *sig; char *value1_str = "!11"; int value1 = 11; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x17) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!11"; int value1 = 11; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x17) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup52(void) { int result = 0; Signature *sig; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x1F) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value3_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!11"; int value1 = 11; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x17) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup53(void) { int result = 0; Signature *sig; char *value1_str = "!11"; char *value2_str = "<13"; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!11"; int value1 = 11; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x17) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup54(void) { int result = 0; Signature *sig; char *value2_str = "<13"; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "!11"; int value1 = 11; char *value2_str = "<13"; int value2 = 13; char *value3_str = ">34"; int value3 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x17) { goto end; } for (i = (value2 / 8) + 1; i < value3 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value3 / 8] != 0xF8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup55(void) { int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!37"; int value3 = 37; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xD8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup56(void) { int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; char *value3_str = "!37"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!37"; int value3 = 37; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xD8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup57(void) { int result = 0; Signature *sig; char *value1_str = "<13"; char *value2_str = ">34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!37"; int value3 = 37; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xD8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup58(void) { int result = 0; Signature *sig; char *value1_str = "<13"; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!37"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xD8) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!37"; int value3 = 37; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xD8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup59(void) { int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; char *value3_str = "!37"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!37"; int value3 = 37; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xD8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup60(void) { int result = 0; Signature *sig; char *value1_str = "<13"; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!37"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xD8) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!37"; int value3 = 37; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xD8) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup61(void) { int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!44"; int value3 = 44; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value3 / 8] != 0xEF) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup62(void) { int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; char *value3_str = "!44"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!44"; int value3 = 44; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value3 / 8] != 0xEF) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup63(void) { int result = 0; Signature *sig; char *value1_str = "<13"; char *value2_str = ">34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!44"; int value3 = 44; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value3 / 8] != 0xEF) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup64(void) { int result = 0; Signature *sig; char *value1_str = "<13"; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!44"; int value3 = 44; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value3 / 8] != 0xEF) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!44"; int value3 = 44; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value3 / 8] != 0xEF) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup65(void) { int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; char *value3_str = "!44"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!44"; int value3 = 44; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value3 / 8] != 0xEF) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup66(void) { int result = 0; Signature *sig; char *value1_str = "<13"; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!44"; int value3 = 44; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value3 / 8] != 0xEF) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; result = 1; end: SigFree(sig); return result; #if 0 int result = 0; Signature *sig; char *value1_str = "<13"; int value1 = 13; char *value2_str = ">34"; int value2 = 34; char *value3_str = "!44"; int value3 = 44; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1F) { goto end; } for (i = (value1 / 8) + 1; i < value2 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value3 / 8] != 0xEF) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; #endif } static int DetectIPProtoTestSetup67(void) { int result = 0; Signature *sig; char *value1_str = ">14"; int value1 = 14; char *value2_str = "<34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0x80) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup68(void) { int result = 0; Signature *sig; char *value1_str = ">14"; int value1 = 14; char *value2_str = "<34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0x80) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup69(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<14"; int value2 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0x38) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup70(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<14"; int value2 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0x38) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup71(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!14"; int value2 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xB8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup72(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!14"; int value2 = 14; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xB8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup73(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0xFB) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup74(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!34"; int value2 = 34; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0xFB) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup75(void) { int result = 0; Signature *sig; char *value1_str = "!8"; char *value2_str = ">10"; int value2 = 10; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup76(void) { int result = 0; Signature *sig; char *value1_str = "!8"; char *value2_str = ">10"; int value2 = 10; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup77(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">10"; int value2 = 10; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup78(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">10"; int value2 = 10; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup79(void) { int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<10"; int value2 = 10; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup80(void) { int result = 0; Signature *sig; char *value1_str = "!4"; int value1 = 4; char *value2_str = "<10"; int value2 = 10; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (sig->proto.proto[value1 / 8] != 0xEF) { goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup81(void) { int result = 0; Signature *sig; char *value1_str = "!9"; int value1 = 9; char *value2_str = "<13"; int value2 = 13; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1D) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup82(void) { int result = 0; Signature *sig; char *value1_str = "!9"; int value1 = 9; char *value2_str = "<13"; int value2 = 13; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x1D) { goto end; } for (i = (value2 / 8) + 1; i < (256 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup83(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!13"; int value2 = 13; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup84(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!13"; int value2 = 13; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup85(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!35"; int value2 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup86(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!35"; int value2 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup87(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">10"; int value2 = 10; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x07) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup88(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">10"; int value2 = 10; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x07) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup89(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">10"; int value2 = 10; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x07) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup90(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">10"; int value2 = 10; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x07) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup91(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">10"; int value2 = 10; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x07) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup92(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">10"; int value2 = 10; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x07) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup93(void) { int result = 0; Signature *sig; char *value1_str = "!9"; char *value2_str = ">12"; int value2 = 12; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xE0) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup94(void) { int result = 0; Signature *sig; char *value1_str = "!9"; char *value2_str = ">12"; int value2 = 12; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xE0) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup95(void) { int result = 0; Signature *sig; char *value1_str = "!9"; char *value2_str = ">12"; int value2 = 12; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xE0) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup96(void) { int result = 0; Signature *sig; char *value1_str = "!9"; char *value2_str = ">12"; int value2 = 12; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xE0) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup97(void) { int result = 0; Signature *sig; char *value1_str = "!9"; char *value2_str = ">12"; int value2 = 12; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xE0) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup98(void) { int result = 0; Signature *sig; char *value1_str = "!9"; char *value2_str = ">12"; int value2 = 12; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xE0) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup99(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!13"; int value2 = 13; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xD8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup100(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!13"; int value2 = 13; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xD8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup101(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!13"; int value2 = 13; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xD8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup102(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!13"; int value2 = 13; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xD8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup103(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!13"; int value2 = 13; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xD8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup104(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!13"; int value2 = 13; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xD8) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup105(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!18"; int value2 = 18; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value2 / 8] != 0xFB) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup106(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!18"; int value2 = 18; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value2 / 8] != 0xFB) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup107(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!18"; int value2 = 18; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value2 / 8] != 0xFB) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup108(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!18"; int value2 = 18; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value2 / 8] != 0xFB) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup109(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!18"; int value2 = 18; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value2 / 8] != 0xFB) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup110(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!18"; int value2 = 18; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } if (sig->proto.proto[value2 / 8] != 0xFB) { goto end; } for (i = (value2 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup111(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!33"; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x05) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup112(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!33"; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x05) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup113(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!33"; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x05) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup114(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!33"; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x05) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup115(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!33"; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x05) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup116(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!33"; char *value3_str = "<35"; int value3 = 35; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value3 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value3 / 8] != 0x05) { goto end; } for (i = (value3 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup117(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!38"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup118(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!38"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup119(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!38"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup120(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!38"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup121(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!38"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup122(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!38"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup123(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!45"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup124(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!45"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup125(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!45"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup126(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!45"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup127(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!45"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup128(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "<34"; int value2 = 34; char *value3_str = "!45"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value2 / 8] != 0x03) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup129(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = ">10"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } if (DetectIPProtoSetup(NULL, sig, value2_str) == 0) goto end; result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup130(void) { int result = 0; Signature *sig; char *value1_str = "<10"; char *value2_str = ">10"; int value2 = 10; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) == 0) goto end; for (i = 0; i < (value2 / 8); i++) { if (sig->proto.proto[i] != 0) goto end; } if (sig->proto.proto[value2 / 8] != 0xF8) { goto end; } for (i = (value2 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup131(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!10"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup132(void) { int result = 0; Signature *sig; char *value1_str = "<10"; int value1 = 10; char *value2_str = "!10"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0xFF) goto end; } if (sig->proto.proto[value1 / 8] != 0x03) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0x0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup133(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!10"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0x0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup134(void) { int result = 0; Signature *sig; char *value1_str = ">10"; int value1 = 10; char *value2_str = "!10"; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; for (i = 0; i < (value1 / 8); i++) { if (sig->proto.proto[i] != 0x0) goto end; } if (sig->proto.proto[value1 / 8] != 0xF8) { goto end; } for (i = (value1 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0xFF) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup135(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!27"; char *value4_str = "!29"; char *value5_str = "!30"; char *value6_str = "!34"; char *value7_str = "<36"; char *value8_str = "!38"; int value8 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xFE) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value8 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup136(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!27"; char *value4_str = "!29"; char *value5_str = "!30"; char *value6_str = "!34"; char *value7_str = "<36"; char *value8_str = "!38"; int value8 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xFE) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value8 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup137(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!27"; char *value4_str = "!29"; char *value5_str = "!30"; char *value6_str = "!34"; char *value7_str = "<36"; char *value8_str = "!38"; int value8 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xFE) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value8 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup138(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!27"; char *value4_str = "!29"; char *value5_str = "!30"; char *value6_str = "!34"; char *value7_str = "<36"; char *value8_str = "!38"; int value8 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xFE) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value8 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup139(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!27"; char *value4_str = "!29"; char *value5_str = "!30"; char *value6_str = "!34"; char *value7_str = "<36"; char *value8_str = "!38"; int value8 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xFE) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value8 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup140(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!27"; char *value4_str = "!29"; char *value5_str = "!30"; char *value6_str = "!34"; char *value7_str = "<36"; char *value8_str = "!38"; int value8 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xFE) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value8 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup141(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!27"; char *value4_str = "!29"; char *value5_str = "!30"; char *value6_str = "!34"; char *value7_str = "<36"; char *value8_str = "!38"; int value8 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xFE) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value8 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup142(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!27"; char *value4_str = "!29"; char *value5_str = "!30"; char *value6_str = "!34"; char *value7_str = "<36"; char *value8_str = "!38"; int value8 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xFE) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value8 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup143(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!10"; char *value4_str = "!14"; char *value5_str = "!27"; char *value6_str = "!29"; char *value7_str = "!30"; char *value8_str = "!34"; char *value9_str = "<36"; char *value10_str = "!38"; int value10 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value9_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value10_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xBA) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value10 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup144(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!10"; char *value4_str = "!14"; char *value5_str = "!27"; char *value6_str = "!29"; char *value7_str = "!30"; char *value8_str = "!34"; char *value9_str = "<36"; char *value10_str = "!38"; int value10 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value10_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value9_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xBA) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value10 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSetup145(void) { int result = 0; Signature *sig; char *value1_str = "!4"; char *value2_str = ">8"; char *value3_str = "!10"; char *value4_str = "!14"; char *value5_str = "!27"; char *value6_str = "!29"; char *value7_str = "!30"; char *value8_str = "!34"; char *value9_str = "<36"; char *value10_str = "!38"; int value10 = 38; int i; if ((sig = SigAlloc()) == NULL) goto end; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value10_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value9_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; if (sig->proto.proto[0] != 0) { goto end; } if (sig->proto.proto[1] != 0xBA) { goto end; } if (sig->proto.proto[2] != 0xFF) { goto end; } if (sig->proto.proto[3] != 0x97) { goto end; } if (sig->proto.proto[4] != 0x0B) { goto end; } for (i = (value10 / 8) + 1; i < 256 / 8; i++) { if (sig->proto.proto[i] != 0) goto end; } result = 1; end: SigFree(sig); return result; } static int DetectIPProtoTestSig1(void) { int result = 0; uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char *sigs[4]; sigs[0] = "alert ip any any -> any any " "(msg:\"Not tcp\"; ip_proto:!tcp; content:\"GET \"; sid:1;)"; sigs[1] = "alert ip any any -> any any " "(msg:\"Less than 7\"; content:\"GET \"; ip_proto:<7; sid:2;)"; sigs[2] = "alert ip any any -> any any " "(msg:\"Greater than 5\"; content:\"GET \"; ip_proto:>5; sid:3;)"; sigs[3] = "alert ip any any -> any any " "(msg:\"Equals tcp\"; content:\"GET \"; ip_proto:tcp; sid:4;)"; /* sids to match */ uint32_t sid[4] = {1, 2, 3, 4}; /* expected matches for each sid within this packet we are testing */ uint32_t results[4] = {0, 1, 1, 1}; /* remember that UTHGenericTest expect the first parameter * as an array of packet pointers. And also a bidimensional array of results * For example: * results[numpacket][position] should hold the number of times * that the sid at sid[position] matched that packet (should be always 1..) * But here we built it as unidimensional array */ result = UTHGenericTest(&p, 1, sigs, sid, results, 4); UTHFreePacket(p); end: DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); return result; } static int DetectIPProtoTestSig2(void) { int result = 0; uint8_t raw_eth[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x0d, 0x00, 0x26, 0x88, 0x61, 0x3a, 0x80, 0x08, 0x00, 0x45, 0xc0, 0x00, 0x36, 0xe4, 0xcd, 0x00, 0x00, 0x01, 0x67, 0xc7, 0xab, 0xac, 0x1c, 0x7f, 0xfe, 0xe0, 0x00, 0x00, 0x0d, 0x20, 0x00, 0x90, 0x20, 0x00, 0x01, 0x00, 0x02, 0x00, 0x69, 0x00, 0x02, 0x00, 0x04, 0x81, 0xf4, 0x07, 0xd0, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x04, 0x4a, 0xea, 0x7a, 0x8e, }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; p->proto = 0; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth), NULL); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_AC; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"Check ipproto usage\"; " "ip_proto:!103; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { result = 1; goto end; } else { result = 0; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; end: if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx) DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; } static int DetectIPProtoTestSig3(void) { int result = 0; uint8_t raw_eth[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x0d, 0x00, 0x26, 0x88, 0x61, 0x3a, 0x80, 0x08, 0x00, 0x45, 0xc0, 0x00, 0x36, 0xe4, 0xcd, 0x00, 0x00, 0x01, 0x67, 0xc7, 0xab, 0xac, 0x1c, 0x7f, 0xfe, 0xe0, 0x00, 0x00, 0x0d, 0x20, 0x00, 0x90, 0x20, 0x00, 0x01, 0x00, 0x02, 0x00, 0x69, 0x00, 0x02, 0x00, 0x04, 0x81, 0xf4, 0x07, 0xd0, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x04, 0x4a, 0xea, 0x7a, 0x8e, }; Packet *p = UTHBuildPacket((uint8_t *)"boom", 4, IPPROTO_TCP); //Packet *p = SCMalloc(SIZE_OF_PACKET); if (p == NULL) return 0; //memset(p, 0, SIZE_OF_PACKET); DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; p->pkt = ((uint8_t *)p) + sizeof(*p); p->proto = 0; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth), NULL); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_AC; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"Check ipproto usage\"; " "ip_proto:103; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { result = 0; goto end; } else { result = 1; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; end: if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx) DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; } #endif /* UNITTESTS */ /** * \internal * \brief Register ip_proto tests. */ static void DetectIPProtoRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectIPProtoTestParse01", DetectIPProtoTestParse01, 1); UtRegisterTest("DetectIPProtoTestParse02", DetectIPProtoTestParse02, 1); UtRegisterTest("DetectIPProtoTestSetup01", DetectIPProtoTestSetup01, 1); UtRegisterTest("DetectIPProtoTestSetup02", DetectIPProtoTestSetup02, 1); UtRegisterTest("DetectIPProtoTestSetup03", DetectIPProtoTestSetup03, 1); UtRegisterTest("DetectIPProtoTestSetup04", DetectIPProtoTestSetup04, 1); UtRegisterTest("DetectIPProtoTestSetup05", DetectIPProtoTestSetup05, 1); UtRegisterTest("DetectIPProtoTestSetup06", DetectIPProtoTestSetup06, 1); UtRegisterTest("DetectIPProtoTestSetup07", DetectIPProtoTestSetup07, 1); UtRegisterTest("DetectIPProtoTestSetup08", DetectIPProtoTestSetup08, 1); UtRegisterTest("DetectIPProtoTestSetup09", DetectIPProtoTestSetup09, 1); UtRegisterTest("DetectIPProtoTestSetup10", DetectIPProtoTestSetup10, 1); UtRegisterTest("DetectIPProtoTestSetup11", DetectIPProtoTestSetup11, 1); UtRegisterTest("DetectIPProtoTestSetup12", DetectIPProtoTestSetup12, 1); UtRegisterTest("DetectIPProtoTestSetup13", DetectIPProtoTestSetup13, 1); UtRegisterTest("DetectIPProtoTestSetup14", DetectIPProtoTestSetup14, 1); UtRegisterTest("DetectIPProtoTestSetup15", DetectIPProtoTestSetup15, 1); UtRegisterTest("DetectIPProtoTestSetup16", DetectIPProtoTestSetup16, 1); UtRegisterTest("DetectIPProtoTestSetup17", DetectIPProtoTestSetup17, 1); UtRegisterTest("DetectIPProtoTestSetup18", DetectIPProtoTestSetup18, 1); UtRegisterTest("DetectIPProtoTestSetup19", DetectIPProtoTestSetup19, 1); UtRegisterTest("DetectIPProtoTestSetup20", DetectIPProtoTestSetup20, 1); UtRegisterTest("DetectIPProtoTestSetup21", DetectIPProtoTestSetup21, 1); UtRegisterTest("DetectIPProtoTestSetup22", DetectIPProtoTestSetup22, 1); UtRegisterTest("DetectIPProtoTestSetup23", DetectIPProtoTestSetup23, 1); UtRegisterTest("DetectIPProtoTestSetup24", DetectIPProtoTestSetup24, 1); UtRegisterTest("DetectIPProtoTestSetup25", DetectIPProtoTestSetup25, 1); UtRegisterTest("DetectIPProtoTestSetup26", DetectIPProtoTestSetup26, 1); UtRegisterTest("DetectIPProtoTestSetup27", DetectIPProtoTestSetup27, 1); UtRegisterTest("DetectIPProtoTestSetup28", DetectIPProtoTestSetup28, 1); UtRegisterTest("DetectIPProtoTestSetup29", DetectIPProtoTestSetup29, 1); UtRegisterTest("DetectIPProtoTestSetup30", DetectIPProtoTestSetup30, 1); UtRegisterTest("DetectIPProtoTestSetup31", DetectIPProtoTestSetup31, 1); UtRegisterTest("DetectIPProtoTestSetup32", DetectIPProtoTestSetup32, 1); UtRegisterTest("DetectIPProtoTestSetup33", DetectIPProtoTestSetup33, 1); UtRegisterTest("DetectIPProtoTestSetup34", DetectIPProtoTestSetup34, 1); UtRegisterTest("DetectIPProtoTestSetup35", DetectIPProtoTestSetup35, 1); UtRegisterTest("DetectIPProtoTestSetup36", DetectIPProtoTestSetup36, 1); UtRegisterTest("DetectIPProtoTestSetup37", DetectIPProtoTestSetup37, 1); UtRegisterTest("DetectIPProtoTestSetup38", DetectIPProtoTestSetup38, 1); UtRegisterTest("DetectIPProtoTestSetup39", DetectIPProtoTestSetup39, 1); UtRegisterTest("DetectIPProtoTestSetup40", DetectIPProtoTestSetup40, 1); UtRegisterTest("DetectIPProtoTestSetup41", DetectIPProtoTestSetup41, 1); UtRegisterTest("DetectIPProtoTestSetup42", DetectIPProtoTestSetup42, 1); UtRegisterTest("DetectIPProtoTestSetup43", DetectIPProtoTestSetup43, 1); UtRegisterTest("DetectIPProtoTestSetup44", DetectIPProtoTestSetup44, 1); UtRegisterTest("DetectIPProtoTestSetup45", DetectIPProtoTestSetup45, 1); UtRegisterTest("DetectIPProtoTestSetup46", DetectIPProtoTestSetup46, 1); UtRegisterTest("DetectIPProtoTestSetup47", DetectIPProtoTestSetup47, 1); UtRegisterTest("DetectIPProtoTestSetup48", DetectIPProtoTestSetup48, 1); UtRegisterTest("DetectIPProtoTestSetup49", DetectIPProtoTestSetup49, 1); UtRegisterTest("DetectIPProtoTestSetup50", DetectIPProtoTestSetup50, 1); UtRegisterTest("DetectIPProtoTestSetup51", DetectIPProtoTestSetup51, 1); UtRegisterTest("DetectIPProtoTestSetup52", DetectIPProtoTestSetup52, 1); UtRegisterTest("DetectIPProtoTestSetup53", DetectIPProtoTestSetup53, 1); UtRegisterTest("DetectIPProtoTestSetup54", DetectIPProtoTestSetup54, 1); UtRegisterTest("DetectIPProtoTestSetup55", DetectIPProtoTestSetup55, 1); UtRegisterTest("DetectIPProtoTestSetup56", DetectIPProtoTestSetup56, 1); UtRegisterTest("DetectIPProtoTestSetup57", DetectIPProtoTestSetup57, 1); UtRegisterTest("DetectIPProtoTestSetup58", DetectIPProtoTestSetup58, 1); UtRegisterTest("DetectIPProtoTestSetup59", DetectIPProtoTestSetup59, 1); UtRegisterTest("DetectIPProtoTestSetup60", DetectIPProtoTestSetup60, 1); UtRegisterTest("DetectIPProtoTestSetup61", DetectIPProtoTestSetup61, 1); UtRegisterTest("DetectIPProtoTestSetup62", DetectIPProtoTestSetup62, 1); UtRegisterTest("DetectIPProtoTestSetup63", DetectIPProtoTestSetup63, 1); UtRegisterTest("DetectIPProtoTestSetup64", DetectIPProtoTestSetup64, 1); UtRegisterTest("DetectIPProtoTestSetup65", DetectIPProtoTestSetup65, 1); UtRegisterTest("DetectIPProtoTestSetup66", DetectIPProtoTestSetup66, 1); UtRegisterTest("DetectIPProtoTestSetup67", DetectIPProtoTestSetup67, 1); UtRegisterTest("DetectIPProtoTestSetup68", DetectIPProtoTestSetup68, 1); UtRegisterTest("DetectIPProtoTestSetup69", DetectIPProtoTestSetup69, 1); UtRegisterTest("DetectIPProtoTestSetup70", DetectIPProtoTestSetup70, 1); UtRegisterTest("DetectIPProtoTestSetup71", DetectIPProtoTestSetup71, 1); UtRegisterTest("DetectIPProtoTestSetup72", DetectIPProtoTestSetup72, 1); UtRegisterTest("DetectIPProtoTestSetup73", DetectIPProtoTestSetup73, 1); UtRegisterTest("DetectIPProtoTestSetup74", DetectIPProtoTestSetup74, 1); UtRegisterTest("DetectIPProtoTestSetup75", DetectIPProtoTestSetup75, 1); UtRegisterTest("DetectIPProtoTestSetup76", DetectIPProtoTestSetup76, 1); UtRegisterTest("DetectIPProtoTestSetup77", DetectIPProtoTestSetup77, 1); UtRegisterTest("DetectIPProtoTestSetup78", DetectIPProtoTestSetup78, 1); UtRegisterTest("DetectIPProtoTestSetup79", DetectIPProtoTestSetup79, 1); UtRegisterTest("DetectIPProtoTestSetup80", DetectIPProtoTestSetup80, 1); UtRegisterTest("DetectIPProtoTestSetup81", DetectIPProtoTestSetup81, 1); UtRegisterTest("DetectIPProtoTestSetup82", DetectIPProtoTestSetup82, 1); UtRegisterTest("DetectIPProtoTestSetup83", DetectIPProtoTestSetup83, 1); UtRegisterTest("DetectIPProtoTestSetup84", DetectIPProtoTestSetup84, 1); UtRegisterTest("DetectIPProtoTestSetup85", DetectIPProtoTestSetup85, 1); UtRegisterTest("DetectIPProtoTestSetup86", DetectIPProtoTestSetup86, 1); UtRegisterTest("DetectIPProtoTestSetup87", DetectIPProtoTestSetup87, 1); UtRegisterTest("DetectIPProtoTestSetup88", DetectIPProtoTestSetup88, 1); UtRegisterTest("DetectIPProtoTestSetup89", DetectIPProtoTestSetup89, 1); UtRegisterTest("DetectIPProtoTestSetup90", DetectIPProtoTestSetup90, 1); UtRegisterTest("DetectIPProtoTestSetup91", DetectIPProtoTestSetup91, 1); UtRegisterTest("DetectIPProtoTestSetup92", DetectIPProtoTestSetup92, 1); UtRegisterTest("DetectIPProtoTestSetup93", DetectIPProtoTestSetup93, 1); UtRegisterTest("DetectIPProtoTestSetup94", DetectIPProtoTestSetup94, 1); UtRegisterTest("DetectIPProtoTestSetup95", DetectIPProtoTestSetup95, 1); UtRegisterTest("DetectIPProtoTestSetup96", DetectIPProtoTestSetup96, 1); UtRegisterTest("DetectIPProtoTestSetup97", DetectIPProtoTestSetup97, 1); UtRegisterTest("DetectIPProtoTestSetup98", DetectIPProtoTestSetup98, 1); UtRegisterTest("DetectIPProtoTestSetup99", DetectIPProtoTestSetup99, 1); UtRegisterTest("DetectIPProtoTestSetup100", DetectIPProtoTestSetup100, 1); UtRegisterTest("DetectIPProtoTestSetup101", DetectIPProtoTestSetup101, 1); UtRegisterTest("DetectIPProtoTestSetup102", DetectIPProtoTestSetup102, 1); UtRegisterTest("DetectIPProtoTestSetup103", DetectIPProtoTestSetup103, 1); UtRegisterTest("DetectIPProtoTestSetup104", DetectIPProtoTestSetup104, 1); UtRegisterTest("DetectIPProtoTestSetup105", DetectIPProtoTestSetup105, 1); UtRegisterTest("DetectIPProtoTestSetup106", DetectIPProtoTestSetup106, 1); UtRegisterTest("DetectIPProtoTestSetup107", DetectIPProtoTestSetup107, 1); UtRegisterTest("DetectIPProtoTestSetup108", DetectIPProtoTestSetup108, 1); UtRegisterTest("DetectIPProtoTestSetup109", DetectIPProtoTestSetup109, 1); UtRegisterTest("DetectIPProtoTestSetup110", DetectIPProtoTestSetup110, 1); UtRegisterTest("DetectIPProtoTestSetup111", DetectIPProtoTestSetup111, 1); UtRegisterTest("DetectIPProtoTestSetup112", DetectIPProtoTestSetup112, 1); UtRegisterTest("DetectIPProtoTestSetup113", DetectIPProtoTestSetup113, 1); UtRegisterTest("DetectIPProtoTestSetup114", DetectIPProtoTestSetup114, 1); UtRegisterTest("DetectIPProtoTestSetup115", DetectIPProtoTestSetup115, 1); UtRegisterTest("DetectIPProtoTestSetup116", DetectIPProtoTestSetup116, 1); UtRegisterTest("DetectIPProtoTestSetup117", DetectIPProtoTestSetup117, 1); UtRegisterTest("DetectIPProtoTestSetup118", DetectIPProtoTestSetup118, 1); UtRegisterTest("DetectIPProtoTestSetup119", DetectIPProtoTestSetup119, 1); UtRegisterTest("DetectIPProtoTestSetup120", DetectIPProtoTestSetup120, 1); UtRegisterTest("DetectIPProtoTestSetup121", DetectIPProtoTestSetup121, 1); UtRegisterTest("DetectIPProtoTestSetup122", DetectIPProtoTestSetup122, 1); UtRegisterTest("DetectIPProtoTestSetup123", DetectIPProtoTestSetup123, 1); UtRegisterTest("DetectIPProtoTestSetup124", DetectIPProtoTestSetup124, 1); UtRegisterTest("DetectIPProtoTestSetup125", DetectIPProtoTestSetup125, 1); UtRegisterTest("DetectIPProtoTestSetup126", DetectIPProtoTestSetup126, 1); UtRegisterTest("DetectIPProtoTestSetup127", DetectIPProtoTestSetup127, 1); UtRegisterTest("DetectIPProtoTestSetup128", DetectIPProtoTestSetup128, 1); UtRegisterTest("DetectIPProtoTestSetup129", DetectIPProtoTestSetup129, 1); UtRegisterTest("DetectIPProtoTestSetup130", DetectIPProtoTestSetup130, 1); UtRegisterTest("DetectIPProtoTestSetup131", DetectIPProtoTestSetup131, 1); UtRegisterTest("DetectIPProtoTestSetup132", DetectIPProtoTestSetup132, 1); UtRegisterTest("DetectIPProtoTestSetup133", DetectIPProtoTestSetup133, 1); UtRegisterTest("DetectIPProtoTestSetup134", DetectIPProtoTestSetup134, 1); UtRegisterTest("DetectIPProtoTestSetup135", DetectIPProtoTestSetup135, 1); UtRegisterTest("DetectIPProtoTestSetup136", DetectIPProtoTestSetup136, 1); UtRegisterTest("DetectIPProtoTestSetup137", DetectIPProtoTestSetup137, 1); UtRegisterTest("DetectIPProtoTestSetup138", DetectIPProtoTestSetup138, 1); UtRegisterTest("DetectIPProtoTestSetup139", DetectIPProtoTestSetup139, 1); UtRegisterTest("DetectIPProtoTestSetup140", DetectIPProtoTestSetup140, 1); UtRegisterTest("DetectIPProtoTestSetup141", DetectIPProtoTestSetup141, 1); UtRegisterTest("DetectIPProtoTestSetup142", DetectIPProtoTestSetup142, 1); UtRegisterTest("DetectIPProtoTestSetup143", DetectIPProtoTestSetup143, 1); UtRegisterTest("DetectIPProtoTestSetup144", DetectIPProtoTestSetup144, 1); UtRegisterTest("DetectIPProtoTestSetup145", DetectIPProtoTestSetup145, 1); UtRegisterTest("DetectIPProtoTestSig1", DetectIPProtoTestSig1, 1); UtRegisterTest("DetectIPProtoTestSig2", DetectIPProtoTestSig2, 1); UtRegisterTest("DetectIPProtoTestSig3", DetectIPProtoTestSig3, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-host-os-info.h0000644000000000000000000000230412253546156014475 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_HOST_OS_INFO_H__ #define __UTIL_HOST_OS_INFO_H__ #define SC_HINFO_IS_IPV6 0 #define SC_HINFO_IS_IPV4 1 int SCHInfoAddHostOSInfo(char *, char *, int); int SCHInfoGetHostOSFlavour(char *); int SCHInfoGetIPv4HostOSFlavour(uint8_t *); int SCHInfoGetIPv6HostOSFlavour(uint8_t *); void SCHInfoCleanResources(void); void SCHInfoLoadFromConfig(void); void SCHInfoRegisterTests(void); #endif /* __UTIL_HOST_OS_INFO_H__ */ suricata-1.4.7/src/detect-http-uri.h0000644000000000000000000000205312253546156014220 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias Galvan */ #ifndef _DETECT_HTTP_URI_H #define _DETECT_HTTP_URI_H /* prototypes */ void DetectHttpUriRegister (void); int DetectHttpUriDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, Flow *f, uint8_t flags, void *state); #endif /* _DETECT_HTTP_URI_H */ suricata-1.4.7/src/detect-rev.c0000644000000000000000000000431712253546156013240 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the rev keyword */ #include "suricata-common.h" #include "detect.h" #include "util-debug.h" #include "util-error.h" static int DetectRevSetup (DetectEngineCtx *, Signature *, char *); void DetectRevRegister (void) { sigmatch_table[DETECT_REV].name = "rev"; sigmatch_table[DETECT_REV].desc = "set version of the rule"; sigmatch_table[DETECT_REV].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Rev-Revision"; sigmatch_table[DETECT_REV].Match = NULL; sigmatch_table[DETECT_REV].Setup = DetectRevSetup; sigmatch_table[DETECT_REV].Free = NULL; sigmatch_table[DETECT_REV].RegisterTests = NULL; } static int DetectRevSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { char *str = rawstr; char dubbed = 0; /* strip "'s */ if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') { str = SCStrdup(rawstr+1); if (unlikely(str == NULL)) return -1; str[strlen(rawstr)-2] = '\0'; dubbed = 1; } unsigned long rev = 0; char *endptr = NULL; rev = strtoul(rawstr, &endptr, 10); if (endptr == NULL || *endptr != '\0') { SCLogError(SC_ERR_INVALID_SIGNATURE, "Saw an invalid character as arg " "to rev keyword"); goto error; } s->rev = (uint32_t)rev; if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; } suricata-1.4.7/src/source-erf-file.c0000644000000000000000000002122312253546156014160 00000000000000/* Copyright (C) 2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited. * * Support for reading ERF files. * * Only ethernet supported at this time. */ #include "suricata-common.h" #include "suricata.h" #include "tm-threads.h" #define DAG_TYPE_ETH 2 typedef struct DagFlags_ { uint8_t iface:2; uint8_t vlen:1; uint8_t trunc:1; uint8_t rxerror:1; uint8_t dserror:1; uint8_t reserved:1; uint8_t direction:1; } DagFlags; typedef struct DagRecord_ { uint64_t ts; uint8_t type; DagFlags flags; uint16_t rlen; uint16_t lctr; uint16_t wlen; uint16_t pad; } __attribute__((packed)) DagRecord; typedef struct ErfFileThreadVars_ { ThreadVars *tv; TmSlot *slot; FILE *erf; uint32_t pkts; uint64_t bytes; } ErfFileThreadVars; static inline TmEcode ReadErfRecord(ThreadVars *, Packet *, void *); TmEcode ReceiveErfFileLoop(ThreadVars *, void *, void *); TmEcode ReceiveErfFileThreadInit(ThreadVars *, void *, void **); void ReceiveErfFileThreadExitStats(ThreadVars *, void *); TmEcode ReceiveErfFileThreadDeinit(ThreadVars *, void *); TmEcode DecodeErfFileThreadInit(ThreadVars *, void *, void **); TmEcode DecodeErfFile(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); /** * \brief Register the ERF file receiver (reader) module. */ void TmModuleReceiveErfFileRegister(void) { tmm_modules[TMM_RECEIVEERFFILE].name = "ReceiveErfFile"; tmm_modules[TMM_RECEIVEERFFILE].ThreadInit = ReceiveErfFileThreadInit; tmm_modules[TMM_RECEIVEERFFILE].Func = NULL; tmm_modules[TMM_RECEIVEERFFILE].PktAcqLoop = ReceiveErfFileLoop; tmm_modules[TMM_RECEIVEERFFILE].ThreadExitPrintStats = ReceiveErfFileThreadExitStats; tmm_modules[TMM_RECEIVEERFFILE].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEERFFILE].RegisterTests = NULL; tmm_modules[TMM_RECEIVEERFFILE].cap_flags = 0; tmm_modules[TMM_RECEIVEERFFILE].flags = TM_FLAG_RECEIVE_TM; } /** * \brief Register the ERF file decoder module. */ void TmModuleDecodeErfFileRegister(void) { tmm_modules[TMM_DECODEERFFILE].name = "DecodeErfFile"; tmm_modules[TMM_DECODEERFFILE].ThreadInit = DecodeErfFileThreadInit; tmm_modules[TMM_DECODEERFFILE].Func = DecodeErfFile; tmm_modules[TMM_DECODEERFFILE].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEERFFILE].ThreadDeinit = NULL; tmm_modules[TMM_DECODEERFFILE].RegisterTests = NULL; tmm_modules[TMM_DECODEERFFILE].cap_flags = 0; tmm_modules[TMM_DECODEERFFILE].flags = TM_FLAG_DECODE_TM; } /** * \brief ERF file reading loop. */ TmEcode ReceiveErfFileLoop(ThreadVars *tv, void *data, void *slot) { Packet *p = NULL; uint16_t packet_q_len = 0; ErfFileThreadVars *etv = (ErfFileThreadVars *)data; etv->slot = ((TmSlot *)slot)->slot_next; while (1) { if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } /* Make sure we have at least one packet in the packet pool, * to prevent us from alloc'ing packets at line rate. */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate a packet."); EngineStop(); SCReturnInt(TM_ECODE_FAILED); } PKT_SET_SRC(p, PKT_SRC_WIRE); if (ReadErfRecord(tv, p, data) != TM_ECODE_OK) { TmqhOutputPacketpool(etv->tv, p); EngineStop(); SCReturnInt(TM_ECODE_FAILED); } if (TmThreadsSlotProcessPkt(etv->tv, etv->slot, p) != TM_ECODE_OK) { EngineStop(); SCReturnInt(TM_ECODE_FAILED); } } SCReturnInt(TM_ECODE_FAILED); } static inline TmEcode ReadErfRecord(ThreadVars *tv, Packet *p, void *data) { SCEnter(); ErfFileThreadVars *etv = (ErfFileThreadVars *)data; DagRecord dr; int r = fread(&dr, sizeof(DagRecord), 1, etv->erf); if (r < 1) { if (feof(etv->erf)) { SCLogInfo("End of ERF file reached"); } else { SCLogInfo("Error reading ERF record"); } SCReturnInt(TM_ECODE_FAILED); } int rlen = ntohs(dr.rlen); int wlen = ntohs(dr.wlen); r = fread(GET_PKT_DATA(p), rlen - sizeof(DagRecord), 1, etv->erf); if (r < 1) { if (feof(etv->erf)) { SCLogInfo("End of ERF file reached"); } else { SCLogInfo("Error reading ERF record"); } SCReturnInt(TM_ECODE_FAILED); } /* Only support ethernet at this time. */ if (dr.type != DAG_TYPE_ETH) { SCLogError(SC_ERR_UNIMPLEMENTED, "DAG record type %d not implemented.", dr.type); SCReturnInt(TM_ECODE_FAILED); } GET_PKT_LEN(p) = wlen; p->datalink = LINKTYPE_ETHERNET; /* Convert ERF time to timeval - from libpcap. */ uint64_t ts = dr.ts; p->ts.tv_sec = ts >> 32; ts = (ts & 0xffffffffULL) * 1000000; ts += 0x80000000; /* rounding */ p->ts.tv_usec = ts >> 32; if (p->ts.tv_usec >= 1000000) { p->ts.tv_usec -= 1000000; p->ts.tv_sec++; } etv->pkts++; etv->bytes += wlen; SCReturnInt(TM_ECODE_OK); } /** * \brief Initialize the ERF receiver thread. */ TmEcode ReceiveErfFileThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Error: No filename provided."); SCReturnInt(TM_ECODE_FAILED); } FILE *erf = fopen((const char *)initdata, "r"); if (erf == NULL) { SCLogError(SC_ERR_FOPEN, "Failed to open %s: %s", (char *)initdata, strerror(errno)); exit(EXIT_FAILURE); } ErfFileThreadVars *etv = SCMalloc(sizeof(ErfFileThreadVars)); if (unlikely(etv == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for ERF file thread vars."); fclose(erf); SCReturnInt(TM_ECODE_FAILED); } memset(etv, 0, sizeof(*etv)); etv->erf = erf; etv->tv = tv; *data = (void *)etv; SCLogInfo("Processing ERF file %s", (char *)initdata); SCReturnInt(TM_ECODE_OK); } /** * \brief Initialize the ERF decoder thread. */ TmEcode DecodeErfFileThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if (dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; SCReturnInt(TM_ECODE_OK); } /** * \brief Decode the ERF file. * * This function ups the decoder counters and then passes the packet * off to the ethernet decoder. */ TmEcode DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* Update counters. */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); SCReturnInt(TM_ECODE_OK); } /** * \brief Print some stats to the log at program exit. * * \param tv Pointer to ThreadVars. * \param data Pointer to data, ErfFileThreadVars. */ void ReceiveErfFileThreadExitStats(ThreadVars *tv, void *data) { ErfFileThreadVars *etv = (ErfFileThreadVars *)data; SCLogInfo("Packets: %"PRIu32"; Bytes: %"PRIu64, etv->pkts, etv->bytes); } suricata-1.4.7/src/decode-ipv4.h0000644000000000000000000002324512253546156013307 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Brian Rectanus */ #ifndef __DECODE_IPV4_H__ #define __DECODE_IPV4_H__ #define IPV4_HEADER_LEN 20 /**< Header length */ #define IPV4_OPTMAX 40 /**< Max options length */ #define IPV4_MAXPACKET_LEN 65535 /**< Maximum packet size */ /** IP Option Types */ #define IPV4_OPT_EOL 0x00 /**< Option: End of List */ #define IPV4_OPT_NOP 0x01 /**< Option: No op */ #define IPV4_OPT_RR 0x07 /**< Option: Record Route */ #define IPV4_OPT_QS 0x19 /**< Option: Quick Start */ #define IPV4_OPT_TS 0x44 /**< Option: Timestamp */ #define IPV4_OPT_SEC 0x82 /**< Option: Security */ #define IPV4_OPT_LSRR 0x83 /**< Option: Loose Source Route */ #define IPV4_OPT_CIPSO 0x86 /**< Option: Commercial IP Security */ #define IPV4_OPT_SID 0x88 /**< Option: Stream Identifier */ #define IPV4_OPT_SSRR 0x89 /**< Option: Strict Source Route */ #define IPV4_OPT_RTRALT 0x94 /**< Option: Router Alert */ /** IP Option Lengths (fixed) */ #define IPV4_OPT_SEC_LEN 11 /**< SEC Option Fixed Length */ #define IPV4_OPT_SID_LEN 4 /**< SID Option Fixed Length */ #define IPV4_OPT_RTRALT_LEN 4 /**< RTRALT Option Fixed Length */ /** IP Option Lengths (variable) */ #define IPV4_OPT_ROUTE_MIN 3 /**< RR, SRR, LTRR Option Min Length */ #define IPV4_OPT_QS_MIN 8 /**< QS Option Min Length */ #define IPV4_OPT_TS_MIN 5 /**< TS Option Min Length */ #define IPV4_OPT_CIPSO_MIN 10 /**< CIPSO Option Min Length */ /** IP Option fields */ #define IPV4_OPTS ip4vars.ip_opts #define IPV4_OPTS_CNT ip4vars.ip_opt_cnt typedef struct IPV4Opt_ { /** \todo We may want to break type up into its 3 fields * as the reassembler may want to know which options * must be copied to each fragment. */ uint8_t type; /**< option type */ uint8_t len; /**< option length (type+len+data) */ uint8_t *data; /**< option data */ } IPV4Opt; typedef struct IPV4Hdr_ { uint8_t ip_verhl; /**< version & header length */ uint8_t ip_tos; /**< type of service */ uint16_t ip_len; /**< length */ uint16_t ip_id; /**< id */ uint16_t ip_off; /**< frag offset */ uint8_t ip_ttl; /**< time to live */ uint8_t ip_proto; /**< protocol (tcp, udp, etc) */ uint16_t ip_csum; /**< checksum */ union { struct { struct in_addr ip_src;/**< source address */ struct in_addr ip_dst;/**< destination address */ } ip4_un1; uint16_t ip_addrs[4]; } ip4_hdrun1; } IPV4Hdr; #define s_ip_src ip4_hdrun1.ip4_un1.ip_src #define s_ip_dst ip4_hdrun1.ip4_un1.ip_dst #define s_ip_addrs ip4_hdrun1.ip_addrs #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) #define IPV4_GET_RAW_IPSRC(ip4h) ((ip4h)->s_ip_src) #define IPV4_GET_RAW_IPDST(ip4h) ((ip4h)->s_ip_dst) /** return the raw (directly from the header) src ip as uint32_t */ #define IPV4_GET_RAW_IPSRC_U32(ip4h) (uint32_t)((ip4h)->s_ip_src.s_addr) /** return the raw (directly from the header) dst ip as uint32_t */ #define IPV4_GET_RAW_IPDST_U32(ip4h) (uint32_t)((ip4h)->s_ip_dst.s_addr) /* 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) /* ONLY call these functions after making sure that: * 1. p->ip4h is set * 2. p->ip4h is valid (len is correct) */ #define IPV4_GET_VER(p) \ IPV4_GET_RAW_VER((p)->ip4h) #define IPV4_GET_HLEN(p) \ (IPV4_GET_RAW_HLEN((p)->ip4h) << 2) #define IPV4_GET_IPTOS(p) \ IPV4_GET_RAW_IPTOS((p)->ip4h) #define IPV4_GET_IPLEN(p) \ (ntohs(IPV4_GET_RAW_IPLEN((p)->ip4h))) #define IPV4_GET_IPID(p) \ (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) \ (ntohs(IPV4_GET_RAW_IPOFFSET((p)->ip4h))) /* IPV4_GET_IPOFFSET: get the final offset */ #define IPV4_GET_IPOFFSET(p) \ (_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) \ (uint8_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) \ (uint8_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) \ (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x2000) >> 13) #define IPV4_GET_IPTTL(p) \ IPV4_GET_RAW_IPTTL(p->ip4h) #define IPV4_GET_IPPROTO(p) \ IPV4_GET_RAW_IPPROTO((p)->ip4h) #define CLEAR_IPV4_PACKET(p) do { \ (p)->ip4h = NULL; \ (p)->ip4vars.comp_csum = 0; \ (p)->ip4vars.ip_src_u32 = 0; \ (p)->ip4vars.ip_dst_u32 = 0; \ (p)->ip4vars.ip_opt_cnt = 0; \ (p)->ip4vars.o_rr = NULL; \ (p)->ip4vars.o_qs = NULL; \ (p)->ip4vars.o_ts = NULL; \ (p)->ip4vars.o_sec = NULL; \ (p)->ip4vars.o_lsrr = NULL; \ (p)->ip4vars.o_cipso = NULL; \ (p)->ip4vars.o_sid = NULL; \ (p)->ip4vars.o_ssrr = NULL; \ (p)->ip4vars.o_rtralt = NULL; \ } while (0) /* helper structure with parsed ipv4 info */ typedef struct IPV4Vars_ { int32_t comp_csum; /* checksum computed over the ipv4 packet */ uint32_t ip_src_u32; /* source IP */ uint32_t ip_dst_u32; /* dest IP */ IPV4Opt ip_opts[IPV4_OPTMAX]; uint8_t ip_opt_cnt; /* These are here for direct access and dup tracking */ IPV4Opt *o_rr; IPV4Opt *o_qs; IPV4Opt *o_ts; IPV4Opt *o_sec; IPV4Opt *o_lsrr; IPV4Opt *o_cipso; IPV4Opt *o_sid; IPV4Opt *o_ssrr; IPV4Opt *o_rtralt; } IPV4Vars; void DecodeIPV4RegisterTests(void); /** ----- Inline functions ----- */ static inline uint16_t IPV4CalculateChecksum(uint16_t *, uint16_t); /** * \brief Calculates the checksum for the IP packet * * \param pkt Pointer to the start of the IP packet * \param hlen Length of the IP header * * \retval csum Checksum for the IP packet */ static inline uint16_t IPV4CalculateChecksum(uint16_t *pkt, uint16_t hlen) { uint32_t csum = pkt[0]; csum += pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + pkt[8] + pkt[9]; hlen -= 20; pkt += 10; if (hlen == 0) { ; } else if (hlen == 4) { csum += pkt[0] + pkt[1]; } else if (hlen == 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; } else if (hlen == 12) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5]; } else if (hlen == 16) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7]; } else if (hlen == 20) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9]; } else if (hlen == 24) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11]; } else if (hlen == 28) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13]; } else if (hlen == 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; } else if (hlen == 36) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15] + pkt[16] + pkt[17]; } else if (hlen == 40) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15] + pkt[16] + pkt[17] + pkt[18] + pkt[19]; } csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); return (uint16_t) ~csum; } #endif /* __DECODE_IPV4_H__ */ suricata-1.4.7/src/win32-service.h0000644000000000000000000000211212253546156013572 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Ondrej Slanina */ #ifndef __WIN32_SERVICE_H__ #define __WIN32_SERVICE_H__ #ifdef OS_WIN32 int SCRunningAsService(void); int SCServiceInit(int argc, char **argv); int SCServiceInstall(int argc, char **argv); int SCServiceRemove(int argc, char **argv); int SCServiceChangeParams(int argc, char **argv); #endif /* OS_WIN32 */ #endif suricata-1.4.7/src/detect-urilen.h0000644000000000000000000000302412253546156013741 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh */ #ifndef _DETECT_URILEN_H #define _DETECT_URILEN_H #define DETECT_URILEN_LT 0 /**< "less than" operator */ #define DETECT_URILEN_GT 1 /**< "greater than" operator */ #define DETECT_URILEN_RA 2 /**< range operator */ #define DETECT_URILEN_EQ 3 /**< equal operator */ typedef struct DetectUrilenData_ { uint16_t urilen1; /**< 1st Uri Length value in the signature*/ uint16_t urilen2; /**< 2nd Uri Length value in the signature*/ uint8_t mode; /**< operator used in the signature */ uint8_t raw_buffer; }DetectUrilenData; int DetectUrilenMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); void DetectUrilenRegister(void); #endif /* _DETECT_URILEN_H */ suricata-1.4.7/src/stream-tcp-private.h0000644000000000000000000001763112253546156014735 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __STREAM_TCP_PRIVATE_H__ #define __STREAM_TCP_PRIVATE_H__ #include "decode.h" typedef struct StreamTcpSackRecord_ { uint32_t le; /**< left edge, host order */ uint32_t re; /**< right edge, host order */ struct StreamTcpSackRecord_ *next; } StreamTcpSackRecord; typedef struct TcpSegment_ { uint8_t *payload; uint16_t payload_len; /**< actual size of the payload */ uint16_t pool_size; /**< size of the memory */ uint32_t seq; struct TcpSegment_ *next; struct TcpSegment_ *prev; uint8_t flags; } TcpSegment; typedef struct TcpStream_ { uint16_t flags; /**< Flag specific to the stream e.g. Timestamp */ uint8_t wscale; /**< wscale setting in this direction */ uint8_t os_policy; /**< target based OS policy used for reassembly and handling packets*/ uint32_t isn; /**< initial sequence number */ uint32_t next_seq; /**< next expected sequence number */ uint32_t last_ack; /**< last ack'd sequence number in this stream */ uint32_t next_win; /**< next max seq within window */ uint32_t window; /**< current window setting, after wscale is applied */ uint32_t last_ts; /**< Time stamp (TSVAL) of the last seen packet for this stream*/ uint32_t last_pkt_ts; /**< Time of last seen packet for this stream (needed for PAWS update) This will be used to validate the last_ts, when connection has been idle for longer time.(RFC 1323)*/ /* reassembly */ uint32_t ra_app_base_seq; /**< reassembled seq. We've reassembled up to this point. */ uint32_t ra_raw_base_seq; /**< reassembled seq. We've reassembled up to this point. */ TcpSegment *seg_list; /**< list of TCP segments that are not yet (fully) used in reassembly */ TcpSegment *seg_list_tail; /**< Last segment in the reassembled stream seg list*/ StreamTcpSackRecord *sack_head; /**< head of list of SACK records */ StreamTcpSackRecord *sack_tail; /**< tail of list of SACK records */ } TcpStream; /* from /usr/include/netinet/tcp.h */ enum { TCP_NONE, TCP_LISTEN, TCP_SYN_SENT, TCP_SYN_RECV, TCP_ESTABLISHED, TCP_FIN_WAIT1, TCP_FIN_WAIT2, TCP_TIME_WAIT, TCP_LAST_ACK, TCP_CLOSE_WAIT, TCP_CLOSING, TCP_CLOSED, }; /* * Per SESSION flags */ /** Flag for mid stream session */ #define STREAMTCP_FLAG_MIDSTREAM 0x0001 /** Flag for mid stream established session */ #define STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED 0x0002 /** Flag for mid session when syn/ack is received */ #define STREAMTCP_FLAG_MIDSTREAM_SYNACK 0x0004 /** Flag for TCP Timestamp option */ #define STREAMTCP_FLAG_TIMESTAMP 0x0008 /** Server supports wscale (even though it can be 0) */ #define STREAMTCP_FLAG_SERVER_WSCALE 0x0010 /** Flag to indicate the zero value of timestamp */ #define STREAMTCP_FLAG_ZERO_TIMESTAMP 0x0020 /** Flag to indicate that the session is handling asynchronous stream.*/ #define STREAMTCP_FLAG_ASYNC 0x0040 /** Flag to indicate we're dealing with 4WHS: SYN, SYN, SYN/ACK, ACK * (http://www.breakingpointsystems.com/community/blog/tcp-portals-the-three-way-handshake-is-a-lie) */ #define STREAMTCP_FLAG_4WHS 0x0080 /** Flag to indicate the app layer has detected the app layer protocol on * the current TCP session */ #define STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED 0x0100 /** Flag to indicate that this session is possible trying to evade the detection * (http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html) */ #define STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT 0x0200 /** Flag to indicate the client (SYN pkt) permits SACK */ #define STREAMTCP_FLAG_CLIENT_SACKOK 0x0400 /** Flag to indicate both sides of the session permit SACK (SYN + SYN/ACK) */ #define STREAMTCP_FLAG_SACKOK 0x0800 /** Flag for triggering RAW reassembly before the size limit is reached or the stream reaches EOF. */ #define STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY 0x1000 /** 3WHS confirmed by server -- if suri sees 3whs ACK but server doesn't (pkt * is lost on the way to server), SYN/ACK is retransmitted. If server sends * normal packet we assume 3whs to be completed. Only used for SYN/ACK resend * event. */ #define STREAMTCP_FLAG_3WHS_CONFIRMED 0x2000 /* * Per STREAM flags */ /** stream is in a gap state */ #define STREAMTCP_STREAM_FLAG_GAP 0x01 /** Flag to avoid stream reassembly/app layer inspection for the stream */ #define STREAMTCP_STREAM_FLAG_NOREASSEMBLY 0x02 /** Flag to pause stream reassembly / app layer inspection for the stream.*/ #define STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY 0x04 /** Stream has reached it's reassembly depth, all further packets are ignored */ #define STREAMTCP_STREAM_FLAG_DEPTH_REACHED 0x08 /** Stream has sent a FIN/RST */ #define STREAMTCP_STREAM_FLAG_CLOSE_INITIATED 0x10 /* * Per SEGMENT flags */ /** Flag to indicate that the current segment has been processed by the * reassembly code and should be deleted after app layer protocol has been * detected. */ #define SEGMENTTCP_FLAG_RAW_PROCESSED 0x01 /** App Layer reassembly code is done with this segment */ #define SEGMENTTCP_FLAG_APPLAYER_PROCESSED 0x02 #define PAWS_24DAYS 2073600 /**< 24 days in seconds */ #define PKT_IS_IN_RIGHT_DIR(ssn, p) ((ssn)->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK ? \ PKT_IS_TOSERVER(p) ? (p)->flowflags &= ~FLOW_PKT_TOSERVER \ (p)->flowflags |= FLOW_PKT_TOCLIENT : (p)->flowflags &= ~FLOW_PKT_TOCLIENT \ (p)->flowflags |= FLOW_PKT_TOSERVER : 0) /* Macro's for comparing Sequence numbers * Page 810 from TCP/IP Illustrated, Volume 2. */ #define SEQ_EQ(a,b) ((int32_t)((a) - (b)) == 0) #define SEQ_LT(a,b) ((int32_t)((a) - (b)) < 0) #define SEQ_LEQ(a,b) ((int32_t)((a) - (b)) <= 0) #define SEQ_GT(a,b) ((int32_t)((a) - (b)) > 0) #define SEQ_GEQ(a,b) ((int32_t)((a) - (b)) >= 0) #define STREAMTCP_SET_RA_BASE_SEQ(stream, seq) { \ do { \ (stream)->ra_raw_base_seq = (seq); \ (stream)->ra_app_base_seq = (seq); \ } while(0); \ } #define StreamTcpSetEvent(p, e) { \ SCLogDebug("setting event %"PRIu8" on pkt %p (%"PRIu64")", (e), p, (p)->pcap_cnt); \ ENGINE_SET_EVENT((p), (e)); \ } typedef struct TcpSession_ { uint8_t state; uint16_t flags; TcpStream server; TcpStream client; struct StreamMsg_ *toserver_smsg_head; /**< list of stream msgs (for detection inspection) */ struct StreamMsg_ *toserver_smsg_tail; /**< list of stream msgs (for detection inspection) */ struct StreamMsg_ *toclient_smsg_head; /**< list of stream msgs (for detection inspection) */ struct StreamMsg_ *toclient_smsg_tail; /**< list of stream msgs (for detection inspection) */ } TcpSession; #endif /* __STREAM_TCP_PRIVATE_H__ */ suricata-1.4.7/src/util-magic.c0000644000000000000000000004501712253546156013233 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Wrappers and tests for libmagic usage. * * Libmagic's API is not thread safe. The data the pointer returned by * magic_buffer is overwritten by the next magic_buffer call. This is * why we need to lock calls and copy the returned string. */ #include "suricata-common.h" #include "conf.h" #include "util-unittest.h" #include static magic_t g_magic_ctx = NULL; static SCMutex g_magic_lock; /** * \brief Initialize the "magic" context. */ int MagicInit(void) { BUG_ON(g_magic_ctx != NULL); SCEnter(); char *filename = NULL; FILE *fd = NULL; SCMutexInit(&g_magic_lock, NULL); SCMutexLock(&g_magic_lock); g_magic_ctx = magic_open(0); if (g_magic_ctx == NULL) { SCLogError(SC_ERR_MAGIC_OPEN, "magic_open failed: %s", magic_error(g_magic_ctx)); goto error; } (void)ConfGet("magic-file", &filename); if (filename != NULL) { SCLogInfo("using magic-file %s", filename); if ( (fd = fopen(filename, "r")) == NULL) { SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } fclose(fd); } if (magic_load(g_magic_ctx, filename) != 0) { SCLogError(SC_ERR_MAGIC_LOAD, "magic_load failed: %s", magic_error(g_magic_ctx)); goto error; } SCMutexUnlock(&g_magic_lock); SCReturnInt(0); error: if (g_magic_ctx != NULL) { magic_close(g_magic_ctx); g_magic_ctx = NULL; } SCMutexUnlock(&g_magic_lock); SCReturnInt(-1); } /** * \brief Find the magic value for a buffer. * * \param buf the buffer * \param buflen length of the buffer * * \retval result pointer to null terminated string */ char *MagicGlobalLookup(uint8_t *buf, uint32_t buflen) { const char *result = NULL; char *magic = NULL; SCMutexLock(&g_magic_lock); if (buf != NULL && buflen > 0) { result = magic_buffer(g_magic_ctx, (void *)buf, (size_t)buflen); if (result != NULL) { magic = SCStrdup(result); if (magic == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup magic"); } } } SCMutexUnlock(&g_magic_lock); SCReturnPtr(magic, "const char"); } /** * \brief Find the magic value for a buffer. * * \param buf the buffer * \param buflen length of the buffer * * \retval result pointer to null terminated string */ char *MagicThreadLookup(magic_t *ctx, uint8_t *buf, uint32_t buflen) { const char *result = NULL; char *magic = NULL; if (buf != NULL && buflen > 0) { result = magic_buffer(*ctx, (void *)buf, (size_t)buflen); if (result != NULL) { magic = SCStrdup(result); if (magic == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup magic"); } } } SCReturnPtr(magic, "const char"); } void MagicDeinit(void) { SCMutexLock(&g_magic_lock); if (g_magic_ctx != NULL) { magic_close(g_magic_ctx); g_magic_ctx = NULL; } SCMutexUnlock(&g_magic_lock); SCMutexDestroy(&g_magic_lock); } #ifdef UNITTESTS #ifndef OS_FREEBSD #define MICROSOFT_OFFICE_DOC "Microsoft Office Document" #else #define MICROSOFT_OFFICE_DOC "OLE 2 Compound Document" #endif /** \test magic lib calls -- init */ int MagicInitTest01(void) { magic_t magic_ctx; magic_ctx = magic_open(0); if (magic_load(magic_ctx, NULL) == -1) return 0; magic_close(magic_ctx); return 1; } /** \test magic init through api */ int MagicInitTest02(void) { if (g_magic_ctx != NULL) { printf("g_magic_ctx != NULL at start of the test: "); return 0; } MagicInit(); if (g_magic_ctx == NULL) { printf("g_magic_ctx == NULL: "); return 0; } MagicDeinit(); if (g_magic_ctx != NULL) { printf("g_magic_ctx != NULL at end of the test: "); return 0; } return 1; } /** \test magic lib calls -- lookup */ int MagicDetectTest01(void) { magic_t magic_ctx; char *result = NULL; char buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a}; size_t buffer_len = sizeof(buffer); int retval = 0; magic_ctx = magic_open(0); if (magic_load(magic_ctx, NULL) == -1) return 0; result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); if (result == NULL || strncmp(result, "PDF document", 12) != 0) { printf("result %p:%s, not \"PDF document\": ", result,result?result:"(null)"); goto end; } retval = 1; end: magic_close(magic_ctx); return retval; } /** \test magic lib calls -- lookup */ int MagicDetectTest02(void) { magic_t magic_ctx; char *result = NULL; char buffer[] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xfe, 0xff, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; size_t buffer_len = sizeof(buffer); int retval = 0; magic_ctx = magic_open(0); if (magic_load(magic_ctx, NULL) == -1) return 0; result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); if (result == NULL || strcmp(result, MICROSOFT_OFFICE_DOC) != 0) { printf("result %p:%s, not \"Microsoft Office Document\": ", result,result?result:"(null)"); goto end; } retval = 1; end: magic_close(magic_ctx); return retval; } /** \test magic lib calls -- lookup */ int MagicDetectTest03(void) { magic_t magic_ctx; char *result = NULL; char buffer[] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6, 0x32, 0x0c, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x62, 0x61, 0x72, 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, }; size_t buffer_len = sizeof(buffer); int retval = 0; magic_ctx = magic_open(0); if (magic_load(magic_ctx, NULL) == -1) return 0; result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); if (result == NULL || strcmp(result, "OpenDocument Text") != 0) { printf("result %p:%s, not \"OpenDocument Text\": ", result,result?result:"(null)"); goto end; } retval = 1; end: magic_close(magic_ctx); return retval; } /** \test magic lib calls -- lookup */ int MagicDetectTest04(void) { magic_t magic_ctx; char *result = NULL; char buffer[] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x8b, 0x70, 0x96, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46, 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, 0x08, 0x00, 0xa8, 0x42, 0x1d, 0x37, 0x5d, 0xa7, 0xb2, 0xc1, 0xde, 0x01, 0x00, 0x00, 0x7e, 0x04, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x78, 0x6d, 0x6c, 0x95, 0x54, 0x4d, 0x6f, 0xdb, 0x30, 0x0c, 0xbd, 0xe7, 0x57, 0x18, 0x02, 0x06, 0x6c, 0x07, 0xc5, 0xe9, 0xb6, 0xc3, 0x22, 0xc4, 0x29, 0x86, 0x7d, 0x00, 0x05, 0x8a, 0x9d, 0xb2, 0x43, 0x8f, 0xb2, 0x24, 0xa7, 0xc2, 0x64, 0xc9, 0x15, }; size_t buffer_len = sizeof(buffer); int retval = 0; magic_ctx = magic_open(0); if (magic_load(magic_ctx, NULL) == -1) return 0; result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); if (result == NULL || strcmp(result, "OpenOffice.org 1.x Database file") != 0) { printf("result %p:%s, not \"OpenOffice.org 1.x Database file\": ", result,result?result:"(null)"); goto end; } retval = 1; end: magic_close(magic_ctx); return retval; } /** \test magic api calls -- lookup */ int MagicDetectTest05(void) { const char *result = NULL; uint8_t buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a}; size_t buffer_len = sizeof(buffer); int retval = 0; MagicInit(); result = MagicGlobalLookup(buffer, buffer_len); if (result == NULL || strncmp(result, "PDF document", 12) != 0) { printf("result %p:%s, not \"PDF document\": ", result,result?result:"(null)"); goto end; } retval = 1; end: MagicDeinit(); return retval; } /** \test magic api calls -- lookup */ int MagicDetectTest06(void) { const char *result = NULL; uint8_t buffer[] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xfe, 0xff, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; size_t buffer_len = sizeof(buffer); int retval = 0; MagicInit(); result = MagicGlobalLookup(buffer, buffer_len); if (result == NULL || strcmp(result, MICROSOFT_OFFICE_DOC) != 0) { printf("result %p:%s, not \"Microsoft Office Document\": ", result,result?result:"(null)"); goto end; } retval = 1; end: MagicDeinit(); return retval; } /** \test magic api calls -- lookup */ int MagicDetectTest07(void) { const char *result = NULL; uint8_t buffer[] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6, 0x32, 0x0c, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x62, 0x61, 0x72, 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, }; size_t buffer_len = sizeof(buffer); int retval = 0; MagicInit(); result = MagicGlobalLookup(buffer, buffer_len); if (result == NULL || strcmp(result, "OpenDocument Text") != 0) { printf("result %p:%s, not \"OpenDocument Text\": ", result,result?result:"(null)"); goto end; } retval = 1; end: MagicDeinit(); return retval; } /** \test magic api calls -- lookup */ int MagicDetectTest08(void) { const char *result = NULL; uint8_t buffer[] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x8b, 0x70, 0x96, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46, 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, 0x08, 0x00, 0xa8, 0x42, 0x1d, 0x37, 0x5d, 0xa7, 0xb2, 0xc1, 0xde, 0x01, 0x00, 0x00, 0x7e, 0x04, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x78, 0x6d, 0x6c, 0x95, 0x54, 0x4d, 0x6f, 0xdb, 0x30, 0x0c, 0xbd, 0xe7, 0x57, 0x18, 0x02, 0x06, 0x6c, 0x07, 0xc5, 0xe9, 0xb6, 0xc3, 0x22, 0xc4, 0x29, 0x86, 0x7d, 0x00, 0x05, 0x8a, 0x9d, 0xb2, 0x43, 0x8f, 0xb2, 0x24, 0xa7, 0xc2, 0x64, 0xc9, 0x15, }; size_t buffer_len = sizeof(buffer); int retval = 0; MagicInit(); result = MagicGlobalLookup(buffer, buffer_len); if (result == NULL || strcmp(result, "OpenOffice.org 1.x Database file") != 0) { printf("result %p:%s, not \"OpenOffice.org 1.x Database file\": ", result,result?result:"(null)"); goto end; } retval = 1; end: MagicDeinit(); return retval; } /** \test magic api calls -- make sure memory is shared */ int MagicDetectTest09(void) { const char *result1 = NULL; const char *result2 = NULL; uint8_t buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a}; size_t buffer_len = sizeof(buffer); int retval = 0; MagicInit(); result1 = MagicGlobalLookup(buffer, buffer_len); if (result1 == NULL || strncmp(result1, "PDF document", 12) != 0) { printf("result %p:%s, not \"PDF document\": ", result1,result1?result1:"(null)"); goto end; } result2 = MagicGlobalLookup(buffer, buffer_len); if (result2 == NULL || strncmp(result2, "PDF document", 12) != 0) { printf("result %p:%s, not \"PDF document\": ", result2,result2?result2:"(null)"); goto end; } if (result1 != result2) { printf("pointers not equal, weird... %p != %p: ", result1, result2); goto end; } retval = 1; end: MagicDeinit(); return retval; } /** \test results in valgrind warning about invalid read, tested with * file 5.09 and 5.11 */ static int MagicDetectTest10ValgrindError(void) { const char *result = NULL; uint8_t buffer[] = { 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2C, 0x01,0x2C,0x00,0x00,0xFF,0xFE,0x00,0x4C,0x53,0x69,0x67,0x6E,0x61,0x74,0x75,0x72, 0x65,0x3A,0x34,0x31,0x31,0x65,0x33,0x38,0x61,0x61,0x61,0x31,0x37,0x65,0x33,0x30, 0x66,0x30,0x32,0x38,0x62,0x61,0x30,0x31,0x36,0x32,0x36,0x37,0x66,0x66,0x30,0x31, 0x36,0x36,0x61,0x65,0x35,0x39,0x65,0x38,0x31,0x39,0x62,0x61,0x32,0x34,0x63,0x39, 0x62,0x31,0x33,0x37,0x33,0x62,0x31,0x61,0x35,0x61,0x38,0x65,0x64,0x63,0x36,0x30, 0x65,0x37,0xFF,0xE2,0x02,0x2C,0x49,0x43,0x43,0x5F,0x50,0x52,0x4F,0x46,0x49,0x4C, 0x45,0x00,0x01,0x01,0x00,0x00,0x02,0x1C,0x41,0x44,0x42,0x45,0x02,0x10,0x00,0x00, 0x6D,0x6E,0x74,0x72,0x52,0x47,0x42,0x20,0x58,0x59,0x5A,0x20,0x07,0xCF,0x00,0x05, 0x00,0x09,0x00,0x15,0x00,0x0B,0x00,0x21,0x61,0x63,0x73,0x70,0x41,0x50,0x50,0x4C, 0x00,0x00,0x00,0x00,0x6E,0x6F,0x6E,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; size_t buffer_len = sizeof(buffer); int retval = 0; MagicInit(); result = MagicGlobalLookup(buffer, buffer_len); if (result == NULL || strncmp(result, "JPEG", 4) != 0) { printf("result %p:%s, not \"JPEG\": ", result,result?result:"(null)"); goto end; } retval = 1; end: MagicDeinit(); return retval; } #endif /* UNITTESTS */ void MagicRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("MagicInitTest01", MagicInitTest01, 1); UtRegisterTest("MagicInitTest02", MagicInitTest02, 1); UtRegisterTest("MagicDetectTest01", MagicDetectTest01, 1); UtRegisterTest("MagicDetectTest02", MagicDetectTest02, 1); UtRegisterTest("MagicDetectTest03", MagicDetectTest03, 1); UtRegisterTest("MagicDetectTest04", MagicDetectTest04, 1); UtRegisterTest("MagicDetectTest05", MagicDetectTest05, 1); UtRegisterTest("MagicDetectTest06", MagicDetectTest06, 1); UtRegisterTest("MagicDetectTest07", MagicDetectTest07, 1); UtRegisterTest("MagicDetectTest08", MagicDetectTest08, 1); /* fails in valgrind, somehow it returns different pointers then. UtRegisterTest("MagicDetectTest09", MagicDetectTest09, 1); */ UtRegisterTest("MagicDetectTest10ValgrindError", MagicDetectTest10ValgrindError, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-cuda-handlers.c0000644000000000000000000011110512253546156014655 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file Provides cuda utility functions. * * \author Anoop Saldanha * * A module in the engine that wants to use the cuda engine, might need * some utilities to handle contexts, modules and device_pointers. * * Let us say we have a module that needs to share a context among various * sections inside it. To enable it share contexts within various * sections the module first register itself using the function * SCCudaHlRegisterModule() and receive a unique handle. Once it has * retrieved the unique handle, it can then call SCCudaHlGetCudaContext(), * with the handle. A new cuda context would be created and the internal * data structures would be updated to associate this newly created * context with this module handle. Any future calls to * SCCudaHlGetCudaContext() with the same handle will return the * cuda_context, which has already been created and associated with the * handle. Any calls to SCCudaHlGetCudaContext() with a new handle, * would result in the creation of a new cuda context. * * Similarly if we want to create a new cuda_module against a particular * context, we can call SCCudaHlGetCudaModule() with the handle and it * should work as above. Please do note that a cuda module can't be * created against a handle using SCCudaHlGetCudaModule(), unless * a cuda_context has been associated with the handle by a previous call * to SCCudaHlGetCudaContext(). Also do note that, a cuda module is * created against a cuda context that is associated with the current * host thread. So do takecare to associate your host thread with the * cuda_context that is associated with the handle, against which you * want to call SCCudaHlGetCudaModule(). * * \todo Provide support for multiple cuda context storage, although it is * highly unlikely we would need this feature. * * We also need to use a mutex for module_data. */ #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "decode.h" #include "util-cuda.h" #include "util-cuda-handlers.h" #include "util-mpm-b2g-cuda.h" #include "tmqh-simple.h" #include "conf.h" #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" #include "packet-queue.h" #include "util-mpm.h" /* macros decides if cuda is enabled for the platform or not */ #ifdef __SC_CUDA_SUPPORT__ /* file only exists if cuda is enabled */ #include "cuda-ptxdump.h" static SCCudaHlModuleData *module_data = NULL; static uint8_t module_handle = 1; /* holds the parsed cuda configuration from our yaml file */ static SCCudaHlCudaProfile *cuda_profiles = NULL; /* used by unittests only */ static SCCudaHlCudaProfile *backup_cuda_profiles = NULL; /** * \brief Needed by unittests. Backup the existing cuda profile in handlers. */ void SCCudaHlBackupRegisteredProfiles(void) { backup_cuda_profiles = cuda_profiles; cuda_profiles = NULL; return; } /** * \brief Needed by unittests. Restore the previous backup of handlers' * cuda profile. */ void SCCudaHlRestoreBackupRegisteredProfiles(void) { cuda_profiles = backup_cuda_profiles; return; } /** * \brief Parse the "cuda" subsection config from our conf file. */ void SCCudaHlGetYamlConf(void) { SCCudaHlCudaProfile *profile = NULL; /* "mpm" profile, found under "cuda.mpm" in the conf file */ profile = SCMalloc(sizeof(SCCudaHlCudaProfile)); if (unlikely(profile == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(profile, 0, sizeof(SCCudaHlCudaProfile)); profile->name = "mpm"; profile->data = MpmCudaConfParse(); if (cuda_profiles == NULL) { cuda_profiles = profile; } else { profile->next = cuda_profiles; cuda_profiles = profile; } return; } /** * \brief Get a particular cuda profile specified as arg. * * \param profile_name Name of the the profile to retrieve. * * \retval Data associated with the profile. */ void *SCCudaHlGetProfile(char *profile_name) { SCCudaHlCudaProfile *profile = cuda_profiles; if (cuda_profiles == NULL ) { SCLogInfo("No cuda profile registered"); return NULL; } if (profile_name == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "argument profile NULL"); return NULL; } while (profile != NULL && strcasecmp(profile->name, profile_name) != 0) { profile = profile->next; } if (profile != NULL) return profile->data; else return NULL; } /** * \brief Clean the cuda profiles, held in cuda_profiles. */ void SCCudaHlCleanProfiles(void) { SCCudaHlCudaProfile *profile = cuda_profiles; SCCudaHlCudaProfile *profile_next = NULL; while (profile != NULL) { profile_next = profile->next; if (profile->data != NULL) { if (strcasecmp(profile->name, "mpm") == 0) { MpmCudaConfCleanup(profile->data); } } SCFree(profile); profile = profile_next; } cuda_profiles = NULL; return; } /** * \internal * \brief Get a unique handle for a new module registration. This new handle * returned uniquely represents a module. All future calls to functions * requires suppling this handle. * * \param module_handle A unique module handle that needs to used to refer * to data(like cuda_contexts, cuda_modules, device pointers). */ static int SCCudaHlGetUniqueHandle(void) { return module_handle++; } /** * \internal * \brief Returns a SCCudaHlModuleData instance from the global data store * that matches the handle sent as arg. * * \param handle The handle for the SCCudaHlModuleData that has to be returned. * * \retval data The SCCudaHlModuleData instance that matches the handle. */ SCCudaHlModuleData *SCCudaHlGetModuleData(uint8_t handle) { SCCudaHlModuleData *data = module_data; if (data == NULL) return NULL; while (data != NULL && data->handle != handle) { data = data->next; } return data; } /** * \internal * \brief Returns a SCCudaHlModuleCUmodule instance that matches the cumodule_handle * from a SCCudaHlModuleData. * * \param data The module data this CUmodule belongs to, obtained by a call to * SCCudaHlGetModuleData() * \param cumodule_handle The handle for the SCCudaHlModuleCUmodule that has to be returned. * * \retval The SCCudaHlModuleCUmodule instance that matches the handle. */ static SCCudaHlModuleCUmodule *SCCudaHlGetModuleCUmodule(SCCudaHlModuleData *data, uint8_t cumodule_handle) { SCCudaHlModuleCUmodule *cumodule = NULL; if (data == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Argument data cannot be NULL"); return NULL; } cumodule = data->cuda_modules; if (cumodule == NULL) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "No cumodule registered by the cumodule_handle %"PRIu8, cumodule_handle); return NULL; } while (cumodule != NULL && cumodule->cuda_module_handle != cumodule_handle) { cumodule = cumodule->next; } return cumodule; } /** * \brief Returns a cuda_module against the handle in the argument. * * If a cuda_module is not present for a handle, it is created * and associated with this handle and the cuda_module is returned * in the argument. * * \param p_module Pointer to a cuda module instance that should be updated * with a cuda module. * \param handle A unique handle which identifies a module. Obtained from * a call to SCCudaHlGetUniqueHandle(). * * \retval A unique handle within the module that is associated with the * loaded CUmodule. Needed for future API calls. * \retval -1 on failure. */ int SCCudaHlGetCudaModuleFromFile(CUmodule *p_module, const char *filename, int handle) { SCCudaHlModuleData *data = NULL; SCCudaHlModuleCUmodule *new_module_cumodule = NULL; SCCudaHlModuleCUmodule *module_cumodules = NULL; if (p_module == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Error invalid arguments" "p_module NULL"); return -1; } /* check if the particular module that wants a CUDA module is already * registered or not. If it is registered, check if a context has * been associated with the module. If yes, then we can go ahead and * create a cuda module and associate it with the module referenced by * the handle in the functions arguments. If no, log warning and get * out of here */ if ( ((data = SCCudaHlGetModuleData(handle)) == NULL) || (data->cuda_context == 0)) { SCLogDebug("Module not registered or no cuda context associated with " "this module. You can't create a CUDA module without" "associating a context with a module first. To use this " "registration facility, first register a module using " "context using SCCudaHlRegisterModule(), and then register " "a cuda context with that module using " "SCCudaHlGetCudaContext(), after which you can call this " "function "); return -1; } /* Register new CUmodule in the module */ new_module_cumodule = SCMalloc(sizeof(SCCudaHlModuleCUmodule)); if (unlikely(new_module_cumodule == NULL)) { exit(EXIT_FAILURE); } memset(new_module_cumodule, 0, sizeof(SCCudaHlModuleCUmodule)); /* Create a cuda module, update the module with this cuda module reference * and then return the module reference back to the calling function using * the argument */ if (SCCudaModuleLoad(p_module, filename) == -1) goto error; new_module_cumodule->cuda_module = p_module[0]; new_module_cumodule->cuda_module_handle = SCCudaHlGetUniqueHandle(); /* insert it into the cuda_modules list for the module instance */ if (data->cuda_modules == NULL) { data->cuda_modules = new_module_cumodule; return new_module_cumodule->cuda_module_handle; } module_cumodules = data->cuda_modules; while (module_cumodules->next != NULL) module_cumodules = module_cumodules->next; module_cumodules->next = new_module_cumodule; return new_module_cumodule->cuda_module_handle; error: return -1; } /** * \brief Returns a cuda context against the handle in the argument. * * If a cuda_context is not present for a handle, it is created * and associated with this handle and the context is returned * in the argument. If a cuda_context is already present for * a handle, it is returned. * * \param p_context Pointer to a cuda context instance that should be updated * with a cuda context. * \param cuda_profile The cuda profile, supplied as a string. * \param handle A unique handle which identifies a module. Obtained from * a call to SCCudaHlGetUniqueHandle(). * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaHlGetCudaContext(CUcontext *p_context, char *cuda_profile, int handle) { SCCudaHlModuleData *data = NULL; SCCudaDevices *devices = NULL; if (p_context == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Error invalid arguments. " "p_context NULL"); return -1; } /* check if the particular module that wants a CUDA context * is already registered or not. If it is not registered * log a warning and get out of here */ if ( (data = SCCudaHlGetModuleData(handle)) == NULL) { SCLogDebug("Module not registered. You can't create a CUDA context " "without registering a module first. To use this " "registration facility, first register a module using " "SCCudaHlRegisterModule(), and then register " "a cuda context with that module hanle using " "SCCudaHlGetCudaContext(), after which you can call this " "function "); return -1; } if (data->cuda_context != 0) { p_context[0] = data->cuda_context; return 0; } int device_id = SC_CUDA_DEFAULT_DEVICE; if (cuda_profile != NULL) { /* Get default log level and format. */ MpmCudaConf *profile = SCCudaHlGetProfile(cuda_profile); if (profile != NULL) { if (SCCudaIsCudaDeviceIdValid(profile->device_id)) { device_id = profile->device_id; } else { SCLogError(SC_ERR_CUDA_ERROR, "Invalid device id \"%d\" supplied. " "Using the first device.", profile->device_id); } } } /* Get the device list for this CUDA platform and create a new cuda context */ devices = SCCudaGetDeviceList(); if (SCCudaCtxCreate(p_context, 0, devices->devices[device_id]->device) == -1) goto error; data->cuda_context = p_context[0]; return 0; error: return -1; } /** * \brief Returns a cuda_module against the handle in the argument. * * If a cuda_module is not present for a handle, it is created * and associated with this handle and the cuda_module is returned * in the argument. * * \param p_module The loaded CUmodule that is returned. * \param ptx_image Name of the module source file, w/o the .cu extension * \param handle A unique handle which identifies a module. Obtained from * a call to SCCudaHlGetUniqueHandle(). * * \retval A unique handle within the module that is associated with the * loaded CUmodule. Needed for future API calls. * \retval -1 on failure. */ int SCCudaHlGetCudaModule(CUmodule *p_module, const char *ptx_image, int handle) { SCCudaHlModuleData *data = NULL; SCCudaHlModuleCUmodule *new_module_cumodule = NULL; SCCudaHlModuleCUmodule *module_cumodules = NULL; if (p_module == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Error invalid arguments" "p_module NULL"); return -1; } /* check if the particular module that wants a CUDA module is already * registered or not. If it is registered, check if a context has * been associated with the module. If yes, then we can go ahead and * create a cuda module and associate it with the module referenced by * the handle in the functions arguments. If no, log warning and get * out of here */ if ( ((data = SCCudaHlGetModuleData(handle)) == NULL) || (data->cuda_context == 0)) { SCLogDebug("Module not registered or no cuda context associated with " "this module. You can't create a CUDA module without" "associating a context with a module first. To use this " "registration facility, first register a module using " "context using SCCudaHlRegisterModule(), and then register " "a cuda context with that module using " "SCCudaHlGetCudaContext(), after which you can call this " "function "); return -1; } /* Register new CUmodule in the module */ new_module_cumodule = SCMalloc(sizeof(SCCudaHlModuleCUmodule)); if (unlikely(new_module_cumodule == NULL)) { exit(EXIT_FAILURE); } memset(new_module_cumodule, 0, sizeof(SCCudaHlModuleCUmodule)); /* select the ptx image based on the compute capability supported by all * devices (i.e. the lowest) */ char* image = SCMalloc(strlen(ptx_image)+15); if (unlikely(image == NULL)) { exit(EXIT_FAILURE); } memset(image, 0x0, strlen(ptx_image)+15); int major = INT_MAX; int minor = INT_MAX; SCCudaDevices *devices = SCCudaGetDeviceList(); int i=0; for (; icount; i++){ if (devices->devices[i]->major_rev < major){ major = devices->devices[i]->major_rev; minor = devices->devices[i]->minor_rev; } if (devices->devices[i]->major_rev == major && devices->devices[i]->minor_rev < minor){ minor = devices->devices[i]->minor_rev; } } snprintf(image, strlen(ptx_image) + 15, "%s_sm_%u%u", ptx_image, major, minor); /* we don't have a cuda module associated with this module. Create a * cuda module, update the module with this cuda module reference and * then return the module refernce back to the calling function using * the argument */ SCLogDebug("Loading kernel module: %s\n",image); if (SCCudaModuleLoadData(p_module, (void *)SCCudaPtxDumpGetModule(image)) == -1) goto error; SCFree(image); new_module_cumodule->cuda_module = p_module[0]; new_module_cumodule->cuda_module_handle = SCCudaHlGetUniqueHandle(); /* insert it into the cuda_modules list for the module instance */ if (data->cuda_modules == NULL) { data->cuda_modules = new_module_cumodule; return new_module_cumodule->cuda_module_handle; } module_cumodules = data->cuda_modules; while (module_cumodules->next != NULL) module_cumodules = module_cumodules->next; module_cumodules->next = new_module_cumodule; return new_module_cumodule->cuda_module_handle; error: SCFree(image); return -1; } /** * \brief Verify if a device pointer by a particular name is registered under * a module. If it is registered, return this device pointer instance * back; else return NULL. * * \param data Pointer to the module SCCudaHlModuleData instance which has to * checked for the registration of the device pointer. * \param name Name of the device pointer to search in the module. * * \retval module_device_ptr Pointer to the device pointer instance on finding * it; NULL otherwise. */ SCCudaHlModuleDevicePointer *SCCudaHlCudaDevicePtrAvailable(SCCudaHlModuleCUmodule *cumodule, const char *name) { SCCudaHlModuleDevicePointer *module_device_ptr = cumodule->device_ptrs; while (module_device_ptr != NULL && strcmp(module_device_ptr->name, name) != 0) { module_device_ptr = module_device_ptr->next; } return module_device_ptr; } /** * \brief Returns a cuda_device_pointer against the handle in the argument. * * If a device pointer by the name \"name\" is not registered for the * handle, it is created and associated with this handle and cuda mem is * alloted and the cuda_device_pointer is returned in the argument. * If a device pointer by the name \"name\" is already registered with * the handle, the cuda_device_pointer is returned in the argument. * * \param device_ptr Pointer to the device pointer instance which should be * with the cuda_device_pointer that has to be returned back. * \param name Name of the device pointer by which we have to search * module for its existance. * \param size Size of the cuda device memory to be alloted. * \param host_ptr If any host memory has to be transferred to the cuda device * memory, it can sent using this argument. host_ptr should * hold atleast size bytes in memory. * \param handle A unique handle which identifies a module. Obtained from * a call to SCCudaHlGetUniqueHandle(). * \param cumodule_handle A handle that identifies the CUmodule within the above module. * Obtained from a call to SCCudaHlGetCudaModule() or * SCCudaHlGetCudaModuleFromFile(). * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaHlGetCudaDevicePtr(CUdeviceptr *device_ptr, const char *name, size_t size, void *host_ptr, int handle, int cumodule_handle) { SCCudaHlModuleData *data = NULL; SCCudaHlModuleCUmodule *cumodule = NULL; SCCudaHlModuleDevicePointer *new_module_device_ptr = NULL; SCCudaHlModuleDevicePointer *module_device_ptr = NULL; if (device_ptr == NULL || name == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Error invalid arguments" "device_ptr is NULL or name is NULL"); goto error; } /* check if the particular module that wants to allocate device memory is * already registered or not. If it is registered, check if a context has * been associated with the module. If yes, then we can go ahead and * create the device memory or return the reference to the device memory if * we already have the device memory associated with the module. If no, " * log warning and get out of here */ if ( ((data = SCCudaHlGetModuleData(handle)) == NULL) || (data->cuda_context == 0)) { SCLogDebug("Module not registered or no cuda context associated with " "this module. You can't create a CUDA module without" "associating a context with a module first. To use this " "registration facility, first register a module using " "context using SCCudaHlRegisterModule(), and then register " "a cuda context with that module using " "SCCudaHlGetCudaContext(), after which you can call this " "function "); goto error; } if ( (cumodule = SCCudaHlGetModuleCUmodule(data, cumodule_handle)) == NULL ) { SCLogDebug("CUmodule not registered with the module. Before you can request" "a device pointer for a module you need to load the CUmodule into" "the engine module using SCCudaHlGetCudaModule() or" "SCCudaHlGetCudaModuleFromFile()."); goto error; } /* if we already have a device pointer registered by this name return the * cuda device pointer instance */ if ( (module_device_ptr = SCCudaHlCudaDevicePtrAvailable(cumodule, name)) != NULL) { device_ptr[0] = module_device_ptr->d_ptr; return 0; } new_module_device_ptr = SCMalloc(sizeof(SCCudaHlModuleDevicePointer)); if (unlikely(new_module_device_ptr == NULL)) goto error; memset(new_module_device_ptr, 0, sizeof(SCCudaHlModuleDevicePointer)); if ( (new_module_device_ptr->name = SCStrdup(name)) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCCudaHlGetCudaDevicePtr. Exiting..."); exit(EXIT_FAILURE); } /* allocate the cuda memory */ if (SCCudaMemAlloc(&new_module_device_ptr->d_ptr, size) == -1) goto error; /* if the user has supplied a host buffer, copy contents to the device mem */ if (host_ptr != NULL) { if (SCCudaMemcpyHtoD(new_module_device_ptr->d_ptr, host_ptr, size) == -1) { goto error; } } /* send the newly assigned device pointer back to the caller */ device_ptr[0] = new_module_device_ptr->d_ptr; /* insert it into the device_ptr list for the module instance */ if (cumodule->device_ptrs == NULL) { cumodule->device_ptrs = new_module_device_ptr; return 0; } module_device_ptr = cumodule->device_ptrs; while (module_device_ptr->next != NULL) module_device_ptr = module_device_ptr->next; module_device_ptr->next = new_module_device_ptr; return 0; error: if (new_module_device_ptr != NULL) SCFree(new_module_device_ptr); return -1; } /** * \brief Frees a Cuda Device Pointer. * * If a device pointer by the name \"name\" is registered for this * handle, it is freed. * * \param name Name of the device pointer by which we have to search * module for its existance. * \param handle A unique handle which identifies a module. Obtained from * a call to SCCudaHlGetUniqueHandle(). * \param cumodule A handle that identifies the CUmodule within the above module. * Obtained from a call to SCCudaHlGetCudaModule() or * SCCudaHlGetCudaModuleFromFile(). * \retval 0 On success. * \retval -1 On failure. */ int SCCudaHlFreeCudaDevicePtr(const char *name, int handle, int cumodule_handle) { SCCudaHlModuleData *data = NULL; SCCudaHlModuleCUmodule *cumodule = NULL; SCCudaHlModuleDevicePointer *module_device_ptr = NULL; SCCudaHlModuleDevicePointer *temp_module_device_ptr = NULL; if (name == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Error invalid arguments" "device_ptr is NULL or name is NULL"); goto error; } /* check if the particular module that wants to free device memory is * already registered or not. If it is registered, check if a context has * been associated with the module. If yes, then we can go ahead and * free the device memory. */ if ( ((data = SCCudaHlGetModuleData(handle)) == NULL) || (data->cuda_context == 0)) { SCLogDebug("Module not registered or no cuda context associated with " "this module. You can't create a CUDA module without" "associating a context with a module first. To use this " "registration facility, first register a module using " "context using SCCudaHlRegisterModule(), and then register " "a cuda context with that module using " "SCCudaHlGetCudaContext(), after which you can call this " "function "); goto error; } if ( (cumodule = SCCudaHlGetModuleCUmodule(data, cumodule_handle)) == NULL ) { SCLogDebug("CUmodule not registered with the module. Before you can request" "a device pointer for a module you need to load the CUmodule into" "the engine module using SCCudaHlGetCudaModule() or" "SCCudaHlGetCudaModuleFromFile()."); goto error; } /* if we do not have a device pointer registered by this name get out */ if ( (module_device_ptr = SCCudaHlCudaDevicePtrAvailable(cumodule, name)) == NULL) { goto error; } SCCudaMemFree(module_device_ptr->d_ptr); module_device_ptr->d_ptr = 0; if (module_device_ptr == cumodule->device_ptrs) { cumodule->device_ptrs = cumodule->device_ptrs->next; } else { temp_module_device_ptr = cumodule->device_ptrs; while (strcmp(temp_module_device_ptr->next->name, name) != 0) { temp_module_device_ptr = temp_module_device_ptr->next; } temp_module_device_ptr->next = temp_module_device_ptr->next->next; } SCFree(module_device_ptr->name); SCFree(module_device_ptr); return 0; error: return -1; } /** * \brief Registers a Dispatcher function against this handle. * * \param SCCudaHlDispFunc Pointer to a dispatcher function to be registered * for this handle. * \param handle A unique handle which identifies a module. Obtained * from a call to SCCudaHlGetUniqueHandle(). * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaHlRegisterDispatcherFunc(void *(*SCCudaHlDispFunc)(void *), int handle) { SCCudaHlModuleData *data = NULL; if (SCCudaHlDispFunc == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Error invalid arguments" "SCCudaHlDispFunc NULL"); return -1; } if ( (data = SCCudaHlGetModuleData(handle)) == NULL) { SCLogDebug("Module not registered. To avail the benefits of this " "registration facility, first register a module using " "context using SCCudaHlRegisterModule(), after which you " "can call this function"); return -1; } data->SCCudaHlDispFunc = SCCudaHlDispFunc; return 0; } /** * \brief Get the name of the module associated with the module whose handle is * sent as the arg. * * \param handle The handle of the module which has to be searched. * * \retval data->name The name of the module on finding a module that matches * the handle sent as argument; NULL on failure. */ const char *SCCudaHlGetModuleName(int handle) { SCCudaHlModuleData *data = module_data; while (data != NULL && data->handle != handle) { data = data->next; } if (data == NULL) return NULL; return data->name; } /** * \brief Get the handle associated with this module who name is sent as the arg. * * \param name The name of the module which has to be searched. * * \retval data->handle The handle to the module on finding a module that * matches the name sent as argument; -1 on failure. */ int SCCudaHlGetModuleHandle(const char *name) { SCCudaHlModuleData *data = module_data; while (data != NULL && strcmp(data->name, name) != 0) { data = data->next; } if (data == NULL) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "A cuda module by the name \"%s\" " "hasn't been registered", name); return -1; } return data->handle; } /** * \brief Register a new module. To understand what exactly these utilities are * needed for please look at the file comments. * * \param name A unique name to register the module with. No module should have * registered itself previously with this name. * * \retval handle A unique handle that is associated with this module and all * future use of API would require supplying this handle. */ int SCCudaHlRegisterModule(const char *name) { SCCudaHlModuleData *data = module_data; SCCudaHlModuleData *new_data = NULL; while (data != NULL && strcmp(data->name, name) != 0) { data = data->next; } if (data != NULL) { SCLogInfo("Module \"%s\" already registered. Returning the handle " "for the already registered module", name); return data->handle; } /* the module is not already registered. Register the module */ new_data = SCMalloc(sizeof(SCCudaHlModuleData)); if (unlikely(new_data == NULL)) { exit(EXIT_FAILURE); } memset(new_data, 0, sizeof(SCCudaHlModuleData)); if ( (new_data->name = SCStrdup(name)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } new_data->handle = SCCudaHlGetUniqueHandle(); /* first module to be registered */ if (module_data == NULL) { module_data = new_data; return new_data->handle; } /* add this new module_data instance to the global module_data list */ data = module_data; while (data->next != NULL) data = data->next; data->next = new_data; return new_data->handle; } /** * \brief DeRegister a registered module. * * \param name Name of the module to deregister. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaHlDeRegisterModule(const char *name) { SCCudaHlModuleData *data = NULL; SCCudaHlModuleData *prev_data = NULL; SCCudaHlModuleCUmodule *cumodule = NULL; SCCudaHlModuleCUmodule *temp_cumodule = NULL; SCCudaHlModuleDevicePointer *device_ptr = NULL; SCCudaHlModuleDevicePointer *temp_device_ptr = NULL; int module_handle = SCCudaHlGetModuleHandle(name); /* get the module */ data = (module_handle == -1) ? NULL : SCCudaHlGetModuleData(module_handle); /* a module by this name doesn't exist. Log Error and return */ if (data == NULL) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Module \"%s\" not " "registered", name); return -1; } /* the application must take care to check that the following cuda context * which is being freed is floating(not attached to any host thread) */ if (data->cuda_context != 0) SCCudaCtxPushCurrent(data->cuda_context); /* looks like we do have a module registered by this name. * Go through all CUmodules registered in this module and * free cuda device pointers and unload the module. */ cumodule = data->cuda_modules; while (cumodule != NULL) { /* free all device pointers */ device_ptr = cumodule->device_ptrs; while (device_ptr != NULL) { temp_device_ptr = device_ptr; device_ptr = device_ptr->next; if (SCCudaMemFree(temp_device_ptr->d_ptr) == -1) goto error; SCFree(temp_device_ptr->name); SCFree(temp_device_ptr); } cumodule->device_ptrs = NULL; /* unload the cuda module */ temp_cumodule = cumodule; cumodule = cumodule->next; if (SCCudaModuleUnload(temp_cumodule->cuda_module) == -1) goto error; SCFree(temp_cumodule); } data->cuda_modules = NULL; if (data->name != NULL) SCFree((void *)data->name); /* clean the dispatcher function registered */ data->SCCudaHlDispFunc = NULL; /* destroy the cuda context */ if (data->cuda_context != 0) { if (SCCudaCtxDestroy(data->cuda_context) == -1) goto error; } /* find the previous module data instance */ if (module_data == data) { module_data = module_data->next; } else { prev_data = module_data; while (prev_data->next != data) prev_data = prev_data->next; prev_data->next = data->next; } /* delete the module data instance */ SCFree(data); /* mission accomplished. let's go */ return 0; error: return -1; } /** * \brief DeRegister all the modules registered under cuda handlers. */ void SCCudaHlDeRegisterAllRegisteredModules(void) { SCCudaHlModuleData *data = module_data; SCCudaHlModuleData *next_data = NULL; next_data = data; while (data != NULL) { next_data = data->next; if (SCCudaHlDeRegisterModule(data->name) == -1) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Error de-registering module " "\"%s\"", data->name); } data = next_data; } module_data = NULL; return; } /** * \brief Pushes a cuda context for the calling thread. * * Before calling this function make sure that the cuda context belonging * to the registered module, is floating(not attached to any host thread). * * \param name Name of the registered module whose cuda context has to be * pushed for the calling thread. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaHlPushCudaContextFromModule(const char *name) { SCCudaHlModuleData *data = SCCudaHlGetModuleData(SCCudaHlGetModuleHandle(name)); if (data == NULL) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "No module registered by the " "name \"%s\"", name); return -1; } if (SCCudaCtxPushCurrent(data->cuda_context) == -1) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Error pushing cuda context from " "module \"%s\" for this calling thread\n", name); return -1; } return 0; } /** * \brief Used for testing purposes. Running tests with cuda enabled * requires some hacks, which is what this function does. * * \retval 1 Always. */ int SCCudaHlTestEnvCudaContextInit(void) { CUcontext context; int module_handle = SCCudaHlRegisterModule("SC_RULES_CONTENT_B2G_CUDA"); if (SCCudaHlGetCudaContext(&context, NULL, module_handle) == -1) { printf("Error getting a cuda context"); } if (SCCudaHlPushCudaContextFromModule("SC_RULES_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); } return 1; } /** * \brief Used for testing purposes. Running tests with cuda enabled * requires some hacks, which is what this function does. * * \retval 1 Always. */ int SCCudaHlTestEnvCudaContextDeInit(void) { if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } return 1; } #endif /* __SC_CUDA_SUPPORT */ suricata-1.4.7/src/host-queue.c0000644000000000000000000000555012253546156013275 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Host queue handler functions */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "host-queue.h" #include "util-error.h" #include "util-debug.h" #include "util-print.h" HostQueue *HostQueueInit (HostQueue *q) { if (q != NULL) { memset(q, 0, sizeof(HostQueue)); HQLOCK_INIT(q); } return q; } HostQueue *HostQueueNew() { HostQueue *q = (HostQueue *)SCMalloc(sizeof(HostQueue)); if (q == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in HostQueueNew. Exiting..."); exit(EXIT_SUCCESS); } q = HostQueueInit(q); return q; } /** * \brief Destroy a host queue * * \param q the host queue to destroy */ void HostQueueDestroy (HostQueue *q) { HQLOCK_DESTROY(q); } /** * \brief add a host to a queue * * \param q queue * \param h host */ void HostEnqueue (HostQueue *q, Host *h) { #ifdef DEBUG BUG_ON(q == NULL || h == NULL); #endif HQLOCK_LOCK(q); /* more hosts in queue */ if (q->top != NULL) { h->lnext = q->top; q->top->lprev = h; q->top = h; /* only host */ } else { q->top = h; q->bot = h; } q->len++; #ifdef DBG_PERF if (q->len > q->dbg_maxlen) q->dbg_maxlen = q->len; #endif /* DBG_PERF */ HQLOCK_UNLOCK(q); } /** * \brief remove a host from the queue * * \param q queue * * \retval h host or NULL if empty list. */ Host *HostDequeue (HostQueue *q) { HQLOCK_LOCK(q); Host *h = q->bot; if (h == NULL) { HQLOCK_UNLOCK(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; } #ifdef DEBUG BUG_ON(q->len == 0); #endif if (q->len > 0) q->len--; h->lnext = NULL; h->lprev = NULL; HQLOCK_UNLOCK(q); return h; } uint32_t HostQueueLen(HostQueue *q) { uint32_t len; HQLOCK_LOCK(q); len = q->len; HQLOCK_UNLOCK(q); return len; } suricata-1.4.7/src/util-byte.c0000644000000000000000000003307412253546156013116 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus * * Byte utility functions */ #include "suricata-common.h" #include "util-byte.h" #include "util-unittest.h" #include "util-debug.h" int ByteExtractUint64(uint64_t *res, int e, uint16_t len, const uint8_t *bytes) { uint64_t i64; int ret; /* Uint64 is limited to 8 bytes */ if (len > 8) { /** \todo Need standard return values */ return -1; } ret = ByteExtract(&i64, e, len, bytes); if (ret <= 0) { return ret; } *res = (uint64_t)i64; return ret; } int ByteExtractUint32(uint32_t *res, int e, uint16_t len, const uint8_t *bytes) { uint64_t i64; int ret; /* Uint32 is limited to 4 bytes */ if (len > 4) { /** \todo Need standard return values */ return -1; } ret = ByteExtract(&i64, e, len, bytes); if (ret <= 0) { return ret; } *res = (uint32_t)i64; return ret; } int ByteExtractUint16(uint16_t *res, int e, uint16_t len, const uint8_t *bytes) { uint64_t i64; int ret; /* Uint16 is limited to 2 bytes */ if (len > 2) { /** \todo Need standard return values */ return -1; } ret = ByteExtract(&i64, e, len, bytes); if (ret <= 0) { return ret; } *res = (uint16_t)i64; return ret; } int ByteExtractString(uint64_t *res, int base, uint16_t len, const char *str) { const char *ptr = str; char *endptr = NULL; /* 23 - This is the largest string (octal, with a zero prefix) that * will not overflow uint64_t. The only way this length * could be over 23 and still not overflow is if it were zero * prefixed and we only support 1 byte of zero prefix for octal. * * "01777777777777777777777" = 0xffffffffffffffff */ char strbuf[24]; if (len > 23) { SCLogError(SC_ERR_ARG_LEN_LONG, "len too large (23 max)"); return -1; } if (len) { /* Extract out the string so it can be null terminated */ memcpy(strbuf, str, len); strbuf[len] = '\0'; ptr = strbuf; } errno = 0; *res = strtoull(ptr, &endptr, base); if (errno == ERANGE) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range"); return -1; /* If there is no numeric value in the given string then strtoull(), makes endptr equals to ptr and return 0 as result */ } else if (endptr == ptr && *res == 0) { SCLogDebug("No numeric value"); return -1; } else if (endptr == ptr) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value"); return -1; } /* This will interfere with some rules that do not know the length * in advance and instead are just using the max. */ #if 0 else if (len && *endptr != '\0') { fprintf(stderr, "ByteExtractString: Extra characters following numeric value\n"); return -1; } #endif return (endptr - ptr); } int ByteExtractStringUint64(uint64_t *res, int base, uint16_t len, const char *str) { return ByteExtractString(res, base, len, str); } int ByteExtractStringUint32(uint32_t *res, int base, uint16_t len, const char *str) { uint64_t i64; int ret; ret = ByteExtractString(&i64, base, len, str); if (ret <= 0) { return ret; } *res = (uint32_t)i64; if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " "(%" PRIu64 " > %" PRIu32 ")", i64, UINT_MAX); return -1; } return ret; } int ByteExtractStringUint16(uint16_t *res, int base, uint16_t len, const char *str) { uint64_t i64; int ret; ret = ByteExtractString(&i64, base, len, str); if (ret <= 0) { return ret; } *res = (uint16_t)i64; if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " "(%" PRIu64 " > %" PRIu16 ")", i64, USHRT_MAX); return -1; } return ret; } int ByteExtractStringUint8(uint8_t *res, int base, uint16_t len, const char *str) { uint64_t i64; int ret; ret = ByteExtractString(&i64, base, len, str); if (ret <= 0) { return ret; } *res = (uint8_t)i64; if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " "(%" PRIu64 " > %" PRIu8 ")", i64, UCHAR_MAX); return -1; } return ret; } int ByteExtractStringSigned(int64_t *res, int base, uint16_t len, const char *str) { const char *ptr = str; char *endptr; /* 23 - This is the largest string (octal, with a zero prefix) that * will not overflow int64_t. The only way this length * could be over 23 and still not overflow is if it were zero * prefixed and we only support 1 byte of zero prefix for octal. * * "-0777777777777777777777" = 0xffffffffffffffff */ char strbuf[24]; if (len > 23) { SCLogError(SC_ERR_ARG_LEN_LONG, "len too large (23 max)"); return -1; } if (len) { /* Extract out the string so it can be null terminated */ memcpy(strbuf, str, len); strbuf[len] = '\0'; ptr = strbuf; } errno = 0; *res = strtoll(ptr, &endptr, base); if (errno == ERANGE) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range"); return -1; } else if (endptr == str) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value"); return -1; } /* This will interfere with some rules that do not know the length * in advance and instead are just using the max. */ #if 0 else if (len && *endptr != '\0') { fprintf(stderr, "ByteExtractStringSigned: Extra characters following numeric value\n"); return -1; } #endif //fprintf(stderr, "ByteExtractStringSigned: Extracted base %d: 0x%" PRIx64 "\n", base, *res); return (endptr - ptr); } int ByteExtractStringInt64(int64_t *res, int base, uint16_t len, const char *str) { return ByteExtractStringSigned(res, base, len, str); } int ByteExtractStringInt32(int32_t *res, int base, uint16_t len, const char *str) { int64_t i64; int ret; ret = ByteExtractStringSigned(&i64, base, len, str); if (ret <= 0) { return ret; } *res = (int32_t)i64; if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " "(%" PRIi64 " > %" PRIi32 ")\n", i64, INT_MAX); return -1; } return ret; } int ByteExtractStringInt16(int16_t *res, int base, uint16_t len, const char *str) { int64_t i64; int ret; ret = ByteExtractStringSigned(&i64, base, len, str); if (ret <= 0) { return ret; } *res = (int16_t)i64; if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " "(%" PRIi64 " > %" PRIi16 ")\n", i64, SHRT_MAX); return -1; } return ret; } int ByteExtractStringInt8(int8_t *res, int base, uint16_t len, const char *str) { int64_t i64; int ret; ret = ByteExtractStringSigned(&i64, base, len, str); if (ret <= 0) { return ret; } *res = (int8_t)i64; if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " "(%" PRIi64 " > %" PRIi8 ")\n", i64, CHAR_MAX); return -1; } return ret; } /* UNITTESTS */ #ifdef UNITTESTS static int ByteTest01 (void) { uint16_t val = 0x0102; uint16_t i16 = 0xbfbf; uint8_t bytes[2] = { 0x02, 0x01 }; int ret = ByteExtractUint16(&i16, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); if ((ret == 2) && (i16 == val)) { return 1; } return 0; } static int ByteTest02 (void) { uint16_t val = 0x0102; uint16_t i16 = 0xbfbf; uint8_t bytes[2] = { 0x01, 0x02 }; int ret = ByteExtractUint16(&i16, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); if ((ret == 2) && (i16 == val)) { return 1; } return 0; } static int ByteTest03 (void) { uint32_t val = 0x01020304; uint32_t i32 = 0xbfbfbfbf; uint8_t bytes[4] = { 0x04, 0x03, 0x02, 0x01 }; int ret = ByteExtractUint32(&i32, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); if ((ret == 4) && (i32 == val)) { return 1; } return 0; } static int ByteTest04 (void) { uint32_t val = 0x01020304; uint32_t i32 = 0xbfbfbfbf; uint8_t bytes[4] = { 0x01, 0x02, 0x03, 0x04 }; int ret = ByteExtractUint32(&i32, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); if ((ret == 4) && (i32 == val)) { return 1; } return 0; } static int ByteTest05 (void) { uint64_t val = 0x0102030405060708ULL; uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; uint8_t bytes[8] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }; int ret = ByteExtractUint64(&i64, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); if ((ret == 8) && (i64 == val)) { return 1; } return 0; } static int ByteTest06 (void) { uint64_t val = 0x0102030405060708ULL; uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; uint8_t bytes[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; int ret = ByteExtractUint64(&i64, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); if ((ret == 8) && (i64 == val)) { return 1; } return 0; } static int ByteTest07 (void) { const char *str = "1234567890"; uint64_t val = 1234567890; uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; int ret = ByteExtractStringUint64(&i64, 10, strlen(str), str); if ((ret == 10) && (i64 == val)) { return 1; } return 0; } static int ByteTest08 (void) { const char *str = "1234567890"; uint32_t val = 1234567890; uint32_t i32 = 0xbfbfbfbf; int ret = ByteExtractStringUint32(&i32, 10, strlen(str), str); if ((ret == 10) && (i32 == val)) { return 1; } return 0; } static int ByteTest09 (void) { const char *str = "12345"; uint16_t val = 12345; uint16_t i16 = 0xbfbf; int ret = ByteExtractStringUint16(&i16, 10, strlen(str), str); if ((ret == 5) && (i16 == val)) { return 1; } return 0; } static int ByteTest10 (void) { const char *str = "123"; uint8_t val = 123; uint8_t i8 = 0xbf; int ret = ByteExtractStringUint8(&i8, 10, strlen(str), str); if ((ret == 3) && (i8 == val)) { return 1; } return 0; } static int ByteTest11 (void) { const char *str = "-1234567890"; int64_t val = -1234567890; int64_t i64 = 0xbfbfbfbfbfbfbfbfULL; int ret = ByteExtractStringInt64(&i64, 10, strlen(str), str); if ((ret == 11) && (i64 == val)) { return 1; } return 0; } static int ByteTest12 (void) { const char *str = "-1234567890"; int32_t val = -1234567890; int32_t i32 = 0xbfbfbfbf; int ret = ByteExtractStringInt32(&i32, 10, strlen(str), str); if ((ret == 11) && (i32 == val)) { return 1; } return 0; } static int ByteTest13 (void) { const char *str = "-12345"; int16_t val = -12345; int16_t i16 = 0xbfbf; int ret = ByteExtractStringInt16(&i16, 10, strlen(str), str); if ((ret == 6) && (i16 == val)) { return 1; } return 0; } static int ByteTest14 (void) { const char *str = "-123"; int8_t val = -123; int8_t i8 = 0xbf; int ret = ByteExtractStringInt8(&i8, 10, strlen(str), str); if ((ret == 4) && (i8 == val)) { return 1; } return 0; } /** \test max u32 value */ static int ByteTest15 (void) { const char *str = "4294967295"; uint32_t val = 4294967295UL; uint32_t u32 = 0xffffffff; int ret = ByteExtractStringUint32(&u32, 10, strlen(str), str); if ((ret == 10) && (u32 == val)) { return 1; } return 0; } /** \test max u32 value + 1 */ static int ByteTest16 (void) { const char *str = "4294967296"; uint32_t u32 = 0; int ret = ByteExtractStringUint32(&u32, 10, strlen(str), str); if (ret != 0) { return 1; } return 0; } #endif /* UNITTESTS */ void ByteRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("ByteTest01", ByteTest01, 1); UtRegisterTest("ByteTest02", ByteTest02, 1); UtRegisterTest("ByteTest03", ByteTest03, 1); UtRegisterTest("ByteTest04", ByteTest04, 1); UtRegisterTest("ByteTest05", ByteTest05, 1); UtRegisterTest("ByteTest06", ByteTest06, 1); UtRegisterTest("ByteTest07", ByteTest07, 1); UtRegisterTest("ByteTest08", ByteTest08, 1); UtRegisterTest("ByteTest09", ByteTest09, 1); UtRegisterTest("ByteTest10", ByteTest10, 1); UtRegisterTest("ByteTest11", ByteTest11, 1); UtRegisterTest("ByteTest12", ByteTest12, 1); UtRegisterTest("ByteTest13", ByteTest13, 1); UtRegisterTest("ByteTest14", ByteTest14, 1); UtRegisterTest("ByteTest15", ByteTest15, 1); UtRegisterTest("ByteTest16", ByteTest16, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-spm-bs2bm.h0000644000000000000000000000235512253546156013760 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo */ #ifndef __UTIL_SPM_BS2BM__ #define __UTIL_SPM_BS2BM__ #include "suricata-common.h" #include "suricata.h" #define ALPHABET_SIZE 256 void Bs2BmBadchars(const uint8_t *, uint16_t, uint8_t *); void Bs2BmBadcharsNocase(const uint8_t *, uint16_t, uint8_t *); uint8_t * Bs2Bm(const uint8_t *, uint32_t, const uint8_t *, uint16_t, uint8_t []); uint8_t *Bs2BmNocase(const uint8_t *, uint32_t, const uint8_t *, uint16_t, uint8_t []); #endif /* __UTIL_SPM_BS2BM__ */ suricata-1.4.7/src/detect-engine-hrhd.c0000644000000000000000000024670412253546156014644 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP raw header match. * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-hrhd.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { SCEnter(); htp_tx_t *tx = NULL; uint32_t cnt = 0; int idx; /* we need to lock because the buffers are not actually true buffers * but are ones that point to a buffer given by libhtp */ FLOWLOCK_RDLOCK(f); if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL) continue; bstr *raw_headers = htp_tx_get_request_headers_raw(tx); if (raw_headers != NULL) { cnt += HttpRawHeaderPatternSearch(det_ctx, (uint8_t *)bstr_ptr(raw_headers), bstr_len(raw_headers), flags); } else { SCLogDebug("no raw headers"); } #ifdef HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW raw_headers = htp_tx_get_response_headers_raw(tx); if (raw_headers != NULL) { cnt += HttpRawHeaderPatternSearch(det_ctx, (uint8_t *)bstr_ptr(raw_headers), bstr_len(raw_headers), flags); } else { SCLogDebug("no raw headers"); } #endif /* HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW */ } end: FLOWLOCK_UNLOCK(f); SCReturnInt(cnt); } /** * \brief Do the http_raw_header content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL) return 0; bstr *raw_headers = NULL; if (flags & STREAM_TOSERVER) { raw_headers = htp_tx_get_request_headers_raw(tx); } #ifdef HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW else { raw_headers = htp_tx_get_response_headers_raw(tx); } #endif /* HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW */ if (raw_headers == NULL) return 0; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRHDMATCH], f, (uint8_t *)bstr_ptr(raw_headers), bstr_len(raw_headers), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest01(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest02(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; depth:15; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest03(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:!\"one\"; depth:5; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest04(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; depth:5; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest05(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:!\"one\"; depth:15; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; offset:10; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest07(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:!\"one\"; offset:15; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest08(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; offset:15; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest09(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:!\"one\"; offset:10; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest10(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:\"three\"; http_raw_header; within:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:!\"three\"; http_raw_header; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:!\"three\"; http_raw_header; within:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:\"three\"; http_raw_header; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest14(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; distance:7; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest15(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:!\"five\"; http_raw_header; distance:15; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest16(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:!\"five\"; http_raw_header; distance:7; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest17(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; distance:15; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest18(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http_buf[] = "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = HttpRawHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); if (r != 2) { printf("expected result 2, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpRawHeaderTest19(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http_buf[] = "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"one\"; http_raw_header; fast_pattern; content:\"five\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = HttpRawHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); if (r != 1) { printf("expected result 1, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpRawHeaderTest20(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; flow:to_server; " "pcre:/body1/D; " "content:!\"dummy\"; http_raw_header; within:7; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawHeaderTest21(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; flow:to_server; " "pcre:/body1/D; " "content:!\"dummy\"; within:7; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawHeaderTest22(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; flow:to_server; " "pcre:/body1/D; " "content:!\"dummy\"; distance:3; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawHeaderTest23(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; flow:to_server; " "pcre:/body1/D; " "content:!\"dummy\"; distance:13; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawHeaderTest24(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; flow:to_server; " "pcre:/body1/D; " "content:\"dummy\"; within:15; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawHeaderTest25(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; flow:to_server; " "pcre:/body1/D; " "content:\"dummy\"; within:10; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawHeaderTest26(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; flow:to_server; " "pcre:/body1/D; " "content:\"dummy\"; distance:8; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawHeaderTest27(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; flow:to_server; " "pcre:/body1/D; " "content:\"dummy\"; distance:14; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawHeaderTest28(void) { #ifdef HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_client; " "content:\"Content-Length: 6\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; #else return 1; #endif } static int DetectEngineHttpRawHeaderTest29(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_client; " "content:\"Content-Length: 7\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } #if 0 static int DetectEngineHttpRawHeaderTest30(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Content-Length: 6\"; http_raw_header; " "content:\"User-Agent: Mozilla\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list != NULL) { goto end; } result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } #endif /* #if 0 */ #endif /* UNITTESTS */ void DetectEngineHttpRawHeaderRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpRawHeaderTest01", DetectEngineHttpRawHeaderTest01, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest02", DetectEngineHttpRawHeaderTest02, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest03", DetectEngineHttpRawHeaderTest03, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest04", DetectEngineHttpRawHeaderTest04, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest05", DetectEngineHttpRawHeaderTest05, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest06", DetectEngineHttpRawHeaderTest06, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest07", DetectEngineHttpRawHeaderTest07, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest08", DetectEngineHttpRawHeaderTest08, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest09", DetectEngineHttpRawHeaderTest09, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest10", DetectEngineHttpRawHeaderTest10, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest11", DetectEngineHttpRawHeaderTest11, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest12", DetectEngineHttpRawHeaderTest12, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest13", DetectEngineHttpRawHeaderTest13, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest14", DetectEngineHttpRawHeaderTest14, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest15", DetectEngineHttpRawHeaderTest15, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest16", DetectEngineHttpRawHeaderTest16, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest17", DetectEngineHttpRawHeaderTest17, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest18", DetectEngineHttpRawHeaderTest18, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest19", DetectEngineHttpRawHeaderTest19, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest20", DetectEngineHttpRawHeaderTest20, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest21", DetectEngineHttpRawHeaderTest21, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest22", DetectEngineHttpRawHeaderTest22, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest23", DetectEngineHttpRawHeaderTest23, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest24", DetectEngineHttpRawHeaderTest24, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest25", DetectEngineHttpRawHeaderTest25, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest26", DetectEngineHttpRawHeaderTest26, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest27", DetectEngineHttpRawHeaderTest27, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest28", DetectEngineHttpRawHeaderTest28, 1); UtRegisterTest("DetectEngineHttpRawHeaderTest29", DetectEngineHttpRawHeaderTest29, 1); #if 0 UtRegisterTest("DetectEngineHttpRawHeaderTest30", DetectEngineHttpRawHeaderTest30, 1); #endif #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-engine-port.h0000644000000000000000000000450612253546156014700 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_PORT_H__ #define __DETECT_PORT_H__ /* prototypes */ int DetectPortParse(DetectPort **head, char *str); DetectPort *DetectPortCopy(DetectEngineCtx *, DetectPort *); DetectPort *DetectPortCopySingle(DetectEngineCtx *, DetectPort *); int DetectPortInsertCopy(DetectEngineCtx *,DetectPort **, DetectPort *); int DetectPortInsert(DetectEngineCtx *,DetectPort **, DetectPort *); void DetectPortCleanupList (DetectPort *head); DetectPort *DetectPortLookup(DetectPort *head, DetectPort *dp); int DetectPortAdd(DetectPort **head, DetectPort *dp); DetectPort *DetectPortLookupGroup(DetectPort *dp, uint16_t port); void DetectPortPrintMemory(void); DetectPort *DetectPortDpHashLookup(DetectEngineCtx *, DetectPort *); DetectPort *DetectPortDpHashGetListPtr(DetectEngineCtx *); int DetectPortDpHashInit(DetectEngineCtx *); void DetectPortDpHashFree(DetectEngineCtx *); int DetectPortDpHashAdd(DetectEngineCtx *, DetectPort *); void DetectPortDpHashReset(DetectEngineCtx *); DetectPort *DetectPortSpHashLookup(DetectEngineCtx *, DetectPort *); int DetectPortSpHashInit(DetectEngineCtx *); void DetectPortSpHashFree(DetectEngineCtx *); int DetectPortSpHashAdd(DetectEngineCtx *, DetectPort *); void DetectPortSpHashReset(DetectEngineCtx *); int DetectPortJoin(DetectEngineCtx *,DetectPort *target, DetectPort *source); void DetectPortPrint(DetectPort *); void DetectPortPrintList(DetectPort *head); int DetectPortCmp(DetectPort *, DetectPort *); void DetectPortFree(DetectPort *); int DetectPortTestConfVars(void); void DetectPortTests(void); #endif /* __DETECT_PORT_H__ */ suricata-1.4.7/src/util-signal.c0000644000000000000000000000326112253546156013423 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "suricata.h" #include "util-debug.h" int UtilSignalBlock(int signum) { sigset_t x; if (sigemptyset(&x) < 0) return -1; if (sigaddset(&x, signum) < 0) return -1; if (sigprocmask(SIG_BLOCK, &x, NULL) < 0) return -1; return 0; } void UtilSignalHandlerSetup(int sig, void (*handler)()) { #if defined (OS_WIN32) signal(sig, handler); #else struct sigaction action; memset(&action, 0x00, sizeof(struct sigaction)); action.sa_handler = handler; sigemptyset(&(action.sa_mask)); sigaddset(&(action.sa_mask),sig); action.sa_flags = 0; sigaction(sig, &action, 0); #endif /* OS_WIN32 */ return; } int UtilSignalIsHandler(int sig, void (*handler)()) { struct sigaction action; memset(&action, 0x00, sizeof(struct sigaction)); sigaction(sig, NULL, &action); return (action.sa_handler == handler); } suricata-1.4.7/src/flow-alert-sid.c0000644000000000000000000002464412253546156014034 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements per flow bits. Actually, not a bit, * but called that way because of Snort's flowbits. * It's a binary storage. * * \todo move away from a linked list implementation * \todo use different datatypes, such as string, int, etc. * \todo have more than one instance of the same var, and be able to match on a * specific one, or one all at a time. So if a certain capture matches * multiple times, we can operate on all of them. */ #include "suricata-common.h" #include "threads.h" #include "flow-alert-sid.h" #include "flow.h" #include "flow-util.h" #include "flow-private.h" #include "detect.h" #include "util-var.h" #include "util-unittest.h" #include "util-debug.h" /* get the flowbit with idx from the flow */ static FlowAlertSid *FlowAlertSidGet(Flow *f, uint32_t sid) { GenericVar *gv = f->flowvar; for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWALERTSID) { FlowAlertSid *fas = (FlowAlertSid *)gv; SCLogDebug("fas->type %"PRIu32", fas->sid %"PRIu32"", fas->type, fas->sid); if (fas->sid == sid) { return (FlowAlertSid *)gv; } } } return NULL; } /* add a flowbit to the flow */ static void FlowAlertSidAdd(Flow *f, uint32_t sid) { FlowAlertSid *fb = FlowAlertSidGet(f, sid); if (fb == NULL) { fb = SCMalloc(sizeof(FlowAlertSid)); if (unlikely(fb == NULL)) return; fb->type = DETECT_FLOWALERTSID; fb->sid = sid; fb->next = NULL; SCLogDebug("fb->type %u, sid %"PRIu32"", fb->type, fb->sid); GenericVarAppend(&f->flowvar, (GenericVar *)fb); SCLogDebug("fb->type %u, sid %"PRIu32"", fb->type, fb->sid); SCLogDebug("adding flowalertsid with sid %" PRIu32 " (%"PRIu32")", sid, fb->sid); #ifdef FLOWALERTSID_STATS SCMutexLock(&flowbits_mutex); flowbits_added++; flowbits_memuse += sizeof(FlowAlertSid); if (flowbits_memuse > flowbits_memuse_max) flowbits_memuse_max = flowbits_memuse; SCMutexUnlock(&flowbits_mutex); #endif /* FLOWALERTSID_STATS */ } } static void FlowAlertSidRemove(Flow *f, uint32_t sid) { FlowAlertSid *fb = FlowAlertSidGet(f, sid); if (fb == NULL) return; GenericVarRemove(&f->flowvar, (GenericVar *)fb); //printf("FlowAlertSidRemove: remove flowbit with idx %" PRIu32 "\n", idx); #ifdef FLOWALERTSID_STATS SCMutexLock(&flowbits_mutex); flowbits_removed++; if (flowbits_memuse >= sizeof(FlowAlertSid)) flowbits_memuse -= sizeof(FlowAlertSid); else { printf("ERROR: flowbits memory usage going below 0!\n"); flowbits_memuse = 0; } SCMutexUnlock(&flowbits_mutex); #endif /* FLOWALERTSID_STATS */ } void FlowAlertSidSet(Flow *f, uint32_t sid) { FLOWLOCK_WRLOCK(f); FlowAlertSid *fb = FlowAlertSidGet(f, sid); if (fb == NULL) { FlowAlertSidAdd(f, sid); } FLOWLOCK_UNLOCK(f); } void FlowAlertSidUnset(Flow *f, uint32_t sid) { FLOWLOCK_WRLOCK(f); FlowAlertSid *fb = FlowAlertSidGet(f, sid); if (fb != NULL) { FlowAlertSidRemove(f, sid); } FLOWLOCK_UNLOCK(f); } void FlowAlertSidToggle(Flow *f, uint32_t sid) { FLOWLOCK_WRLOCK(f); FlowAlertSid *fb = FlowAlertSidGet(f, sid); if (fb != NULL) { FlowAlertSidRemove(f, sid); } else { FlowAlertSidAdd(f, sid); } FLOWLOCK_UNLOCK(f); } int FlowAlertSidIsset(Flow *f, uint32_t sid) { int r = 0; FLOWLOCK_RDLOCK(f); FlowAlertSid *fb = FlowAlertSidGet(f, sid); if (fb != NULL) { r = 1; } FLOWLOCK_UNLOCK(f); return r; } int FlowAlertSidIsnotset(Flow *f, uint32_t sid) { int r = 0; FLOWLOCK_RDLOCK(f); FlowAlertSid *fb = FlowAlertSidGet(f, sid); if (fb == NULL) { r = 1; } FLOWLOCK_UNLOCK(f); return r; } void FlowAlertSidFree(FlowAlertSid *fb) { if (fb == NULL) return; SCFree(fb); #ifdef FLOWALERTSID_STATS SCMutexLock(&flowbits_mutex); flowbits_removed++; if (flowbits_memuse >= sizeof(FlowAlertSid)) flowbits_memuse -= sizeof(FlowAlertSid); else { printf("ERROR: flowbits memory usage going below 0!\n"); flowbits_memuse = 0; } SCMutexUnlock(&flowbits_mutex); #endif /* FLOWALERTSID_STATS */ } /* TESTS */ #ifdef UNITTESTS static int FlowAlertSidTest01 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSid *fb = FlowAlertSidGet(&f,0); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest02 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSid *fb = FlowAlertSidGet(&f,0); if (fb == NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest03 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSid *fb = FlowAlertSidGet(&f,0); if (fb == NULL) { printf("fb == NULL although it was just added: "); goto end; } FlowAlertSidRemove(&f, 0); fb = FlowAlertSidGet(&f,0); if (fb != NULL) { printf("fb != NULL although it was just removed: "); goto end; } else { ret = 1; } end: GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest04 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSidAdd(&f, 1); FlowAlertSidAdd(&f, 2); FlowAlertSidAdd(&f, 3); FlowAlertSid *fb = FlowAlertSidGet(&f,0); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest05 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSidAdd(&f, 1); FlowAlertSidAdd(&f, 2); FlowAlertSidAdd(&f, 3); FlowAlertSid *fb = FlowAlertSidGet(&f,1); if (fb == NULL) { printf("fb == NULL: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest06 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSidAdd(&f, 1); FlowAlertSidAdd(&f, 2); FlowAlertSidAdd(&f, 3); FlowAlertSid *fb = FlowAlertSidGet(&f,2); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest07 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSidAdd(&f, 1); FlowAlertSidAdd(&f, 2); FlowAlertSidAdd(&f, 3); FlowAlertSid *fb = FlowAlertSidGet(&f,3); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest08 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSidAdd(&f, 1); FlowAlertSidAdd(&f, 2); FlowAlertSidAdd(&f, 3); FlowAlertSid *fb = FlowAlertSidGet(&f,0); if (fb == NULL) goto end; FlowAlertSidRemove(&f,0); fb = FlowAlertSidGet(&f,0); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest09 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSidAdd(&f, 1); FlowAlertSidAdd(&f, 2); FlowAlertSidAdd(&f, 3); FlowAlertSid *fb = FlowAlertSidGet(&f,1); if (fb == NULL) goto end; FlowAlertSidRemove(&f,1); fb = FlowAlertSidGet(&f,1); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest10 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSidAdd(&f, 1); FlowAlertSidAdd(&f, 2); FlowAlertSidAdd(&f, 3); FlowAlertSid *fb = FlowAlertSidGet(&f,2); if (fb == NULL) goto end; FlowAlertSidRemove(&f,2); fb = FlowAlertSidGet(&f,2); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } static int FlowAlertSidTest11 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowAlertSidAdd(&f, 0); FlowAlertSidAdd(&f, 1); FlowAlertSidAdd(&f, 2); FlowAlertSidAdd(&f, 3); FlowAlertSid *fb = FlowAlertSidGet(&f,3); if (fb == NULL) goto end; FlowAlertSidRemove(&f,3); fb = FlowAlertSidGet(&f,3); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } #endif /* UNITTESTS */ void FlowAlertSidRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FlowAlertSidTest01", FlowAlertSidTest01, 1); UtRegisterTest("FlowAlertSidTest02", FlowAlertSidTest02, 1); UtRegisterTest("FlowAlertSidTest03", FlowAlertSidTest03, 1); UtRegisterTest("FlowAlertSidTest04", FlowAlertSidTest04, 1); UtRegisterTest("FlowAlertSidTest05", FlowAlertSidTest05, 1); UtRegisterTest("FlowAlertSidTest06", FlowAlertSidTest06, 1); UtRegisterTest("FlowAlertSidTest07", FlowAlertSidTest07, 1); UtRegisterTest("FlowAlertSidTest08", FlowAlertSidTest08, 1); UtRegisterTest("FlowAlertSidTest09", FlowAlertSidTest09, 1); UtRegisterTest("FlowAlertSidTest10", FlowAlertSidTest10, 1); UtRegisterTest("FlowAlertSidTest11", FlowAlertSidTest11, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-daemon.h0000644000000000000000000000203512253546156013414 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias Galvan */ #ifndef __UTIL_DAEMON_H__ #define __UTIL_DAEMON_H__ /** \todo Adjust path */ #define DAEMON_WORKING_DIRECTORY "/" #ifdef OS_WIN32 #define Daemonize() #else void Daemonize (void); #endif int CheckValidDaemonModes (int, int); #endif /* __UTIL_DAEMON_H__ */ suricata-1.4.7/src/util-mpm.c0000644000000000000000000012003612253546156012737 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Pattern matcher utility Functions */ #include "suricata-common.h" #include "util-mpm.h" #include "util-debug.h" /* include pattern matchers */ #include "util-mpm-wumanber.h" #include "util-mpm-b2g.h" #include "util-mpm-b2g-cuda.h" #include "util-mpm-b3g.h" #include "util-mpm-b2gc.h" #include "util-mpm-b2gm.h" #include "util-mpm-ac.h" #include "util-mpm-ac-gfbs.h" #include "util-mpm-ac-bs.h" #include "util-hashlist.h" #include "detect-engine.h" #include "util-cuda-handlers.h" #include "util-cuda.h" #include "util-misc.h" #include "conf.h" #include "conf-yaml-loader.h" #include "queue.h" #include "util-unittest.h" /** * \brief Register a new Mpm Context. * * \param name A new profile to be registered to store this MpmCtx. * * \retval id Return the id created for the new MpmCtx profile. */ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *name, uint8_t flags) { /* the very first entry */ if (de_ctx->mpm_ctx_factory_container == NULL) { de_ctx->mpm_ctx_factory_container = SCMalloc(sizeof(MpmCtxFactoryContainer)); if (de_ctx->mpm_ctx_factory_container == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(de_ctx->mpm_ctx_factory_container, 0, sizeof(MpmCtxFactoryContainer)); MpmCtxFactoryItem *item = SCMalloc(sizeof(MpmCtxFactoryItem)); if (unlikely(item == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } item[0].name = SCStrdup(name); if (item[0].name == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } /* toserver */ item[0].mpm_ctx_ts = SCMalloc(sizeof(MpmCtx)); if (item[0].mpm_ctx_ts == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(item[0].mpm_ctx_ts, 0, sizeof(MpmCtx)); item[0].mpm_ctx_ts->global = 1; /* toclient */ item[0].mpm_ctx_tc = SCMalloc(sizeof(MpmCtx)); if (item[0].mpm_ctx_tc == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(item[0].mpm_ctx_tc, 0, sizeof(MpmCtx)); item[0].mpm_ctx_tc->global = 1; /* our id starts from 0 always. Helps us with the ctx retrieval from * the array */ item[0].id = 0; /* store the flag */ item[0].flags = flags; /* store the newly created item */ de_ctx->mpm_ctx_factory_container->items = item; de_ctx->mpm_ctx_factory_container->no_of_items++; /* the first id is always 0 */ return item[0].id; } else { int i; MpmCtxFactoryItem *items = de_ctx->mpm_ctx_factory_container->items; for (i = 0; i < de_ctx->mpm_ctx_factory_container->no_of_items; i++) { if (items[i].name != NULL && strcmp(items[i].name, name) == 0) { /* looks like we have this mpm_ctx freed */ if (items[i].mpm_ctx_ts == NULL) { items[i].mpm_ctx_ts = SCMalloc(sizeof(MpmCtx)); if (items[i].mpm_ctx_ts == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(items[i].mpm_ctx_ts, 0, sizeof(MpmCtx)); items[i].mpm_ctx_ts->global = 1; } if (items[i].mpm_ctx_tc == NULL) { items[i].mpm_ctx_tc = SCMalloc(sizeof(MpmCtx)); if (items[i].mpm_ctx_tc == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(items[i].mpm_ctx_tc, 0, sizeof(MpmCtx)); items[i].mpm_ctx_tc->global = 1; } items[i].flags = flags; return items[i].id; } } /* let's make the new entry */ items = SCRealloc(items, (de_ctx->mpm_ctx_factory_container->no_of_items + 1) * sizeof(MpmCtxFactoryItem)); if (items == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } de_ctx->mpm_ctx_factory_container->items = items; MpmCtxFactoryItem *new_item = &items[de_ctx->mpm_ctx_factory_container->no_of_items]; new_item[0].name = SCStrdup(name); if (new_item[0].name == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } /* toserver */ new_item[0].mpm_ctx_ts = SCMalloc(sizeof(MpmCtx)); if (new_item[0].mpm_ctx_ts == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(new_item[0].mpm_ctx_ts, 0, sizeof(MpmCtx)); new_item[0].mpm_ctx_ts->global = 1; /* toclient */ new_item[0].mpm_ctx_tc = SCMalloc(sizeof(MpmCtx)); if (new_item[0].mpm_ctx_tc == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(new_item[0].mpm_ctx_tc, 0, sizeof(MpmCtx)); new_item[0].mpm_ctx_tc->global = 1; new_item[0].id = de_ctx->mpm_ctx_factory_container->no_of_items; new_item[0].flags = flags; de_ctx->mpm_ctx_factory_container->no_of_items++; /* the newly created id */ return new_item[0].id; } } int32_t MpmFactoryIsMpmCtxAvailable(DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) { if (mpm_ctx == NULL) return 0; if (de_ctx->mpm_ctx_factory_container == NULL) { return 0; } else { int i; for (i = 0; i < de_ctx->mpm_ctx_factory_container->no_of_items; i++) { if (mpm_ctx == de_ctx->mpm_ctx_factory_container->items[i].mpm_ctx_ts || mpm_ctx == de_ctx->mpm_ctx_factory_container->items[i].mpm_ctx_tc) { return 1; } } return 0; } } MpmCtx *MpmFactoryGetMpmCtxForProfile(DetectEngineCtx *de_ctx, int32_t id, int direction) { if (id == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { MpmCtx *mpm_ctx = SCMalloc(sizeof(MpmCtx)); if (unlikely(mpm_ctx == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(mpm_ctx, 0, sizeof(MpmCtx)); return mpm_ctx; } else if (id < -1) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument - %d\n", id); return NULL; } else if (id >= de_ctx->mpm_ctx_factory_container->no_of_items) { /* this id does not exist */ return NULL; } else { return (direction == 0) ? de_ctx->mpm_ctx_factory_container->items[id].mpm_ctx_ts : de_ctx->mpm_ctx_factory_container->items[id].mpm_ctx_tc; } } void MpmFactoryReClaimMpmCtx(DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) { if (mpm_ctx == NULL) return; if (!MpmFactoryIsMpmCtxAvailable(de_ctx, mpm_ctx)) { if (mpm_ctx->mpm_type != MPM_NOTSET) mpm_table[mpm_ctx->mpm_type].DestroyCtx(mpm_ctx); SCFree(mpm_ctx); } return; } void MpmFactoryDeRegisterAllMpmCtxProfiles(DetectEngineCtx *de_ctx) { if (de_ctx->mpm_ctx_factory_container == NULL) return; int i = 0; MpmCtxFactoryItem *items = de_ctx->mpm_ctx_factory_container->items; for (i = 0; i < de_ctx->mpm_ctx_factory_container->no_of_items; i++) { if (items[i].name != NULL) SCFree(items[i].name); if (items[i].mpm_ctx_ts != NULL) { if (items[i].mpm_ctx_ts->mpm_type != MPM_NOTSET) mpm_table[items[i].mpm_ctx_ts->mpm_type].DestroyCtx(items[i].mpm_ctx_ts); SCFree(items[i].mpm_ctx_ts); } if (items[i].mpm_ctx_tc != NULL) { if (items[i].mpm_ctx_tc->mpm_type != MPM_NOTSET) mpm_table[items[i].mpm_ctx_tc->mpm_type].DestroyCtx(items[i].mpm_ctx_tc); SCFree(items[i].mpm_ctx_tc); } } SCFree(de_ctx->mpm_ctx_factory_container->items); SCFree(de_ctx->mpm_ctx_factory_container); de_ctx->mpm_ctx_factory_container = NULL; return; } /** * \brief Setup a pmq * * \param pmq Pattern matcher queue to be initialized * \param maxid Max sig id to be matched on * \param patmaxid Max pattern id to be matched on * * \retval -1 error * \retval 0 ok */ int PmqSetup(PatternMatcherQueue *pmq, uint32_t sig_maxid, uint32_t patmaxid) { SCEnter(); SCLogDebug("sig_maxid %u, patmaxid %u", sig_maxid, patmaxid); if (pmq == NULL) { SCReturnInt(-1); } memset(pmq, 0, sizeof(PatternMatcherQueue)); if (patmaxid > 0) { pmq->pattern_id_array_size = patmaxid * sizeof(uint32_t); pmq->pattern_id_array = SCMalloc(pmq->pattern_id_array_size); if (pmq->pattern_id_array == NULL) { SCReturnInt(-1); } memset(pmq->pattern_id_array, 0, pmq->pattern_id_array_size); pmq->pattern_id_array_cnt = 0; /* lookup bitarray */ pmq->pattern_id_bitarray_size = (patmaxid / 8) + 1; pmq->pattern_id_bitarray = SCMalloc(pmq->pattern_id_bitarray_size); if (pmq->pattern_id_bitarray == NULL) { SCReturnInt(-1); } memset(pmq->pattern_id_bitarray, 0, pmq->pattern_id_bitarray_size); SCLogDebug("pmq->pattern_id_array %p, pmq->pattern_id_bitarray %p", pmq->pattern_id_array, pmq->pattern_id_bitarray); } SCReturnInt(0); } /** \brief Verify and store a match * * used at search runtime * * \param thread_ctx mpm thread ctx * \param pmq storage for match results * \param list end match to check against (entire list will be checked) * \param offset match offset in the buffer * \param patlen length of the pattern we're checking * * \retval 0 no match after all * \retval 1 (new) match */ int MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t patid) { SCEnter(); /* Handle pattern id storage */ if (pmq != NULL && pmq->pattern_id_bitarray != NULL) { SCLogDebug("using pattern id arrays, storing %"PRIu32, patid); if (!(pmq->pattern_id_bitarray[(patid / 8)] & (1<<(patid % 8)))) { /* flag this pattern id as being added now */ pmq->pattern_id_bitarray[(patid / 8)] |= (1<<(patid % 8)); /* append the pattern_id to the array with matches */ pmq->pattern_id_array[pmq->pattern_id_array_cnt] = patid; pmq->pattern_id_array_cnt++; SCLogDebug("pattern_id_array_cnt %u", pmq->pattern_id_array_cnt); } } SCReturnInt(1); } /** * \brief Merge two pmq's bitarrays * * \param src source pmq * \param dst destination pmq to merge into */ void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst) { uint32_t u; if (src->pattern_id_array_cnt == 0) return; for (u = 0; u < src->pattern_id_bitarray_size && u < dst->pattern_id_bitarray_size; u++) { dst->pattern_id_bitarray[u] |= src->pattern_id_bitarray[u]; } /** \todo now set merged flag? */ } /** \brief Reset a Pmq for reusage. Meant to be called after a single search. * \param pmq Pattern matcher to be reset. * \todo memset is expensive, but we need it as we merge pmq's. We might use * a flag so we can clear pmq's the old way if we can. */ void PmqReset(PatternMatcherQueue *pmq) { if (pmq == NULL) return; memset(pmq->pattern_id_bitarray, 0, pmq->pattern_id_bitarray_size); //memset(pmq->pattern_id_array, 0, pmq->pattern_id_array_size); pmq->pattern_id_array_cnt = 0; /* uint32_t u; for (u = 0; u < pmq->pattern_id_array_cnt; u++) { pmq->pattern_id_bitarray[(pmq->pattern_id_array[u] / 8)] &= ~(1<<(pmq->pattern_id_array[u] % 8)); } pmq->pattern_id_array_cnt = 0; */ } /** \brief Cleanup a Pmq * \param pmq Pattern matcher queue to be cleaned up. */ void PmqCleanup(PatternMatcherQueue *pmq) { if (pmq == NULL) return; if (pmq->pattern_id_array != NULL) { SCFree(pmq->pattern_id_array); pmq->pattern_id_array = NULL; } if (pmq->pattern_id_bitarray != NULL) { SCFree(pmq->pattern_id_bitarray); pmq->pattern_id_bitarray = NULL; } pmq->pattern_id_array_cnt = 0; } /** \brief Cleanup and free a Pmq * \param pmq Pattern matcher queue to be free'd. */ void PmqFree(PatternMatcherQueue *pmq) { if (pmq == NULL) return; PmqCleanup(pmq); } /** * \brief Return the pattern max length of a registered matcher * \retval 0 if it has no limit * \retval max_pattern_length of the specified matcher type * \retval -1 if the type is not registered return -1 */ int32_t MpmMatcherGetMaxPatternLength(uint16_t matcher) { if (matcher < MPM_TABLE_SIZE) return mpm_table[matcher].max_pattern_length; else return -1; } void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher, uint32_t max_id) { mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx, max_id); } void MpmInitCtx (MpmCtx *mpm_ctx, uint16_t matcher, int module_handle) { mpm_ctx->mpm_type = matcher; mpm_table[matcher].InitCtx(mpm_ctx, module_handle); } void MpmTableSetup(void) { memset(mpm_table, 0, sizeof(mpm_table)); MpmWuManberRegister(); MpmB2gRegister(); #ifdef __SC_CUDA_SUPPORT__ MpmB2gCudaRegister(); #endif MpmB3gRegister(); MpmB2gcRegister(); MpmB2gmRegister(); MpmACRegister(); MpmACBSRegister(); MpmACGfbsRegister(); } /** \brief Function to return the default hash size for the mpm algorithm, * which has been defined by the user in the config file * * \param conf_val pointer to the string value of hash size * \retval hash_value returns the hash value as defined by user, otherwise * default low size value */ uint32_t MpmGetHashSize(const char *conf_val) { SCEnter(); uint32_t hash_value = HASHSIZE_LOW; if(strcmp(conf_val, "lowest") == 0) { hash_value = HASHSIZE_LOWEST; } else if(strcmp(conf_val, "low") == 0) { hash_value = HASHSIZE_LOW; } else if(strcmp(conf_val, "medium") == 0) { hash_value = HASHSIZE_MEDIUM; } else if(strcmp(conf_val, "high") == 0) { hash_value = HASHSIZE_HIGH; /* "highest" is supported in 1.0 to 1.0.2, so we keep supporting * it for backwards compatibility */ } else if(strcmp(conf_val, "highest") == 0) { hash_value = HASHSIZE_HIGHER; } else if(strcmp(conf_val, "higher") == 0) { hash_value = HASHSIZE_HIGHER; } else if(strcmp(conf_val, "max") == 0) { hash_value = HASHSIZE_MAX; } SCReturnInt(hash_value); } /** \brief Function to return the default bloomfilter size for the mpm algorithm, * which has been defined by the user in the config file * * \param conf_val pointer to the string value of bloom filter size * \retval bloom_value returns the bloom filter value as defined by user, * otherwise default medium size value */ uint32_t MpmGetBloomSize(const char *conf_val) { SCEnter(); uint32_t bloom_value = BLOOMSIZE_MEDIUM; if(strncmp(conf_val, "low", 3) == 0) { bloom_value = BLOOMSIZE_LOW; } else if(strncmp(conf_val, "medium", 6) == 0) { bloom_value = BLOOMSIZE_MEDIUM; } else if(strncmp(conf_val, "high", 4) == 0) { bloom_value = BLOOMSIZE_HIGH; } SCReturnInt(bloom_value); } #ifdef __SC_CUDA_SUPPORT__ /** * \brief Parse the "mpm" profile under the cuda subsection of our conf file. * * \retval profile Pointer to a struct containing the parsed data. */ MpmCudaConf *MpmCudaConfParse(void) { ConfNode *cuda_node = NULL; ConfNode *seq_node = NULL; MpmCudaConf *profile = NULL; const char *packet_buffer_limit = NULL; const char *packet_size_limit = NULL; const char *packet_buffers = NULL; const char *batching_timeout = NULL; const char *page_locked = NULL; const char *device_id = NULL; const char *cuda_streams = NULL; if ((profile = SCMalloc(sizeof(MpmCudaConf))) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(profile, 0, sizeof(MpmCudaConf)); profile->packet_buffer_limit = MPM_PACKET_BUFFER_LIMIT; profile->packet_size_limit = MPM_PACKET_SIZE_LIMIT; profile->packet_buffers = MPM_PACKET_BUFFERS; profile->batching_timeout = MPM_BATCHING_TIMEOUT; profile->page_locked = MPM_PAGE_LOCKED; profile->device_id = SC_CUDA_DEFAULT_DEVICE; profile->cuda_streams = MPM_CUDA_STREAMS; cuda_node = ConfGetNode("cuda"); if (cuda_node == NULL) { SCLogInfo("No conf found for \"cuda\" in yaml file. Use default conf"); goto end; } TAILQ_FOREACH(seq_node, &cuda_node->head, next) { if (strcasecmp(seq_node->val, "mpm") == 0) { packet_buffer_limit = ConfNodeLookupChildValue (seq_node->head.tqh_first, "packet-buffer-limit"); packet_size_limit = ConfNodeLookupChildValue (seq_node->head.tqh_first, "packet-size-limit"); packet_buffers = ConfNodeLookupChildValue (seq_node->head.tqh_first, "packet-buffers"); batching_timeout = ConfNodeLookupChildValue (seq_node->head.tqh_first, "batching-timeout"); page_locked = ConfNodeLookupChildValue (seq_node->head.tqh_first, "page-locked"); device_id = ConfNodeLookupChildValue (seq_node->head.tqh_first, "device-id"); cuda_streams = ConfNodeLookupChildValue (seq_node->head.tqh_first, "cuda-streams"); /* packet_buffer_size */ if (packet_buffer_limit == NULL || strcasecmp(packet_buffer_limit, "") == 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.packet_buffer_limit. Either NULL or empty"); } else { profile->packet_buffer_limit = atoi(packet_buffer_limit); if (profile->packet_buffer_limit <= 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.packet_buffer_limit - %s", packet_buffer_limit); profile->packet_buffer_limit = MPM_PACKET_BUFFER_LIMIT; } } /* packet_size_limit */ if (packet_size_limit == NULL || strcasecmp(packet_size_limit, "") == 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.packet_size_limit. Either NULL or empty"); } else { if (ParseSizeStringU16(packet_size_limit, &profile->packet_size_limit) < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.packet_size_limit - %s", packet_size_limit); exit(EXIT_FAILURE); } if (profile->packet_size_limit <= 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.packet_size_limit - %s", packet_size_limit); profile->packet_size_limit = MPM_PACKET_SIZE_LIMIT; } } /* packet_buffers */ if (packet_buffers == NULL || strcasecmp(packet_buffers, "") == 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.packet_buffers. Either NULL or empty"); } else { profile->packet_buffers = atoi(packet_buffers); if (profile->packet_buffers <= 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.packet_buffers - %s", packet_buffers); profile->packet_buffers = MPM_PACKET_BUFFERS; } } /* batching_timeout */ if (batching_timeout == NULL || strcasecmp(batching_timeout, "") == 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.batching_timeout. Either NULL or empty"); } else { profile->batching_timeout = atof(batching_timeout); if (profile->batching_timeout < 0.000001) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.batching_timeout - %s", batching_timeout); profile->batching_timeout = MPM_BATCHING_TIMEOUT; } } /* page_locked */ if (page_locked == NULL || strcasecmp(page_locked, "") == 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.page_locked. Either NULL or empty"); } else { if (strcasecmp(page_locked, "enabled") == 0) { profile->page_locked = MPM_PAGE_LOCKED; } else if (strcasecmp(page_locked, "disabled") == 0) { profile->page_locked = !MPM_PAGE_LOCKED; } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.page_locked - %s", page_locked); } } /* device_id */ if (device_id == NULL || strcasecmp(device_id, "") == 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.device_id Either NULL or empty"); profile->device_id = SC_CUDA_DEFAULT_DEVICE; continue; } else { profile->device_id = atoi(device_id); if (profile->device_id < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.device_id - %s", device_id); profile->device_id = SC_CUDA_DEFAULT_DEVICE; continue; } } /* cuda_streams */ if (cuda_streams == NULL || strcasecmp(cuda_streams, "") == 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.cuda_streams Either NULL or empty"); profile->cuda_streams = MPM_CUDA_STREAMS; continue; } else { profile->cuda_streams = atoi(cuda_streams); if (profile->cuda_streams < 1) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "cuda.mpm.cuda_streams - %s", cuda_streams); profile->cuda_streams = MPM_CUDA_STREAMS; continue; } } } /* if (strcasecmp(seq_node->val, "mpm") == 0) */ } /* TAILQ_FOREACH(seq_node, &cuda_node->head, next) */ end: SCLogDebug("Configuration for \"cuda.mpm\"\n" "packet_buffer_size: %u\n" "packet_size_limit: %d\n" "packet_buffers: %d\n" "batching_timeout: %d\n" "page_locked: %d\n" "device_id: %d\n", profile->packet_buffer_limit, profile->packet_size_limit, profile->packet_buffers, profile->batching_timeout, profile->page_locked, profile->device_id); return profile; } /** * \brief Cleanup the parsed "mpm" profile cuda conf. */ void MpmCudaConfCleanup(MpmCudaConf *conf) { if (conf != NULL) SCFree(conf); return; } #endif /* __SC_CUDA_SUPPORT */ /************************************Unittests*********************************/ #ifdef UNITTESTS #ifdef __SC_CUDA_SUPPORT__ static int MpmInitYamlConf(char *conf) { ConfCreateContextBackup(); ConfInit(); return ConfYamlLoadString(conf, strlen(conf)); } static void MpmDeInitYamlConf(void) { ConfDeInit(); ConfRestoreContextBackup(); return; } static int MpmTest01(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n" " packet_buffer_limit: 4000\n" " packet_size_limit: 1500\n" " packet_buffers: 10\n" " batching_timeout: 1\n" " page_locked: enabled\n" " device_id: 0\n" " cuda_streams: 2\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == 4000); result &= (profile->packet_size_limit == 1500); result &= (profile->packet_buffers == 10); result &= (profile->batching_timeout == 1); result &= (profile->page_locked == 1); result &= (profile->device_id == 0); result &= (profile->cuda_streams == 2); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest02(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n" " packet_buffer_limit: 4001\n" " packet_size_limit: 1500\n" " packet_buffers: 12\n" " batching_timeout: 10\n" " page_locked: disabled\n" " device_id: 5\n" " cuda_streams: 4\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == 4001); result &= (profile->packet_size_limit == 1500); result &= (profile->packet_buffers == 12); result &= (profile->batching_timeout == 10); result &= (profile->page_locked == 0); result &= (profile->device_id == 5); result &= (profile->cuda_streams == 4); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest03(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n" " packet_buffer_limit: 0\n" " packet_size_limit: 0\n" " packet_buffers: 0\n" " batching_timeout: 0\n" " page_locked: enbled\n" " device_id: -1\n" " cuda_streams: -1\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == MPM_PACKET_SIZE_LIMIT); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == MPM_BATCHING_TIMEOUT); result &= (profile->page_locked == MPM_PAGE_LOCKED); result &= (profile->device_id == SC_CUDA_DEFAULT_DEVICE); result &= (profile->cuda_streams == MPM_CUDA_STREAMS); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest04(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n" " packet_buffer_limit: -1\n" " packet_size_limit: -1\n" " packet_buffers: -1\n" " batching_timeout: -1\n" " page_locked: enbled\n" " device_id: -1\n" " cuda_streams: -1\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == MPM_PACKET_SIZE_LIMIT); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == MPM_BATCHING_TIMEOUT); result &= (profile->page_locked == MPM_PAGE_LOCKED); result &= (profile->device_id == SC_CUDA_DEFAULT_DEVICE); result &= (profile->cuda_streams == MPM_CUDA_STREAMS); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest05(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n" " packet_buffer_limit:\n" " packet_size_limit:\n" " packet_buffers:\n" " batching_timeout: 2\n" " page_locked: enabled\n" " device_id: 1\n" " cuda_streams: 0\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == MPM_PACKET_SIZE_LIMIT); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == 2); result &= (profile->page_locked == 1); result &= (profile->device_id == 1); result &= (profile->cuda_streams == 0); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest06(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n" " packet_buffer_limit: \n" " packet_size_limit: \n" " packet_buffers: \n" " batching_timeout: \n" " page_locked: \n" " device_id: \n" " cuda_streams: \n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == MPM_PACKET_SIZE_LIMIT); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == MPM_BATCHING_TIMEOUT); result &= (profile->page_locked == MPM_PAGE_LOCKED); result &= (profile->device_id == SC_CUDA_DEFAULT_DEVICE); result &= (profile->cuda_streams == MPM_CUDA_STREAMS); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest07(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n" " packet_buffer_limit:\n" " packet_size_limit:\n" " packet_buffers:\n" " batching_timeout:\n" " page_locked:\n" " device_id:\n" " cuda_streams:\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == MPM_PACKET_SIZE_LIMIT); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == MPM_BATCHING_TIMEOUT); result &= (profile->page_locked == MPM_PAGE_LOCKED); result &= (profile->device_id == SC_CUDA_DEFAULT_DEVICE); result &= (profile->cuda_streams == MPM_CUDA_STREAMS); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest08(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n" " packet_size_limit: 2000\n" " page_locked: disabled\n" " device_id: 4\n" " cuda_streams: 8\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == 2000); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == MPM_BATCHING_TIMEOUT); result &= (profile->page_locked == !MPM_PAGE_LOCKED); result &= (profile->device_id == 4); result &= (profile->cuda_streams == 8); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest09(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n" " - mpm:\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == MPM_PACKET_SIZE_LIMIT); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == MPM_BATCHING_TIMEOUT); result &= (profile->page_locked == MPM_PAGE_LOCKED); result &= (profile->device_id == SC_CUDA_DEFAULT_DEVICE); result &= (profile->cuda_streams == MPM_CUDA_STREAMS); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest10(void) { char *conf = "%YAML 1.1\n" "---\n" "cuda:\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == MPM_PACKET_SIZE_LIMIT); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == MPM_BATCHING_TIMEOUT); result &= (profile->page_locked == MPM_PAGE_LOCKED); result &= (profile->device_id == SC_CUDA_DEFAULT_DEVICE); result &= (profile->cuda_streams == MPM_CUDA_STREAMS); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } static int MpmTest11(void) { char *conf = "%YAML 1.1\n" "---\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (MpmInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCCudaHlBackupRegisteredProfiles(); SCCudaHlGetYamlConf(); MpmCudaConf *profile = SCCudaHlGetProfile("mpm"); if (profile == NULL) { printf("Error retrieving mpm profile\n"); goto end; } result = (profile->packet_buffer_limit == MPM_PACKET_BUFFER_LIMIT); result &= (profile->packet_size_limit == MPM_PACKET_SIZE_LIMIT); result &= (profile->packet_buffers == MPM_PACKET_BUFFERS); result &= (profile->batching_timeout == MPM_BATCHING_TIMEOUT); result &= (profile->page_locked == MPM_PAGE_LOCKED); result &= (profile->device_id == SC_CUDA_DEFAULT_DEVICE); result &= (profile->cuda_streams == MPM_CUDA_STREAMS); end: SCCudaHlCleanProfiles(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); MpmDeInitYamlConf(); SCCudaHlRestoreBackupRegisteredProfiles(); return result; } #endif /* __SC_CUDA_SUPPORT__ */ #endif /* UNITTESTS */ void MpmRegisterTests(void) { #ifdef UNITTESTS uint16_t i; for (i = 0; i < MPM_TABLE_SIZE; i++) { if (i == MPM_NOTSET) continue; if (mpm_table[i].RegisterUnittests != NULL) { mpm_table[i].RegisterUnittests(); } else { printf("Warning: mpm %s has no unittest registration function...", mpm_table[i].name); } } #ifdef __SC_CUDA_SUPPORT__ UtRegisterTest("MpmTest01", MpmTest01, 1); UtRegisterTest("MpmTest02", MpmTest02, 1); UtRegisterTest("MpmTest03", MpmTest03, 1); UtRegisterTest("MpmTest04", MpmTest04, 1); UtRegisterTest("MpmTest05", MpmTest05, 1); UtRegisterTest("MpmTest06", MpmTest06, 1); UtRegisterTest("MpmTest07", MpmTest07, 1); UtRegisterTest("MpmTest08", MpmTest08, 1); UtRegisterTest("MpmTest09", MpmTest09, 1); UtRegisterTest("MpmTest10", MpmTest10, 1); UtRegisterTest("MpmTest11", MpmTest11, 1); #endif /* __SC_CUDA_SUPPORT__ */ #endif } suricata-1.4.7/src/detect-id.h0000644000000000000000000000206512253546156013043 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo */ #ifndef __DETECT_ID_H__ #define __DETECT_ID_H__ #define DETECT_IPID_MIN 0 #define DETECT_IPID_MAX 65536 typedef struct DetectIdData_ { uint16_t id; /** ip->id to match */ } DetectIdData; /* prototypes */ void DetectIdRegister (void); #endif /* __DETECT_ID_H__ */ suricata-1.4.7/src/alert-pcapinfo.c0000644000000000000000000001655212253546156014106 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond * * Logs alerts in a line based text format suitable for interaction * with wireshark or another pcap file analysis tools. * * The format of the logging is: * Packet number:GID of matching signature:SID of signature:REV of signature:Flow:To Server:To Client:0:0:Signature Message * The two zeros are reserved for upcoming usage (probably byte start * and byte end of payload) */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "conf.h" #include "threads.h" #include "tm-threads.h" #include "threadvars.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-reference.h" #include "util-classification-config.h" #include "output.h" #include "alert-pcapinfo.h" #include "util-mpm-b2g-cuda.h" #include "util-cuda-handlers.h" #include "util-privs.h" #include "util-print.h" #include "util-proto-name.h" #include "util-optimize.h" #define DEFAULT_LOG_FILENAME "alert-pcapinfo.log" /* We need a new file for each pcap */ #define DEFAULT_PCAPINFO_MODE_APPEND "no" #define MODULE_NAME "AlertPcapInfo" TmEcode AlertPcapInfo (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertPcapInfoThreadInit(ThreadVars *, void *, void **); TmEcode AlertPcapInfoThreadDeinit(ThreadVars *, void *); void AlertPcapInfoExitPrintStats(ThreadVars *, void *); static int AlertPcapInfoOpenFileCtx(LogFileCtx *, const char *, const char *); static void AlertPcapInfoDeInitCtx(OutputCtx *); void TmModuleAlertPcapInfoRegister (void) { tmm_modules[TMM_ALERTPCAPINFO].name = MODULE_NAME; tmm_modules[TMM_ALERTPCAPINFO].ThreadInit = AlertPcapInfoThreadInit; tmm_modules[TMM_ALERTPCAPINFO].Func = AlertPcapInfo; tmm_modules[TMM_ALERTPCAPINFO].ThreadExitPrintStats = AlertPcapInfoExitPrintStats; tmm_modules[TMM_ALERTPCAPINFO].ThreadDeinit = AlertPcapInfoThreadDeinit; tmm_modules[TMM_ALERTPCAPINFO].RegisterTests = NULL; tmm_modules[TMM_ALERTPCAPINFO].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "pcap-info", AlertPcapInfoInitCtx); } typedef struct AlertPcapInfoThread_ { /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ LogFileCtx* file_ctx; } AlertPcapInfoThread; TmEcode AlertPcapInfo (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertPcapInfoThread *aft = (AlertPcapInfoThread *)data; int i; /* logging is useless if we don't have pcap number */ if ((p->pcap_cnt != 0) && (p->alerts.cnt > 0)) { SCMutexLock(&aft->file_ctx->fp_mutex); /* only count logged alert */ aft->file_ctx->alerts += p->alerts.cnt; for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; fprintf(aft->file_ctx->fp, "%" PRIu64 ":%" PRIu32 ":%" PRIu32 ":%d:%d:%d:%d:0:0:%s\n", p->pcap_cnt, pa->s->gid, pa->s->id, pa->s->rev, pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0, p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0, p->flowflags & FLOW_PKT_TOCLIENT ? 1 : 0, pa->s->msg); } SCMutexUnlock(&aft->file_ctx->fp_mutex); } return TM_ECODE_OK; } TmEcode AlertPcapInfoThreadInit(ThreadVars *t, void *initdata, void **data) { AlertPcapInfoThread *aft = SCMalloc(sizeof(AlertPcapInfoThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(AlertPcapInfoThread)); if(initdata == NULL) { SCLogDebug("Error getting context for AlertPcapInfo. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } /** Use the Ouptut Context (file pointer and mutex) */ aft->file_ctx = ((OutputCtx *)initdata)->data; *data = (void *)aft; return TM_ECODE_OK; } TmEcode AlertPcapInfoThreadDeinit(ThreadVars *t, void *data) { AlertPcapInfoThread *aft = (AlertPcapInfoThread *)data; if (aft == NULL) { return TM_ECODE_OK; } /* clear memory */ memset(aft, 0, sizeof(AlertPcapInfoThread)); SCFree(aft); return TM_ECODE_OK; } void AlertPcapInfoExitPrintStats(ThreadVars *tv, void *data) { AlertPcapInfoThread *aft = (AlertPcapInfoThread *)data; if (aft == NULL) { return; } SCLogInfo("(%s) Alerts %" PRIu64 "", tv->name, aft->file_ctx->alerts); } /** * \brief Create a new LogFileCtx for "fast" output style. * \param conf The configuration node for this output. * \return A LogFileCtx pointer on success, NULL on failure. */ OutputCtx *AlertPcapInfoInitCtx(ConfNode *conf) { LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("AlertPcapInfoInitCtx2: Could not create new LogFileCtx"); return NULL; } const char *filename = ConfNodeLookupChildValue(conf, "filename"); if (filename == NULL) filename = DEFAULT_LOG_FILENAME; const char *mode = ConfNodeLookupChildValue(conf, "append"); if (mode == NULL) mode = DEFAULT_PCAPINFO_MODE_APPEND; if (AlertPcapInfoOpenFileCtx(logfile_ctx, filename, mode) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; output_ctx->data = logfile_ctx; output_ctx->DeInit = AlertPcapInfoDeInitCtx; SCLogInfo("Fast log output initialized, filename: %s", filename); return output_ctx; } static void AlertPcapInfoDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; LogFileFreeCtx(logfile_ctx); SCFree(output_ctx); } /** \brief Read the config set the file pointer, open the file * \param file_ctx pointer to a created LogFileCtx using LogFileNewCtx() * \param filename name of log file * \param mode append mode (bool) * \return -1 if failure, 0 if succesful * */ static int AlertPcapInfoOpenFileCtx(LogFileCtx *file_ctx, const char *filename, const char *mode) { char log_path[PATH_MAX]; char *log_dir; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); if (ConfValIsTrue(mode)) { file_ctx->fp = fopen(log_path, "a"); } else { file_ctx->fp = fopen(log_path, "w"); } if (file_ctx->fp == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path, strerror(errno)); return -1; } return 0; } suricata-1.4.7/src/source-napatech.c0000644000000000000000000003314312253546156014256 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author nPulse Technologies, LLC. * \author Matt Keeler * * Support for NAPATECH adapter with the 3GD Driver/API. * Requires libntapi from Napatech A/S. * */ #include "suricata-common.h" #include "suricata.h" #include "threadvars.h" #include "util-optimize.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "tm-modules.h" #include "util-privs.h" #include "tmqh-packetpool.h" #ifndef HAVE_NAPATECH TmEcode NoNapatechSupportExit(ThreadVars *, void *, void **); void TmModuleNapatechStreamRegister (void) { tmm_modules[TMM_RECEIVENAPATECH].name = "NapatechStream"; tmm_modules[TMM_RECEIVENAPATECH].ThreadInit = NoNapatechSupportExit; tmm_modules[TMM_RECEIVENAPATECH].Func = NULL; tmm_modules[TMM_RECEIVENAPATECH].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVENAPATECH].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVENAPATECH].RegisterTests = NULL; tmm_modules[TMM_RECEIVENAPATECH].cap_flags = SC_CAP_NET_ADMIN; } void TmModuleNapatechDecodeRegister (void) { tmm_modules[TMM_DECODENAPATECH].name = "NapatechDecode"; tmm_modules[TMM_DECODENAPATECH].ThreadInit = NoNapatechSupportExit; tmm_modules[TMM_DECODENAPATECH].Func = NULL; tmm_modules[TMM_DECODENAPATECH].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODENAPATECH].ThreadDeinit = NULL; tmm_modules[TMM_DECODENAPATECH].RegisterTests = NULL; tmm_modules[TMM_DECODENAPATECH].cap_flags = 0; tmm_modules[TMM_DECODENAPATECH].flags = TM_FLAG_DECODE_TM; } TmEcode NoNapatechSupportExit(ThreadVars *tv, void *initdata, void **data) { SCLogError(SC_ERR_NAPATECH_NOSUPPORT, "Error creating thread %s: you do not have support for Napatech adapter " "enabled please recompile with --enable-napatech", tv->name); exit(EXIT_FAILURE); } #else /* Implied we do have NAPATECH support */ #include "source-napatech.h" #include extern int max_pending_packets; extern uint8_t suricata_ctl_flags; typedef struct NapatechThreadVars_ { ThreadVars *tv; NtNetStreamRx_t rx_stream; uint64_t stream_id; int hba; uint64_t pkts; uint64_t drops; uint64_t bytes; TmSlot *slot; } NapatechThreadVars; TmEcode NapatechStreamThreadInit(ThreadVars *, void *, void **); void NapatechStreamThreadExitStats(ThreadVars *, void *); TmEcode NapatechStreamLoop(ThreadVars *tv, void *data, void *slot); TmEcode NapatechDecodeThreadInit(ThreadVars *, void *, void **); TmEcode NapatechDecode(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); /** * \brief Register the Napatech receiver (reader) module. */ void TmModuleNapatechStreamRegister(void) { tmm_modules[TMM_RECEIVENAPATECH].name = "NapatechStream"; tmm_modules[TMM_RECEIVENAPATECH].ThreadInit = NapatechStreamThreadInit; tmm_modules[TMM_RECEIVENAPATECH].Func = NULL; tmm_modules[TMM_RECEIVENAPATECH].PktAcqLoop = NapatechStreamLoop; tmm_modules[TMM_RECEIVENAPATECH].ThreadExitPrintStats = NapatechStreamThreadExitStats; tmm_modules[TMM_RECEIVENAPATECH].ThreadDeinit = NapatechStreamThreadDeinit; tmm_modules[TMM_RECEIVENAPATECH].RegisterTests = NULL; tmm_modules[TMM_RECEIVENAPATECH].cap_flags = SC_CAP_NET_RAW; tmm_modules[TMM_RECEIVENAPATECH].flags = TM_FLAG_RECEIVE_TM; } /** * \brief Register the Napatech decoder module. */ void TmModuleNapatechDecodeRegister(void) { tmm_modules[TMM_DECODENAPATECH].name = "NapatechDecode"; tmm_modules[TMM_DECODENAPATECH].ThreadInit = NapatechDecodeThreadInit; tmm_modules[TMM_DECODENAPATECH].Func = NapatechDecode; tmm_modules[TMM_DECODENAPATECH].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODENAPATECH].ThreadDeinit = NULL; tmm_modules[TMM_DECODENAPATECH].RegisterTests = NULL; tmm_modules[TMM_DECODENAPATECH].cap_flags = 0; tmm_modules[TMM_DECODENAPATECH].flags = TM_FLAG_DECODE_TM; } /** * \brief Initialize the Napatech receiver thread, generate a single * NapatechThreadVar structure for each thread, this will * contain a NtNetStreamRx_t stream handle which is used when the * thread executes to acquire the packets. * * \param tv Thread variable to ThreadVars * \param initdata Initial data to the adapter passed from the user, * this is processed by the user. * * For now, we assume that we have only a single name for the NAPATECH * adapter. * * \param data data pointer gets populated with * */ TmEcode NapatechStreamThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); struct NapatechStreamDevConf *conf = (struct NapatechStreamDevConf *)initdata; uintmax_t stream_id = conf->stream_id; *data = NULL; SCLogInfo("Napatech Thread Stream ID:%lu", stream_id); NapatechThreadVars *ntv = SCMalloc(sizeof(NapatechThreadVars)); if (ntv == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for NAPATECH thread vars."); exit(EXIT_FAILURE); } memset(ntv, 0, sizeof (NapatechThreadVars)); ntv->stream_id = stream_id; ntv->tv = tv; ntv->hba = conf->hba; SCLogInfo("Started processing packets from NAPATECH Stream: %lu", ntv->stream_id); *data = (void *)ntv; SCReturnInt(TM_ECODE_OK); } /** * \brief Main Napatech reading Loop function */ TmEcode NapatechStreamLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); int32_t status; char errbuf[100]; uint16_t packet_q_len = 0; uint64_t pkt_ts; NtNetBuf_t packet_buffer; NapatechThreadVars *ntv = (NapatechThreadVars *)data; NtNetRx_t stat_cmd; SCLogInfo("Opening NAPATECH Stream: %lu for processing", ntv->stream_id); if ((status = NT_NetRxOpen(&(ntv->rx_stream), "SuricataStream", NT_NET_INTERFACE_PACKET, ntv->stream_id, ntv->hba)) != NT_SUCCESS) { NT_ExplainError(status, errbuf, sizeof(errbuf)); SCLogError(SC_ERR_NAPATECH_OPEN_FAILED, "Failed to open NAPATECH Stream: %lu - %s", ntv->stream_id, errbuf); SCFree(ntv); SCReturnInt(TM_ECODE_FAILED); } stat_cmd.cmd = NT_NETRX_READ_CMD_STREAM_DROP; SCLogInfo("Napatech Packet Stream Loop Started for Stream ID: %lu", ntv->stream_id); TmSlot *s = (TmSlot *)slot; ntv->slot = s->slot_next; while (!(suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL))) { /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); /* * Napatech returns packets 1 at a time */ status = NT_NetRxGet(ntv->rx_stream, &packet_buffer, 1000); if (unlikely(status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) { /* * no frames currently available */ continue; } else if (unlikely(status != NT_SUCCESS)) { SCLogError(SC_ERR_NAPATECH_STREAM_NEXT_FAILED, "Failed to read from Napatech Stream: %lu", ntv->stream_id); SCReturnInt(TM_ECODE_FAILED); } Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCReturnInt(TM_ECODE_FAILED); } pkt_ts = NT_NET_GET_PKT_TIMESTAMP(packet_buffer); /* * Handle the different timestamp forms that the napatech cards could use * - NT_TIMESTAMP_TYPE_NATIVE is not supported due to having an base of 0 as opposed to NATIVE_UNIX which has a base of 1/1/1970 */ switch(NT_NET_GET_PKT_TIMESTAMP_TYPE(packet_buffer)) { case NT_TIMESTAMP_TYPE_NATIVE_UNIX: p->ts.tv_sec = pkt_ts / 100000000; p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0; break; case NT_TIMESTAMP_TYPE_PCAP: p->ts.tv_sec = pkt_ts >> 32; p->ts.tv_usec = pkt_ts & 0xFFFFFFFF; break; case NT_TIMESTAMP_TYPE_PCAP_NANOTIME: p->ts.tv_sec = pkt_ts >> 32; p->ts.tv_usec = ((pkt_ts & 0xFFFFFFFF) / 1000) + (pkt_ts % 1000) > 500 ? 1 : 0; break; case NT_TIMESTAMP_TYPE_NATIVE_NDIS: /* number of seconds between 1/1/1601 and 1/1/1970 */ p->ts.tv_sec = (pkt_ts / 100000000) - 11644473600; p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0; break; default: SCLogError(SC_ERR_NAPATECH_TIMESTAMP_TYPE_NOT_SUPPORTED, "Packet from Napatech Stream: %lu does not have a supported timestamp format", ntv->stream_id); NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCReturnInt(TM_ECODE_FAILED); } SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); p->datalink = LINKTYPE_ETHERNET; ntv->pkts++; ntv->bytes += NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer); // Update drop counter if (unlikely((status = NT_NetRxRead(ntv->rx_stream, &stat_cmd)) != NT_SUCCESS)) { NT_ExplainError(status, errbuf, sizeof(errbuf)); SCLogWarning(SC_ERR_NAPATECH_STAT_DROPS_FAILED, "Couldn't retrieve drop statistics from the RX stream: %lu - %s", ntv->stream_id, errbuf); } else { ntv->drops += stat_cmd.u.streamDrop.pktsDropped; } if (unlikely(PacketCopyData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) { TmqhOutputPacketpool(ntv->tv, p); NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCReturnInt(TM_ECODE_FAILED); } if (unlikely(TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK)) { TmqhOutputPacketpool(ntv->tv, p); NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCReturnInt(TM_ECODE_FAILED); } NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); } /** * \brief Print some stats to the log at program exit. * * \param tv Pointer to ThreadVars. * \param data Pointer to data, ErfFileThreadVars. */ void NapatechStreamThreadExitStats(ThreadVars *tv, void *data) { NapatechThreadVars *ntv = (NapatechThreadVars *)data; double percent = 0; if (ntv->drops > 0) percent = (((double) ntv->drops) / (ntv->pkts+ntv->drops)) * 100; SCLogInfo("Stream: %lu; Packets: %"PRIu64"; Drops: %"PRIu64" (%5.2f%%); Bytes: %"PRIu64, ntv->stream_id, ntv->pkts, ntv->drops, percent, ntv->bytes); } /** * \brief Deinitializes the NAPATECH card. * \param tv pointer to ThreadVars * \param data pointer that gets cast into PcapThreadVars for ptv */ TmEcode NapatechStreamThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); NapatechThreadVars *ntv = (NapatechThreadVars *)data; SCLogDebug("Closing Napatech Stream: %d", ntv->stream_id); NT_NetRxClose(ntv->rx_stream); SCReturnInt(TM_ECODE_OK); } /** Decode Napatech */ /** * \brief This function passes off to link type decoders. * * NapatechDecode reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param t pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into PcapThreadVars for ptv * \param pq pointer to the current PacketQueue */ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); switch (p->datalink) { case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module NapatechDecode", p->datalink); break; } SCReturnInt(TM_ECODE_OK); } TmEcode NapatechDecodeThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if(dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; SCReturnInt(TM_ECODE_OK); } #endif /* HAVE_NAPATECH */ suricata-1.4.7/src/detect-geoip.c0000644000000000000000000004442612253546156013554 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Ignacio Sanchez * * Implements the geoip keyword. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-geoip.h" #include "util-unittest.h" #include "util-unittest-helper.h" #ifndef HAVE_GEOIP static int DetectGeoipSetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) { SCLogError(SC_ERR_NO_GEOIP_SUPPORT, "no GeoIP support built in, needed for geoip keyword"); return -1; } /** * \brief Registration function for geoip keyword (no libgeoip support) * \todo add support for src_only and dst_only */ void DetectGeoipRegister(void) { sigmatch_table[DETECT_GEOIP].name = "geoip"; sigmatch_table[DETECT_GEOIP].Setup = DetectGeoipSetupNoSupport; sigmatch_table[DETECT_GEOIP].Free = NULL; sigmatch_table[DETECT_GEOIP].RegisterTests = NULL; } #else /* HAVE_GEOIP */ #include static int DetectGeoipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectGeoipSetup(DetectEngineCtx *, Signature *, char *); static void DetectGeoipRegisterTests(void); static void DetectGeoipDataFree(void *); /** * \brief Registration function for geoip keyword * \todo add support for src_only and dst_only */ void DetectGeoipRegister(void) { sigmatch_table[DETECT_GEOIP].name = "geoip"; sigmatch_table[DETECT_GEOIP].Match = DetectGeoipMatch; sigmatch_table[DETECT_GEOIP].Setup = DetectGeoipSetup; sigmatch_table[DETECT_GEOIP].Free = DetectGeoipDataFree; sigmatch_table[DETECT_GEOIP].RegisterTests = DetectGeoipRegisterTests; } /** * \internal * \brief This function is used to initialize the geolocation MaxMind engine * * \retval NULL if the engine couldn't be initialized * \retval (GeoIP *) to the geolocation engine */ static GeoIP *InitGeolocationEngine(void) { return GeoIP_new(GEOIP_MEMORY_CACHE); } /** * \internal * \brief This function is used to geolocate the IP using the MaxMind libraries * * \param ip IP to geolocate (uint32_t ip) * * \retval NULL if it couldn't be geolocated * \retval ptr (const char *) to the country code string */ static const char *GeolocateIPv4(GeoIP *geoengine, uint32_t ip) { if (geoengine != NULL) return GeoIP_country_code_by_ipnum(geoengine, ntohl(ip)); return NULL; } /* Match-on conditions supported */ #define GEOIP_MATCH_SRC_STR "src" #define GEOIP_MATCH_DST_STR "dst" #define GEOIP_MATCH_BOTH_STR "both" #define GEOIP_MATCH_ANY_STR "any" #define GEOIP_MATCH_NO_FLAG 0 #define GEOIP_MATCH_SRC_FLAG 1 #define GEOIP_MATCH_DST_FLAG 2 #define GEOIP_MATCH_ANY_FLAG 3 /* default src and dst*/ #define GEOIP_MATCH_BOTH_FLAG 4 #define GEOIP_MATCH_NEGATED 8 /** * \internal * \brief This function is used to geolocate the IP using the MaxMind libraries * * \param ip IP to geolocate (uint32_t ip) * * \retval 0 no match * \retval 1 match */ static int CheckGeoMatchIPv4(DetectGeoipData *geoipdata, uint32_t ip) { const char *country; int i; country = GeolocateIPv4(geoipdata->geoengine, ip); /* Check if NOT NEGATED match-on condition */ if ((geoipdata->flags & GEOIP_MATCH_NEGATED) == 0) { for (i = 0; i < geoipdata->nlocations; i++) if (country != NULL && strcmp(country, (char *)geoipdata->location[i])==0) return 1; } else { /* Check if NEGATED match-on condition */ for (i = 0; i < geoipdata->nlocations; i++) if (country != NULL && strcmp(country, (char *)geoipdata->location[i])==0) return 0; /* if one matches, rule does NOT match (negated) */ return 1; /* returns 1 if no location matches (negated) */ } return 0; } /** * \internal * \brief This function is used to match packets with a IPs in an specified country * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectGeoipData * * \retval 0 no match * \retval 1 match */ static int DetectGeoipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectGeoipData *geoipdata = (DetectGeoipData *)m->ctx; int matches = 0; if (PKT_IS_IPV4(p)) { if (geoipdata->flags & ( GEOIP_MATCH_SRC_FLAG | GEOIP_MATCH_BOTH_FLAG )) { if (CheckGeoMatchIPv4(geoipdata, GET_IPV4_SRC_ADDR_U32(p))) { if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG) matches++; else return 1; } } if (geoipdata->flags & ( GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_BOTH_FLAG )) { if (CheckGeoMatchIPv4(geoipdata, GET_IPV4_DST_ADDR_U32(p))) { if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG) matches++; else return 1; } } /* if matches == 2 is because match-on is "both" */ if (matches == 2) return 1; } return 0; } /** * \brief This function is used to parse geoipdata * * \param str Pointer to the geoipdata value string * * \retval pointer to DetectGeoipData on success * \retval NULL on failure */ static DetectGeoipData *DetectGeoipDataParse (char *str) { DetectGeoipData *geoipdata = NULL; uint16_t pos = 0; uint16_t prevpos = 0; uint16_t slen = 0; int skiplocationparsing = 0; slen = strlen(str); if (slen == 0) goto error; /* We have a correct geoip options string */ geoipdata = SCMalloc(sizeof(DetectGeoipData)); if (unlikely(geoipdata == NULL)) goto error; memset(geoipdata, 0x00, sizeof(DetectGeoipData)); /* Parse the geoip option string */ while (pos <= slen) { /* search for ',' or end of string */ if (str[pos] == ',' || pos == slen) { if (geoipdata->flags == GEOIP_MATCH_NO_FLAG) { /* Parse match-on condition */ if (pos == slen) /* if end of option str then there are no match-on cond. */ { /* There was NO match-on condition! we default to ANY*/ skiplocationparsing = 0; geoipdata->flags |= GEOIP_MATCH_ANY_FLAG; } else { skiplocationparsing = 1; if (strncmp(&str[prevpos], GEOIP_MATCH_SRC_STR, pos-prevpos) == 0) geoipdata->flags |= GEOIP_MATCH_SRC_FLAG; else if (strncmp(&str[prevpos], GEOIP_MATCH_DST_STR, pos-prevpos) == 0) geoipdata->flags |= GEOIP_MATCH_DST_FLAG; else if (strncmp(&str[prevpos], GEOIP_MATCH_BOTH_STR, pos-prevpos) == 0) geoipdata->flags |= GEOIP_MATCH_BOTH_FLAG; else if (strncmp(&str[prevpos], GEOIP_MATCH_ANY_STR, pos-prevpos) == 0) geoipdata->flags |= GEOIP_MATCH_ANY_FLAG; else { /* There was NO match-on condition! we default to ANY*/ skiplocationparsing = 0; geoipdata->flags |= GEOIP_MATCH_ANY_FLAG; } } } if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0) { /* Parse location string: for now just the country code(s) */ if (str[prevpos] == '!') { geoipdata->flags |= GEOIP_MATCH_NEGATED; prevpos++; /* dot not copy the ! */ } if (geoipdata->nlocations >= GEOOPTION_MAXLOCATIONS) { SCLogError(SC_ERR_INVALID_ARGUMENT, "too many arguements for geoip keyword"); goto error; } if (pos-prevpos > GEOOPTION_MAXSIZE) strlcpy((char *)geoipdata->location[geoipdata->nlocations], &str[prevpos], GEOOPTION_MAXSIZE); else strlcpy((char *)geoipdata->location[geoipdata->nlocations], &str[prevpos], pos-prevpos+1); if (geoipdata->nlocations < GEOOPTION_MAXLOCATIONS) geoipdata->nlocations++; } prevpos = pos+1; skiplocationparsing = 0; /* match-on condition for sure has been parsed already */ } pos++; } SCLogDebug("GeoIP: %"PRIu32" countries loaded", geoipdata->nlocations); for (int i=0; inlocations; i++) SCLogDebug("GeoIP country code: %s", geoipdata->location[i]); SCLogDebug("flags %02X", geoipdata->flags); if (geoipdata->flags & GEOIP_MATCH_NEGATED) { SCLogDebug("negated geoip"); } /* Initialize the geolocation engine */ geoipdata->geoengine = InitGeolocationEngine(); if (geoipdata->geoengine == NULL) goto error; return geoipdata; error: if (geoipdata != NULL) DetectGeoipDataFree(geoipdata); return NULL; } /** * \internal * \brief this function is used to add the geoip option into the signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param optstr pointer to the user provided options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectGeoipSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { DetectGeoipData *geoipdata = NULL; SigMatch *sm = NULL; geoipdata = DetectGeoipDataParse(optstr); if (geoipdata == NULL) goto error; /* Get this into a SigMatch and put it in the Signature. */ sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_GEOIP; sm->ctx = (void *)geoipdata; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (geoipdata != NULL) DetectGeoipDataFree(geoipdata); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectGeoipData * * \param geoipdata pointer to DetectGeoipData */ static void DetectGeoipDataFree(void *ptr) { if (ptr != NULL) { DetectGeoipData *geoipdata = (DetectGeoipData *)ptr; SCFree(geoipdata); } } #ifdef UNITTESTS static int GeoipParseTest(char *rule, int ncountries, char **countries, uint32_t flags) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectGeoipData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, rule); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_MATCH] == NULL) { printf("empty server body list: "); goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_MATCH]->type != DETECT_GEOIP) { printf("last sm not geoip: "); goto end; } data = (DetectGeoipData *)s->sm_lists_tail[DETECT_SM_LIST_MATCH]->ctx; if (data->flags != flags) { printf("flags not right: (flags=%d)",data->flags); goto end; } if (data->nlocations!=ncountries) { printf("wrong number of parsed countries: "); goto end; } for (int i=0; ilocation[i],countries[i])!=0) { printf("wrong parsed country code: "); goto end; } } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } static int GeoipParseTest01(void) { char *ccodes[1] = {"US"}; return GeoipParseTest("alert tcp any any -> any any (geoip:US;sid:1;)", 1, ccodes, GEOIP_MATCH_ANY_FLAG); } static int GeoipParseTest02(void) { char *ccodes[1] = {"US"}; return GeoipParseTest("alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes, GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED); } static int GeoipParseTest03(void) { char *ccodes[1] = {"US"}; return GeoipParseTest("alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes, GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED); } static int GeoipParseTest04(void) { char *ccodes[1] = {"US"}; return GeoipParseTest("alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes, GEOIP_MATCH_SRC_FLAG); } static int GeoipParseTest05(void) { char *ccodes[1] = {"US"}; return GeoipParseTest("alert tcp any any -> any any (geoip:dst,!US;sid:1;)", 1, ccodes, GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED); } static int GeoipParseTest06(void) { char *ccodes[3] = {"US", "ES", "UK"}; return GeoipParseTest("alert tcp any any -> any any (geoip:US,ES,UK;sid:1;)", 3, ccodes, GEOIP_MATCH_ANY_FLAG); } static int GeoipParseTest07(void) { char *ccodes[3] = {"US", "ES", "UK"}; return GeoipParseTest("alert tcp any any -> any any (geoip:both,!US,ES,UK;sid:1;)", 3, ccodes, GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED); } /** * \internal * \brief This test tests geoip success and failure. */ static int GeoipMatchTest(char *rule, char *srcip, char *dstip) { uint8_t *buf = (uint8_t *) "GET / HTTP/1.0\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p1 = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); p1 = UTHBuildPacketSrcDst(buf, buflen, IPPROTO_TCP, srcip, dstip); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, rule); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); result = 2; SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1) == 0) { goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: return result; } static int GeoipMatchTest01(void) { /* Tests with IP of google DNS as US for both src and dst IPs */ return GeoipMatchTest("alert tcp any any -> any any (geoip:US;sid:1;)", "8.8.8.8", "8.8.8.8"); /* Expected result 1 = match */ } static int GeoipMatchTest02(void) { /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ return GeoipMatchTest("alert tcp any any -> any any (geoip:JP;sid:1;)", "8.8.8.8", "202.12.27.33"); /* Expected result 1 = match */ } static int GeoipMatchTest03(void) { /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ return GeoipMatchTest("alert tcp any any -> any any (geoip:dst,JP;sid:1;)", "8.8.8.8", "202.12.27.33"); /* Expected result 1 = match */ } static int GeoipMatchTest04(void) { /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ return GeoipMatchTest("alert tcp any any -> any any (geoip:src,JP;sid:1;)", "8.8.8.8", "202.12.27.33"); /* Expected result 2 = NO match */ } static int GeoipMatchTest05(void) { /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ return GeoipMatchTest("alert tcp any any -> any any (geoip:src,JP,US;sid:1;)", "8.8.8.8", "202.12.27.33"); /* Expected result 1 = match */ } static int GeoipMatchTest06(void) { /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ return GeoipMatchTest("alert tcp any any -> any any (geoip:src,ES,JP,US,UK,PT;sid:1;)", "8.8.8.8", "202.12.27.33"); /* Expected result 1 = match */ } static int GeoipMatchTest07(void) { /* Tests with IP of google DNS as US, and m.root-servers.net as japan */ return GeoipMatchTest("alert tcp any any -> any any (geoip:src,!ES,JP,US,UK,PT;sid:1;)", "8.8.8.8", "202.12.27.33"); /* Expected result 2 = NO match */ } #endif /* UNITTESTS */ /** * \internal * \brief This function registers unit tests for DetectGeoip */ static void DetectGeoipRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("GeoipParseTest01", GeoipParseTest01, 1); UtRegisterTest("GeoipParseTest02", GeoipParseTest02, 1); UtRegisterTest("GeoipParseTest03", GeoipParseTest03, 1); UtRegisterTest("GeoipParseTest04", GeoipParseTest04, 1); UtRegisterTest("GeoipParseTest05", GeoipParseTest05, 1); UtRegisterTest("GeoipParseTest06", GeoipParseTest06, 1); UtRegisterTest("GeoipParseTest07", GeoipParseTest07, 1); UtRegisterTest("GeoipMatchTest01", GeoipMatchTest01, 1); UtRegisterTest("GeoipMatchTest02", GeoipMatchTest02, 1); UtRegisterTest("GeoipMatchTest03", GeoipMatchTest03, 1); UtRegisterTest("GeoipMatchTest04", GeoipMatchTest04, 2); UtRegisterTest("GeoipMatchTest05", GeoipMatchTest05, 1); UtRegisterTest("GeoipMatchTest06", GeoipMatchTest06, 1); UtRegisterTest("GeoipMatchTest07", GeoipMatchTest07, 2); #endif /* UNITTESTS */ } #endif /* HAVE_GEOIP */ suricata-1.4.7/src/unix-manager.h0000644000000000000000000000252512253546156013575 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #ifndef UNIX_MANAGER_H #define UNIX_MANAGER_H #ifdef BUILD_UNIX_SOCKET #include #endif #define UNIX_CMD_TAKE_ARGS 1 SCCondT unix_manager_cond; SCMutex unix_manager_mutex; void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode); void UnixSocketKillSocketThread(void); #ifdef BUILD_UNIX_SOCKET TmEcode UnixManagerRegisterCommand(const char * keyword, TmEcode (*Func)(json_t *, json_t *, void *), void *data, int flags); TmEcode UnixManagerRegisterBackgroundTask( TmEcode (*Func)(void *), void *data); #endif #endif /* UNIX_MANAGER_H */ suricata-1.4.7/src/detect-fast-pattern.c0000644000000000000000000226721012253546156015061 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implements the fast_pattern keyword */ #include "suricata-common.h" #include "detect.h" #include "flow.h" #include "detect-content.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-fast-pattern.h" #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #define DETECT_FAST_PATTERN_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; static int DetectFastPatternSetup(DetectEngineCtx *, Signature *, char *); void DetectFastPatternRegisterTests(void); /* holds the list of sm match lists that need to be searched for a keyword * that has fp support */ SCFPSupportSMList *sm_fp_support_smlist_list = NULL; /** * \brief Lets one add a sm list id to be searched for potential fp supported * keywords later. * * \param list_id SM list id. */ static void SupportFastPatternForSigMatchList(int list_id) { if (sm_fp_support_smlist_list != NULL) { SCFPSupportSMList *tmp_smlist_fp = sm_fp_support_smlist_list; while (tmp_smlist_fp != NULL) { if (tmp_smlist_fp->list_id == list_id) return; tmp_smlist_fp = tmp_smlist_fp->next; } } SCFPSupportSMList *new_smlist_fp = SCMalloc(sizeof(SCFPSupportSMList)); if (unlikely(new_smlist_fp == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(new_smlist_fp, 0, sizeof(SCFPSupportSMList)); new_smlist_fp->list_id = list_id; new_smlist_fp->next = sm_fp_support_smlist_list; sm_fp_support_smlist_list = new_smlist_fp; return; } /** * \brief Registers the keywords(SMs) that should be given fp support. */ void SupportFastPatternForSigMatchTypes(void) { SupportFastPatternForSigMatchList(DETECT_SM_LIST_PMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_UMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCBDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSBDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HMDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRUDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HUADMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHHDMATCH); SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHHDMATCH); return; } /** * \brief Registration function for fast_pattern keyword */ void DetectFastPatternRegister(void) { sigmatch_table[DETECT_FAST_PATTERN].name = "fast_pattern"; sigmatch_table[DETECT_FAST_PATTERN].desc = "force using preceding content in the multi pattern matcher"; sigmatch_table[DETECT_FAST_PATTERN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#fast_pattern"; sigmatch_table[DETECT_FAST_PATTERN].Match = NULL; sigmatch_table[DETECT_FAST_PATTERN].Setup = DetectFastPatternSetup; sigmatch_table[DETECT_FAST_PATTERN].Free = NULL; sigmatch_table[DETECT_FAST_PATTERN].RegisterTests = DetectFastPatternRegisterTests; sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_PAYLOAD; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(DETECT_FAST_PATTERN_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " "offset %" PRId32 ": %s", DETECT_FAST_PATTERN_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* get some way to return an error code! */ return; } //static int DetectFastPatternParseArg( /** * \brief Configures the previous content context for a fast_pattern modifier * keyword used in the rule. * * \param de_ctx Pointer to the Detection Engine Context. * \param s Pointer to the Signature to which the current keyword belongs. * \param null_str Should hold an empty string always. * * \retval 0 On success. * \retval -1 On failure. */ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *arg_substr = NULL; DetectContentData *cd = NULL; if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL && s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL) { SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " "rule, without a preceding content based keyword. " "Currently we provide fast_pattern support for content, " "uricontent, http_client_body, http_server_body, http_header, " "http_raw_header, http_method, http_cookie, " "http_raw_uri, http_stat_msg, http_stat_code, " "http_user_agent, http_host or http_raw_host option"); return -1; } SigMatch *pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " "the rule, without a content context. Please use a " "content based keyword before using fast_pattern"); return -1; } cd = pm->ctx; if ((cd->flags & DETECT_CONTENT_NEGATED) && ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_OFFSET) || (cd->flags & DETECT_CONTENT_DEPTH))) { /* we can't have any of these if we are having "only" */ SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern; cannot be " "used with negated content, along with relative modifiers"); goto error; } if (arg == NULL|| strcmp(arg, "") == 0) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple fast_pattern " "options for the same content"); goto error; } else { /*allow only one content to have fast_pattern modifier*/ int list_id = 0; for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { SigMatch *sm = NULL; for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = sm->ctx; if (tmp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern " "can be used on only one content in a rule"); goto error; } } } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */ } } cd->flags |= DETECT_CONTENT_FAST_PATTERN; return 0; } /* Execute the regex and populate args with captures. */ ret = pcre_exec(parse_regex, parse_regex_study, arg, strlen(arg), 0, 0, ov, MAX_SUBSTRINGS); /* fast pattern only */ if (ret == 2) { if ((cd->flags & DETECT_CONTENT_NEGATED) || (cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_OFFSET) || (cd->flags & DETECT_CONTENT_DEPTH)) { /* we can't have any of these if we are having "only" */ SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern: only; cannot be " "used with negated content or with any of the relative " "modifiers like distance, within, offset, depth"); goto error; } cd->flags |= DETECT_CONTENT_FAST_PATTERN_ONLY; /* fast pattern chop */ } else if (ret == 4) { res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, 2, &arg_substr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for fast_pattern offset"); goto error; } int offset = atoi(arg_substr); if (offset > 65535) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Fast pattern offset exceeds " "limit"); goto error; } res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, 3, &arg_substr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for fast_pattern offset"); goto error; } int length = atoi(arg_substr); if (offset > 65535) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Fast pattern length exceeds " "limit"); goto error; } if (offset + length > 65535) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Fast pattern (length + offset) " "exceeds limit pattern length limit"); goto error; } if (offset + length > cd->content_len) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Fast pattern (length + " "offset (%u)) exceeds pattern length (%u)", offset + length, cd->content_len); goto error; } cd->fp_chop_offset = offset; cd->fp_chop_len = length; cd->flags |= DETECT_CONTENT_FAST_PATTERN_CHOP; } else { SCLogError(SC_ERR_PCRE_PARSE, "parse error, ret %" PRId32 ", string %s", ret, arg); goto error; } //int args; //args = 0; //printf("ret-%d\n", ret); //for (args = 0; args < ret; args++) { // res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, // args, &arg_substr); // if (res < 0) { // SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " // "for arg 1"); // goto error; // } // printf("%d-%s\n", args, arg_substr); //} cd->flags |= DETECT_CONTENT_FAST_PATTERN; return 0; error: return -1; } /*----------------------------------Unittests---------------------------------*/ #ifdef UNITTESTS /** * \test Checks if a fast_pattern is registered in a Signature */ int DetectFastPatternTest01(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; tcpv4-csum:valid; fast_pattern; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; break; } else { result = 0; break; } } sm = sm->next; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature */ int DetectFastPatternTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern; " "content:\"boo\"; fast_pattern; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that we have no fast_pattern registerd for a Signature when the * Signature doesn't contain a fast_pattern */ int DetectFastPatternTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( !(((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { result = 1; } else { result = 0; break; } } sm = sm->next; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a fast_pattern is not registered in a Signature, when we * supply a fast_pattern with an argument */ int DetectFastPatternTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern:boo; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a fast_pattern is used in the mpm phase. */ int DetectFastPatternTest05(void) { uint8_t *buf = (uint8_t *) "Oh strin1. But what " "strin2. This is strings3. We strins_str4. we " "have strins_string5"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; fast_pattern; " "content:\"strings_str4\"; content:\"strings_string5\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (PacketPatternSearchWithStreamCtx(det_ctx, p) != 0) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: UTHFreePackets(&p, 1); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a fast_pattern is used in the mpm phase. */ int DetectFastPatternTest06(void) { uint8_t *buf = (uint8_t *) "Oh this is a string1. But what is this with " "string2. This is strings3. We have strings_str4. We also have " "strings_string5"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; fast_pattern; " "content:\"strings_str4\"; content:\"strings_string5\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (PacketPatternSearchWithStreamCtx(det_ctx, p) != 0) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: UTHFreePackets(&p, 1); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a fast_pattern is used in the mpm phase, when the payload * doesn't contain the fast_pattern string within it. */ int DetectFastPatternTest07(void) { uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. now here comes our " "dark knight strings_string5. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; fast_pattern; " "content:\"strings_str4\"; content:\"strings_string5\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: UTHFreePackets(&p, 1); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a fast_pattern is used in the mpm phase and that we get * exactly 1 match for the mpm phase. */ int DetectFastPatternTest08(void) { uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. now here comes our " "dark knight strings3. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("de_ctx init: "); goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; fast_pattern; " "content:\"strings_str4\"; content:\"strings_string5\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); if (r != 1) { printf("expected 1, got %"PRIu32": ", r); goto end; } result = 1; end: UTHFreePackets(&p, 1); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a fast_pattern is used in the mpm phase, when the payload * doesn't contain the fast_pattern string within it. */ int DetectFastPatternTest09(void) { uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. no_strings4 _imp now here " "comes our dark knight strings3. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; " "content:\"strings4_imp\"; fast_pattern; " "content:\"strings_string5\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: UTHFreePackets(&p, 1); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a the SigInit chooses the fast_pattern with better pattern * strength, when we have multiple fast_patterns in the Signature. Also * checks that we get a match for the fast_pattern from the mpm phase. */ int DetectFastPatternTest10(void) { uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. strings4_imp now here " "comes our dark knight strings5. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("de_ctx init: "); goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; " "content:\"strings4_imp\"; fast_pattern; " "content:\"strings_string5\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); if (r != 1) { printf("expected 1, got %"PRIu32": ", r); goto end; } result = 1; end: UTHFreePackets(&p, 1); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a the SigInit chooses the fast_pattern with better pattern * strength, when we have multiple fast_patterns in the Signature. Also * checks that we get no matches for the fast_pattern from the mpm phase. */ int DetectFastPatternTest11(void) { uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. strings5_imp now here " "comes our dark knight strings5. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; " "content:\"strings4_imp\"; fast_pattern; " "content:\"strings_string5\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) result = 1; end: UTHFreePackets(&p, 1); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } return result; } /** * \test Checks that we don't get a match for the mpm phase. */ int DetectFastPatternTest12(void) { uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. strings5_imp now here " "comes our dark knight strings5. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; " "content:\"strings4_imp\"; " "content:\"strings_string5\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: UTHFreePackets(&p, 1); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks that a the SigInit chooses the fast_pattern with a better * strength from the available patterns, when we don't specify a * fast_pattern. We also check that we get a match from the mpm * phase. */ int DetectFastPatternTest13(void) { uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. strings5_imp now here " "comes our dark knight strings_string5. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("de_ctx init: "); goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"string1\"; " "content:\"string2\"; content:\"strings3\"; " "content:\"strings4_imp\"; " "content:\"strings_string5\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); if (r != 1) { printf("expected 1 result, got %"PRIu32": ", r); goto end; } result = 1; end: UTHFreePackets(&p, 1); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks to make sure that other sigs work that should when fast_pattern is inspecting on the same payload * */ int DetectFastPatternTest14(void) { uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. strings5_imp now here " "comes our dark knight strings_string5. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int alertcnt = 0; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; FlowInitConfig(FLOW_QUIET); de_ctx->mpm_matcher = MPM_B3G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"strings_string5\"; content:\"knight\"; fast_pattern; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test different content\"; content:\"Dummy is our name\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)){ alertcnt++; }else{ SCLogInfo("could not match on sig 1 with when fast_pattern is inspecting payload"); goto end; } if (PacketAlertCheck(p, 2)){ result = 1; }else{ SCLogInfo("match on sig 1 fast_pattern no match sig 2 inspecting same payload"); } end: UTHFreePackets(&p, 1); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); return result; } /** * \test Checks if a fast_pattern is registered in a Signature */ int DetectFastPatternTest15(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; break; } else { result = 0; break; } } sm = sm->next; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature */ int DetectFastPatternTest16(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; break; } else { result = 0; break; } } sm = sm->next; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest17(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; DetectContentData *cd = sm->ctx; if (sm->type == DETECT_CONTENT) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && cd->fp_chop_offset == 0 && cd->fp_chop_len == 0) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest18(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; DetectContentData *cd = sm->ctx; if (sm->type == DETECT_CONTENT) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content: \"one\"; content:\"two\"; distance:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && cd->fp_chop_offset == 0 && cd->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; within:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && cd->fp_chop_offset == 0 && cd->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; offset:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && cd->fp_chop_offset == 0 && cd->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; depth:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && cd->fp_chop_offset == 0 && cd->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_NEGATED && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && cd->fp_chop_offset == 0 && cd->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest37(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; content:\"oneonetwo\"; fast_pattern:3,4; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest38(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest39(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest40(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest41(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest42(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; distance:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest43(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; within:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest44(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; offset:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest45(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; depth:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest46(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:65977,4; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest47(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"twooneone\"; fast_pattern:3,65977; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest48(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:65534,4; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest49(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_NEGATED && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && cd->fp_chop_offset == 3 && cd->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest50(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; distance:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest51(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; within:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest52(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; offset:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest53(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; depth:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* content fast_pattern tests ^ */ /* uricontent fast_pattern tests v */ /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest54(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"/one/\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; break; } else { result = 0; break; } } sm = sm->next; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest55(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; break; } else { result = 0; break; } } sm = sm->next; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest56(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; DetectContentData *ud = sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest57(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; DetectContentData *ud = sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest58(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest59(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest60(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest61(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest62(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest63(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest64(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest65(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest66(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest67(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent: \"one\"; uricontent:\"two\"; distance:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest68(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest69(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest70(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest71(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:!\"one\"; fast_pattern; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest72(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest73(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest74(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest75(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest76(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest77(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest78(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest79(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest80(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest81(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest82(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest83(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest84(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest85(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:65977,4; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest86(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,65977; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest87(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:65534,4; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest88(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest89(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; distance:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest90(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; within:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest91(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; offset:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest92(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; depth:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* uricontent fast_pattern tests ^ */ /* http_uri fast_pattern tests v */ int DetectFastPatternTest93(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest94(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; break; } else { result = 0; break; } } sm = sm->next; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest95(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; break; } else { result = 0; break; } } sm = sm->next; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest96(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; DetectContentData *ud = sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest97(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; DetectContentData *ud = sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest98(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest99(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; distance:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest100(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest101(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; within:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest102(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest103(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; offset:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest104(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest105(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; depth:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest106(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:!\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest107(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent: \"one\"; uricontent:\"two\"; distance:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest108(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest109(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest110(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest111(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_uri; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest112(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest113(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest114(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest115(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest116(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest117(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest118(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest119(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest120(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest121(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest122(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest123(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest124(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest125(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:65977,4; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest126(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,65977; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest127(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:65534,4; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest128(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest129(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; distance:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest130(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; within:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest131(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; http_uri; offset:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest132(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; depth:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest133(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_uri fast_pattern tests ^ */ /* http_client_body fast_pattern tests v */ int DetectFastPatternTest134(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest135(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_client_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest136(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_client_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest137(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest138(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest139(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest140(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; distance:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest141(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest142(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; within:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest143(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest144(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; offset:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest145(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest146(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; depth:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest147(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:!\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest148(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content: \"one\"; http_client_body; content:\"two\"; http_client_body; distance:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest149(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest150(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest151(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest152(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_client_body; content:\"two\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest153(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest154(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest155(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest156(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest157(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest158(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest159(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest160(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest161(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest162(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest163(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest164(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest165(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest166(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:65977,4; http_client_body; content:\"three\"; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest167(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,65977; http_client_body; content:\"three\"; distance:10; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest168(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:65534,4; http_client_body; content:\"three\"; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest169(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest170(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; distance:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest171(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; within:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest172(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:!\"twooneone\"; fast_pattern:3,4; http_client_body; offset:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest173(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; depth:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest174(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_client_body fast_pattern tests ^ */ /* content fast_pattern tests v */ int DetectFastPatternTest175(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; content:!\"one\"; distance:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest176(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; content:!\"one\"; within:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest177(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; content:!\"one\"; offset:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest178(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; content:!\"one\"; depth:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* content fast_pattern tests ^ */ /* http_header fast_pattern tests v */ int DetectFastPatternTest179(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_header; " "content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest180(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_header; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest181(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_header; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest182(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest183(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest184(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest185(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; distance:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest186(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest187(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; within:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest188(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest189(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; offset:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest190(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest191(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; depth:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest192(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:!\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest193(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content: \"one\"; http_header; content:\"two\"; http_header; distance:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest194(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; within:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest195(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; offset:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest196(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; depth:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest197(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_header; content:\"two\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest198(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest199(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest200(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest201(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest202(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest203(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest204(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest205(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest206(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest207(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest208(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest209(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest210(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest211(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:65977,4; http_header; content:\"three\"; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest212(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,65977; http_header; content:\"three\"; distance:10; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest213(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:65534,4; http_header; content:\"three\"; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest214(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest215(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; distance:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest216(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; within:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest217(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; offset:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest218(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; depth:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest219(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_header fast_pattern tests ^ */ /* http_raw_header fast_pattern tests v */ int DetectFastPatternTest220(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; " "content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest221(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"/one/\"; fast_pattern:only; http_raw_header; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest222(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"oneoneone\"; fast_pattern:3,4; http_raw_header; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest223(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest224(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"oneoneone\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest225(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; fast_pattern:only; http_raw_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest226(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; distance:10; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest227(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; fast_pattern:only; http_raw_header; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest228(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; within:10; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest229(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; fast_pattern:only; http_raw_header; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest230(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; offset:10; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest231(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; fast_pattern:only; http_raw_header; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest232(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; depth:10; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest233(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:!\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest234(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content: \"one\"; http_raw_header; content:\"two\"; http_raw_header; distance:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest235(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; within:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest236(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; offset:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest237(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; depth:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest238(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:!\"one\"; fast_pattern; http_raw_header; content:\"two\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest239(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"two\"; http_raw_header; content:!\"one\"; fast_pattern; http_raw_header; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest240(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"two\"; http_raw_header; content:!\"one\"; fast_pattern; http_raw_header; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest241(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"two\"; http_raw_header; content:!\"one\"; fast_pattern; http_raw_header; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest242(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"two\"; http_raw_header; content:!\"one\"; fast_pattern; http_raw_header; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest243(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest244(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest245(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest246(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest247(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest248(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest249(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest250(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest251(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest252(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; fast_pattern:65977,4; http_raw_header; content:\"three\"; http_raw_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest253(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,65977; http_raw_header; content:\"three\"; distance:10; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest254(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; fast_pattern:65534,4; http_raw_header; content:\"three\"; http_raw_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest255(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest256(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; distance:10; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest257(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; within:10; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest258(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; offset:10; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest259(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; depth:10; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest260(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_raw_header fast_pattern tests ^ */ /* http_method fast_pattern tests v */ int DetectFastPatternTest261(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_method; " "content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest262(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_method; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest263(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_method; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest264(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest265(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest266(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest267(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; distance:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest268(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest269(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; within:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest270(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest271(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; offset:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest272(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest273(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; depth:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest274(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:!\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest275(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content: \"one\"; http_method; content:\"two\"; http_method; distance:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest276(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; within:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest277(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; offset:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest278(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; depth:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest279(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_method; content:\"two\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest280(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest281(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest282(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest283(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest284(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest285(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest286(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest287(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest288(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest289(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest290(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest291(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest292(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest293(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:65977,4; http_method; content:\"three\"; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest294(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,65977; http_method; content:\"three\"; distance:10; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest295(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:65534,4; http_method; content:\"three\"; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest296(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest297(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; distance:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest298(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; within:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest299(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; offset:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest300(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; depth:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest301(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_method fast_pattern tests ^ */ /* http_cookie fast_pattern tests v */ int DetectFastPatternTest302(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; " "content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest303(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_cookie; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest304(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_cookie; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest305(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest306(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest307(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest308(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; distance:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest309(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest310(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; within:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest311(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest312(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; offset:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest313(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest314(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; depth:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest315(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:!\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest316(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content: \"one\"; http_cookie; content:\"two\"; http_cookie; distance:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest317(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest318(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest319(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest320(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_cookie; content:\"two\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest321(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest322(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest323(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest324(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest325(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest326(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest327(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest328(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest329(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest330(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest331(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest332(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest333(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest334(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:65977,4; http_cookie; content:\"three\"; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest335(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,65977; http_cookie; content:\"three\"; distance:10; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest336(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:65534,4; http_cookie; content:\"three\"; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest337(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest338(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; distance:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest339(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; within:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest340(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; offset:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest341(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; depth:10; content:\"three2\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest342(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_cookie fast_pattern tests ^ */ /* http_raw_uri fast_pattern tests v */ int DetectFastPatternTest343(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest344(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_raw_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest345(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest346(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest347(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest348(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest349(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; distance:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest350(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest351(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; within:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest352(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest353(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; offset:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest354(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest355(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; depth:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest356(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest357(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content: \"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; distance:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest358(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; within:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest359(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; offset:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest360(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; depth:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest361(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_raw_uri; " "content:\"two\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest362(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest363(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest364(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest365(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest366(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest367(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest368(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest369(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest370(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest371(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest372(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest373(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest374(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest375(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:65977,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest376(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_raw_uri; " "content:\"three\"; distance:10; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest377(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:65534,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest378(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest379(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; distance:10; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest380(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; within:10; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest381(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; offset:10; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest382(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; depth:10; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest383(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_raw_uri fast_pattern tests ^ */ /* http_stat_msg fast_pattern tests v */ int DetectFastPatternTest384(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest385(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_msg; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest386(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_msg; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest387(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest388(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest389(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest390(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; distance:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest391(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest392(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; within:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest393(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest394(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; offset:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest395(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest396(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; depth:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest397(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest398(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\" one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; distance:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest399(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; within:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest400(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; offset:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest401(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; depth:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest402(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_stat_msg; " "content:\"two\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest403(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest404(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest405(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest406(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest407(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest408(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest409(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest410(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest411(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest412(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest413(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest414(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest415(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest416(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:65977,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest417(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_stat_msg; " "content:\"three\"; distance:10; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest418(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:65534,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest419(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest420(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; distance:10; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest421(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; within:10; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest422(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; offset:10; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest423(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; depth:10; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest424(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_stat_msg fast_pattern tests ^ */ /* http_stat_code fast_pattern tests v */ int DetectFastPatternTest425(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest426(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_code; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest427(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_code; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest428(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest429(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest430(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest431(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; distance:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest432(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest433(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; within:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest434(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest435(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; offset:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest436(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest437(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; depth:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest438(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest439(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\" one\"; http_stat_code; " "content:\"two\"; http_stat_code; distance:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest440(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; within:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest441(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; offset:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest442(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; depth:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest443(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_stat_code; " "content:\"two\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest444(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest445(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest446(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest447(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest448(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest449(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest450(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest451(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest452(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest453(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest454(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest455(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest456(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest457(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:65977,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest458(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_stat_code; " "content:\"three\"; distance:10; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest459(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:65534,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest460(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest461(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; distance:10; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest462(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; within:10; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest463(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; offset:10; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest464(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; depth:10; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest465(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_stat_code fast_pattern tests ^ */ /* http_server_body fast_pattern tests v */ int DetectFastPatternTest466(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest467(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_server_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest468(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_server_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest469(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest470(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest471(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest472(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; distance:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest473(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest474(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; within:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest475(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest476(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; offset:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest477(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest478(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; depth:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest479(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest480(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\" one\"; http_server_body; " "content:\"two\"; http_server_body; distance:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest481(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; within:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest482(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; offset:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest483(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; depth:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest484(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_server_body; " "content:\"two\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest485(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest486(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest487(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest488(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest489(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest490(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest491(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest492(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest493(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest494(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest495(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest496(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest497(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest498(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:65977,4; http_server_body; " "content:\"three\"; http_server_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest499(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_server_body; " "content:\"three\"; distance:10; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest500(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:65534,4; http_server_body; " "content:\"three\"; http_server_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest501(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest502(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; distance:10; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest503(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; within:10; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest504(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; offset:10; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest505(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; depth:10; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest506(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_server_body fast_pattern tests ^ */ /* file_data fast_pattern tests v */ int DetectFastPatternTest507(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest508(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest509(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest510(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest511(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest512(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest513(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest514(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest515(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest516(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest517(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest518(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest519(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest520(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest521(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\" one\"; " "content:\"two\"; distance:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest522(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest523(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest524(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest525(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:!\"one\"; fast_pattern; " "content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest526(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest527(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest528(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest529(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest530(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest531(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest532(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest533(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest534(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest535(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest536(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest537(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest538(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest539(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:65977,4; " "content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest540(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,65977; " "content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest541(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:65534,4; " "content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest542(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest543(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; distance:10; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest544(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; within:10; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest545(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; offset:10; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest546(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; depth:10; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest547(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* file_data fast_pattern tests ^ */ /* http_user_agent fast_pattern tests v */ int DetectFastPatternTest548(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest549(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_user_agent; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest550(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_user_agent; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest551(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest552(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest553(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest554(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; distance:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest555(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest556(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; within:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest557(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest558(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; offset:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest559(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest560(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; depth:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest561(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest562(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\" one\"; http_user_agent; " "content:\"two\"; http_user_agent; distance:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest563(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; within:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest564(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; offset:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest565(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; depth:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest566(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_user_agent; " "content:\"two\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest567(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest568(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest569(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest570(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest571(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest572(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest573(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest574(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest575(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest576(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest577(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest578(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest579(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest580(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:65977,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest581(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_user_agent; " "content:\"three\"; distance:10; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest582(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:65534,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest583(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest584(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; distance:10; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest585(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; within:10; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest586(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; offset:10; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest587(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; depth:10; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest588(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_user_agent fast_pattern tests ^ */ /* http_host fast_pattern tests v */ int DetectFastPatternTest589(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest590(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_host; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest591(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_host; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest592(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest593(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest594(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest595(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; distance:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest596(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest597(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; within:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest598(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest599(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; offset:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest600(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest601(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; depth:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest602(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:!\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest603(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\" one\"; http_host; " "content:\"two\"; http_host; distance:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest604(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; within:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest605(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; offset:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest606(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; depth:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest607(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_host; " "content:\"two\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest608(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest609(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest610(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest611(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest612(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest613(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest614(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest615(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest616(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest617(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest618(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest619(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest620(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest621(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:65977,4; http_host; " "content:\"three\"; http_host; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest622(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_host; " "content:\"three\"; distance:10; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest623(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:65534,4; http_host; " "content:\"three\"; http_host; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest624(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest625(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; distance:10; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest626(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; within:10; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest627(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; offset:10; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest628(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; depth:10; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest629(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /* http_host fast_pattern tests ^ */ /* http_rawhost fast_pattern tests v */ int DetectFastPatternTest630(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest631(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_host; nocase; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) && (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_NOCASE)) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a fast_pattern is registered in a Signature for uricontent. */ int DetectFastPatternTest632(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_host; nocase; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) && (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_NOCASE)) { result = 1; } else { result = 0; } } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest633(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest634(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; if (sm == NULL) { goto end; } DetectContentData *ud = sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest635(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; distance:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest636(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; distance:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest637(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; within:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest638(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; within:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest639(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; offset:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest640(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; offset:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest641(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; depth:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest642(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; depth:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest643(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest644(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\" one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; distance:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest645(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; within:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest646(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; offset:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest647(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; depth:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest648(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:!\"one\"; fast_pattern; http_raw_host; nocase; " "content:\"two\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && ud->fp_chop_offset == 0 && ud->fp_chop_len == 0) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest649(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; distance:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest650(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; within:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest651(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; offset:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest652(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; depth:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest653(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest654(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest655(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; within:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest656(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; offset:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest657(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; depth:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest658(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; distance:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest659(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; within:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest660(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; offset:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest661(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; depth:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest662(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:65977,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest663(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_raw_host; nocase; " "content:\"three\"; distance:10; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest664(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:65534,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest665(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest666(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; distance:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest667(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; within:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest668(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; offset:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest669(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; depth:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectFastPatternTest670(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && ud->fp_chop_offset == 3 && ud->fp_chop_len == 4) { result = 1; } else { result = 0; } end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif void DetectFastPatternRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01, 1); UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02, 1); UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03, 1); UtRegisterTest("DetectFastPatternTest04", DetectFastPatternTest04, 1); UtRegisterTest("DetectFastPatternTest05", DetectFastPatternTest05, 1); UtRegisterTest("DetectFastPatternTest06", DetectFastPatternTest06, 1); UtRegisterTest("DetectFastPatternTest07", DetectFastPatternTest07, 1); UtRegisterTest("DetectFastPatternTest08", DetectFastPatternTest08, 1); UtRegisterTest("DetectFastPatternTest09", DetectFastPatternTest09, 1); UtRegisterTest("DetectFastPatternTest10", DetectFastPatternTest10, 1); UtRegisterTest("DetectFastPatternTest11", DetectFastPatternTest11, 1); UtRegisterTest("DetectFastPatternTest12", DetectFastPatternTest12, 1); UtRegisterTest("DetectFastPatternTest13", DetectFastPatternTest13, 1); UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14, 1); UtRegisterTest("DetectFastPatternTest15", DetectFastPatternTest15, 1); UtRegisterTest("DetectFastPatternTest16", DetectFastPatternTest16, 1); UtRegisterTest("DetectFastPatternTest17", DetectFastPatternTest17, 1); UtRegisterTest("DetectFastPatternTest18", DetectFastPatternTest18, 1); UtRegisterTest("DetectFastPatternTest19", DetectFastPatternTest19, 1); UtRegisterTest("DetectFastPatternTest20", DetectFastPatternTest20, 1); UtRegisterTest("DetectFastPatternTest21", DetectFastPatternTest21, 1); UtRegisterTest("DetectFastPatternTest22", DetectFastPatternTest22, 1); UtRegisterTest("DetectFastPatternTest23", DetectFastPatternTest23, 1); UtRegisterTest("DetectFastPatternTest24", DetectFastPatternTest24, 1); UtRegisterTest("DetectFastPatternTest25", DetectFastPatternTest25, 1); UtRegisterTest("DetectFastPatternTest26", DetectFastPatternTest26, 1); UtRegisterTest("DetectFastPatternTest27", DetectFastPatternTest27, 1); UtRegisterTest("DetectFastPatternTest28", DetectFastPatternTest28, 1); UtRegisterTest("DetectFastPatternTest29", DetectFastPatternTest29, 1); UtRegisterTest("DetectFastPatternTest30", DetectFastPatternTest30, 1); UtRegisterTest("DetectFastPatternTest31", DetectFastPatternTest31, 1); UtRegisterTest("DetectFastPatternTest32", DetectFastPatternTest32, 1); UtRegisterTest("DetectFastPatternTest33", DetectFastPatternTest33, 1); UtRegisterTest("DetectFastPatternTest34", DetectFastPatternTest34, 1); UtRegisterTest("DetectFastPatternTest35", DetectFastPatternTest35, 1); UtRegisterTest("DetectFastPatternTest36", DetectFastPatternTest36, 1); UtRegisterTest("DetectFastPatternTest37", DetectFastPatternTest37, 1); UtRegisterTest("DetectFastPatternTest38", DetectFastPatternTest38, 1); UtRegisterTest("DetectFastPatternTest39", DetectFastPatternTest39, 1); UtRegisterTest("DetectFastPatternTest40", DetectFastPatternTest40, 1); UtRegisterTest("DetectFastPatternTest41", DetectFastPatternTest41, 1); UtRegisterTest("DetectFastPatternTest42", DetectFastPatternTest42, 1); UtRegisterTest("DetectFastPatternTest43", DetectFastPatternTest43, 1); UtRegisterTest("DetectFastPatternTest44", DetectFastPatternTest44, 1); UtRegisterTest("DetectFastPatternTest45", DetectFastPatternTest45, 1); UtRegisterTest("DetectFastPatternTest46", DetectFastPatternTest46, 1); UtRegisterTest("DetectFastPatternTest47", DetectFastPatternTest47, 1); UtRegisterTest("DetectFastPatternTest48", DetectFastPatternTest48, 1); UtRegisterTest("DetectFastPatternTest49", DetectFastPatternTest49, 1); UtRegisterTest("DetectFastPatternTest50", DetectFastPatternTest50, 1); UtRegisterTest("DetectFastPatternTest51", DetectFastPatternTest51, 1); UtRegisterTest("DetectFastPatternTest52", DetectFastPatternTest52, 1); UtRegisterTest("DetectFastPatternTest53", DetectFastPatternTest53, 1); /* content fast_pattern tests ^ */ /* uricontent fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest54", DetectFastPatternTest54, 1); UtRegisterTest("DetectFastPatternTest55", DetectFastPatternTest55, 1); UtRegisterTest("DetectFastPatternTest56", DetectFastPatternTest56, 1); UtRegisterTest("DetectFastPatternTest57", DetectFastPatternTest57, 1); UtRegisterTest("DetectFastPatternTest58", DetectFastPatternTest58, 1); UtRegisterTest("DetectFastPatternTest59", DetectFastPatternTest59, 1); UtRegisterTest("DetectFastPatternTest60", DetectFastPatternTest60, 1); UtRegisterTest("DetectFastPatternTest61", DetectFastPatternTest61, 1); UtRegisterTest("DetectFastPatternTest62", DetectFastPatternTest62, 1); UtRegisterTest("DetectFastPatternTest63", DetectFastPatternTest63, 1); UtRegisterTest("DetectFastPatternTest64", DetectFastPatternTest64, 1); UtRegisterTest("DetectFastPatternTest65", DetectFastPatternTest65, 1); UtRegisterTest("DetectFastPatternTest66", DetectFastPatternTest66, 1); UtRegisterTest("DetectFastPatternTest67", DetectFastPatternTest67, 1); UtRegisterTest("DetectFastPatternTest68", DetectFastPatternTest68, 1); UtRegisterTest("DetectFastPatternTest69", DetectFastPatternTest69, 1); UtRegisterTest("DetectFastPatternTest70", DetectFastPatternTest70, 1); UtRegisterTest("DetectFastPatternTest71", DetectFastPatternTest71, 1); UtRegisterTest("DetectFastPatternTest72", DetectFastPatternTest72, 1); UtRegisterTest("DetectFastPatternTest73", DetectFastPatternTest73, 1); UtRegisterTest("DetectFastPatternTest74", DetectFastPatternTest74, 1); UtRegisterTest("DetectFastPatternTest75", DetectFastPatternTest75, 1); UtRegisterTest("DetectFastPatternTest76", DetectFastPatternTest76, 1); UtRegisterTest("DetectFastPatternTest77", DetectFastPatternTest77, 1); UtRegisterTest("DetectFastPatternTest78", DetectFastPatternTest78, 1); UtRegisterTest("DetectFastPatternTest79", DetectFastPatternTest79, 1); UtRegisterTest("DetectFastPatternTest80", DetectFastPatternTest80, 1); UtRegisterTest("DetectFastPatternTest81", DetectFastPatternTest81, 1); UtRegisterTest("DetectFastPatternTest82", DetectFastPatternTest82, 1); UtRegisterTest("DetectFastPatternTest83", DetectFastPatternTest83, 1); UtRegisterTest("DetectFastPatternTest84", DetectFastPatternTest84, 1); UtRegisterTest("DetectFastPatternTest85", DetectFastPatternTest85, 1); UtRegisterTest("DetectFastPatternTest86", DetectFastPatternTest86, 1); UtRegisterTest("DetectFastPatternTest87", DetectFastPatternTest87, 1); UtRegisterTest("DetectFastPatternTest88", DetectFastPatternTest88, 1); UtRegisterTest("DetectFastPatternTest89", DetectFastPatternTest89, 1); UtRegisterTest("DetectFastPatternTest90", DetectFastPatternTest90, 1); UtRegisterTest("DetectFastPatternTest91", DetectFastPatternTest91, 1); UtRegisterTest("DetectFastPatternTest92", DetectFastPatternTest92, 1); /* uricontent fast_pattern tests ^ */ /* http_uri fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest93", DetectFastPatternTest93, 1); UtRegisterTest("DetectFastPatternTest94", DetectFastPatternTest94, 1); UtRegisterTest("DetectFastPatternTest95", DetectFastPatternTest95, 1); UtRegisterTest("DetectFastPatternTest96", DetectFastPatternTest96, 1); UtRegisterTest("DetectFastPatternTest97", DetectFastPatternTest97, 1); UtRegisterTest("DetectFastPatternTest98", DetectFastPatternTest98, 1); UtRegisterTest("DetectFastPatternTest99", DetectFastPatternTest99, 1); UtRegisterTest("DetectFastPatternTest100", DetectFastPatternTest100, 1); UtRegisterTest("DetectFastPatternTest101", DetectFastPatternTest101, 1); UtRegisterTest("DetectFastPatternTest102", DetectFastPatternTest102, 1); UtRegisterTest("DetectFastPatternTest103", DetectFastPatternTest103, 1); UtRegisterTest("DetectFastPatternTest104", DetectFastPatternTest104, 1); UtRegisterTest("DetectFastPatternTest105", DetectFastPatternTest105, 1); UtRegisterTest("DetectFastPatternTest106", DetectFastPatternTest106, 1); UtRegisterTest("DetectFastPatternTest107", DetectFastPatternTest107, 1); UtRegisterTest("DetectFastPatternTest108", DetectFastPatternTest108, 1); UtRegisterTest("DetectFastPatternTest109", DetectFastPatternTest109, 1); UtRegisterTest("DetectFastPatternTest110", DetectFastPatternTest110, 1); UtRegisterTest("DetectFastPatternTest111", DetectFastPatternTest111, 1); UtRegisterTest("DetectFastPatternTest112", DetectFastPatternTest112, 1); UtRegisterTest("DetectFastPatternTest113", DetectFastPatternTest113, 1); UtRegisterTest("DetectFastPatternTest114", DetectFastPatternTest114, 1); UtRegisterTest("DetectFastPatternTest115", DetectFastPatternTest115, 1); UtRegisterTest("DetectFastPatternTest116", DetectFastPatternTest116, 1); UtRegisterTest("DetectFastPatternTest117", DetectFastPatternTest117, 1); UtRegisterTest("DetectFastPatternTest118", DetectFastPatternTest118, 1); UtRegisterTest("DetectFastPatternTest119", DetectFastPatternTest119, 1); UtRegisterTest("DetectFastPatternTest120", DetectFastPatternTest120, 1); UtRegisterTest("DetectFastPatternTest121", DetectFastPatternTest121, 1); UtRegisterTest("DetectFastPatternTest122", DetectFastPatternTest122, 1); UtRegisterTest("DetectFastPatternTest123", DetectFastPatternTest123, 1); UtRegisterTest("DetectFastPatternTest124", DetectFastPatternTest124, 1); UtRegisterTest("DetectFastPatternTest125", DetectFastPatternTest125, 1); UtRegisterTest("DetectFastPatternTest126", DetectFastPatternTest126, 1); UtRegisterTest("DetectFastPatternTest127", DetectFastPatternTest127, 1); UtRegisterTest("DetectFastPatternTest128", DetectFastPatternTest128, 1); UtRegisterTest("DetectFastPatternTest129", DetectFastPatternTest129, 1); UtRegisterTest("DetectFastPatternTest130", DetectFastPatternTest130, 1); UtRegisterTest("DetectFastPatternTest131", DetectFastPatternTest131, 1); UtRegisterTest("DetectFastPatternTest132", DetectFastPatternTest132, 1); UtRegisterTest("DetectFastPatternTest133", DetectFastPatternTest133, 1); /* http_uri fast_pattern tests ^ */ /* http_client_body fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest134", DetectFastPatternTest134, 1); UtRegisterTest("DetectFastPatternTest135", DetectFastPatternTest135, 1); UtRegisterTest("DetectFastPatternTest136", DetectFastPatternTest136, 1); UtRegisterTest("DetectFastPatternTest137", DetectFastPatternTest137, 1); UtRegisterTest("DetectFastPatternTest138", DetectFastPatternTest138, 1); UtRegisterTest("DetectFastPatternTest139", DetectFastPatternTest139, 1); UtRegisterTest("DetectFastPatternTest140", DetectFastPatternTest140, 1); UtRegisterTest("DetectFastPatternTest141", DetectFastPatternTest141, 1); UtRegisterTest("DetectFastPatternTest142", DetectFastPatternTest142, 1); UtRegisterTest("DetectFastPatternTest143", DetectFastPatternTest143, 1); UtRegisterTest("DetectFastPatternTest144", DetectFastPatternTest144, 1); UtRegisterTest("DetectFastPatternTest145", DetectFastPatternTest145, 1); UtRegisterTest("DetectFastPatternTest146", DetectFastPatternTest146, 1); UtRegisterTest("DetectFastPatternTest147", DetectFastPatternTest147, 1); UtRegisterTest("DetectFastPatternTest148", DetectFastPatternTest148, 1); UtRegisterTest("DetectFastPatternTest149", DetectFastPatternTest149, 1); UtRegisterTest("DetectFastPatternTest150", DetectFastPatternTest150, 1); UtRegisterTest("DetectFastPatternTest151", DetectFastPatternTest151, 1); UtRegisterTest("DetectFastPatternTest152", DetectFastPatternTest152, 1); UtRegisterTest("DetectFastPatternTest153", DetectFastPatternTest153, 1); UtRegisterTest("DetectFastPatternTest154", DetectFastPatternTest154, 1); UtRegisterTest("DetectFastPatternTest155", DetectFastPatternTest155, 1); UtRegisterTest("DetectFastPatternTest156", DetectFastPatternTest156, 1); UtRegisterTest("DetectFastPatternTest157", DetectFastPatternTest157, 1); UtRegisterTest("DetectFastPatternTest158", DetectFastPatternTest158, 1); UtRegisterTest("DetectFastPatternTest159", DetectFastPatternTest159, 1); UtRegisterTest("DetectFastPatternTest160", DetectFastPatternTest160, 1); UtRegisterTest("DetectFastPatternTest161", DetectFastPatternTest161, 1); UtRegisterTest("DetectFastPatternTest162", DetectFastPatternTest162, 1); UtRegisterTest("DetectFastPatternTest163", DetectFastPatternTest163, 1); UtRegisterTest("DetectFastPatternTest164", DetectFastPatternTest164, 1); UtRegisterTest("DetectFastPatternTest165", DetectFastPatternTest165, 1); UtRegisterTest("DetectFastPatternTest166", DetectFastPatternTest166, 1); UtRegisterTest("DetectFastPatternTest167", DetectFastPatternTest167, 1); UtRegisterTest("DetectFastPatternTest168", DetectFastPatternTest168, 1); UtRegisterTest("DetectFastPatternTest169", DetectFastPatternTest169, 1); UtRegisterTest("DetectFastPatternTest170", DetectFastPatternTest170, 1); UtRegisterTest("DetectFastPatternTest171", DetectFastPatternTest171, 1); UtRegisterTest("DetectFastPatternTest172", DetectFastPatternTest172, 1); UtRegisterTest("DetectFastPatternTest173", DetectFastPatternTest173, 1); UtRegisterTest("DetectFastPatternTest174", DetectFastPatternTest174, 1); /* http_client_body fast_pattern tests ^ */ /* content fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest175", DetectFastPatternTest175, 1); UtRegisterTest("DetectFastPatternTest176", DetectFastPatternTest176, 1); UtRegisterTest("DetectFastPatternTest177", DetectFastPatternTest177, 1); UtRegisterTest("DetectFastPatternTest178", DetectFastPatternTest178, 1); /* content fast_pattern tests ^ */ /* http_header fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest179", DetectFastPatternTest179, 1); UtRegisterTest("DetectFastPatternTest180", DetectFastPatternTest180, 1); UtRegisterTest("DetectFastPatternTest181", DetectFastPatternTest181, 1); UtRegisterTest("DetectFastPatternTest182", DetectFastPatternTest182, 1); UtRegisterTest("DetectFastPatternTest183", DetectFastPatternTest183, 1); UtRegisterTest("DetectFastPatternTest184", DetectFastPatternTest184, 1); UtRegisterTest("DetectFastPatternTest185", DetectFastPatternTest185, 1); UtRegisterTest("DetectFastPatternTest186", DetectFastPatternTest186, 1); UtRegisterTest("DetectFastPatternTest187", DetectFastPatternTest187, 1); UtRegisterTest("DetectFastPatternTest188", DetectFastPatternTest188, 1); UtRegisterTest("DetectFastPatternTest189", DetectFastPatternTest189, 1); UtRegisterTest("DetectFastPatternTest190", DetectFastPatternTest190, 1); UtRegisterTest("DetectFastPatternTest191", DetectFastPatternTest191, 1); UtRegisterTest("DetectFastPatternTest192", DetectFastPatternTest192, 1); UtRegisterTest("DetectFastPatternTest193", DetectFastPatternTest193, 1); UtRegisterTest("DetectFastPatternTest194", DetectFastPatternTest194, 1); UtRegisterTest("DetectFastPatternTest195", DetectFastPatternTest195, 1); UtRegisterTest("DetectFastPatternTest196", DetectFastPatternTest196, 1); UtRegisterTest("DetectFastPatternTest197", DetectFastPatternTest197, 1); UtRegisterTest("DetectFastPatternTest198", DetectFastPatternTest198, 1); UtRegisterTest("DetectFastPatternTest199", DetectFastPatternTest199, 1); UtRegisterTest("DetectFastPatternTest200", DetectFastPatternTest200, 1); UtRegisterTest("DetectFastPatternTest201", DetectFastPatternTest201, 1); UtRegisterTest("DetectFastPatternTest202", DetectFastPatternTest202, 1); UtRegisterTest("DetectFastPatternTest203", DetectFastPatternTest203, 1); UtRegisterTest("DetectFastPatternTest204", DetectFastPatternTest204, 1); UtRegisterTest("DetectFastPatternTest205", DetectFastPatternTest205, 1); UtRegisterTest("DetectFastPatternTest206", DetectFastPatternTest206, 1); UtRegisterTest("DetectFastPatternTest207", DetectFastPatternTest207, 1); UtRegisterTest("DetectFastPatternTest208", DetectFastPatternTest208, 1); UtRegisterTest("DetectFastPatternTest209", DetectFastPatternTest209, 1); UtRegisterTest("DetectFastPatternTest210", DetectFastPatternTest210, 1); UtRegisterTest("DetectFastPatternTest211", DetectFastPatternTest211, 1); UtRegisterTest("DetectFastPatternTest212", DetectFastPatternTest212, 1); UtRegisterTest("DetectFastPatternTest213", DetectFastPatternTest213, 1); UtRegisterTest("DetectFastPatternTest214", DetectFastPatternTest214, 1); UtRegisterTest("DetectFastPatternTest215", DetectFastPatternTest215, 1); UtRegisterTest("DetectFastPatternTest216", DetectFastPatternTest216, 1); UtRegisterTest("DetectFastPatternTest217", DetectFastPatternTest217, 1); UtRegisterTest("DetectFastPatternTest218", DetectFastPatternTest218, 1); UtRegisterTest("DetectFastPatternTest219", DetectFastPatternTest219, 1); /* http_header fast_pattern tests ^ */ /* http_raw_header fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest220", DetectFastPatternTest220, 1); UtRegisterTest("DetectFastPatternTest221", DetectFastPatternTest221, 1); UtRegisterTest("DetectFastPatternTest222", DetectFastPatternTest222, 1); UtRegisterTest("DetectFastPatternTest223", DetectFastPatternTest223, 1); UtRegisterTest("DetectFastPatternTest224", DetectFastPatternTest224, 1); UtRegisterTest("DetectFastPatternTest225", DetectFastPatternTest225, 1); UtRegisterTest("DetectFastPatternTest226", DetectFastPatternTest226, 1); UtRegisterTest("DetectFastPatternTest227", DetectFastPatternTest227, 1); UtRegisterTest("DetectFastPatternTest228", DetectFastPatternTest228, 1); UtRegisterTest("DetectFastPatternTest229", DetectFastPatternTest229, 1); UtRegisterTest("DetectFastPatternTest230", DetectFastPatternTest230, 1); UtRegisterTest("DetectFastPatternTest231", DetectFastPatternTest231, 1); UtRegisterTest("DetectFastPatternTest232", DetectFastPatternTest232, 1); UtRegisterTest("DetectFastPatternTest233", DetectFastPatternTest233, 1); UtRegisterTest("DetectFastPatternTest234", DetectFastPatternTest234, 1); UtRegisterTest("DetectFastPatternTest235", DetectFastPatternTest235, 1); UtRegisterTest("DetectFastPatternTest236", DetectFastPatternTest236, 1); UtRegisterTest("DetectFastPatternTest237", DetectFastPatternTest237, 1); UtRegisterTest("DetectFastPatternTest238", DetectFastPatternTest238, 1); UtRegisterTest("DetectFastPatternTest239", DetectFastPatternTest239, 1); UtRegisterTest("DetectFastPatternTest240", DetectFastPatternTest240, 1); UtRegisterTest("DetectFastPatternTest241", DetectFastPatternTest241, 1); UtRegisterTest("DetectFastPatternTest242", DetectFastPatternTest242, 1); UtRegisterTest("DetectFastPatternTest243", DetectFastPatternTest243, 1); UtRegisterTest("DetectFastPatternTest244", DetectFastPatternTest244, 1); UtRegisterTest("DetectFastPatternTest245", DetectFastPatternTest245, 1); UtRegisterTest("DetectFastPatternTest246", DetectFastPatternTest246, 1); UtRegisterTest("DetectFastPatternTest247", DetectFastPatternTest247, 1); UtRegisterTest("DetectFastPatternTest248", DetectFastPatternTest248, 1); UtRegisterTest("DetectFastPatternTest249", DetectFastPatternTest249, 1); UtRegisterTest("DetectFastPatternTest250", DetectFastPatternTest250, 1); UtRegisterTest("DetectFastPatternTest251", DetectFastPatternTest251, 1); UtRegisterTest("DetectFastPatternTest252", DetectFastPatternTest252, 1); UtRegisterTest("DetectFastPatternTest253", DetectFastPatternTest253, 1); UtRegisterTest("DetectFastPatternTest254", DetectFastPatternTest254, 1); UtRegisterTest("DetectFastPatternTest255", DetectFastPatternTest255, 1); UtRegisterTest("DetectFastPatternTest256", DetectFastPatternTest256, 1); UtRegisterTest("DetectFastPatternTest257", DetectFastPatternTest257, 1); UtRegisterTest("DetectFastPatternTest258", DetectFastPatternTest258, 1); UtRegisterTest("DetectFastPatternTest259", DetectFastPatternTest259, 1); UtRegisterTest("DetectFastPatternTest260", DetectFastPatternTest260, 1); /* http_raw_header fast_pattern tests ^ */ /* http_method fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest261", DetectFastPatternTest261, 1); UtRegisterTest("DetectFastPatternTest262", DetectFastPatternTest262, 1); UtRegisterTest("DetectFastPatternTest263", DetectFastPatternTest263, 1); UtRegisterTest("DetectFastPatternTest264", DetectFastPatternTest264, 1); UtRegisterTest("DetectFastPatternTest265", DetectFastPatternTest265, 1); UtRegisterTest("DetectFastPatternTest266", DetectFastPatternTest266, 1); UtRegisterTest("DetectFastPatternTest267", DetectFastPatternTest267, 1); UtRegisterTest("DetectFastPatternTest268", DetectFastPatternTest268, 1); UtRegisterTest("DetectFastPatternTest269", DetectFastPatternTest269, 1); UtRegisterTest("DetectFastPatternTest270", DetectFastPatternTest270, 1); UtRegisterTest("DetectFastPatternTest271", DetectFastPatternTest271, 1); UtRegisterTest("DetectFastPatternTest272", DetectFastPatternTest272, 1); UtRegisterTest("DetectFastPatternTest273", DetectFastPatternTest273, 1); UtRegisterTest("DetectFastPatternTest274", DetectFastPatternTest274, 1); UtRegisterTest("DetectFastPatternTest275", DetectFastPatternTest275, 1); UtRegisterTest("DetectFastPatternTest276", DetectFastPatternTest276, 1); UtRegisterTest("DetectFastPatternTest277", DetectFastPatternTest277, 1); UtRegisterTest("DetectFastPatternTest278", DetectFastPatternTest278, 1); UtRegisterTest("DetectFastPatternTest279", DetectFastPatternTest279, 1); UtRegisterTest("DetectFastPatternTest280", DetectFastPatternTest280, 1); UtRegisterTest("DetectFastPatternTest281", DetectFastPatternTest281, 1); UtRegisterTest("DetectFastPatternTest282", DetectFastPatternTest282, 1); UtRegisterTest("DetectFastPatternTest283", DetectFastPatternTest283, 1); UtRegisterTest("DetectFastPatternTest284", DetectFastPatternTest284, 1); UtRegisterTest("DetectFastPatternTest285", DetectFastPatternTest285, 1); UtRegisterTest("DetectFastPatternTest286", DetectFastPatternTest286, 1); UtRegisterTest("DetectFastPatternTest287", DetectFastPatternTest287, 1); UtRegisterTest("DetectFastPatternTest288", DetectFastPatternTest288, 1); UtRegisterTest("DetectFastPatternTest289", DetectFastPatternTest289, 1); UtRegisterTest("DetectFastPatternTest290", DetectFastPatternTest290, 1); UtRegisterTest("DetectFastPatternTest291", DetectFastPatternTest291, 1); UtRegisterTest("DetectFastPatternTest292", DetectFastPatternTest292, 1); UtRegisterTest("DetectFastPatternTest293", DetectFastPatternTest293, 1); UtRegisterTest("DetectFastPatternTest294", DetectFastPatternTest294, 1); UtRegisterTest("DetectFastPatternTest295", DetectFastPatternTest295, 1); UtRegisterTest("DetectFastPatternTest296", DetectFastPatternTest296, 1); UtRegisterTest("DetectFastPatternTest297", DetectFastPatternTest297, 1); UtRegisterTest("DetectFastPatternTest298", DetectFastPatternTest298, 1); UtRegisterTest("DetectFastPatternTest299", DetectFastPatternTest299, 1); UtRegisterTest("DetectFastPatternTest300", DetectFastPatternTest300, 1); UtRegisterTest("DetectFastPatternTest301", DetectFastPatternTest301, 1); /* http_method fast_pattern tests ^ */ /* http_cookie fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest302", DetectFastPatternTest302, 1); UtRegisterTest("DetectFastPatternTest303", DetectFastPatternTest303, 1); UtRegisterTest("DetectFastPatternTest304", DetectFastPatternTest304, 1); UtRegisterTest("DetectFastPatternTest305", DetectFastPatternTest305, 1); UtRegisterTest("DetectFastPatternTest306", DetectFastPatternTest306, 1); UtRegisterTest("DetectFastPatternTest307", DetectFastPatternTest307, 1); UtRegisterTest("DetectFastPatternTest308", DetectFastPatternTest308, 1); UtRegisterTest("DetectFastPatternTest309", DetectFastPatternTest309, 1); UtRegisterTest("DetectFastPatternTest310", DetectFastPatternTest310, 1); UtRegisterTest("DetectFastPatternTest311", DetectFastPatternTest311, 1); UtRegisterTest("DetectFastPatternTest312", DetectFastPatternTest312, 1); UtRegisterTest("DetectFastPatternTest313", DetectFastPatternTest313, 1); UtRegisterTest("DetectFastPatternTest314", DetectFastPatternTest314, 1); UtRegisterTest("DetectFastPatternTest315", DetectFastPatternTest315, 1); UtRegisterTest("DetectFastPatternTest316", DetectFastPatternTest316, 1); UtRegisterTest("DetectFastPatternTest317", DetectFastPatternTest317, 1); UtRegisterTest("DetectFastPatternTest318", DetectFastPatternTest318, 1); UtRegisterTest("DetectFastPatternTest319", DetectFastPatternTest319, 1); UtRegisterTest("DetectFastPatternTest320", DetectFastPatternTest320, 1); UtRegisterTest("DetectFastPatternTest321", DetectFastPatternTest321, 1); UtRegisterTest("DetectFastPatternTest322", DetectFastPatternTest322, 1); UtRegisterTest("DetectFastPatternTest323", DetectFastPatternTest323, 1); UtRegisterTest("DetectFastPatternTest324", DetectFastPatternTest324, 1); UtRegisterTest("DetectFastPatternTest325", DetectFastPatternTest325, 1); UtRegisterTest("DetectFastPatternTest326", DetectFastPatternTest326, 1); UtRegisterTest("DetectFastPatternTest327", DetectFastPatternTest327, 1); UtRegisterTest("DetectFastPatternTest328", DetectFastPatternTest328, 1); UtRegisterTest("DetectFastPatternTest329", DetectFastPatternTest329, 1); UtRegisterTest("DetectFastPatternTest330", DetectFastPatternTest330, 1); UtRegisterTest("DetectFastPatternTest331", DetectFastPatternTest331, 1); UtRegisterTest("DetectFastPatternTest332", DetectFastPatternTest332, 1); UtRegisterTest("DetectFastPatternTest333", DetectFastPatternTest333, 1); UtRegisterTest("DetectFastPatternTest334", DetectFastPatternTest334, 1); UtRegisterTest("DetectFastPatternTest335", DetectFastPatternTest335, 1); UtRegisterTest("DetectFastPatternTest336", DetectFastPatternTest336, 1); UtRegisterTest("DetectFastPatternTest337", DetectFastPatternTest337, 1); UtRegisterTest("DetectFastPatternTest338", DetectFastPatternTest338, 1); UtRegisterTest("DetectFastPatternTest339", DetectFastPatternTest339, 1); UtRegisterTest("DetectFastPatternTest340", DetectFastPatternTest340, 1); UtRegisterTest("DetectFastPatternTest341", DetectFastPatternTest341, 1); UtRegisterTest("DetectFastPatternTest342", DetectFastPatternTest342, 1); /* http_cookie fast_pattern tests ^ */ /* http_raw_uri fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest343", DetectFastPatternTest343, 1); UtRegisterTest("DetectFastPatternTest344", DetectFastPatternTest344, 1); UtRegisterTest("DetectFastPatternTest345", DetectFastPatternTest345, 1); UtRegisterTest("DetectFastPatternTest346", DetectFastPatternTest346, 1); UtRegisterTest("DetectFastPatternTest347", DetectFastPatternTest347, 1); UtRegisterTest("DetectFastPatternTest348", DetectFastPatternTest348, 1); UtRegisterTest("DetectFastPatternTest349", DetectFastPatternTest349, 1); UtRegisterTest("DetectFastPatternTest350", DetectFastPatternTest350, 1); UtRegisterTest("DetectFastPatternTest351", DetectFastPatternTest351, 1); UtRegisterTest("DetectFastPatternTest352", DetectFastPatternTest352, 1); UtRegisterTest("DetectFastPatternTest353", DetectFastPatternTest353, 1); UtRegisterTest("DetectFastPatternTest354", DetectFastPatternTest354, 1); UtRegisterTest("DetectFastPatternTest355", DetectFastPatternTest355, 1); UtRegisterTest("DetectFastPatternTest356", DetectFastPatternTest356, 1); UtRegisterTest("DetectFastPatternTest357", DetectFastPatternTest357, 1); UtRegisterTest("DetectFastPatternTest358", DetectFastPatternTest358, 1); UtRegisterTest("DetectFastPatternTest359", DetectFastPatternTest359, 1); UtRegisterTest("DetectFastPatternTest360", DetectFastPatternTest360, 1); UtRegisterTest("DetectFastPatternTest361", DetectFastPatternTest361, 1); UtRegisterTest("DetectFastPatternTest362", DetectFastPatternTest362, 1); UtRegisterTest("DetectFastPatternTest363", DetectFastPatternTest363, 1); UtRegisterTest("DetectFastPatternTest364", DetectFastPatternTest364, 1); UtRegisterTest("DetectFastPatternTest365", DetectFastPatternTest365, 1); UtRegisterTest("DetectFastPatternTest366", DetectFastPatternTest366, 1); UtRegisterTest("DetectFastPatternTest367", DetectFastPatternTest367, 1); UtRegisterTest("DetectFastPatternTest368", DetectFastPatternTest368, 1); UtRegisterTest("DetectFastPatternTest369", DetectFastPatternTest369, 1); UtRegisterTest("DetectFastPatternTest370", DetectFastPatternTest370, 1); UtRegisterTest("DetectFastPatternTest371", DetectFastPatternTest371, 1); UtRegisterTest("DetectFastPatternTest372", DetectFastPatternTest372, 1); UtRegisterTest("DetectFastPatternTest373", DetectFastPatternTest373, 1); UtRegisterTest("DetectFastPatternTest374", DetectFastPatternTest374, 1); UtRegisterTest("DetectFastPatternTest375", DetectFastPatternTest375, 1); UtRegisterTest("DetectFastPatternTest376", DetectFastPatternTest376, 1); UtRegisterTest("DetectFastPatternTest377", DetectFastPatternTest377, 1); UtRegisterTest("DetectFastPatternTest378", DetectFastPatternTest378, 1); UtRegisterTest("DetectFastPatternTest379", DetectFastPatternTest379, 1); UtRegisterTest("DetectFastPatternTest380", DetectFastPatternTest380, 1); UtRegisterTest("DetectFastPatternTest381", DetectFastPatternTest381, 1); UtRegisterTest("DetectFastPatternTest382", DetectFastPatternTest382, 1); UtRegisterTest("DetectFastPatternTest383", DetectFastPatternTest383, 1); /* http_raw_uri fast_pattern tests ^ */ /* http_stat_msg fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest384", DetectFastPatternTest384, 1); UtRegisterTest("DetectFastPatternTest385", DetectFastPatternTest385, 1); UtRegisterTest("DetectFastPatternTest386", DetectFastPatternTest386, 1); UtRegisterTest("DetectFastPatternTest387", DetectFastPatternTest387, 1); UtRegisterTest("DetectFastPatternTest388", DetectFastPatternTest388, 1); UtRegisterTest("DetectFastPatternTest389", DetectFastPatternTest389, 1); UtRegisterTest("DetectFastPatternTest390", DetectFastPatternTest390, 1); UtRegisterTest("DetectFastPatternTest391", DetectFastPatternTest391, 1); UtRegisterTest("DetectFastPatternTest392", DetectFastPatternTest392, 1); UtRegisterTest("DetectFastPatternTest393", DetectFastPatternTest393, 1); UtRegisterTest("DetectFastPatternTest394", DetectFastPatternTest394, 1); UtRegisterTest("DetectFastPatternTest395", DetectFastPatternTest395, 1); UtRegisterTest("DetectFastPatternTest396", DetectFastPatternTest396, 1); UtRegisterTest("DetectFastPatternTest397", DetectFastPatternTest397, 1); UtRegisterTest("DetectFastPatternTest398", DetectFastPatternTest398, 1); UtRegisterTest("DetectFastPatternTest399", DetectFastPatternTest399, 1); UtRegisterTest("DetectFastPatternTest400", DetectFastPatternTest400, 1); UtRegisterTest("DetectFastPatternTest401", DetectFastPatternTest401, 1); UtRegisterTest("DetectFastPatternTest402", DetectFastPatternTest402, 1); UtRegisterTest("DetectFastPatternTest403", DetectFastPatternTest403, 1); UtRegisterTest("DetectFastPatternTest404", DetectFastPatternTest404, 1); UtRegisterTest("DetectFastPatternTest405", DetectFastPatternTest405, 1); UtRegisterTest("DetectFastPatternTest406", DetectFastPatternTest406, 1); UtRegisterTest("DetectFastPatternTest407", DetectFastPatternTest407, 1); UtRegisterTest("DetectFastPatternTest408", DetectFastPatternTest408, 1); UtRegisterTest("DetectFastPatternTest409", DetectFastPatternTest409, 1); UtRegisterTest("DetectFastPatternTest410", DetectFastPatternTest410, 1); UtRegisterTest("DetectFastPatternTest411", DetectFastPatternTest411, 1); UtRegisterTest("DetectFastPatternTest412", DetectFastPatternTest412, 1); UtRegisterTest("DetectFastPatternTest413", DetectFastPatternTest413, 1); UtRegisterTest("DetectFastPatternTest414", DetectFastPatternTest414, 1); UtRegisterTest("DetectFastPatternTest415", DetectFastPatternTest415, 1); UtRegisterTest("DetectFastPatternTest416", DetectFastPatternTest415, 1); UtRegisterTest("DetectFastPatternTest417", DetectFastPatternTest417, 1); UtRegisterTest("DetectFastPatternTest418", DetectFastPatternTest418, 1); UtRegisterTest("DetectFastPatternTest419", DetectFastPatternTest419, 1); UtRegisterTest("DetectFastPatternTest420", DetectFastPatternTest420, 1); UtRegisterTest("DetectFastPatternTest421", DetectFastPatternTest421, 1); UtRegisterTest("DetectFastPatternTest422", DetectFastPatternTest422, 1); UtRegisterTest("DetectFastPatternTest423", DetectFastPatternTest423, 1); UtRegisterTest("DetectFastPatternTest424", DetectFastPatternTest424, 1); /* http_stat_msg fast_pattern tests ^ */ /* http_stat_code fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest425", DetectFastPatternTest425, 1); UtRegisterTest("DetectFastPatternTest426", DetectFastPatternTest426, 1); UtRegisterTest("DetectFastPatternTest427", DetectFastPatternTest427, 1); UtRegisterTest("DetectFastPatternTest428", DetectFastPatternTest428, 1); UtRegisterTest("DetectFastPatternTest429", DetectFastPatternTest429, 1); UtRegisterTest("DetectFastPatternTest430", DetectFastPatternTest430, 1); UtRegisterTest("DetectFastPatternTest431", DetectFastPatternTest431, 1); UtRegisterTest("DetectFastPatternTest432", DetectFastPatternTest432, 1); UtRegisterTest("DetectFastPatternTest433", DetectFastPatternTest433, 1); UtRegisterTest("DetectFastPatternTest434", DetectFastPatternTest434, 1); UtRegisterTest("DetectFastPatternTest435", DetectFastPatternTest435, 1); UtRegisterTest("DetectFastPatternTest436", DetectFastPatternTest436, 1); UtRegisterTest("DetectFastPatternTest437", DetectFastPatternTest437, 1); UtRegisterTest("DetectFastPatternTest438", DetectFastPatternTest438, 1); UtRegisterTest("DetectFastPatternTest439", DetectFastPatternTest439, 1); UtRegisterTest("DetectFastPatternTest440", DetectFastPatternTest440, 1); UtRegisterTest("DetectFastPatternTest441", DetectFastPatternTest441, 1); UtRegisterTest("DetectFastPatternTest442", DetectFastPatternTest442, 1); UtRegisterTest("DetectFastPatternTest443", DetectFastPatternTest443, 1); UtRegisterTest("DetectFastPatternTest444", DetectFastPatternTest444, 1); UtRegisterTest("DetectFastPatternTest445", DetectFastPatternTest445, 1); UtRegisterTest("DetectFastPatternTest446", DetectFastPatternTest446, 1); UtRegisterTest("DetectFastPatternTest447", DetectFastPatternTest447, 1); UtRegisterTest("DetectFastPatternTest448", DetectFastPatternTest448, 1); UtRegisterTest("DetectFastPatternTest449", DetectFastPatternTest449, 1); UtRegisterTest("DetectFastPatternTest450", DetectFastPatternTest450, 1); UtRegisterTest("DetectFastPatternTest451", DetectFastPatternTest451, 1); UtRegisterTest("DetectFastPatternTest452", DetectFastPatternTest452, 1); UtRegisterTest("DetectFastPatternTest453", DetectFastPatternTest453, 1); UtRegisterTest("DetectFastPatternTest454", DetectFastPatternTest454, 1); UtRegisterTest("DetectFastPatternTest455", DetectFastPatternTest455, 1); UtRegisterTest("DetectFastPatternTest456", DetectFastPatternTest456, 1); UtRegisterTest("DetectFastPatternTest457", DetectFastPatternTest457, 1); UtRegisterTest("DetectFastPatternTest458", DetectFastPatternTest458, 1); UtRegisterTest("DetectFastPatternTest459", DetectFastPatternTest459, 1); UtRegisterTest("DetectFastPatternTest460", DetectFastPatternTest460, 1); UtRegisterTest("DetectFastPatternTest461", DetectFastPatternTest461, 1); UtRegisterTest("DetectFastPatternTest462", DetectFastPatternTest462, 1); UtRegisterTest("DetectFastPatternTest463", DetectFastPatternTest463, 1); UtRegisterTest("DetectFastPatternTest464", DetectFastPatternTest464, 1); UtRegisterTest("DetectFastPatternTest465", DetectFastPatternTest465, 1); /* http_stat_code fast_pattern tests ^ */ /* http_server_body fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest466", DetectFastPatternTest466, 1); UtRegisterTest("DetectFastPatternTest467", DetectFastPatternTest467, 1); UtRegisterTest("DetectFastPatternTest468", DetectFastPatternTest468, 1); UtRegisterTest("DetectFastPatternTest469", DetectFastPatternTest469, 1); UtRegisterTest("DetectFastPatternTest470", DetectFastPatternTest470, 1); UtRegisterTest("DetectFastPatternTest471", DetectFastPatternTest471, 1); UtRegisterTest("DetectFastPatternTest472", DetectFastPatternTest472, 1); UtRegisterTest("DetectFastPatternTest473", DetectFastPatternTest473, 1); UtRegisterTest("DetectFastPatternTest474", DetectFastPatternTest474, 1); UtRegisterTest("DetectFastPatternTest475", DetectFastPatternTest475, 1); UtRegisterTest("DetectFastPatternTest476", DetectFastPatternTest476, 1); UtRegisterTest("DetectFastPatternTest477", DetectFastPatternTest477, 1); UtRegisterTest("DetectFastPatternTest478", DetectFastPatternTest478, 1); UtRegisterTest("DetectFastPatternTest479", DetectFastPatternTest479, 1); UtRegisterTest("DetectFastPatternTest480", DetectFastPatternTest480, 1); UtRegisterTest("DetectFastPatternTest481", DetectFastPatternTest481, 1); UtRegisterTest("DetectFastPatternTest482", DetectFastPatternTest482, 1); UtRegisterTest("DetectFastPatternTest483", DetectFastPatternTest483, 1); UtRegisterTest("DetectFastPatternTest484", DetectFastPatternTest484, 1); UtRegisterTest("DetectFastPatternTest485", DetectFastPatternTest485, 1); UtRegisterTest("DetectFastPatternTest486", DetectFastPatternTest486, 1); UtRegisterTest("DetectFastPatternTest487", DetectFastPatternTest487, 1); UtRegisterTest("DetectFastPatternTest488", DetectFastPatternTest488, 1); UtRegisterTest("DetectFastPatternTest489", DetectFastPatternTest489, 1); UtRegisterTest("DetectFastPatternTest490", DetectFastPatternTest490, 1); UtRegisterTest("DetectFastPatternTest491", DetectFastPatternTest491, 1); UtRegisterTest("DetectFastPatternTest492", DetectFastPatternTest492, 1); UtRegisterTest("DetectFastPatternTest493", DetectFastPatternTest493, 1); UtRegisterTest("DetectFastPatternTest494", DetectFastPatternTest494, 1); UtRegisterTest("DetectFastPatternTest495", DetectFastPatternTest495, 1); UtRegisterTest("DetectFastPatternTest496", DetectFastPatternTest496, 1); UtRegisterTest("DetectFastPatternTest497", DetectFastPatternTest497, 1); UtRegisterTest("DetectFastPatternTest498", DetectFastPatternTest498, 1); UtRegisterTest("DetectFastPatternTest499", DetectFastPatternTest499, 1); UtRegisterTest("DetectFastPatternTest500", DetectFastPatternTest500, 1); UtRegisterTest("DetectFastPatternTest501", DetectFastPatternTest501, 1); UtRegisterTest("DetectFastPatternTest502", DetectFastPatternTest502, 1); UtRegisterTest("DetectFastPatternTest503", DetectFastPatternTest503, 1); UtRegisterTest("DetectFastPatternTest504", DetectFastPatternTest504, 1); UtRegisterTest("DetectFastPatternTest505", DetectFastPatternTest505, 1); UtRegisterTest("DetectFastPatternTest506", DetectFastPatternTest506, 1); /* http_server_body fast_pattern tests ^ */ /* file_data fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest507", DetectFastPatternTest507, 1); UtRegisterTest("DetectFastPatternTest508", DetectFastPatternTest508, 1); UtRegisterTest("DetectFastPatternTest509", DetectFastPatternTest509, 1); UtRegisterTest("DetectFastPatternTest510", DetectFastPatternTest510, 1); UtRegisterTest("DetectFastPatternTest511", DetectFastPatternTest511, 1); UtRegisterTest("DetectFastPatternTest512", DetectFastPatternTest512, 1); UtRegisterTest("DetectFastPatternTest513", DetectFastPatternTest513, 1); UtRegisterTest("DetectFastPatternTest514", DetectFastPatternTest514, 1); UtRegisterTest("DetectFastPatternTest515", DetectFastPatternTest515, 1); UtRegisterTest("DetectFastPatternTest516", DetectFastPatternTest516, 1); UtRegisterTest("DetectFastPatternTest517", DetectFastPatternTest517, 1); UtRegisterTest("DetectFastPatternTest518", DetectFastPatternTest518, 1); UtRegisterTest("DetectFastPatternTest519", DetectFastPatternTest519, 1); UtRegisterTest("DetectFastPatternTest520", DetectFastPatternTest520, 1); UtRegisterTest("DetectFastPatternTest521", DetectFastPatternTest521, 1); UtRegisterTest("DetectFastPatternTest522", DetectFastPatternTest522, 1); UtRegisterTest("DetectFastPatternTest523", DetectFastPatternTest523, 1); UtRegisterTest("DetectFastPatternTest524", DetectFastPatternTest524, 1); UtRegisterTest("DetectFastPatternTest525", DetectFastPatternTest525, 1); UtRegisterTest("DetectFastPatternTest526", DetectFastPatternTest526, 1); UtRegisterTest("DetectFastPatternTest527", DetectFastPatternTest527, 1); UtRegisterTest("DetectFastPatternTest528", DetectFastPatternTest528, 1); UtRegisterTest("DetectFastPatternTest529", DetectFastPatternTest529, 1); UtRegisterTest("DetectFastPatternTest530", DetectFastPatternTest530, 1); UtRegisterTest("DetectFastPatternTest531", DetectFastPatternTest531, 1); UtRegisterTest("DetectFastPatternTest532", DetectFastPatternTest532, 1); UtRegisterTest("DetectFastPatternTest533", DetectFastPatternTest533, 1); UtRegisterTest("DetectFastPatternTest534", DetectFastPatternTest534, 1); UtRegisterTest("DetectFastPatternTest535", DetectFastPatternTest535, 1); UtRegisterTest("DetectFastPatternTest536", DetectFastPatternTest536, 1); UtRegisterTest("DetectFastPatternTest537", DetectFastPatternTest537, 1); UtRegisterTest("DetectFastPatternTest538", DetectFastPatternTest538, 1); UtRegisterTest("DetectFastPatternTest539", DetectFastPatternTest539, 1); UtRegisterTest("DetectFastPatternTest540", DetectFastPatternTest540, 1); UtRegisterTest("DetectFastPatternTest541", DetectFastPatternTest541, 1); UtRegisterTest("DetectFastPatternTest542", DetectFastPatternTest542, 1); UtRegisterTest("DetectFastPatternTest543", DetectFastPatternTest543, 1); UtRegisterTest("DetectFastPatternTest544", DetectFastPatternTest544, 1); UtRegisterTest("DetectFastPatternTest545", DetectFastPatternTest545, 1); UtRegisterTest("DetectFastPatternTest546", DetectFastPatternTest546, 1); UtRegisterTest("DetectFastPatternTest547", DetectFastPatternTest547, 1); /* file_data fast_pattern tests ^ */ /* http_user_agent fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest548", DetectFastPatternTest548, 1); UtRegisterTest("DetectFastPatternTest549", DetectFastPatternTest549, 1); UtRegisterTest("DetectFastPatternTest550", DetectFastPatternTest550, 1); UtRegisterTest("DetectFastPatternTest551", DetectFastPatternTest551, 1); UtRegisterTest("DetectFastPatternTest552", DetectFastPatternTest552, 1); UtRegisterTest("DetectFastPatternTest553", DetectFastPatternTest553, 1); UtRegisterTest("DetectFastPatternTest554", DetectFastPatternTest554, 1); UtRegisterTest("DetectFastPatternTest555", DetectFastPatternTest555, 1); UtRegisterTest("DetectFastPatternTest556", DetectFastPatternTest556, 1); UtRegisterTest("DetectFastPatternTest557", DetectFastPatternTest557, 1); UtRegisterTest("DetectFastPatternTest558", DetectFastPatternTest558, 1); UtRegisterTest("DetectFastPatternTest559", DetectFastPatternTest559, 1); UtRegisterTest("DetectFastPatternTest560", DetectFastPatternTest560, 1); UtRegisterTest("DetectFastPatternTest561", DetectFastPatternTest561, 1); UtRegisterTest("DetectFastPatternTest562", DetectFastPatternTest562, 1); UtRegisterTest("DetectFastPatternTest563", DetectFastPatternTest563, 1); UtRegisterTest("DetectFastPatternTest564", DetectFastPatternTest564, 1); UtRegisterTest("DetectFastPatternTest565", DetectFastPatternTest565, 1); UtRegisterTest("DetectFastPatternTest566", DetectFastPatternTest566, 1); UtRegisterTest("DetectFastPatternTest567", DetectFastPatternTest567, 1); UtRegisterTest("DetectFastPatternTest568", DetectFastPatternTest568, 1); UtRegisterTest("DetectFastPatternTest569", DetectFastPatternTest569, 1); UtRegisterTest("DetectFastPatternTest570", DetectFastPatternTest570, 1); UtRegisterTest("DetectFastPatternTest571", DetectFastPatternTest571, 1); UtRegisterTest("DetectFastPatternTest572", DetectFastPatternTest572, 1); UtRegisterTest("DetectFastPatternTest573", DetectFastPatternTest573, 1); UtRegisterTest("DetectFastPatternTest574", DetectFastPatternTest574, 1); UtRegisterTest("DetectFastPatternTest575", DetectFastPatternTest575, 1); UtRegisterTest("DetectFastPatternTest576", DetectFastPatternTest576, 1); UtRegisterTest("DetectFastPatternTest577", DetectFastPatternTest577, 1); UtRegisterTest("DetectFastPatternTest578", DetectFastPatternTest578, 1); UtRegisterTest("DetectFastPatternTest579", DetectFastPatternTest579, 1); UtRegisterTest("DetectFastPatternTest580", DetectFastPatternTest580, 1); UtRegisterTest("DetectFastPatternTest581", DetectFastPatternTest581, 1); UtRegisterTest("DetectFastPatternTest582", DetectFastPatternTest582, 1); UtRegisterTest("DetectFastPatternTest583", DetectFastPatternTest583, 1); UtRegisterTest("DetectFastPatternTest584", DetectFastPatternTest584, 1); UtRegisterTest("DetectFastPatternTest585", DetectFastPatternTest585, 1); UtRegisterTest("DetectFastPatternTest586", DetectFastPatternTest586, 1); UtRegisterTest("DetectFastPatternTest587", DetectFastPatternTest587, 1); UtRegisterTest("DetectFastPatternTest588", DetectFastPatternTest588, 1); /* http_user_agent fast_pattern tests ^ */ /* http_host fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest589", DetectFastPatternTest589, 1); UtRegisterTest("DetectFastPatternTest590", DetectFastPatternTest590, 1); UtRegisterTest("DetectFastPatternTest591", DetectFastPatternTest591, 1); UtRegisterTest("DetectFastPatternTest592", DetectFastPatternTest592, 1); UtRegisterTest("DetectFastPatternTest593", DetectFastPatternTest593, 1); UtRegisterTest("DetectFastPatternTest594", DetectFastPatternTest594, 1); UtRegisterTest("DetectFastPatternTest595", DetectFastPatternTest595, 1); UtRegisterTest("DetectFastPatternTest596", DetectFastPatternTest596, 1); UtRegisterTest("DetectFastPatternTest597", DetectFastPatternTest597, 1); UtRegisterTest("DetectFastPatternTest598", DetectFastPatternTest598, 1); UtRegisterTest("DetectFastPatternTest599", DetectFastPatternTest599, 1); UtRegisterTest("DetectFastPatternTest600", DetectFastPatternTest600, 1); UtRegisterTest("DetectFastPatternTest601", DetectFastPatternTest601, 1); UtRegisterTest("DetectFastPatternTest602", DetectFastPatternTest602, 1); UtRegisterTest("DetectFastPatternTest603", DetectFastPatternTest603, 1); UtRegisterTest("DetectFastPatternTest604", DetectFastPatternTest604, 1); UtRegisterTest("DetectFastPatternTest605", DetectFastPatternTest605, 1); UtRegisterTest("DetectFastPatternTest606", DetectFastPatternTest606, 1); UtRegisterTest("DetectFastPatternTest607", DetectFastPatternTest607, 1); UtRegisterTest("DetectFastPatternTest608", DetectFastPatternTest608, 1); UtRegisterTest("DetectFastPatternTest609", DetectFastPatternTest609, 1); UtRegisterTest("DetectFastPatternTest610", DetectFastPatternTest610, 1); UtRegisterTest("DetectFastPatternTest611", DetectFastPatternTest611, 1); UtRegisterTest("DetectFastPatternTest612", DetectFastPatternTest612, 1); UtRegisterTest("DetectFastPatternTest613", DetectFastPatternTest613, 1); UtRegisterTest("DetectFastPatternTest614", DetectFastPatternTest614, 1); UtRegisterTest("DetectFastPatternTest615", DetectFastPatternTest615, 1); UtRegisterTest("DetectFastPatternTest616", DetectFastPatternTest616, 1); UtRegisterTest("DetectFastPatternTest617", DetectFastPatternTest617, 1); UtRegisterTest("DetectFastPatternTest618", DetectFastPatternTest618, 1); UtRegisterTest("DetectFastPatternTest619", DetectFastPatternTest619, 1); UtRegisterTest("DetectFastPatternTest620", DetectFastPatternTest620, 1); UtRegisterTest("DetectFastPatternTest621", DetectFastPatternTest621, 1); UtRegisterTest("DetectFastPatternTest622", DetectFastPatternTest622, 1); UtRegisterTest("DetectFastPatternTest623", DetectFastPatternTest623, 1); UtRegisterTest("DetectFastPatternTest624", DetectFastPatternTest624, 1); UtRegisterTest("DetectFastPatternTest625", DetectFastPatternTest625, 1); UtRegisterTest("DetectFastPatternTest626", DetectFastPatternTest626, 1); UtRegisterTest("DetectFastPatternTest627", DetectFastPatternTest627, 1); UtRegisterTest("DetectFastPatternTest628", DetectFastPatternTest628, 1); UtRegisterTest("DetectFastPatternTest629", DetectFastPatternTest629, 1); /* http_host fast_pattern tests ^ */ /* http_rawhost fast_pattern tests v */ UtRegisterTest("DetectFastPatternTest630", DetectFastPatternTest630, 1); UtRegisterTest("DetectFastPatternTest631", DetectFastPatternTest631, 1); UtRegisterTest("DetectFastPatternTest632", DetectFastPatternTest632, 1); UtRegisterTest("DetectFastPatternTest633", DetectFastPatternTest633, 1); UtRegisterTest("DetectFastPatternTest634", DetectFastPatternTest634, 1); UtRegisterTest("DetectFastPatternTest635", DetectFastPatternTest635, 1); UtRegisterTest("DetectFastPatternTest636", DetectFastPatternTest636, 1); UtRegisterTest("DetectFastPatternTest637", DetectFastPatternTest637, 1); UtRegisterTest("DetectFastPatternTest638", DetectFastPatternTest638, 1); UtRegisterTest("DetectFastPatternTest639", DetectFastPatternTest639, 1); UtRegisterTest("DetectFastPatternTest640", DetectFastPatternTest640, 1); UtRegisterTest("DetectFastPatternTest641", DetectFastPatternTest641, 1); UtRegisterTest("DetectFastPatternTest642", DetectFastPatternTest642, 1); UtRegisterTest("DetectFastPatternTest643", DetectFastPatternTest643, 1); UtRegisterTest("DetectFastPatternTest644", DetectFastPatternTest644, 1); UtRegisterTest("DetectFastPatternTest645", DetectFastPatternTest645, 1); UtRegisterTest("DetectFastPatternTest646", DetectFastPatternTest646, 1); UtRegisterTest("DetectFastPatternTest647", DetectFastPatternTest647, 1); UtRegisterTest("DetectFastPatternTest648", DetectFastPatternTest648, 1); UtRegisterTest("DetectFastPatternTest649", DetectFastPatternTest649, 1); UtRegisterTest("DetectFastPatternTest650", DetectFastPatternTest650, 1); UtRegisterTest("DetectFastPatternTest651", DetectFastPatternTest651, 1); UtRegisterTest("DetectFastPatternTest652", DetectFastPatternTest652, 1); UtRegisterTest("DetectFastPatternTest653", DetectFastPatternTest653, 1); UtRegisterTest("DetectFastPatternTest654", DetectFastPatternTest654, 1); UtRegisterTest("DetectFastPatternTest655", DetectFastPatternTest655, 1); UtRegisterTest("DetectFastPatternTest656", DetectFastPatternTest656, 1); UtRegisterTest("DetectFastPatternTest657", DetectFastPatternTest657, 1); UtRegisterTest("DetectFastPatternTest658", DetectFastPatternTest658, 1); UtRegisterTest("DetectFastPatternTest659", DetectFastPatternTest659, 1); UtRegisterTest("DetectFastPatternTest660", DetectFastPatternTest660, 1); UtRegisterTest("DetectFastPatternTest661", DetectFastPatternTest661, 1); UtRegisterTest("DetectFastPatternTest662", DetectFastPatternTest662, 1); UtRegisterTest("DetectFastPatternTest663", DetectFastPatternTest663, 1); UtRegisterTest("DetectFastPatternTest664", DetectFastPatternTest664, 1); UtRegisterTest("DetectFastPatternTest665", DetectFastPatternTest665, 1); UtRegisterTest("DetectFastPatternTest666", DetectFastPatternTest666, 1); UtRegisterTest("DetectFastPatternTest667", DetectFastPatternTest667, 1); UtRegisterTest("DetectFastPatternTest668", DetectFastPatternTest668, 1); UtRegisterTest("DetectFastPatternTest669", DetectFastPatternTest669, 1); UtRegisterTest("DetectFastPatternTest670", DetectFastPatternTest670, 1); #endif return; } suricata-1.4.7/src/util-privs.c0000644000000000000000000001650512253546156013316 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * File to drop the engine capabilities using libcap-ng by * Steve Grubb */ #ifndef OS_WIN32 #include #include #include "util-debug.h" #include "suricata-common.h" #include "suricata.h" #ifdef HAVE_LIBCAP_NG #include #ifdef HAVE_SYS_PRCTL_H #include #endif #include "threadvars.h" #include "util-cpu.h" #include "util-privs.h" #include "runmodes.h" /** flag indicating if we'll be using caps */ extern int sc_set_caps; /** our current runmode */ extern int run_mode; /** * \brief Drop all the previliges of the given thread */ void SCDropAllCaps() { capng_clear(CAPNG_SELECT_BOTH); if (capng_apply(CAPNG_SELECT_BOTH) < 0) { SCLogError(SC_ERR_CHANGING_CAPS_FAILED, "failed in dropping the caps"); exit(EXIT_FAILURE); } } /** * \brief Drop the previliges of the main thread */ void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid) { if (sc_set_caps == FALSE) return; capng_clear(CAPNG_SELECT_BOTH); switch (run_mode) { case RUNMODE_PCAP_DEV: case RUNMODE_AFP_DEV: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_RAW, /* needed for pcap live mode */ -1); break; case RUNMODE_PFRING: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_ADMIN, -1); break; case RUNMODE_NFQ: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_ADMIN, /* needed for nfqueue inline mode */ -1); break; } if (capng_change_id(userid, groupid, CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING) < 0) { SCLogError(SC_ERR_CHANGING_CAPS_FAILED, "capng_change_id for main thread" " failed"); exit(EXIT_FAILURE); } SCLogInfo("dropped the caps for main thread"); } void SCDropCaps(ThreadVars *tv) { #if 0 capng_clear(CAPNG_SELECT_BOTH); capng_apply(CAPNG_SELECT_BOTH); if (tv->cap_flags & SC_CAP_IPC_LOCK) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); } if (tv->cap_flags & SC_CAP_NET_ADMIN) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); } if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); } if (tv->cap_flags & SC_CAP_NET_BROADCAST) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); } if (tv->cap_flags & SC_CAP_NET_RAW) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); } if (tv->cap_flags & SC_CAP_SYS_ADMIN) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); } if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); } #endif } #endif /* HAVE_LIBCAP_NG */ /** * \brief Function to get the user and group ID from the specified user name * * \param user_name pointer to the given user name * \param uid pointer to the user id in which result will be stored * \param gid pointer to the group id in which result will be stored * * \retval upon success it return 0 */ int SCGetUserID(char *user_name, char *group_name, uint32_t *uid, uint32_t *gid) { uint32_t userid = 0; uint32_t groupid = 0; struct passwd *pw; /* Get the user ID */ if (isdigit((unsigned char)user_name[0]) != 0) { userid = atoi(user_name); pw = getpwuid(userid); if (pw == NULL) { SCLogError(SC_ERR_UID_FAILED, "unable to get the user ID, " "check if user exist!!"); exit(EXIT_FAILURE); } } else { pw = getpwnam(user_name); if (pw == NULL) { SCLogError(SC_ERR_UID_FAILED, "unable to get the user ID, " "check if user exist!!"); exit(EXIT_FAILURE); } userid = pw->pw_uid; } /* Get the group ID */ if (group_name != NULL) { struct group *gp; if (isdigit((unsigned char)group_name[0]) != 0) { groupid = atoi(group_name); } else { gp = getgrnam(group_name); if (gp == NULL) { SCLogError(SC_ERR_GID_FAILED, "unable to get the group" " ID, check if group exist!!"); exit(EXIT_FAILURE); } groupid = gp->gr_gid; } } else { groupid = pw->pw_gid; } /* close the group database */ endgrent(); /* close the user database */ endpwent(); *uid = userid; *gid = groupid; return 0; } /** * \brief Function to get the group ID from the specified group name * * \param group_name pointer to the given group name * \param gid pointer to the group id in which result will be stored * * \retval upon success it return 0 */ int SCGetGroupID(char *group_name, uint32_t *gid) { uint32_t grpid = 0; struct group *gp; /* Get the group ID */ if (isdigit((unsigned char)group_name[0]) != 0) { grpid = atoi(group_name); } else { gp = getgrnam(group_name); if (gp == NULL) { SCLogError(SC_ERR_GID_FAILED, "unable to get the group ID," " check if group exist!!"); exit(EXIT_FAILURE); } grpid = gp->gr_gid; } /* close the group database */ endgrent(); *gid = grpid; return 0; } #endif /* OS_WIN32 */ suricata-1.4.7/src/detect-icmp-seq.c0000644000000000000000000002501312253546156014156 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * * Implements the icmp_seq keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-icmp-seq.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #define PARSE_REGEX "^\\s*(\"\\s*)?([0-9]+)(\\s*\")?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectIcmpSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectIcmpSeqSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpSeqRegisterTests(void); void DetectIcmpSeqFree(void *); /** * \brief Registration function for icmp_seq */ void DetectIcmpSeqRegister (void) { sigmatch_table[DETECT_ICMP_SEQ].name = "icmp_seq"; sigmatch_table[DETECT_ICMP_SEQ].desc = "check for a ICMP sequence number"; sigmatch_table[DETECT_ICMP_SEQ].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icmp_seq"; sigmatch_table[DETECT_ICMP_SEQ].Match = DetectIcmpSeqMatch; sigmatch_table[DETECT_ICMP_SEQ].Setup = DetectIcmpSeqSetup; sigmatch_table[DETECT_ICMP_SEQ].Free = DetectIcmpSeqFree; sigmatch_table[DETECT_ICMP_SEQ].RegisterTests = DetectIcmpSeqRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief This function is used to match icmp_seq rule option set on a packet * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectIcmpSeqData * * \retval 0 no match * \retval 1 match */ int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { uint16_t seqn; DetectIcmpSeqData *iseq = (DetectIcmpSeqData *)m->ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; if (PKT_IS_ICMPV4(p)) { switch (ICMPV4_GET_TYPE(p)){ case ICMP_ECHOREPLY: case ICMP_ECHO: case ICMP_TIMESTAMP: case ICMP_TIMESTAMPREPLY: case ICMP_INFO_REQUEST: case ICMP_INFO_REPLY: case ICMP_ADDRESS: case ICMP_ADDRESSREPLY: SCLogDebug("ICMPV4_GET_SEQ(p) %"PRIu16" (network byte order), " "%"PRIu16" (host byte order)", ICMPV4_GET_SEQ(p), ntohs(ICMPV4_GET_SEQ(p))); seqn = ICMPV4_GET_SEQ(p); break; default: SCLogDebug("Packet has no seq field"); return 0; } } else if (PKT_IS_ICMPV6(p)) { switch (ICMPV6_GET_TYPE(p)) { case ICMP6_ECHO_REQUEST: case ICMP6_ECHO_REPLY: SCLogDebug("ICMPV6_GET_SEQ(p) %"PRIu16" (network byte order), " "%"PRIu16" (host byte order)", ICMPV6_GET_SEQ(p), ntohs(ICMPV6_GET_SEQ(p))); seqn = ICMPV6_GET_SEQ(p); break; default: SCLogDebug("Packet has no seq field"); return 0; } } else { SCLogDebug("Packet not ICMPV4 nor ICMPV6"); return 0; } if (seqn == iseq->seq) return 1; return 0; } /** * \brief This function is used to parse icmp_seq option passed via icmp_seq: keyword * * \param icmpseqstr Pointer to the user provided icmp_seq options * * \retval iseq pointer to DetectIcmpSeqData on success * \retval NULL on failure */ DetectIcmpSeqData *DetectIcmpSeqParse (char *icmpseqstr) { DetectIcmpSeqData *iseq = NULL; char *substr[3] = {NULL, NULL, NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int i; const char *str_ptr; ret = pcre_exec(parse_regex, parse_regex_study, icmpseqstr, strlen(icmpseqstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH,"Parse error %s", icmpseqstr); goto error; } for (i = 1; i < ret; i++) { res = pcre_get_substring((char *)icmpseqstr, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed"); goto error; } substr[i-1] = (char *)str_ptr; } iseq = SCMalloc(sizeof(DetectIcmpSeqData)); if (unlikely(iseq == NULL)) goto error; iseq->seq = 0; if (substr[0] != NULL && strlen(substr[0]) != 0) { if (substr[2] == NULL) { SCLogError(SC_ERR_MISSING_QUOTE,"Missing quote in input"); goto error; } } else { if (substr[2] != NULL) { SCLogError(SC_ERR_MISSING_QUOTE,"Missing quote in input"); goto error; } } uint16_t seq = 0; if (ByteExtractStringUint16(&seq, 10, 0, substr[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp seq %s is not " "valid", substr[1]); goto error; } iseq->seq = htons(seq); for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } return iseq; error: for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } if (iseq != NULL) DetectIcmpSeqFree(iseq); return NULL; } /** * \brief this function is used to add the parsed icmp_seq data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param icmpseqstr pointer to the user provided icmp_seq option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectIcmpSeqSetup (DetectEngineCtx *de_ctx, Signature *s, char *icmpseqstr) { DetectIcmpSeqData *iseq = NULL; SigMatch *sm = NULL; iseq = DetectIcmpSeqParse(icmpseqstr); if (iseq == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ICMP_SEQ; sm->ctx = (void *)iseq; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (iseq != NULL) DetectIcmpSeqFree(iseq); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectIcmpSeqData * * \param ptr pointer to DetectIcmpSeqData */ void DetectIcmpSeqFree (void *ptr) { DetectIcmpSeqData *iseq = (DetectIcmpSeqData *)ptr; SCFree(iseq); } #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" /** * \test DetectIcmpSeqParseTest01 is a test for setting a valid icmp_seq value */ int DetectIcmpSeqParseTest01 (void) { DetectIcmpSeqData *iseq = NULL; iseq = DetectIcmpSeqParse("300"); if (iseq != NULL && htons(iseq->seq) == 300) { DetectIcmpSeqFree(iseq); return 1; } return 0; } /** * \test DetectIcmpSeqParseTest02 is a test for setting a valid icmp_seq value * with spaces all around */ int DetectIcmpSeqParseTest02 (void) { DetectIcmpSeqData *iseq = NULL; iseq = DetectIcmpSeqParse(" 300 "); if (iseq != NULL && htons(iseq->seq) == 300) { DetectIcmpSeqFree(iseq); return 1; } return 0; } /** * \test DetectIcmpSeqParseTest03 is a test for setting an invalid icmp_seq value */ int DetectIcmpSeqParseTest03 (void) { DetectIcmpSeqData *iseq = NULL; iseq = DetectIcmpSeqParse("badc"); if (iseq != NULL) { DetectIcmpSeqFree(iseq); return 1; } return 0; } /** * \test DetectIcmpSeqMatchTest01 is a test for checking the working of * icmp_seq keyword by creating 2 rules and matching a crafted packet * against them. Only the first one shall trigger. */ int DetectIcmpSeqMatchTest01 (void) { int result = 0; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(NULL, 0, IPPROTO_ICMP); p->icmpv4vars.seq = htons(2216); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any (icmp_seq:2216; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx, "alert icmp any any -> any any (icmp_seq:5000; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { printf("sid 1 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 2)) { printf("sid 2 alerted, but should not have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); end: return result; } #endif /* UNITTESTS */ void DetectIcmpSeqRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("DetectIcmpSeqParseTest01", DetectIcmpSeqParseTest01, 1); UtRegisterTest("DetectIcmpSeqParseTest02", DetectIcmpSeqParseTest02, 1); UtRegisterTest("DetectIcmpSeqParseTest03", DetectIcmpSeqParseTest03, 0); UtRegisterTest("DetectIcmpSeqMatchTest01", DetectIcmpSeqMatchTest01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/respond-reject-libnet11.h0000644000000000000000000000211512253546156015536 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author William Metcalf */ #ifndef __RESPOND_REJECT_LIBNET11_H__ #define __RESPOND_REJECT_LIBNET11_H__ int RejectSendLibnet11L3IPv4TCP(ThreadVars *, Packet *, void *,int); int RejectSendLibnet11L3IPv4ICMP(ThreadVars *, Packet *, void *,int); #endif /* __RESPOND_REJECT_LIBNET11_H__ */ suricata-1.4.7/src/util-spm.c0000644000000000000000000034647312253546156012764 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * PR (17/01/2010): Single pattern search algorithms: * Currently there are 3 algorithms to choose: BasicSearch, Bs2Bm and * BoyerMoore (Boyer Moores algorithm). The first one doesn't need a context. * But for Bs2Bm and BoyerMoore, you'll need to build some arrays. * * !! If you are going to use the same pattern multiple times, * please, try to store the context some where. For Bs2Bm, the * context is an array of "badchars". For BoyerMoore you need to store * two arrays of shifts. Have a look at the wrappers and unittests * for examples of this. If you cant store the context, use the * wrappers: Bs2bmSearch, BoyerMooreSearch, and the ones caseless, or BasicSearch * That is the most basic. * * Use the stats and util-clock.h to determine which one fit better for you * Boyer Moore should be used for patterns greater than 1 of length * In the range of 2 - 6, if the text length is greater than 1000 you could * use boyer moore, otherwise, basic search. If the pattern is greater * than 6 and the textlen is greater than 500, use boyer moore. * This is an aproximation, but use the stats and util-clock to determine which one * fit better for your case. * */ #include "suricata-common.h" #include "suricata.h" #include "util-unittest.h" #include "util-spm.h" #include "util-spm-bs.h" #include "util-spm-bs2bm.h" #include "util-spm-bm.h" #include "util-clock.h" /** * Wrappers for building context and searching (Bs2Bm and boyermoore) * Use them if you cant store the context * */ /** * \brief Search a pattern in the text using the Bs2Bm algorithm (build a bad characters array) * * \param text Text to search in * \param textlen length of the text * \param needle pattern to search for * \param needlelen length of the pattern */ uint8_t *Bs2bmSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) { uint8_t badchars[ALPHABET_SIZE]; Bs2BmBadchars(needle, needlelen, badchars); return Bs2Bm(text, textlen, needle, needlelen, badchars); } /** * \brief Search a pattern in the text using the Bs2Bm nocase algorithm (build a bad characters array) * * \param text Text to search in * \param textlen length of the text * \param needle pattern to search for * \param needlelen length of the pattern */ uint8_t *Bs2bmNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) { uint8_t badchars[ALPHABET_SIZE]; Bs2BmBadchars(needle, needlelen, badchars); return Bs2BmNocase(text, textlen, needle, needlelen, badchars); } /** * \brief Search a pattern in the text using Boyer Moore algorithm * (build a bad character shifts array and good prefixes shift array) * * \param text Text to search in * \param textlen length of the text * \param needle pattern to search for * \param needlelen length of the pattern */ uint8_t *BoyerMooreSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) { uint16_t bmBc[ALPHABET_SIZE]; uint16_t *bmGs = SCMalloc(sizeof(uint16_t)*(needlelen + 1)); if (unlikely(bmGs == NULL)) return NULL; PreBmGs(needle, needlelen, bmGs); PreBmBc(needle, needlelen, bmBc); uint8_t *ret = BoyerMoore(needle, needlelen, text, textlen, bmGs, bmBc); SCFree(bmGs); return ret; } /** * \brief Search a pattern in the text using Boyer Moore nocase algorithm * (build a bad character shifts array and good prefixes shift array) * * \param text Text to search in * \param textlen length of the text * \param needle pattern to search for * \param needlelen length of the pattern */ uint8_t *BoyerMooreNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) { uint16_t bmBc[ALPHABET_SIZE]; uint16_t *bmGs = SCMalloc(sizeof(uint16_t)*(needlelen + 1)); if (unlikely(bmGs == NULL)) return NULL; PreBmGsNocase(needle, needlelen, bmGs); PreBmBcNocase(needle, needlelen, bmBc); uint8_t *ret = BoyerMooreNocase(needle, needlelen, text, textlen, bmGs, bmBc); SCFree(bmGs); return ret; } #ifdef UNITTESTS /** Comment out this if you want stats * #define ENABLE_SEARCH_STATS 1 */ /* Number of times to repeat the search (for stats) */ #define STATS_TIMES 1000000 /** * \brief Unittest helper function wrappers for the search algorithms * \param text pointer to the buffer to search in * \param needle pointer to the pattern to search for * \param times If you are testing performance, se the numebr of times * that you want to repeat the search */ uint8_t *BasicSearchWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { ret = BasicSearch(text, textlen, needle, needlelen); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *BasicSearchNocaseWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { ret = BasicSearchNocase(text, textlen, needle, needlelen); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *Bs2bmWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t badchars[ALPHABET_SIZE]; Bs2BmBadchars(needle, needlelen, badchars); uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { ret = Bs2Bm(text, textlen, needle, needlelen, badchars); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *Bs2bmNocaseWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t badchars[ALPHABET_SIZE]; Bs2BmBadchars(needle, needlelen, badchars); uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { ret = Bs2BmNocase(text, textlen, needle, needlelen, badchars); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *BoyerMooreWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint16_t bmBc[ALPHABET_SIZE]; uint16_t *bmGs = SCMalloc(sizeof(uint16_t)*(needlelen + 1)); if (unlikely(bmGs == NULL)) return NULL; uint8_t *ret = NULL; int i = 0; PreBmGs(needle, needlelen, bmGs); PreBmBc(needle, needlelen, bmBc); CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { ret = BoyerMoore(needle, needlelen, text, textlen, bmGs, bmBc); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; SCFree(bmGs); return ret; } uint8_t *BoyerMooreNocaseWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint16_t bmBc[ALPHABET_SIZE]; uint16_t *bmGs = SCMalloc(sizeof(uint16_t)*(needlelen + 1)); if (unlikely(bmGs == NULL)) return NULL; uint8_t *ret = NULL; int i = 0; PreBmGsNocase(needle, needlelen, bmGs); PreBmBcNocase(needle, needlelen, bmBc); CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { ret = BoyerMooreNocase(needle, needlelen, text, textlen, bmGs, bmBc); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; SCFree(bmGs); return ret; } /** * \brief Unittest helper function wrappers for the search algorithms * \param text pointer to the buffer to search in * \param needle pointer to the pattern to search for * \param times If you are testing performance, se the numebr of times * that you want to repeat the search */ uint8_t *BasicSearchCtxWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { /* This wrapper is a fake, no context needed! */ ret = BasicSearch(text, textlen, needle, needlelen); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *BasicSearchNocaseCtxWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { /* This wrapper is a fake, no context needed! */ ret = BasicSearchNocase(text, textlen, needle, needlelen); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *Bs2bmCtxWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t badchars[ALPHABET_SIZE]; uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { /* Stats including context building */ Bs2BmBadchars(needle, needlelen, badchars); ret = Bs2Bm(text, textlen, needle, needlelen, badchars); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *Bs2bmNocaseCtxWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t badchars[ALPHABET_SIZE]; uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { /* Stats including context building */ Bs2BmBadchars(needle, needlelen, badchars); ret = Bs2BmNocase(text, textlen, needle, needlelen, badchars); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *BoyerMooreCtxWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint16_t bmBc[ALPHABET_SIZE]; uint16_t *bmGs = SCMalloc(sizeof(uint16_t)*(needlelen + 1)); if (unlikely(bmGs == NULL)) return NULL; uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { /* Stats including context building */ PreBmGs(needle, needlelen, bmGs); PreBmBc(needle, needlelen, bmBc); ret = BoyerMoore(needle, needlelen, text, textlen, bmGs, bmBc); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; SCFree(bmGs); return ret; } uint8_t *RawCtxWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { ret = SpmSearch(text, textlen, needle, needlelen); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; return ret; } uint8_t *BoyerMooreNocaseCtxWrapper(uint8_t *text, uint8_t *needle, int times) { uint32_t textlen = strlen((char *)text); uint16_t needlelen = strlen((char *)needle); uint16_t bmBc[ALPHABET_SIZE]; uint16_t *bmGs = SCMalloc(sizeof(uint16_t)*(needlelen + 1)); if (unlikely(bmGs == NULL)) return NULL; uint8_t *ret = NULL; int i = 0; CLOCK_INIT; if (times > 1) CLOCK_START; for (i = 0; i < times; i++) { /* Stats including context building */ PreBmGsNocase(needle, needlelen, bmGs); PreBmBcNocase(needle, needlelen, bmBc); ret = BoyerMooreNocase(needle, needlelen, text, textlen, bmGs, bmBc); } if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; SCFree(bmGs); return ret; } /** * \test Generic test for BasicSearch matching */ int UtilSpmBasicSearchTest01() { uint8_t *needle = (uint8_t *)"oPqRsT"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = BasicSearchWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 1; else return 0; } /** * \test Generic test for BasicSearch nocase matching */ int UtilSpmBasicSearchNocaseTest01() { uint8_t *needle = (uint8_t *)"OpQrSt"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = BasicSearchNocaseWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 1; else return 0; } /** * \test Generic test for Bs2Bm matching */ int UtilSpmBs2bmSearchTest01() { uint8_t *needle = (uint8_t *)"oPqRsT"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = Bs2bmWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 1; else return 0; } /** * \test Generic test for Bs2Bm no case matching */ int UtilSpmBs2bmSearchNocaseTest01() { uint8_t *needle = (uint8_t *)"OpQrSt"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = Bs2bmNocaseWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 1; else return 0; } /** * \test Generic test for boyer moore matching */ int UtilSpmBoyerMooreSearchTest01() { uint8_t *needle = (uint8_t *)"oPqRsT"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = BoyerMooreWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 1; else return 0; } /** * \test Generic test for boyer moore nocase matching */ int UtilSpmBoyerMooreSearchNocaseTest01() { uint8_t *needle = (uint8_t *)"OpQrSt"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 1; else return 0; } /** * \test issue 130 (@redmine) check to ensure that the * problem is not the algorithm implementation */ int UtilSpmBoyerMooreSearchNocaseTestIssue130() { uint8_t *needle = (uint8_t *)"WWW-Authenticate: "; uint8_t *text = (uint8_t *)"Date: Mon, 23 Feb 2009 13:31:49 GMT" "Server: Apache\r\n" "Www-authenticate: Basic realm=\"Authentification user password\"\r\n" "Vary: accept-language,accept-charset\r\n" "Accept-ranges: bytes\r\n" "Connection: close\r\n" "Content-type: text/html; charset=iso-8859-1\r\n" "Content-language: fr\r\n" "Expires: Mon, 23 Feb 2009 13:31:49 GMT\r\n\r\n"; uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 1; else return 0; } /* Generic tests that should not match */ int UtilSpmBasicSearchTest02() { uint8_t *needle = (uint8_t *)"oPQRsT"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = BasicSearchWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 0; else return 1; } int UtilSpmBasicSearchNocaseTest02() { uint8_t *needle = (uint8_t *)"OpZrSt"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = BasicSearchNocaseWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 0; else return 1; } int UtilSpmBs2bmSearchTest02() { uint8_t *needle = (uint8_t *)"oPQRsT"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = Bs2bmWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 0; else return 1; } int UtilSpmBs2bmSearchNocaseTest02() { uint8_t *needle = (uint8_t *)"OpZrSt"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = Bs2bmNocaseWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 0; else return 1; } int UtilSpmBoyerMooreSearchTest02() { uint8_t *needle = (uint8_t *)"oPQRsT"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = BoyerMooreWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 0; else return 1; } int UtilSpmBoyerMooreSearchNocaseTest02() { uint8_t *needle = (uint8_t *)"OpZrSt"; uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); //printf("found: %s\n", found); if (found != NULL) return 0; else return 1; } /** * \test Check that all the algorithms work at any offset and any pattern length */ int UtilSpmSearchOffsetsTest01() { char *text[26][27]; text[0][0]="azzzzzzzzzzzzzzzzzzzzzzzzzz"; text[0][1]="zazzzzzzzzzzzzzzzzzzzzzzzzz"; text[0][2]="zzazzzzzzzzzzzzzzzzzzzzzzzz"; text[0][3]="zzzazzzzzzzzzzzzzzzzzzzzzzz"; text[0][4]="zzzzazzzzzzzzzzzzzzzzzzzzzz"; text[0][5]="zzzzzazzzzzzzzzzzzzzzzzzzzz"; text[0][6]="zzzzzzazzzzzzzzzzzzzzzzzzzz"; text[0][7]="zzzzzzzazzzzzzzzzzzzzzzzzzz"; text[0][8]="zzzzzzzzazzzzzzzzzzzzzzzzzz"; text[0][9]="zzzzzzzzzazzzzzzzzzzzzzzzzz"; text[0][10]="zzzzzzzzzzazzzzzzzzzzzzzzzz"; text[0][11]="zzzzzzzzzzzazzzzzzzzzzzzzzz"; text[0][12]="zzzzzzzzzzzzazzzzzzzzzzzzzz"; text[0][13]="zzzzzzzzzzzzzazzzzzzzzzzzzz"; text[0][14]="zzzzzzzzzzzzzzazzzzzzzzzzzz"; text[0][15]="zzzzzzzzzzzzzzzazzzzzzzzzzz"; text[0][16]="zzzzzzzzzzzzzzzzazzzzzzzzzz"; text[0][17]="zzzzzzzzzzzzzzzzzazzzzzzzzz"; text[0][18]="zzzzzzzzzzzzzzzzzzazzzzzzzz"; text[0][19]="zzzzzzzzzzzzzzzzzzzazzzzzzz"; text[0][20]="zzzzzzzzzzzzzzzzzzzzazzzzzz"; text[0][21]="zzzzzzzzzzzzzzzzzzzzzazzzzz"; text[0][22]="zzzzzzzzzzzzzzzzzzzzzzazzzz"; text[0][23]="zzzzzzzzzzzzzzzzzzzzzzzazzz"; text[0][24]="zzzzzzzzzzzzzzzzzzzzzzzzazz"; text[0][25]="zzzzzzzzzzzzzzzzzzzzzzzzzaz"; text[0][26]="zzzzzzzzzzzzzzzzzzzzzzzzzza"; text[1][0]="aBzzzzzzzzzzzzzzzzzzzzzzzzz"; text[1][1]="zaBzzzzzzzzzzzzzzzzzzzzzzzz"; text[1][2]="zzaBzzzzzzzzzzzzzzzzzzzzzzz"; text[1][3]="zzzaBzzzzzzzzzzzzzzzzzzzzzz"; text[1][4]="zzzzaBzzzzzzzzzzzzzzzzzzzzz"; text[1][5]="zzzzzaBzzzzzzzzzzzzzzzzzzzz"; text[1][6]="zzzzzzaBzzzzzzzzzzzzzzzzzzz"; text[1][7]="zzzzzzzaBzzzzzzzzzzzzzzzzzz"; text[1][8]="zzzzzzzzaBzzzzzzzzzzzzzzzzz"; text[1][9]="zzzzzzzzzaBzzzzzzzzzzzzzzzz"; text[1][10]="zzzzzzzzzzaBzzzzzzzzzzzzzzz"; text[1][11]="zzzzzzzzzzzaBzzzzzzzzzzzzzz"; text[1][12]="zzzzzzzzzzzzaBzzzzzzzzzzzzz"; text[1][13]="zzzzzzzzzzzzzaBzzzzzzzzzzzz"; text[1][14]="zzzzzzzzzzzzzzaBzzzzzzzzzzz"; text[1][15]="zzzzzzzzzzzzzzzaBzzzzzzzzzz"; text[1][16]="zzzzzzzzzzzzzzzzaBzzzzzzzzz"; text[1][17]="zzzzzzzzzzzzzzzzzaBzzzzzzzz"; text[1][18]="zzzzzzzzzzzzzzzzzzaBzzzzzzz"; text[1][19]="zzzzzzzzzzzzzzzzzzzaBzzzzzz"; text[1][20]="zzzzzzzzzzzzzzzzzzzzaBzzzzz"; text[1][21]="zzzzzzzzzzzzzzzzzzzzzaBzzzz"; text[1][22]="zzzzzzzzzzzzzzzzzzzzzzaBzzz"; text[1][23]="zzzzzzzzzzzzzzzzzzzzzzzaBzz"; text[1][24]="zzzzzzzzzzzzzzzzzzzzzzzzaBz"; text[1][25]="zzzzzzzzzzzzzzzzzzzzzzzzzaB"; text[2][0]="aBczzzzzzzzzzzzzzzzzzzzzzzz"; text[2][1]="zaBczzzzzzzzzzzzzzzzzzzzzzz"; text[2][2]="zzaBczzzzzzzzzzzzzzzzzzzzzz"; text[2][3]="zzzaBczzzzzzzzzzzzzzzzzzzzz"; text[2][4]="zzzzaBczzzzzzzzzzzzzzzzzzzz"; text[2][5]="zzzzzaBczzzzzzzzzzzzzzzzzzz"; text[2][6]="zzzzzzaBczzzzzzzzzzzzzzzzzz"; text[2][7]="zzzzzzzaBczzzzzzzzzzzzzzzzz"; text[2][8]="zzzzzzzzaBczzzzzzzzzzzzzzzz"; text[2][9]="zzzzzzzzzaBczzzzzzzzzzzzzzz"; text[2][10]="zzzzzzzzzzaBczzzzzzzzzzzzzz"; text[2][11]="zzzzzzzzzzzaBczzzzzzzzzzzzz"; text[2][12]="zzzzzzzzzzzzaBczzzzzzzzzzzz"; text[2][13]="zzzzzzzzzzzzzaBczzzzzzzzzzz"; text[2][14]="zzzzzzzzzzzzzzaBczzzzzzzzzz"; text[2][15]="zzzzzzzzzzzzzzzaBczzzzzzzzz"; text[2][16]="zzzzzzzzzzzzzzzzaBczzzzzzzz"; text[2][17]="zzzzzzzzzzzzzzzzzaBczzzzzzz"; text[2][18]="zzzzzzzzzzzzzzzzzzaBczzzzzz"; text[2][19]="zzzzzzzzzzzzzzzzzzzaBczzzzz"; text[2][20]="zzzzzzzzzzzzzzzzzzzzaBczzzz"; text[2][21]="zzzzzzzzzzzzzzzzzzzzzaBczzz"; text[2][22]="zzzzzzzzzzzzzzzzzzzzzzaBczz"; text[2][23]="zzzzzzzzzzzzzzzzzzzzzzzaBcz"; text[2][24]="zzzzzzzzzzzzzzzzzzzzzzzzaBc"; text[3][0]="aBcDzzzzzzzzzzzzzzzzzzzzzzz"; text[3][1]="zaBcDzzzzzzzzzzzzzzzzzzzzzz"; text[3][2]="zzaBcDzzzzzzzzzzzzzzzzzzzzz"; text[3][3]="zzzaBcDzzzzzzzzzzzzzzzzzzzz"; text[3][4]="zzzzaBcDzzzzzzzzzzzzzzzzzzz"; text[3][5]="zzzzzaBcDzzzzzzzzzzzzzzzzzz"; text[3][6]="zzzzzzaBcDzzzzzzzzzzzzzzzzz"; text[3][7]="zzzzzzzaBcDzzzzzzzzzzzzzzzz"; text[3][8]="zzzzzzzzaBcDzzzzzzzzzzzzzzz"; text[3][9]="zzzzzzzzzaBcDzzzzzzzzzzzzzz"; text[3][10]="zzzzzzzzzzaBcDzzzzzzzzzzzzz"; text[3][11]="zzzzzzzzzzzaBcDzzzzzzzzzzzz"; text[3][12]="zzzzzzzzzzzzaBcDzzzzzzzzzzz"; text[3][13]="zzzzzzzzzzzzzaBcDzzzzzzzzzz"; text[3][14]="zzzzzzzzzzzzzzaBcDzzzzzzzzz"; text[3][15]="zzzzzzzzzzzzzzzaBcDzzzzzzzz"; text[3][16]="zzzzzzzzzzzzzzzzaBcDzzzzzzz"; text[3][17]="zzzzzzzzzzzzzzzzzaBcDzzzzzz"; text[3][18]="zzzzzzzzzzzzzzzzzzaBcDzzzzz"; text[3][19]="zzzzzzzzzzzzzzzzzzzaBcDzzzz"; text[3][20]="zzzzzzzzzzzzzzzzzzzzaBcDzzz"; text[3][21]="zzzzzzzzzzzzzzzzzzzzzaBcDzz"; text[3][22]="zzzzzzzzzzzzzzzzzzzzzzaBcDz"; text[3][23]="zzzzzzzzzzzzzzzzzzzzzzzaBcD"; text[4][0]="aBcDezzzzzzzzzzzzzzzzzzzzzz"; text[4][1]="zaBcDezzzzzzzzzzzzzzzzzzzzz"; text[4][2]="zzaBcDezzzzzzzzzzzzzzzzzzzz"; text[4][3]="zzzaBcDezzzzzzzzzzzzzzzzzzz"; text[4][4]="zzzzaBcDezzzzzzzzzzzzzzzzzz"; text[4][5]="zzzzzaBcDezzzzzzzzzzzzzzzzz"; text[4][6]="zzzzzzaBcDezzzzzzzzzzzzzzzz"; text[4][7]="zzzzzzzaBcDezzzzzzzzzzzzzzz"; text[4][8]="zzzzzzzzaBcDezzzzzzzzzzzzzz"; text[4][9]="zzzzzzzzzaBcDezzzzzzzzzzzzz"; text[4][10]="zzzzzzzzzzaBcDezzzzzzzzzzzz"; text[4][11]="zzzzzzzzzzzaBcDezzzzzzzzzzz"; text[4][12]="zzzzzzzzzzzzaBcDezzzzzzzzzz"; text[4][13]="zzzzzzzzzzzzzaBcDezzzzzzzzz"; text[4][14]="zzzzzzzzzzzzzzaBcDezzzzzzzz"; text[4][15]="zzzzzzzzzzzzzzzaBcDezzzzzzz"; text[4][16]="zzzzzzzzzzzzzzzzaBcDezzzzzz"; text[4][17]="zzzzzzzzzzzzzzzzzaBcDezzzzz"; text[4][18]="zzzzzzzzzzzzzzzzzzaBcDezzzz"; text[4][19]="zzzzzzzzzzzzzzzzzzzaBcDezzz"; text[4][20]="zzzzzzzzzzzzzzzzzzzzaBcDezz"; text[4][21]="zzzzzzzzzzzzzzzzzzzzzaBcDez"; text[4][22]="zzzzzzzzzzzzzzzzzzzzzzaBcDe"; text[5][0]="aBcDeFzzzzzzzzzzzzzzzzzzzzz"; text[5][1]="zaBcDeFzzzzzzzzzzzzzzzzzzzz"; text[5][2]="zzaBcDeFzzzzzzzzzzzzzzzzzzz"; text[5][3]="zzzaBcDeFzzzzzzzzzzzzzzzzzz"; text[5][4]="zzzzaBcDeFzzzzzzzzzzzzzzzzz"; text[5][5]="zzzzzaBcDeFzzzzzzzzzzzzzzzz"; text[5][6]="zzzzzzaBcDeFzzzzzzzzzzzzzzz"; text[5][7]="zzzzzzzaBcDeFzzzzzzzzzzzzzz"; text[5][8]="zzzzzzzzaBcDeFzzzzzzzzzzzzz"; text[5][9]="zzzzzzzzzaBcDeFzzzzzzzzzzzz"; text[5][10]="zzzzzzzzzzaBcDeFzzzzzzzzzzz"; text[5][11]="zzzzzzzzzzzaBcDeFzzzzzzzzzz"; text[5][12]="zzzzzzzzzzzzaBcDeFzzzzzzzzz"; text[5][13]="zzzzzzzzzzzzzaBcDeFzzzzzzzz"; text[5][14]="zzzzzzzzzzzzzzaBcDeFzzzzzzz"; text[5][15]="zzzzzzzzzzzzzzzaBcDeFzzzzzz"; text[5][16]="zzzzzzzzzzzzzzzzaBcDeFzzzzz"; text[5][17]="zzzzzzzzzzzzzzzzzaBcDeFzzzz"; text[5][18]="zzzzzzzzzzzzzzzzzzaBcDeFzzz"; text[5][19]="zzzzzzzzzzzzzzzzzzzaBcDeFzz"; text[5][20]="zzzzzzzzzzzzzzzzzzzzaBcDeFz"; text[5][21]="zzzzzzzzzzzzzzzzzzzzzaBcDeF"; text[6][0]="aBcDeFgzzzzzzzzzzzzzzzzzzzz"; text[6][1]="zaBcDeFgzzzzzzzzzzzzzzzzzzz"; text[6][2]="zzaBcDeFgzzzzzzzzzzzzzzzzzz"; text[6][3]="zzzaBcDeFgzzzzzzzzzzzzzzzzz"; text[6][4]="zzzzaBcDeFgzzzzzzzzzzzzzzzz"; text[6][5]="zzzzzaBcDeFgzzzzzzzzzzzzzzz"; text[6][6]="zzzzzzaBcDeFgzzzzzzzzzzzzzz"; text[6][7]="zzzzzzzaBcDeFgzzzzzzzzzzzzz"; text[6][8]="zzzzzzzzaBcDeFgzzzzzzzzzzzz"; text[6][9]="zzzzzzzzzaBcDeFgzzzzzzzzzzz"; text[6][10]="zzzzzzzzzzaBcDeFgzzzzzzzzzz"; text[6][11]="zzzzzzzzzzzaBcDeFgzzzzzzzzz"; text[6][12]="zzzzzzzzzzzzaBcDeFgzzzzzzzz"; text[6][13]="zzzzzzzzzzzzzaBcDeFgzzzzzzz"; text[6][14]="zzzzzzzzzzzzzzaBcDeFgzzzzzz"; text[6][15]="zzzzzzzzzzzzzzzaBcDeFgzzzzz"; text[6][16]="zzzzzzzzzzzzzzzzaBcDeFgzzzz"; text[6][17]="zzzzzzzzzzzzzzzzzaBcDeFgzzz"; text[6][18]="zzzzzzzzzzzzzzzzzzaBcDeFgzz"; text[6][19]="zzzzzzzzzzzzzzzzzzzaBcDeFgz"; text[6][20]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; text[7][0]="aBcDeFgHzzzzzzzzzzzzzzzzzzz"; text[7][1]="zaBcDeFgHzzzzzzzzzzzzzzzzzz"; text[7][2]="zzaBcDeFgHzzzzzzzzzzzzzzzzz"; text[7][3]="zzzaBcDeFgHzzzzzzzzzzzzzzzz"; text[7][4]="zzzzaBcDeFgHzzzzzzzzzzzzzzz"; text[7][5]="zzzzzaBcDeFgHzzzzzzzzzzzzzz"; text[7][6]="zzzzzzaBcDeFgHzzzzzzzzzzzzz"; text[7][7]="zzzzzzzaBcDeFgHzzzzzzzzzzzz"; text[7][8]="zzzzzzzzaBcDeFgHzzzzzzzzzzz"; text[7][9]="zzzzzzzzzaBcDeFgHzzzzzzzzzz"; text[7][10]="zzzzzzzzzzaBcDeFgHzzzzzzzzz"; text[7][11]="zzzzzzzzzzzaBcDeFgHzzzzzzzz"; text[7][12]="zzzzzzzzzzzzaBcDeFgHzzzzzzz"; text[7][13]="zzzzzzzzzzzzzaBcDeFgHzzzzzz"; text[7][14]="zzzzzzzzzzzzzzaBcDeFgHzzzzz"; text[7][15]="zzzzzzzzzzzzzzzaBcDeFgHzzzz"; text[7][16]="zzzzzzzzzzzzzzzzaBcDeFgHzzz"; text[7][17]="zzzzzzzzzzzzzzzzzaBcDeFgHzz"; text[7][18]="zzzzzzzzzzzzzzzzzzaBcDeFgHz"; text[7][19]="zzzzzzzzzzzzzzzzzzzaBcDeFgH"; text[8][0]="aBcDeFgHizzzzzzzzzzzzzzzzzz"; text[8][1]="zaBcDeFgHizzzzzzzzzzzzzzzzz"; text[8][2]="zzaBcDeFgHizzzzzzzzzzzzzzzz"; text[8][3]="zzzaBcDeFgHizzzzzzzzzzzzzzz"; text[8][4]="zzzzaBcDeFgHizzzzzzzzzzzzzz"; text[8][5]="zzzzzaBcDeFgHizzzzzzzzzzzzz"; text[8][6]="zzzzzzaBcDeFgHizzzzzzzzzzzz"; text[8][7]="zzzzzzzaBcDeFgHizzzzzzzzzzz"; text[8][8]="zzzzzzzzaBcDeFgHizzzzzzzzzz"; text[8][9]="zzzzzzzzzaBcDeFgHizzzzzzzzz"; text[8][10]="zzzzzzzzzzaBcDeFgHizzzzzzzz"; text[8][11]="zzzzzzzzzzzaBcDeFgHizzzzzzz"; text[8][12]="zzzzzzzzzzzzaBcDeFgHizzzzzz"; text[8][13]="zzzzzzzzzzzzzaBcDeFgHizzzzz"; text[8][14]="zzzzzzzzzzzzzzaBcDeFgHizzzz"; text[8][15]="zzzzzzzzzzzzzzzaBcDeFgHizzz"; text[8][16]="zzzzzzzzzzzzzzzzaBcDeFgHizz"; text[8][17]="zzzzzzzzzzzzzzzzzaBcDeFgHiz"; text[8][18]="zzzzzzzzzzzzzzzzzzaBcDeFgHi"; text[9][0]="aBcDeFgHiJzzzzzzzzzzzzzzzzz"; text[9][1]="zaBcDeFgHiJzzzzzzzzzzzzzzzz"; text[9][2]="zzaBcDeFgHiJzzzzzzzzzzzzzzz"; text[9][3]="zzzaBcDeFgHiJzzzzzzzzzzzzzz"; text[9][4]="zzzzaBcDeFgHiJzzzzzzzzzzzzz"; text[9][5]="zzzzzaBcDeFgHiJzzzzzzzzzzzz"; text[9][6]="zzzzzzaBcDeFgHiJzzzzzzzzzzz"; text[9][7]="zzzzzzzaBcDeFgHiJzzzzzzzzzz"; text[9][8]="zzzzzzzzaBcDeFgHiJzzzzzzzzz"; text[9][9]="zzzzzzzzzaBcDeFgHiJzzzzzzzz"; text[9][10]="zzzzzzzzzzaBcDeFgHiJzzzzzzz"; text[9][11]="zzzzzzzzzzzaBcDeFgHiJzzzzzz"; text[9][12]="zzzzzzzzzzzzaBcDeFgHiJzzzzz"; text[9][13]="zzzzzzzzzzzzzaBcDeFgHiJzzzz"; text[9][14]="zzzzzzzzzzzzzzaBcDeFgHiJzzz"; text[9][15]="zzzzzzzzzzzzzzzaBcDeFgHiJzz"; text[9][16]="zzzzzzzzzzzzzzzzaBcDeFgHiJz"; text[9][17]="zzzzzzzzzzzzzzzzzaBcDeFgHiJ"; text[10][0]="aBcDeFgHiJkzzzzzzzzzzzzzzzz"; text[10][1]="zaBcDeFgHiJkzzzzzzzzzzzzzzz"; text[10][2]="zzaBcDeFgHiJkzzzzzzzzzzzzzz"; text[10][3]="zzzaBcDeFgHiJkzzzzzzzzzzzzz"; text[10][4]="zzzzaBcDeFgHiJkzzzzzzzzzzzz"; text[10][5]="zzzzzaBcDeFgHiJkzzzzzzzzzzz"; text[10][6]="zzzzzzaBcDeFgHiJkzzzzzzzzzz"; text[10][7]="zzzzzzzaBcDeFgHiJkzzzzzzzzz"; text[10][8]="zzzzzzzzaBcDeFgHiJkzzzzzzzz"; text[10][9]="zzzzzzzzzaBcDeFgHiJkzzzzzzz"; text[10][10]="zzzzzzzzzzaBcDeFgHiJkzzzzzz"; text[10][11]="zzzzzzzzzzzaBcDeFgHiJkzzzzz"; text[10][12]="zzzzzzzzzzzzaBcDeFgHiJkzzzz"; text[10][13]="zzzzzzzzzzzzzaBcDeFgHiJkzzz"; text[10][14]="zzzzzzzzzzzzzzaBcDeFgHiJkzz"; text[10][15]="zzzzzzzzzzzzzzzaBcDeFgHiJkz"; text[10][16]="zzzzzzzzzzzzzzzzaBcDeFgHiJk"; text[11][0]="aBcDeFgHiJkLzzzzzzzzzzzzzzz"; text[11][1]="zaBcDeFgHiJkLzzzzzzzzzzzzzz"; text[11][2]="zzaBcDeFgHiJkLzzzzzzzzzzzzz"; text[11][3]="zzzaBcDeFgHiJkLzzzzzzzzzzzz"; text[11][4]="zzzzaBcDeFgHiJkLzzzzzzzzzzz"; text[11][5]="zzzzzaBcDeFgHiJkLzzzzzzzzzz"; text[11][6]="zzzzzzaBcDeFgHiJkLzzzzzzzzz"; text[11][7]="zzzzzzzaBcDeFgHiJkLzzzzzzzz"; text[11][8]="zzzzzzzzaBcDeFgHiJkLzzzzzzz"; text[11][9]="zzzzzzzzzaBcDeFgHiJkLzzzzzz"; text[11][10]="zzzzzzzzzzaBcDeFgHiJkLzzzzz"; text[11][11]="zzzzzzzzzzzaBcDeFgHiJkLzzzz"; text[11][12]="zzzzzzzzzzzzaBcDeFgHiJkLzzz"; text[11][13]="zzzzzzzzzzzzzaBcDeFgHiJkLzz"; text[11][14]="zzzzzzzzzzzzzzaBcDeFgHiJkLz"; text[11][15]="zzzzzzzzzzzzzzzaBcDeFgHiJkL"; text[12][0]="aBcDeFgHiJkLmzzzzzzzzzzzzzz"; text[12][1]="zaBcDeFgHiJkLmzzzzzzzzzzzzz"; text[12][2]="zzaBcDeFgHiJkLmzzzzzzzzzzzz"; text[12][3]="zzzaBcDeFgHiJkLmzzzzzzzzzzz"; text[12][4]="zzzzaBcDeFgHiJkLmzzzzzzzzzz"; text[12][5]="zzzzzaBcDeFgHiJkLmzzzzzzzzz"; text[12][6]="zzzzzzaBcDeFgHiJkLmzzzzzzzz"; text[12][7]="zzzzzzzaBcDeFgHiJkLmzzzzzzz"; text[12][8]="zzzzzzzzaBcDeFgHiJkLmzzzzzz"; text[12][9]="zzzzzzzzzaBcDeFgHiJkLmzzzzz"; text[12][10]="zzzzzzzzzzaBcDeFgHiJkLmzzzz"; text[12][11]="zzzzzzzzzzzaBcDeFgHiJkLmzzz"; text[12][12]="zzzzzzzzzzzzaBcDeFgHiJkLmzz"; text[12][13]="zzzzzzzzzzzzzaBcDeFgHiJkLmz"; text[12][14]="zzzzzzzzzzzzzzaBcDeFgHiJkLm"; text[13][0]="aBcDeFgHiJkLmNzzzzzzzzzzzzz"; text[13][1]="zaBcDeFgHiJkLmNzzzzzzzzzzzz"; text[13][2]="zzaBcDeFgHiJkLmNzzzzzzzzzzz"; text[13][3]="zzzaBcDeFgHiJkLmNzzzzzzzzzz"; text[13][4]="zzzzaBcDeFgHiJkLmNzzzzzzzzz"; text[13][5]="zzzzzaBcDeFgHiJkLmNzzzzzzzz"; text[13][6]="zzzzzzaBcDeFgHiJkLmNzzzzzzz"; text[13][7]="zzzzzzzaBcDeFgHiJkLmNzzzzzz"; text[13][8]="zzzzzzzzaBcDeFgHiJkLmNzzzzz"; text[13][9]="zzzzzzzzzaBcDeFgHiJkLmNzzzz"; text[13][10]="zzzzzzzzzzaBcDeFgHiJkLmNzzz"; text[13][11]="zzzzzzzzzzzaBcDeFgHiJkLmNzz"; text[13][12]="zzzzzzzzzzzzaBcDeFgHiJkLmNz"; text[13][13]="zzzzzzzzzzzzzaBcDeFgHiJkLmN"; text[14][0]="aBcDeFgHiJkLmNozzzzzzzzzzzz"; text[14][1]="zaBcDeFgHiJkLmNozzzzzzzzzzz"; text[14][2]="zzaBcDeFgHiJkLmNozzzzzzzzzz"; text[14][3]="zzzaBcDeFgHiJkLmNozzzzzzzzz"; text[14][4]="zzzzaBcDeFgHiJkLmNozzzzzzzz"; text[14][5]="zzzzzaBcDeFgHiJkLmNozzzzzzz"; text[14][6]="zzzzzzaBcDeFgHiJkLmNozzzzzz"; text[14][7]="zzzzzzzaBcDeFgHiJkLmNozzzzz"; text[14][8]="zzzzzzzzaBcDeFgHiJkLmNozzzz"; text[14][9]="zzzzzzzzzaBcDeFgHiJkLmNozzz"; text[14][10]="zzzzzzzzzzaBcDeFgHiJkLmNozz"; text[14][11]="zzzzzzzzzzzaBcDeFgHiJkLmNoz"; text[14][12]="zzzzzzzzzzzzaBcDeFgHiJkLmNo"; text[15][0]="aBcDeFgHiJkLmNoPzzzzzzzzzzz"; text[15][1]="zaBcDeFgHiJkLmNoPzzzzzzzzzz"; text[15][2]="zzaBcDeFgHiJkLmNoPzzzzzzzzz"; text[15][3]="zzzaBcDeFgHiJkLmNoPzzzzzzzz"; text[15][4]="zzzzaBcDeFgHiJkLmNoPzzzzzzz"; text[15][5]="zzzzzaBcDeFgHiJkLmNoPzzzzzz"; text[15][6]="zzzzzzaBcDeFgHiJkLmNoPzzzzz"; text[15][7]="zzzzzzzaBcDeFgHiJkLmNoPzzzz"; text[15][8]="zzzzzzzzaBcDeFgHiJkLmNoPzzz"; text[15][9]="zzzzzzzzzaBcDeFgHiJkLmNoPzz"; text[15][10]="zzzzzzzzzzaBcDeFgHiJkLmNoPz"; text[15][11]="zzzzzzzzzzzaBcDeFgHiJkLmNoP"; text[16][0]="aBcDeFgHiJkLmNoPqzzzzzzzzzz"; text[16][1]="zaBcDeFgHiJkLmNoPqzzzzzzzzz"; text[16][2]="zzaBcDeFgHiJkLmNoPqzzzzzzzz"; text[16][3]="zzzaBcDeFgHiJkLmNoPqzzzzzzz"; text[16][4]="zzzzaBcDeFgHiJkLmNoPqzzzzzz"; text[16][5]="zzzzzaBcDeFgHiJkLmNoPqzzzzz"; text[16][6]="zzzzzzaBcDeFgHiJkLmNoPqzzzz"; text[16][7]="zzzzzzzaBcDeFgHiJkLmNoPqzzz"; text[16][8]="zzzzzzzzaBcDeFgHiJkLmNoPqzz"; text[16][9]="zzzzzzzzzaBcDeFgHiJkLmNoPqz"; text[16][10]="zzzzzzzzzzaBcDeFgHiJkLmNoPq"; text[17][0]="aBcDeFgHiJkLmNoPqRzzzzzzzzz"; text[17][1]="zaBcDeFgHiJkLmNoPqRzzzzzzzz"; text[17][2]="zzaBcDeFgHiJkLmNoPqRzzzzzzz"; text[17][3]="zzzaBcDeFgHiJkLmNoPqRzzzzzz"; text[17][4]="zzzzaBcDeFgHiJkLmNoPqRzzzzz"; text[17][5]="zzzzzaBcDeFgHiJkLmNoPqRzzzz"; text[17][6]="zzzzzzaBcDeFgHiJkLmNoPqRzzz"; text[17][7]="zzzzzzzaBcDeFgHiJkLmNoPqRzz"; text[17][8]="zzzzzzzzaBcDeFgHiJkLmNoPqRz"; text[17][9]="zzzzzzzzzaBcDeFgHiJkLmNoPqR"; text[18][0]="aBcDeFgHiJkLmNoPqRszzzzzzzz"; text[18][1]="zaBcDeFgHiJkLmNoPqRszzzzzzz"; text[18][2]="zzaBcDeFgHiJkLmNoPqRszzzzzz"; text[18][3]="zzzaBcDeFgHiJkLmNoPqRszzzzz"; text[18][4]="zzzzaBcDeFgHiJkLmNoPqRszzzz"; text[18][5]="zzzzzaBcDeFgHiJkLmNoPqRszzz"; text[18][6]="zzzzzzaBcDeFgHiJkLmNoPqRszz"; text[18][7]="zzzzzzzaBcDeFgHiJkLmNoPqRsz"; text[18][8]="zzzzzzzzaBcDeFgHiJkLmNoPqRs"; text[19][0]="aBcDeFgHiJkLmNoPqRsTzzzzzzz"; text[19][1]="zaBcDeFgHiJkLmNoPqRsTzzzzzz"; text[19][2]="zzaBcDeFgHiJkLmNoPqRsTzzzzz"; text[19][3]="zzzaBcDeFgHiJkLmNoPqRsTzzzz"; text[19][4]="zzzzaBcDeFgHiJkLmNoPqRsTzzz"; text[19][5]="zzzzzaBcDeFgHiJkLmNoPqRsTzz"; text[19][6]="zzzzzzaBcDeFgHiJkLmNoPqRsTz"; text[19][7]="zzzzzzzaBcDeFgHiJkLmNoPqRsT"; text[20][0]="aBcDeFgHiJkLmNoPqRsTuzzzzzz"; text[20][1]="zaBcDeFgHiJkLmNoPqRsTuzzzzz"; text[20][2]="zzaBcDeFgHiJkLmNoPqRsTuzzzz"; text[20][3]="zzzaBcDeFgHiJkLmNoPqRsTuzzz"; text[20][4]="zzzzaBcDeFgHiJkLmNoPqRsTuzz"; text[20][5]="zzzzzaBcDeFgHiJkLmNoPqRsTuz"; text[20][6]="zzzzzzaBcDeFgHiJkLmNoPqRsTu"; text[21][0]="aBcDeFgHiJkLmNoPqRsTuVzzzzz"; text[21][1]="zaBcDeFgHiJkLmNoPqRsTuVzzzz"; text[21][2]="zzaBcDeFgHiJkLmNoPqRsTuVzzz"; text[21][3]="zzzaBcDeFgHiJkLmNoPqRsTuVzz"; text[21][4]="zzzzaBcDeFgHiJkLmNoPqRsTuVz"; text[21][5]="zzzzzaBcDeFgHiJkLmNoPqRsTuV"; text[22][0]="aBcDeFgHiJkLmNoPqRsTuVwzzzz"; text[22][1]="zaBcDeFgHiJkLmNoPqRsTuVwzzz"; text[22][2]="zzaBcDeFgHiJkLmNoPqRsTuVwzz"; text[22][3]="zzzaBcDeFgHiJkLmNoPqRsTuVwz"; text[22][4]="zzzzaBcDeFgHiJkLmNoPqRsTuVw"; text[23][0]="aBcDeFgHiJkLmNoPqRsTuVwXzzz"; text[23][1]="zaBcDeFgHiJkLmNoPqRsTuVwXzz"; text[23][2]="zzaBcDeFgHiJkLmNoPqRsTuVwXz"; text[23][3]="zzzaBcDeFgHiJkLmNoPqRsTuVwX"; text[24][0]="aBcDeFgHiJkLmNoPqRsTuVwXyzz"; text[24][1]="zaBcDeFgHiJkLmNoPqRsTuVwXyz"; text[24][2]="zzaBcDeFgHiJkLmNoPqRsTuVwXy"; text[25][0]="aBcDeFgHiJkLmNoPqRsTuVwXyZz"; text[25][1]="zaBcDeFgHiJkLmNoPqRsTuVwXyZ"; char *needle[26]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; needle[16]="aBcDeFgHiJkLmNoPq"; needle[17]="aBcDeFgHiJkLmNoPqR"; needle[18]="aBcDeFgHiJkLmNoPqRs"; needle[19]="aBcDeFgHiJkLmNoPqRsT"; needle[20]="aBcDeFgHiJkLmNoPqRsTu"; needle[21]="aBcDeFgHiJkLmNoPqRsTuV"; needle[22]="aBcDeFgHiJkLmNoPqRsTuVw"; needle[23]="aBcDeFgHiJkLmNoPqRsTuVwX"; needle[24]="aBcDeFgHiJkLmNoPqRsTuVwXy"; needle[25]="aBcDeFgHiJkLmNoPqRsTuVwXyZ"; int i, j; uint8_t *found = NULL; for (i = 0; i < 26; i++) { for (j = 0; j <= (26 - i); j++) { found = BasicSearchWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i][j]); return 0; } found = Bs2bmWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i][j]); return 0; } found = BoyerMooreWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i][j]); return 0; } } } return 1; } /** * \test Check that all the algorithms (no case) work at any offset and any pattern length */ int UtilSpmSearchOffsetsNocaseTest01() { char *text[26][27]; text[0][0]="azzzzzzzzzzzzzzzzzzzzzzzzzz"; text[0][1]="zazzzzzzzzzzzzzzzzzzzzzzzzz"; text[0][2]="zzazzzzzzzzzzzzzzzzzzzzzzzz"; text[0][3]="zzzazzzzzzzzzzzzzzzzzzzzzzz"; text[0][4]="zzzzazzzzzzzzzzzzzzzzzzzzzz"; text[0][5]="zzzzzazzzzzzzzzzzzzzzzzzzzz"; text[0][6]="zzzzzzazzzzzzzzzzzzzzzzzzzz"; text[0][7]="zzzzzzzazzzzzzzzzzzzzzzzzzz"; text[0][8]="zzzzzzzzazzzzzzzzzzzzzzzzzz"; text[0][9]="zzzzzzzzzazzzzzzzzzzzzzzzzz"; text[0][10]="zzzzzzzzzzazzzzzzzzzzzzzzzz"; text[0][11]="zzzzzzzzzzzazzzzzzzzzzzzzzz"; text[0][12]="zzzzzzzzzzzzazzzzzzzzzzzzzz"; text[0][13]="zzzzzzzzzzzzzazzzzzzzzzzzzz"; text[0][14]="zzzzzzzzzzzzzzazzzzzzzzzzzz"; text[0][15]="zzzzzzzzzzzzzzzazzzzzzzzzzz"; text[0][16]="zzzzzzzzzzzzzzzzazzzzzzzzzz"; text[0][17]="zzzzzzzzzzzzzzzzzazzzzzzzzz"; text[0][18]="zzzzzzzzzzzzzzzzzzazzzzzzzz"; text[0][19]="zzzzzzzzzzzzzzzzzzzazzzzzzz"; text[0][20]="zzzzzzzzzzzzzzzzzzzzazzzzzz"; text[0][21]="zzzzzzzzzzzzzzzzzzzzzazzzzz"; text[0][22]="zzzzzzzzzzzzzzzzzzzzzzazzzz"; text[0][23]="zzzzzzzzzzzzzzzzzzzzzzzazzz"; text[0][24]="zzzzzzzzzzzzzzzzzzzzzzzzazz"; text[0][25]="zzzzzzzzzzzzzzzzzzzzzzzzzaz"; text[0][26]="zzzzzzzzzzzzzzzzzzzzzzzzzza"; text[1][0]="aBzzzzzzzzzzzzzzzzzzzzzzzzz"; text[1][1]="zaBzzzzzzzzzzzzzzzzzzzzzzzz"; text[1][2]="zzaBzzzzzzzzzzzzzzzzzzzzzzz"; text[1][3]="zzzaBzzzzzzzzzzzzzzzzzzzzzz"; text[1][4]="zzzzaBzzzzzzzzzzzzzzzzzzzzz"; text[1][5]="zzzzzaBzzzzzzzzzzzzzzzzzzzz"; text[1][6]="zzzzzzaBzzzzzzzzzzzzzzzzzzz"; text[1][7]="zzzzzzzaBzzzzzzzzzzzzzzzzzz"; text[1][8]="zzzzzzzzaBzzzzzzzzzzzzzzzzz"; text[1][9]="zzzzzzzzzaBzzzzzzzzzzzzzzzz"; text[1][10]="zzzzzzzzzzaBzzzzzzzzzzzzzzz"; text[1][11]="zzzzzzzzzzzaBzzzzzzzzzzzzzz"; text[1][12]="zzzzzzzzzzzzaBzzzzzzzzzzzzz"; text[1][13]="zzzzzzzzzzzzzaBzzzzzzzzzzzz"; text[1][14]="zzzzzzzzzzzzzzaBzzzzzzzzzzz"; text[1][15]="zzzzzzzzzzzzzzzaBzzzzzzzzzz"; text[1][16]="zzzzzzzzzzzzzzzzaBzzzzzzzzz"; text[1][17]="zzzzzzzzzzzzzzzzzaBzzzzzzzz"; text[1][18]="zzzzzzzzzzzzzzzzzzaBzzzzzzz"; text[1][19]="zzzzzzzzzzzzzzzzzzzaBzzzzzz"; text[1][20]="zzzzzzzzzzzzzzzzzzzzaBzzzzz"; text[1][21]="zzzzzzzzzzzzzzzzzzzzzaBzzzz"; text[1][22]="zzzzzzzzzzzzzzzzzzzzzzaBzzz"; text[1][23]="zzzzzzzzzzzzzzzzzzzzzzzaBzz"; text[1][24]="zzzzzzzzzzzzzzzzzzzzzzzzaBz"; text[1][25]="zzzzzzzzzzzzzzzzzzzzzzzzzaB"; text[2][0]="aBczzzzzzzzzzzzzzzzzzzzzzzz"; text[2][1]="zaBczzzzzzzzzzzzzzzzzzzzzzz"; text[2][2]="zzaBczzzzzzzzzzzzzzzzzzzzzz"; text[2][3]="zzzaBczzzzzzzzzzzzzzzzzzzzz"; text[2][4]="zzzzaBczzzzzzzzzzzzzzzzzzzz"; text[2][5]="zzzzzaBczzzzzzzzzzzzzzzzzzz"; text[2][6]="zzzzzzaBczzzzzzzzzzzzzzzzzz"; text[2][7]="zzzzzzzaBczzzzzzzzzzzzzzzzz"; text[2][8]="zzzzzzzzaBczzzzzzzzzzzzzzzz"; text[2][9]="zzzzzzzzzaBczzzzzzzzzzzzzzz"; text[2][10]="zzzzzzzzzzaBczzzzzzzzzzzzzz"; text[2][11]="zzzzzzzzzzzaBczzzzzzzzzzzzz"; text[2][12]="zzzzzzzzzzzzaBczzzzzzzzzzzz"; text[2][13]="zzzzzzzzzzzzzaBczzzzzzzzzzz"; text[2][14]="zzzzzzzzzzzzzzaBczzzzzzzzzz"; text[2][15]="zzzzzzzzzzzzzzzaBczzzzzzzzz"; text[2][16]="zzzzzzzzzzzzzzzzaBczzzzzzzz"; text[2][17]="zzzzzzzzzzzzzzzzzaBczzzzzzz"; text[2][18]="zzzzzzzzzzzzzzzzzzaBczzzzzz"; text[2][19]="zzzzzzzzzzzzzzzzzzzaBczzzzz"; text[2][20]="zzzzzzzzzzzzzzzzzzzzaBczzzz"; text[2][21]="zzzzzzzzzzzzzzzzzzzzzaBczzz"; text[2][22]="zzzzzzzzzzzzzzzzzzzzzzaBczz"; text[2][23]="zzzzzzzzzzzzzzzzzzzzzzzaBcz"; text[2][24]="zzzzzzzzzzzzzzzzzzzzzzzzaBc"; text[3][0]="aBcDzzzzzzzzzzzzzzzzzzzzzzz"; text[3][1]="zaBcDzzzzzzzzzzzzzzzzzzzzzz"; text[3][2]="zzaBcDzzzzzzzzzzzzzzzzzzzzz"; text[3][3]="zzzaBcDzzzzzzzzzzzzzzzzzzzz"; text[3][4]="zzzzaBcDzzzzzzzzzzzzzzzzzzz"; text[3][5]="zzzzzaBcDzzzzzzzzzzzzzzzzzz"; text[3][6]="zzzzzzaBcDzzzzzzzzzzzzzzzzz"; text[3][7]="zzzzzzzaBcDzzzzzzzzzzzzzzzz"; text[3][8]="zzzzzzzzaBcDzzzzzzzzzzzzzzz"; text[3][9]="zzzzzzzzzaBcDzzzzzzzzzzzzzz"; text[3][10]="zzzzzzzzzzaBcDzzzzzzzzzzzzz"; text[3][11]="zzzzzzzzzzzaBcDzzzzzzzzzzzz"; text[3][12]="zzzzzzzzzzzzaBcDzzzzzzzzzzz"; text[3][13]="zzzzzzzzzzzzzaBcDzzzzzzzzzz"; text[3][14]="zzzzzzzzzzzzzzaBcDzzzzzzzzz"; text[3][15]="zzzzzzzzzzzzzzzaBcDzzzzzzzz"; text[3][16]="zzzzzzzzzzzzzzzzaBcDzzzzzzz"; text[3][17]="zzzzzzzzzzzzzzzzzaBcDzzzzzz"; text[3][18]="zzzzzzzzzzzzzzzzzzaBcDzzzzz"; text[3][19]="zzzzzzzzzzzzzzzzzzzaBcDzzzz"; text[3][20]="zzzzzzzzzzzzzzzzzzzzaBcDzzz"; text[3][21]="zzzzzzzzzzzzzzzzzzzzzaBcDzz"; text[3][22]="zzzzzzzzzzzzzzzzzzzzzzaBcDz"; text[3][23]="zzzzzzzzzzzzzzzzzzzzzzzaBcD"; text[4][0]="aBcDezzzzzzzzzzzzzzzzzzzzzz"; text[4][1]="zaBcDezzzzzzzzzzzzzzzzzzzzz"; text[4][2]="zzaBcDezzzzzzzzzzzzzzzzzzzz"; text[4][3]="zzzaBcDezzzzzzzzzzzzzzzzzzz"; text[4][4]="zzzzaBcDezzzzzzzzzzzzzzzzzz"; text[4][5]="zzzzzaBcDezzzzzzzzzzzzzzzzz"; text[4][6]="zzzzzzaBcDezzzzzzzzzzzzzzzz"; text[4][7]="zzzzzzzaBcDezzzzzzzzzzzzzzz"; text[4][8]="zzzzzzzzaBcDezzzzzzzzzzzzzz"; text[4][9]="zzzzzzzzzaBcDezzzzzzzzzzzzz"; text[4][10]="zzzzzzzzzzaBcDezzzzzzzzzzzz"; text[4][11]="zzzzzzzzzzzaBcDezzzzzzzzzzz"; text[4][12]="zzzzzzzzzzzzaBcDezzzzzzzzzz"; text[4][13]="zzzzzzzzzzzzzaBcDezzzzzzzzz"; text[4][14]="zzzzzzzzzzzzzzaBcDezzzzzzzz"; text[4][15]="zzzzzzzzzzzzzzzaBcDezzzzzzz"; text[4][16]="zzzzzzzzzzzzzzzzaBcDezzzzzz"; text[4][17]="zzzzzzzzzzzzzzzzzaBcDezzzzz"; text[4][18]="zzzzzzzzzzzzzzzzzzaBcDezzzz"; text[4][19]="zzzzzzzzzzzzzzzzzzzaBcDezzz"; text[4][20]="zzzzzzzzzzzzzzzzzzzzaBcDezz"; text[4][21]="zzzzzzzzzzzzzzzzzzzzzaBcDez"; text[4][22]="zzzzzzzzzzzzzzzzzzzzzzaBcDe"; text[5][0]="aBcDeFzzzzzzzzzzzzzzzzzzzzz"; text[5][1]="zaBcDeFzzzzzzzzzzzzzzzzzzzz"; text[5][2]="zzaBcDeFzzzzzzzzzzzzzzzzzzz"; text[5][3]="zzzaBcDeFzzzzzzzzzzzzzzzzzz"; text[5][4]="zzzzaBcDeFzzzzzzzzzzzzzzzzz"; text[5][5]="zzzzzaBcDeFzzzzzzzzzzzzzzzz"; text[5][6]="zzzzzzaBcDeFzzzzzzzzzzzzzzz"; text[5][7]="zzzzzzzaBcDeFzzzzzzzzzzzzzz"; text[5][8]="zzzzzzzzaBcDeFzzzzzzzzzzzzz"; text[5][9]="zzzzzzzzzaBcDeFzzzzzzzzzzzz"; text[5][10]="zzzzzzzzzzaBcDeFzzzzzzzzzzz"; text[5][11]="zzzzzzzzzzzaBcDeFzzzzzzzzzz"; text[5][12]="zzzzzzzzzzzzaBcDeFzzzzzzzzz"; text[5][13]="zzzzzzzzzzzzzaBcDeFzzzzzzzz"; text[5][14]="zzzzzzzzzzzzzzaBcDeFzzzzzzz"; text[5][15]="zzzzzzzzzzzzzzzaBcDeFzzzzzz"; text[5][16]="zzzzzzzzzzzzzzzzaBcDeFzzzzz"; text[5][17]="zzzzzzzzzzzzzzzzzaBcDeFzzzz"; text[5][18]="zzzzzzzzzzzzzzzzzzaBcDeFzzz"; text[5][19]="zzzzzzzzzzzzzzzzzzzaBcDeFzz"; text[5][20]="zzzzzzzzzzzzzzzzzzzzaBcDeFz"; text[5][21]="zzzzzzzzzzzzzzzzzzzzzaBcDeF"; text[6][0]="aBcDeFgzzzzzzzzzzzzzzzzzzzz"; text[6][1]="zaBcDeFgzzzzzzzzzzzzzzzzzzz"; text[6][2]="zzaBcDeFgzzzzzzzzzzzzzzzzzz"; text[6][3]="zzzaBcDeFgzzzzzzzzzzzzzzzzz"; text[6][4]="zzzzaBcDeFgzzzzzzzzzzzzzzzz"; text[6][5]="zzzzzaBcDeFgzzzzzzzzzzzzzzz"; text[6][6]="zzzzzzaBcDeFgzzzzzzzzzzzzzz"; text[6][7]="zzzzzzzaBcDeFgzzzzzzzzzzzzz"; text[6][8]="zzzzzzzzaBcDeFgzzzzzzzzzzzz"; text[6][9]="zzzzzzzzzaBcDeFgzzzzzzzzzzz"; text[6][10]="zzzzzzzzzzaBcDeFgzzzzzzzzzz"; text[6][11]="zzzzzzzzzzzaBcDeFgzzzzzzzzz"; text[6][12]="zzzzzzzzzzzzaBcDeFgzzzzzzzz"; text[6][13]="zzzzzzzzzzzzzaBcDeFgzzzzzzz"; text[6][14]="zzzzzzzzzzzzzzaBcDeFgzzzzzz"; text[6][15]="zzzzzzzzzzzzzzzaBcDeFgzzzzz"; text[6][16]="zzzzzzzzzzzzzzzzaBcDeFgzzzz"; text[6][17]="zzzzzzzzzzzzzzzzzaBcDeFgzzz"; text[6][18]="zzzzzzzzzzzzzzzzzzaBcDeFgzz"; text[6][19]="zzzzzzzzzzzzzzzzzzzaBcDeFgz"; text[6][20]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; text[7][0]="aBcDeFgHzzzzzzzzzzzzzzzzzzz"; text[7][1]="zaBcDeFgHzzzzzzzzzzzzzzzzzz"; text[7][2]="zzaBcDeFgHzzzzzzzzzzzzzzzzz"; text[7][3]="zzzaBcDeFgHzzzzzzzzzzzzzzzz"; text[7][4]="zzzzaBcDeFgHzzzzzzzzzzzzzzz"; text[7][5]="zzzzzaBcDeFgHzzzzzzzzzzzzzz"; text[7][6]="zzzzzzaBcDeFgHzzzzzzzzzzzzz"; text[7][7]="zzzzzzzaBcDeFgHzzzzzzzzzzzz"; text[7][8]="zzzzzzzzaBcDeFgHzzzzzzzzzzz"; text[7][9]="zzzzzzzzzaBcDeFgHzzzzzzzzzz"; text[7][10]="zzzzzzzzzzaBcDeFgHzzzzzzzzz"; text[7][11]="zzzzzzzzzzzaBcDeFgHzzzzzzzz"; text[7][12]="zzzzzzzzzzzzaBcDeFgHzzzzzzz"; text[7][13]="zzzzzzzzzzzzzaBcDeFgHzzzzzz"; text[7][14]="zzzzzzzzzzzzzzaBcDeFgHzzzzz"; text[7][15]="zzzzzzzzzzzzzzzaBcDeFgHzzzz"; text[7][16]="zzzzzzzzzzzzzzzzaBcDeFgHzzz"; text[7][17]="zzzzzzzzzzzzzzzzzaBcDeFgHzz"; text[7][18]="zzzzzzzzzzzzzzzzzzaBcDeFgHz"; text[7][19]="zzzzzzzzzzzzzzzzzzzaBcDeFgH"; text[8][0]="aBcDeFgHizzzzzzzzzzzzzzzzzz"; text[8][1]="zaBcDeFgHizzzzzzzzzzzzzzzzz"; text[8][2]="zzaBcDeFgHizzzzzzzzzzzzzzzz"; text[8][3]="zzzaBcDeFgHizzzzzzzzzzzzzzz"; text[8][4]="zzzzaBcDeFgHizzzzzzzzzzzzzz"; text[8][5]="zzzzzaBcDeFgHizzzzzzzzzzzzz"; text[8][6]="zzzzzzaBcDeFgHizzzzzzzzzzzz"; text[8][7]="zzzzzzzaBcDeFgHizzzzzzzzzzz"; text[8][8]="zzzzzzzzaBcDeFgHizzzzzzzzzz"; text[8][9]="zzzzzzzzzaBcDeFgHizzzzzzzzz"; text[8][10]="zzzzzzzzzzaBcDeFgHizzzzzzzz"; text[8][11]="zzzzzzzzzzzaBcDeFgHizzzzzzz"; text[8][12]="zzzzzzzzzzzzaBcDeFgHizzzzzz"; text[8][13]="zzzzzzzzzzzzzaBcDeFgHizzzzz"; text[8][14]="zzzzzzzzzzzzzzaBcDeFgHizzzz"; text[8][15]="zzzzzzzzzzzzzzzaBcDeFgHizzz"; text[8][16]="zzzzzzzzzzzzzzzzaBcDeFgHizz"; text[8][17]="zzzzzzzzzzzzzzzzzaBcDeFgHiz"; text[8][18]="zzzzzzzzzzzzzzzzzzaBcDeFgHi"; text[9][0]="aBcDeFgHiJzzzzzzzzzzzzzzzzz"; text[9][1]="zaBcDeFgHiJzzzzzzzzzzzzzzzz"; text[9][2]="zzaBcDeFgHiJzzzzzzzzzzzzzzz"; text[9][3]="zzzaBcDeFgHiJzzzzzzzzzzzzzz"; text[9][4]="zzzzaBcDeFgHiJzzzzzzzzzzzzz"; text[9][5]="zzzzzaBcDeFgHiJzzzzzzzzzzzz"; text[9][6]="zzzzzzaBcDeFgHiJzzzzzzzzzzz"; text[9][7]="zzzzzzzaBcDeFgHiJzzzzzzzzzz"; text[9][8]="zzzzzzzzaBcDeFgHiJzzzzzzzzz"; text[9][9]="zzzzzzzzzaBcDeFgHiJzzzzzzzz"; text[9][10]="zzzzzzzzzzaBcDeFgHiJzzzzzzz"; text[9][11]="zzzzzzzzzzzaBcDeFgHiJzzzzzz"; text[9][12]="zzzzzzzzzzzzaBcDeFgHiJzzzzz"; text[9][13]="zzzzzzzzzzzzzaBcDeFgHiJzzzz"; text[9][14]="zzzzzzzzzzzzzzaBcDeFgHiJzzz"; text[9][15]="zzzzzzzzzzzzzzzaBcDeFgHiJzz"; text[9][16]="zzzzzzzzzzzzzzzzaBcDeFgHiJz"; text[9][17]="zzzzzzzzzzzzzzzzzaBcDeFgHiJ"; text[10][0]="aBcDeFgHiJkzzzzzzzzzzzzzzzz"; text[10][1]="zaBcDeFgHiJkzzzzzzzzzzzzzzz"; text[10][2]="zzaBcDeFgHiJkzzzzzzzzzzzzzz"; text[10][3]="zzzaBcDeFgHiJkzzzzzzzzzzzzz"; text[10][4]="zzzzaBcDeFgHiJkzzzzzzzzzzzz"; text[10][5]="zzzzzaBcDeFgHiJkzzzzzzzzzzz"; text[10][6]="zzzzzzaBcDeFgHiJkzzzzzzzzzz"; text[10][7]="zzzzzzzaBcDeFgHiJkzzzzzzzzz"; text[10][8]="zzzzzzzzaBcDeFgHiJkzzzzzzzz"; text[10][9]="zzzzzzzzzaBcDeFgHiJkzzzzzzz"; text[10][10]="zzzzzzzzzzaBcDeFgHiJkzzzzzz"; text[10][11]="zzzzzzzzzzzaBcDeFgHiJkzzzzz"; text[10][12]="zzzzzzzzzzzzaBcDeFgHiJkzzzz"; text[10][13]="zzzzzzzzzzzzzaBcDeFgHiJkzzz"; text[10][14]="zzzzzzzzzzzzzzaBcDeFgHiJkzz"; text[10][15]="zzzzzzzzzzzzzzzaBcDeFgHiJkz"; text[10][16]="zzzzzzzzzzzzzzzzaBcDeFgHiJk"; text[11][0]="aBcDeFgHiJkLzzzzzzzzzzzzzzz"; text[11][1]="zaBcDeFgHiJkLzzzzzzzzzzzzzz"; text[11][2]="zzaBcDeFgHiJkLzzzzzzzzzzzzz"; text[11][3]="zzzaBcDeFgHiJkLzzzzzzzzzzzz"; text[11][4]="zzzzaBcDeFgHiJkLzzzzzzzzzzz"; text[11][5]="zzzzzaBcDeFgHiJkLzzzzzzzzzz"; text[11][6]="zzzzzzaBcDeFgHiJkLzzzzzzzzz"; text[11][7]="zzzzzzzaBcDeFgHiJkLzzzzzzzz"; text[11][8]="zzzzzzzzaBcDeFgHiJkLzzzzzzz"; text[11][9]="zzzzzzzzzaBcDeFgHiJkLzzzzzz"; text[11][10]="zzzzzzzzzzaBcDeFgHiJkLzzzzz"; text[11][11]="zzzzzzzzzzzaBcDeFgHiJkLzzzz"; text[11][12]="zzzzzzzzzzzzaBcDeFgHiJkLzzz"; text[11][13]="zzzzzzzzzzzzzaBcDeFgHiJkLzz"; text[11][14]="zzzzzzzzzzzzzzaBcDeFgHiJkLz"; text[11][15]="zzzzzzzzzzzzzzzaBcDeFgHiJkL"; text[12][0]="aBcDeFgHiJkLmzzzzzzzzzzzzzz"; text[12][1]="zaBcDeFgHiJkLmzzzzzzzzzzzzz"; text[12][2]="zzaBcDeFgHiJkLmzzzzzzzzzzzz"; text[12][3]="zzzaBcDeFgHiJkLmzzzzzzzzzzz"; text[12][4]="zzzzaBcDeFgHiJkLmzzzzzzzzzz"; text[12][5]="zzzzzaBcDeFgHiJkLmzzzzzzzzz"; text[12][6]="zzzzzzaBcDeFgHiJkLmzzzzzzzz"; text[12][7]="zzzzzzzaBcDeFgHiJkLmzzzzzzz"; text[12][8]="zzzzzzzzaBcDeFgHiJkLmzzzzzz"; text[12][9]="zzzzzzzzzaBcDeFgHiJkLmzzzzz"; text[12][10]="zzzzzzzzzzaBcDeFgHiJkLmzzzz"; text[12][11]="zzzzzzzzzzzaBcDeFgHiJkLmzzz"; text[12][12]="zzzzzzzzzzzzaBcDeFgHiJkLmzz"; text[12][13]="zzzzzzzzzzzzzaBcDeFgHiJkLmz"; text[12][14]="zzzzzzzzzzzzzzaBcDeFgHiJkLm"; text[13][0]="aBcDeFgHiJkLmNzzzzzzzzzzzzz"; text[13][1]="zaBcDeFgHiJkLmNzzzzzzzzzzzz"; text[13][2]="zzaBcDeFgHiJkLmNzzzzzzzzzzz"; text[13][3]="zzzaBcDeFgHiJkLmNzzzzzzzzzz"; text[13][4]="zzzzaBcDeFgHiJkLmNzzzzzzzzz"; text[13][5]="zzzzzaBcDeFgHiJkLmNzzzzzzzz"; text[13][6]="zzzzzzaBcDeFgHiJkLmNzzzzzzz"; text[13][7]="zzzzzzzaBcDeFgHiJkLmNzzzzzz"; text[13][8]="zzzzzzzzaBcDeFgHiJkLmNzzzzz"; text[13][9]="zzzzzzzzzaBcDeFgHiJkLmNzzzz"; text[13][10]="zzzzzzzzzzaBcDeFgHiJkLmNzzz"; text[13][11]="zzzzzzzzzzzaBcDeFgHiJkLmNzz"; text[13][12]="zzzzzzzzzzzzaBcDeFgHiJkLmNz"; text[13][13]="zzzzzzzzzzzzzaBcDeFgHiJkLmN"; text[14][0]="aBcDeFgHiJkLmNozzzzzzzzzzzz"; text[14][1]="zaBcDeFgHiJkLmNozzzzzzzzzzz"; text[14][2]="zzaBcDeFgHiJkLmNozzzzzzzzzz"; text[14][3]="zzzaBcDeFgHiJkLmNozzzzzzzzz"; text[14][4]="zzzzaBcDeFgHiJkLmNozzzzzzzz"; text[14][5]="zzzzzaBcDeFgHiJkLmNozzzzzzz"; text[14][6]="zzzzzzaBcDeFgHiJkLmNozzzzzz"; text[14][7]="zzzzzzzaBcDeFgHiJkLmNozzzzz"; text[14][8]="zzzzzzzzaBcDeFgHiJkLmNozzzz"; text[14][9]="zzzzzzzzzaBcDeFgHiJkLmNozzz"; text[14][10]="zzzzzzzzzzaBcDeFgHiJkLmNozz"; text[14][11]="zzzzzzzzzzzaBcDeFgHiJkLmNoz"; text[14][12]="zzzzzzzzzzzzaBcDeFgHiJkLmNo"; text[15][0]="aBcDeFgHiJkLmNoPzzzzzzzzzzz"; text[15][1]="zaBcDeFgHiJkLmNoPzzzzzzzzzz"; text[15][2]="zzaBcDeFgHiJkLmNoPzzzzzzzzz"; text[15][3]="zzzaBcDeFgHiJkLmNoPzzzzzzzz"; text[15][4]="zzzzaBcDeFgHiJkLmNoPzzzzzzz"; text[15][5]="zzzzzaBcDeFgHiJkLmNoPzzzzzz"; text[15][6]="zzzzzzaBcDeFgHiJkLmNoPzzzzz"; text[15][7]="zzzzzzzaBcDeFgHiJkLmNoPzzzz"; text[15][8]="zzzzzzzzaBcDeFgHiJkLmNoPzzz"; text[15][9]="zzzzzzzzzaBcDeFgHiJkLmNoPzz"; text[15][10]="zzzzzzzzzzaBcDeFgHiJkLmNoPz"; text[15][11]="zzzzzzzzzzzaBcDeFgHiJkLmNoP"; text[16][0]="aBcDeFgHiJkLmNoPqzzzzzzzzzz"; text[16][1]="zaBcDeFgHiJkLmNoPqzzzzzzzzz"; text[16][2]="zzaBcDeFgHiJkLmNoPqzzzzzzzz"; text[16][3]="zzzaBcDeFgHiJkLmNoPqzzzzzzz"; text[16][4]="zzzzaBcDeFgHiJkLmNoPqzzzzzz"; text[16][5]="zzzzzaBcDeFgHiJkLmNoPqzzzzz"; text[16][6]="zzzzzzaBcDeFgHiJkLmNoPqzzzz"; text[16][7]="zzzzzzzaBcDeFgHiJkLmNoPqzzz"; text[16][8]="zzzzzzzzaBcDeFgHiJkLmNoPqzz"; text[16][9]="zzzzzzzzzaBcDeFgHiJkLmNoPqz"; text[16][10]="zzzzzzzzzzaBcDeFgHiJkLmNoPq"; text[17][0]="aBcDeFgHiJkLmNoPqRzzzzzzzzz"; text[17][1]="zaBcDeFgHiJkLmNoPqRzzzzzzzz"; text[17][2]="zzaBcDeFgHiJkLmNoPqRzzzzzzz"; text[17][3]="zzzaBcDeFgHiJkLmNoPqRzzzzzz"; text[17][4]="zzzzaBcDeFgHiJkLmNoPqRzzzzz"; text[17][5]="zzzzzaBcDeFgHiJkLmNoPqRzzzz"; text[17][6]="zzzzzzaBcDeFgHiJkLmNoPqRzzz"; text[17][7]="zzzzzzzaBcDeFgHiJkLmNoPqRzz"; text[17][8]="zzzzzzzzaBcDeFgHiJkLmNoPqRz"; text[17][9]="zzzzzzzzzaBcDeFgHiJkLmNoPqR"; text[18][0]="aBcDeFgHiJkLmNoPqRszzzzzzzz"; text[18][1]="zaBcDeFgHiJkLmNoPqRszzzzzzz"; text[18][2]="zzaBcDeFgHiJkLmNoPqRszzzzzz"; text[18][3]="zzzaBcDeFgHiJkLmNoPqRszzzzz"; text[18][4]="zzzzaBcDeFgHiJkLmNoPqRszzzz"; text[18][5]="zzzzzaBcDeFgHiJkLmNoPqRszzz"; text[18][6]="zzzzzzaBcDeFgHiJkLmNoPqRszz"; text[18][7]="zzzzzzzaBcDeFgHiJkLmNoPqRsz"; text[18][8]="zzzzzzzzaBcDeFgHiJkLmNoPqRs"; text[19][0]="aBcDeFgHiJkLmNoPqRsTzzzzzzz"; text[19][1]="zaBcDeFgHiJkLmNoPqRsTzzzzzz"; text[19][2]="zzaBcDeFgHiJkLmNoPqRsTzzzzz"; text[19][3]="zzzaBcDeFgHiJkLmNoPqRsTzzzz"; text[19][4]="zzzzaBcDeFgHiJkLmNoPqRsTzzz"; text[19][5]="zzzzzaBcDeFgHiJkLmNoPqRsTzz"; text[19][6]="zzzzzzaBcDeFgHiJkLmNoPqRsTz"; text[19][7]="zzzzzzzaBcDeFgHiJkLmNoPqRsT"; text[20][0]="aBcDeFgHiJkLmNoPqRsTuzzzzzz"; text[20][1]="zaBcDeFgHiJkLmNoPqRsTuzzzzz"; text[20][2]="zzaBcDeFgHiJkLmNoPqRsTuzzzz"; text[20][3]="zzzaBcDeFgHiJkLmNoPqRsTuzzz"; text[20][4]="zzzzaBcDeFgHiJkLmNoPqRsTuzz"; text[20][5]="zzzzzaBcDeFgHiJkLmNoPqRsTuz"; text[20][6]="zzzzzzaBcDeFgHiJkLmNoPqRsTu"; text[21][0]="aBcDeFgHiJkLmNoPqRsTuVzzzzz"; text[21][1]="zaBcDeFgHiJkLmNoPqRsTuVzzzz"; text[21][2]="zzaBcDeFgHiJkLmNoPqRsTuVzzz"; text[21][3]="zzzaBcDeFgHiJkLmNoPqRsTuVzz"; text[21][4]="zzzzaBcDeFgHiJkLmNoPqRsTuVz"; text[21][5]="zzzzzaBcDeFgHiJkLmNoPqRsTuV"; text[22][0]="aBcDeFgHiJkLmNoPqRsTuVwzzzz"; text[22][1]="zaBcDeFgHiJkLmNoPqRsTuVwzzz"; text[22][2]="zzaBcDeFgHiJkLmNoPqRsTuVwzz"; text[22][3]="zzzaBcDeFgHiJkLmNoPqRsTuVwz"; text[22][4]="zzzzaBcDeFgHiJkLmNoPqRsTuVw"; text[23][0]="aBcDeFgHiJkLmNoPqRsTuVwXzzz"; text[23][1]="zaBcDeFgHiJkLmNoPqRsTuVwXzz"; text[23][2]="zzaBcDeFgHiJkLmNoPqRsTuVwXz"; text[23][3]="zzzaBcDeFgHiJkLmNoPqRsTuVwX"; text[24][0]="aBcDeFgHiJkLmNoPqRsTuVwXyzz"; text[24][1]="zaBcDeFgHiJkLmNoPqRsTuVwXyz"; text[24][2]="zzaBcDeFgHiJkLmNoPqRsTuVwXy"; text[25][0]="aBcDeFgHiJkLmNoPqRsTuVwXyZz"; text[25][1]="zaBcDeFgHiJkLmNoPqRsTuVwXyZ"; char *needle[26]; needle[0]="A"; needle[1]="Ab"; needle[2]="AbC"; needle[3]="AbCd"; needle[4]="AbCdE"; needle[5]="AbCdEf"; needle[6]="AbCdEfG"; needle[7]="AbCdEfGh"; needle[8]="AbCdEfGhI"; needle[9]="AbCdEfGhIJ"; needle[10]="AbCdEfGhIjK"; needle[11]="AbCdEfGhIjKl"; needle[12]="AbCdEfGhIjKlM"; needle[13]="AbCdEfGhIjKlMn"; needle[14]="AbCdEfGhIjKlMnO"; needle[15]="AbCdEfGhIjKlMnOp"; needle[16]="AbCdEfGhIjKlMnOpQ"; needle[17]="AbCdEfGhIjKlMnOpQr"; needle[18]="AbCdEfGhIjKlMnOpQrS"; needle[19]="AbCdEfGhIjKlMnOpQrSt"; needle[20]="AbCdEfGhIjKlMnOpQrStU"; needle[21]="AbCdEfGhIjKlMnOpQrStUv"; needle[22]="AbCdEfGhIjKlMnOpQrStUvW"; needle[23]="AbCdEfGhIjKlMnOpQrStUvWx"; needle[24]="AbCdEfGhIjKlMnOpQrStUvWxY"; needle[25]="AbCdEfGhIjKlMnOpQrStUvWxYZ"; int i, j; uint8_t *found = NULL; for (i = 0; i < 26; i++) { for (j = 0; j <= (26-i); j++) { found = BasicSearchNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i][j]); return 0; } found = Bs2bmNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i][j]); return 0; } found = BoyerMooreNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i][j]); return 0; } } } return 1; } /** * \test Give some stats */ int UtilSpmSearchStatsTest01() { char *text[16]; text[0]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; text[1]="aaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaraaaaazaaaaaaazaaaaaaaaaaaaaazaaaaaaaazaaaaaaaaazaaaaaaaaaaaaB"; text[2]="aBaBaBaBaBaBaBaBazaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBzBaBaBaBaBaBaBzBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBazaBaBaBaBaBc"; text[3]="aBcaBcaBcaBcaBczBcaBcaBzaBcaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBzaBcaBcaBcazcaBcaBcaBcaBcaBcD"; text[4]="aBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDzBcDaBcDaBczaBcDaBcDaBczaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBzDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDazcDaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDaBcDaBcDe"; text[5]="aBcDeaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDzaBcDeaBcDezBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDezBcDeaBcDezBcDeaBczeaBcDeaBcDeaBzDeaBcDezBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeF"; text[6]="aBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBczzaBcDeaBcDeaBcDzazcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBczeaBcDezzzaBcDeFg"; text[7]="aBcDeaBczeaBcDzaBcDezBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBzDzaBcDeaBcDeazcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDzaBcDeaBcDeaBcDezBcDzaBcDeaBzDeaBcDeaBcDezBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBrDeaBcDeaBcDezzzaBcDeFgH"; text[8]="aBcDeaBcDeaBczzaBcDeazcDeaBcDezBcDeaBcDzaBcDeaBcDeaBcDeaBczzaBcDeaBcDeaBczeaBcDeaBcDzzBcDeaBcDeaBcDzaBczeaBcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBczeaBcDeaBzDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHi"; text[9]="aBcDeaBcDzaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeazcDeaBcDeaBcDzzBcDeaBcDeaBczeaBcDzaBcDezBcDeaBczeaBcDzaBcDezBcDeaBcDzaBczeaBcDeaBcDzaBcDeazcDeaBcDeaBcDzaBczeaBcDeaBcDzaBzDeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJ"; text[10]="aBcDeaBcDeaBczeaBcDzaBczeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDeaBzDzaBcDeazcDeaBcDeazcDeaBcDzaBcDeazcDeaBcDeaBczzaBcDeaBcDeaBzDeaBcDeaBcDzaBczeaBcDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDeaBzDeaBcDeaBcDezzzaBcDeFgHiJk"; text[11]="aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDeazcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzzBcDeaBcDeaBcDeaBcDzaBcDzaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBzDeaBcDeaBczeaBcDeazcDeaBcDezBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkL"; text[12]="aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDeazcDeaBcDeaBczeaBcDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLm"; text[13]="aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmN"; text[14]="aBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDezzzaBcDeFgHiJkLmNo"; text[15]="aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of greater length (text with a lot of partial matches, worst case for a basic search):\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch:", i+1); found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch:", i+1); found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch:", i+1); found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } /** * \test Give some stats for */ int UtilSpmSearchStatsTest02() { char *text[16]; text[0]="zzzzzzzzzzzzzzzzzza"; text[1]="zzzzzzzzzzzzzzzzzzaB"; text[2]="zzzzzzzzzzzzzzzzzzaBc"; text[3]="zzzzzzzzzzzzzzzzzzaBcD"; text[4]="zzzzzzzzzzzzzzzzzzaBcDe"; text[5]="zzzzzzzzzzzzzzzzzzzzaBcDeF"; text[6]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; text[7]="zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; text[8]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; text[9]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; text[10]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; text[11]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; text[12]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; text[13]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; text[14]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; text[15]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of lower length:\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch:", i+1); found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch:", i+1); found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch:", i+1); found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } int UtilSpmSearchStatsTest03() { char *text[16]; text[0]="zzzzzza"; text[1]="zzzzzzaB"; text[2]="zzzzzzaBc"; text[3]="zzzzzzaBcD"; text[4]="zzzzzzaBcDe"; text[5]="zzzzzzzzaBcDeF"; text[6]="zzzzzzzzaBcDeFg"; text[7]="zzzzzzzzaBcDeFgH"; text[8]="zzzzzzzzaBcDeFgHi"; text[9]="zzzzzzzzaBcDeFgHiJ"; text[10]="zzzzzzzzaBcDeFgHiJk"; text[11]="zzzzzzzzaBcDeFgHiJkL"; text[12]="zzzzzzzzaBcDeFgHiJkLm"; text[13]="zzzzzzzzaBcDeFgHiJkLmN"; text[14]="zzzzzzzzaBcDeFgHiJkLmNo"; text[15]="zzzzzzzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of lower length (badcase for):\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch:", i+1); found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch:", i+1); found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch:", i+1); found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } /** * \test Give some stats */ int UtilSpmSearchStatsTest04() { char *text[16]; text[0]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; text[1]="aaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaraaaaazaaaaaaazaaaaaaaaaaaaaazaaaaaaaazaaaaaaaaazaaaaaaaaaaaaB"; text[2]="aBaBaBaBaBaBaBaBazaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBzBaBaBaBaBaBaBzBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBazaBaBaBaBaBc"; text[3]="aBcaBcaBcaBcaBczBcaBcaBzaBcaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBzaBcaBcaBcazcaBcaBcaBcaBcaBcD"; text[4]="aBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDzBcDaBcDaBczaBcDaBcDaBczaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBzDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDazcDaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDaBcDaBcDe"; text[5]="aBcDeaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDzaBcDeaBcDezBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDezBcDeaBcDezBcDeaBczeaBcDeaBcDeaBzDeaBcDezBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeF"; text[6]="aBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBczzaBcDeaBcDeaBcDzazcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBczeaBcDezzzaBcDeFg"; text[7]="aBcDeaBczeaBcDzaBcDezBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBzDzaBcDeaBcDeazcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDzaBcDeaBcDeaBcDezBcDzaBcDeaBzDeaBcDeaBcDezBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBrDeaBcDeaBcDezzzaBcDeFgH"; text[8]="aBcDeaBcDeaBczzaBcDeazcDeaBcDezBcDeaBcDzaBcDeaBcDeaBcDeaBczzaBcDeaBcDeaBczeaBcDeaBcDzzBcDeaBcDeaBcDzaBczeaBcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBczeaBcDeaBzDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHi"; text[9]="aBcDeaBcDzaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeazcDeaBcDeaBcDzzBcDeaBcDeaBczeaBcDzaBcDezBcDeaBczeaBcDzaBcDezBcDeaBcDzaBczeaBcDeaBcDzaBcDeazcDeaBcDeaBcDzaBczeaBcDeaBcDzaBzDeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJ"; text[10]="aBcDeaBcDeaBczeaBcDzaBczeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDeaBzDzaBcDeazcDeaBcDeazcDeaBcDzaBcDeazcDeaBcDeaBczzaBcDeaBcDeaBzDeaBcDeaBcDzaBczeaBcDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDeaBzDeaBcDeaBcDezzzaBcDeFgHiJk"; text[11]="aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDeazcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzzBcDeaBcDeaBcDeaBcDzaBcDzaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBzDeaBcDeaBczeaBcDeazcDeaBcDezBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkL"; text[12]="aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDeazcDeaBcDeaBczeaBcDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLm"; text[13]="aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmN"; text[14]="aBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDezzzaBcDeFgHiJkLmNo"; text[15]="aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of greater length:\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch (Building Context):", i + 1); found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with SpmSearch (Building Context):", i + 1); found = RawCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } /** * \test Give some stats for */ int UtilSpmSearchStatsTest05() { char *text[16]; text[0]="zzzzzzzzzzzzzzzzzza"; text[1]="zzzzzzzzzzzzzzzzzzaB"; text[2]="zzzzzzzzzzzzzzzzzzaBc"; text[3]="zzzzzzzzzzzzzzzzzzaBcD"; text[4]="zzzzzzzzzzzzzzzzzzaBcDe"; text[5]="zzzzzzzzzzzzzzzzzzzzaBcDeF"; text[6]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; text[7]="zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; text[8]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; text[9]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; text[10]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; text[11]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; text[12]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; text[13]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; text[14]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; text[15]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of lower length:\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch (Building Context):", i+1); found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } int UtilSpmSearchStatsTest06() { char *text[16]; text[0]="zzzzkzzzzzzzkzzzzzza"; text[1]="BBBBkBBBBBBBkBBBBBaB"; text[2]="BcBckcBcBcBckcBcBcaBc"; text[3]="BcDBkDBcDBcDkcDBcDaBcD"; text[4]="BcDekcDeBcDekcDezzaBcDe"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; int i; uint8_t *found = NULL; printf("\nStats for text of lower length (badcase for):\n"); for (i = 0; i < 5; i++) { printf("Pattern length %d with BasicSearch (Building Context):", i+1); found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } int UtilSpmSearchStatsTest07() { char *text[16]; text[0]="zzzza"; text[1]="BBBaB"; text[2]="bbaBc"; text[3]="aaBcD"; text[4]="aBcDe"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; int i; uint8_t *found = NULL; printf("\nStats for text of real lower length (badcase for):\n"); for (i = 0; i < 5; i++) { printf("Pattern length %d with BasicSearch (Building Context):", i+1); found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } /** * \test Give some stats for no case algorithms */ int UtilSpmNocaseSearchStatsTest01() { char *text[16]; text[0]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; text[1]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaB"; text[2]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBc"; text[3]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcD"; text[4]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDe"; text[5]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeF"; text[6]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFg"; text[7]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgH"; text[8]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; text[9]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; text[10]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; text[11]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; text[12]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; text[13]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; text[14]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; text[15]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of greater length:\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch:", i+1); found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch:", i+1); found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch:", i+1); found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } int UtilSpmNocaseSearchStatsTest02() { char *text[16]; text[0]="zzzzzzzzzzzzzzzzzza"; text[1]="zzzzzzzzzzzzzzzzzzaB"; text[2]="zzzzzzzzzzzzzzzzzzaBc"; text[3]="zzzzzzzzzzzzzzzzzzaBcD"; text[4]="zzzzzzzzzzzzzzzzzzaBcDe"; text[5]="zzzzzzzzzzzzzzzzzzzzaBcDeF"; text[6]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; text[7]="zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; text[8]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; text[9]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; text[10]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; text[11]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; text[12]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; text[13]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; text[14]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; text[15]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of lower length:\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch:", i+1); found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch:", i+1); found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch:", i+1); found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } int UtilSpmNocaseSearchStatsTest03() { char *text[16]; text[0]="zzzzkzzzzzzzkzzzzzza"; text[1]="BBBBkBBBBBBBkBBBBBaB"; text[2]="BcBckcBcBcBckcBcBcaBc"; text[3]="BcDBkDBcDBcDkcDBcDaBcD"; text[4]="BcDekcDeBcDekcDezzaBcDe"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; int i; uint8_t *found = NULL; printf("\nStats for text of lower length (badcase for):\n"); for (i = 0; i < 5; i++) { printf("Pattern length %d with BasicSearch:", i+1); found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch:", i+1); found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch:", i+1); found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } /** * \test Give some stats for no case algorithms */ int UtilSpmNocaseSearchStatsTest04() { char *text[16]; text[0]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; text[1]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaB"; text[2]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBc"; text[3]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcD"; text[4]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDe"; text[5]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeF"; text[6]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFg"; text[7]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgH"; text[8]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; text[9]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; text[10]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; text[11]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; text[12]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; text[13]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; text[14]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; text[15]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of greater length:\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch (Building Context):", i+1); found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } int UtilSpmNocaseSearchStatsTest05() { char *text[16]; text[0]="zzzzzzzzzzzzzzzzzza"; text[1]="zzzzzzzzzzzzzzzzzzaB"; text[2]="zzzzzzzzzzzzzzzzzzaBc"; text[3]="zzzzzzzzzzzzzzzzzzaBcD"; text[4]="zzzzzzzzzzzzzzzzzzaBcDe"; text[5]="zzzzzzzzzzzzzzzzzzzzaBcDeF"; text[6]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; text[7]="zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; text[8]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; text[9]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; text[10]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; text[11]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; text[12]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; text[13]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; text[14]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; text[15]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; needle[5]="aBcDeF"; needle[6]="aBcDeFg"; needle[7]="aBcDeFgH"; needle[8]="aBcDeFgHi"; needle[9]="aBcDeFgHiJ"; needle[10]="aBcDeFgHiJk"; needle[11]="aBcDeFgHiJkL"; needle[12]="aBcDeFgHiJkLm"; needle[13]="aBcDeFgHiJkLmN"; needle[14]="aBcDeFgHiJkLmNo"; needle[15]="aBcDeFgHiJkLmNoP"; int i; uint8_t *found = NULL; printf("\nStats for text of lower length:\n"); for (i = 0; i < 16; i++) { printf("Pattern length %d with BasicSearch (Building Context):", i+1); found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } int UtilSpmNocaseSearchStatsTest06() { char *text[16]; text[0]="zzzzkzzzzzzzkzzzzzza"; text[1]="BBBBkBBBBBBBkBBBBBaB"; text[2]="BcBckcBcBcBckcBcBcaBc"; text[3]="BcDBkDBcDBcDkcDBcDaBcD"; text[4]="BcDekcDeBcDekcDezzaBcDe"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; int i; uint8_t *found = NULL; printf("\nStats for text of lower length (badcase for):\n"); for (i = 0; i < 5; i++) { printf("Pattern length %d with BasicSearch (Building Context):", i+1); found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } int UtilSpmNocaseSearchStatsTest07() { char *text[16]; text[0]="zzzza"; text[1]="bbbAb"; text[2]="bbAbC"; text[3]="bAbCd"; text[4]="AbCdE"; char *needle[16]; needle[0]="a"; needle[1]="aB"; needle[2]="aBc"; needle[3]="aBcD"; needle[4]="aBcDe"; int i; uint8_t *found = NULL; printf("\nStats for text of real lower length (badcase for):\n"); for (i = 0; i < 5; i++) { printf("Pattern length %d with BasicSearch (Building Context):", i+1); found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error1 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error2 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); if (found == 0) { printf("Error3 searching for %s in text %s\n", needle[i], text[i]); return 0; } printf("\n"); } return 1; } #endif /* Register unittests */ void UtilSpmSearchRegistertests(void) { #ifdef UNITTESTS /* Generic tests */ UtRegisterTest("UtilSpmBasicSearchTest01", UtilSpmBasicSearchTest01, 1); UtRegisterTest("UtilSpmBasicSearchNocaseTest01", UtilSpmBasicSearchNocaseTest01, 1); UtRegisterTest("UtilSpmBs2bmSearchTest01", UtilSpmBs2bmSearchTest01, 1); UtRegisterTest("UtilSpmBs2bmSearchNocaseTest01", UtilSpmBs2bmSearchNocaseTest01, 1); UtRegisterTest("UtilSpmBoyerMooreSearchTest01", UtilSpmBoyerMooreSearchTest01, 1); UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest01", UtilSpmBoyerMooreSearchNocaseTest01, 1); UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTestIssue130", UtilSpmBoyerMooreSearchNocaseTestIssue130, 1); UtRegisterTest("UtilSpmBs2bmSearchTest02", UtilSpmBs2bmSearchTest02, 1); UtRegisterTest("UtilSpmBs2bmSearchNocaseTest02", UtilSpmBs2bmSearchNocaseTest02, 1); UtRegisterTest("UtilSpmBasicSearchTest02", UtilSpmBasicSearchTest02, 1); UtRegisterTest("UtilSpmBasicSearchNocaseTest02", UtilSpmBasicSearchNocaseTest02, 1); UtRegisterTest("UtilSpmBoyerMooreSearchTest02", UtilSpmBoyerMooreSearchTest02, 1); UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest02", UtilSpmBoyerMooreSearchNocaseTest02, 1); /* test matches at any offset */ UtRegisterTest("UtilSpmSearchOffsetsTest01", UtilSpmSearchOffsetsTest01, 1); UtRegisterTest("UtilSpmSearchOffsetsNocaseTest01", UtilSpmSearchOffsetsNocaseTest01, 1); #ifdef ENABLE_SEARCH_STATS /* Give some stats searching given a prepared context (look at the wrappers) */ UtRegisterTest("UtilSpmSearchStatsTest01", UtilSpmSearchStatsTest01, 1); UtRegisterTest("UtilSpmSearchStatsTest02", UtilSpmSearchStatsTest02, 1); UtRegisterTest("UtilSpmSearchStatsTest03", UtilSpmSearchStatsTest03, 1); UtRegisterTest("UtilSpmNocaseSearchStatsTest01", UtilSpmNocaseSearchStatsTest01, 1); UtRegisterTest("UtilSpmNocaseSearchStatsTest02", UtilSpmNocaseSearchStatsTest02, 1); UtRegisterTest("UtilSpmNocaseSearchStatsTest03", UtilSpmNocaseSearchStatsTest03, 1); /* Stats building context and searching */ UtRegisterTest("UtilSpmSearchStatsTest04", UtilSpmSearchStatsTest04, 1); UtRegisterTest("UtilSpmSearchStatsTest05", UtilSpmSearchStatsTest05, 1); UtRegisterTest("UtilSpmSearchStatsTest06", UtilSpmSearchStatsTest06, 1); UtRegisterTest("UtilSpmSearchStatsTest07", UtilSpmSearchStatsTest07, 1); UtRegisterTest("UtilSpmNocaseSearchStatsTest04", UtilSpmNocaseSearchStatsTest04, 1); UtRegisterTest("UtilSpmNocaseSearchStatsTest05", UtilSpmNocaseSearchStatsTest05, 1); UtRegisterTest("UtilSpmNocaseSearchStatsTest06", UtilSpmNocaseSearchStatsTest06, 1); UtRegisterTest("UtilSpmNocaseSearchStatsTest07", UtilSpmNocaseSearchStatsTest07, 1); #endif #endif } suricata-1.4.7/src/flow-hash.c0000644000000000000000000004770612253546156013077 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon Crespo * * Flow Hashing functions. */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-hash.h" #include "flow-util.h" #include "flow-private.h" #include "flow-manager.h" #include "app-layer-parser.h" #include "util-time.h" #include "util-debug.h" #include "util-hash-lookup3.h" #define FLOW_DEFAULT_FLOW_PRUNE 5 SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx); SC_ATOMIC_EXTERN(unsigned char, flow_flags); static Flow *FlowGetUsedFlow(void); #ifdef FLOW_DEBUG_STATS #define FLOW_DEBUG_STATS_PROTO_ALL 0 #define FLOW_DEBUG_STATS_PROTO_TCP 1 #define FLOW_DEBUG_STATS_PROTO_UDP 2 #define FLOW_DEBUG_STATS_PROTO_ICMP 3 #define FLOW_DEBUG_STATS_PROTO_OTHER 4 static uint64_t flow_hash_count[5] = { 0, 0, 0, 0, 0 }; /* how often are we looking for a hash */ static uint64_t flow_hash_loop_count[5] = { 0, 0, 0, 0, 0 }; /* how often do we loop through a hash bucket */ static FILE *flow_hash_count_fp = NULL; static SCSpinlock flow_hash_count_lock; #define FlowHashCountUpdate do { \ SCSpinLock(&flow_hash_count_lock); \ flow_hash_count[FLOW_DEBUG_STATS_PROTO_ALL]++; \ flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL] += _flow_hash_counter; \ if (f != NULL) { \ if (p->proto == IPPROTO_TCP) { \ flow_hash_count[FLOW_DEBUG_STATS_PROTO_TCP]++; \ flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP] += _flow_hash_counter; \ } else if (p->proto == IPPROTO_UDP) {\ flow_hash_count[FLOW_DEBUG_STATS_PROTO_UDP]++; \ flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP] += _flow_hash_counter; \ } else if (p->proto == IPPROTO_ICMP) {\ flow_hash_count[FLOW_DEBUG_STATS_PROTO_ICMP]++; \ flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP] += _flow_hash_counter; \ } else {\ flow_hash_count[FLOW_DEBUG_STATS_PROTO_OTHER]++; \ flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER] += _flow_hash_counter; \ } \ } \ SCSpinUnlock(&flow_hash_count_lock); \ } while(0); #define FlowHashCountInit uint64_t _flow_hash_counter = 0 #define FlowHashCountIncr _flow_hash_counter++; void FlowHashDebugInit(void) { #ifdef FLOW_DEBUG_STATS SCSpinInit(&flow_hash_count_lock, 0); #endif flow_hash_count_fp = fopen("flow-debug.log", "w+"); if (flow_hash_count_fp != NULL) { fprintf(flow_hash_count_fp, "ts,all,tcp,udp,icmp,other\n"); } } void FlowHashDebugPrint(uint32_t ts) { #ifdef FLOW_DEBUG_STATS if (flow_hash_count_fp == NULL) return; float avg_all = 0, avg_tcp = 0, avg_udp = 0, avg_icmp = 0, avg_other = 0; SCSpinLock(&flow_hash_count_lock); if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL] != 0) avg_all = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_ALL])); if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP] != 0) avg_tcp = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_TCP])); if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP] != 0) avg_udp = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_UDP])); if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP] != 0) avg_icmp= (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_ICMP])); if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER] != 0) avg_other= (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_OTHER])); fprintf(flow_hash_count_fp, "%"PRIu32",%02.3f,%02.3f,%02.3f,%02.3f,%02.3f\n", ts, avg_all, avg_tcp, avg_udp, avg_icmp, avg_other); fflush(flow_hash_count_fp); memset(&flow_hash_count, 0, sizeof(flow_hash_count)); memset(&flow_hash_loop_count, 0, sizeof(flow_hash_loop_count)); SCSpinUnlock(&flow_hash_count_lock); #endif } void FlowHashDebugDeinit(void) { #ifdef FLOW_DEBUG_STATS struct timeval ts; memset(&ts, 0, sizeof(ts)); TimeGet(&ts); FlowHashDebugPrint((uint32_t)ts.tv_sec); if (flow_hash_count_fp != NULL) fclose(flow_hash_count_fp); SCSpinDestroy(&flow_hash_count_lock); #endif } #else #define FlowHashCountUpdate #define FlowHashCountInit #define FlowHashCountIncr #endif /* FLOW_DEBUG_STATS */ /** \brief compare two raw ipv6 addrs * * \note we don't care about the real ipv6 ip's, this is just * to consistently fill the FlowHashKey6 struct, without all * the ntohl calls. * * \warning do not use elsewhere unless you know what you're doing. * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely * what you are looking for. */ static inline int FlowHashRawAddressIPv6GtU32(uint32_t *a, uint32_t *b) { int i; for (i = 0; i < 4; i++) { if (a[i] > b[i]) return 1; if (a[i] < b[i]) break; } return 0; } typedef struct FlowHashKey4_ { union { struct { uint32_t src, dst; uint16_t sp, dp; uint16_t proto; /**< u16 so proto and recur add up to u32 */ uint16_t recur; /**< u16 so proto and recur add up to u32 */ }; uint32_t u32[4]; }; } FlowHashKey4; typedef struct FlowHashKey6_ { union { struct { uint32_t src[4], dst[4]; uint16_t sp, dp; uint16_t proto; /**< u16 so proto and recur add up to u32 */ uint16_t recur; /**< u16 so proto and recur add up to u32 */ }; uint32_t u32[10]; }; } FlowHashKey6; /* calculate the hash key for this packet * * we're using: * hash_rand -- set at init time * source port * destination port * source address * destination address * recursion level -- for tunnels, make sure different tunnel layers can * never get mixed up. * * For ICMP we only consider UNREACHABLE errors atm. */ static inline uint32_t FlowGetKey(Packet *p) { uint32_t key; if (p->ip4h != NULL) { if (p->tcph != NULL || p->udph != NULL) { FlowHashKey4 fhk; if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { fhk.src = p->src.addr_data32[0]; fhk.dst = p->dst.addr_data32[0]; } else { fhk.src = p->dst.addr_data32[0]; fhk.dst = p->src.addr_data32[0]; } if (p->sp > p->dp) { fhk.sp = p->sp; fhk.dp = p->dp; } else { fhk.sp = p->dp; fhk.dp = p->sp; } fhk.proto = (uint16_t)p->proto; fhk.recur = (uint16_t)p->recursion_level; uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand); key = hash % flow_config.hash_size; } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)); uint32_t pdst = IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)); FlowHashKey4 fhk; if (psrc > pdst) { fhk.src = psrc; fhk.dst = pdst; } else { fhk.src = pdst; fhk.dst = psrc; } if (p->icmpv4vars.emb_sport > p->icmpv4vars.emb_dport) { fhk.sp = p->icmpv4vars.emb_sport; fhk.dp = p->icmpv4vars.emb_dport; } else { fhk.sp = p->icmpv4vars.emb_dport; fhk.dp = p->icmpv4vars.emb_sport; } fhk.proto = (uint16_t)ICMPV4_GET_EMB_PROTO(p); fhk.recur = (uint16_t)p->recursion_level; uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand); key = hash % flow_config.hash_size; } else { FlowHashKey4 fhk; if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { fhk.src = p->src.addr_data32[0]; fhk.dst = p->dst.addr_data32[0]; } else { fhk.src = p->dst.addr_data32[0]; fhk.dst = p->src.addr_data32[0]; } fhk.sp = 0xfeed; fhk.dp = 0xbeef; fhk.proto = (uint16_t)p->proto; fhk.recur = (uint16_t)p->recursion_level; uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand); key = hash % flow_config.hash_size; } } else if (p->ip6h != NULL) { FlowHashKey6 fhk; if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { fhk.src[0] = p->src.addr_data32[0]; fhk.src[1] = p->src.addr_data32[1]; fhk.src[2] = p->src.addr_data32[2]; fhk.src[3] = p->src.addr_data32[3]; fhk.dst[0] = p->dst.addr_data32[0]; fhk.dst[1] = p->dst.addr_data32[1]; fhk.dst[2] = p->dst.addr_data32[2]; fhk.dst[3] = p->dst.addr_data32[3]; } else { fhk.src[0] = p->dst.addr_data32[0]; fhk.src[1] = p->dst.addr_data32[1]; fhk.src[2] = p->dst.addr_data32[2]; fhk.src[3] = p->dst.addr_data32[3]; fhk.dst[0] = p->src.addr_data32[0]; fhk.dst[1] = p->src.addr_data32[1]; fhk.dst[2] = p->src.addr_data32[2]; fhk.dst[3] = p->src.addr_data32[3]; } if (p->sp > p->dp) { fhk.sp = p->sp; fhk.dp = p->dp; } else { fhk.sp = p->dp; fhk.dp = p->sp; } fhk.proto = (uint16_t)p->proto; fhk.recur = (uint16_t)p->recursion_level; uint32_t hash = hashword(fhk.u32, 10, flow_config.hash_rand); key = hash % 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))) && \ (f1)->proto == (f2)->proto && \ (f1)->recursion_level == (f2)->recursion_level) /** * \brief See if a ICMP packet belongs to a flow by comparing the embedded * packet in the ICMP error packet to the flow. * * \param f flow * \param p ICMP packet * * \retval 1 match * \retval 0 no match */ static inline int FlowCompareICMPv4(Flow *f, Packet *p) { if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { /* first check the direction of the flow, in other words, the client -> * server direction as it's most likely the ICMP error will be a * response to the clients traffic */ if ((f->src.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32( ICMPV4_GET_EMB_IPV4(p) )) && (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32( ICMPV4_GET_EMB_IPV4(p) )) && f->sp == p->icmpv4vars.emb_sport && f->dp == p->icmpv4vars.emb_dport && f->proto == ICMPV4_GET_EMB_PROTO(p) && f->recursion_level == p->recursion_level) { return 1; /* check the less likely case where the ICMP error was a response to * a packet from the server. */ } else if ((f->dst.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32( ICMPV4_GET_EMB_IPV4(p) )) && (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32( ICMPV4_GET_EMB_IPV4(p) )) && f->dp == p->icmpv4vars.emb_sport && f->sp == p->icmpv4vars.emb_dport && f->proto == ICMPV4_GET_EMB_PROTO(p) && f->recursion_level == p->recursion_level) { return 1; } /* no match, fall through */ } else { /* just treat ICMP as a normal proto for now */ return CMP_FLOW(f, p); } return 0; } static inline int FlowCompare(Flow *f, Packet *p) { if (p->proto == IPPROTO_ICMP) { return FlowCompareICMPv4(f, p); } else { return CMP_FLOW(f, p); } } /** * \brief Check if we should create a flow based on a packet * * We use this check to filter out flow creation based on: * - ICMP error messages * * \param p packet * \retval 1 true * \retval 0 false */ static inline int FlowCreateCheck(Packet *p) { if (PKT_IS_ICMPV4(p)) { if (ICMPV4_IS_ERROR_MSG(p)) { return 0; } } return 1; } /** * \brief Get a new flow * * Get a new flow. We're checking memcap first and will try to make room * if the memcap is reached. * * \retval f *LOCKED* flow on succes, NULL on error. */ static Flow *FlowGetNew(Packet *p) { Flow *f = NULL; if (FlowCreateCheck(p) == 0) { return NULL; } /* get a flow from the spare queue */ f = FlowDequeue(&flow_spare_q); if (f == NULL) { /* If we reached the max memcap, we get a used flow */ if (!(FLOW_CHECK_MEMCAP(sizeof(Flow)))) { /* declare state of emergency */ if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) { SC_ATOMIC_OR(flow_flags, FLOW_EMERGENCY); /* under high load, waking up the flow mgr each time leads * to high cpu usage. Flows are not timed out much faster if * we check a 1000 times a second. */ FlowWakeupFlowManagerThread(); } f = FlowGetUsedFlow(); if (f == NULL) { /* very rare, but we can fail. Just giving up */ return NULL; } /* freed a flow, but it's unlocked */ } else { /* now see if we can alloc a new flow */ f = FlowAlloc(); if (f == NULL) { return NULL; } /* flow is initialized but *unlocked* */ } } else { /* flow has been recycled before it went into the spare queue */ /* flow is initialized (recylced) but *unlocked* */ } FLOWLOCK_WRLOCK(f); return f; } /* 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; FlowHashCountInit; /* get the key to our bucket */ uint32_t key = FlowGetKey(p); /* get our hash bucket and lock it */ FlowBucket *fb = &flow_hash[key]; FBLOCK_LOCK(fb); SCLogDebug("fb %p fb->head %p", fb, fb->head); FlowHashCountIncr; /* see if the bucket already has a flow */ if (fb->head == NULL) { f = FlowGetNew(p); if (f == NULL) { FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return NULL; } /* flow is locked */ fb->head = f; fb->tail = f; FlowReference(&p->flow, f); /* got one, now lock, initialize and return */ FlowInit(f,p); f->fb = fb; FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return f; } /* ok, we have a flow in the bucket. Let's find out if it is our flow */ f = fb->head; /* see if this is the flow we are looking for */ if (FlowCompare(f, p) == 0) { Flow *pf = NULL; /* previous flow */ while (f) { FlowHashCountIncr; pf = f; f = f->hnext; if (f == NULL) { f = pf->hnext = FlowGetNew(p); if (f == NULL) { FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return NULL; } fb->tail = f; /* flow is locked */ f->hprev = pf; FlowReference(&p->flow, f); /* initialize and return */ FlowInit(f,p); f->fb = fb; FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return f; } if (FlowCompare(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; } if (f == fb->tail) { fb->tail = f->hprev; } f->hnext = fb->head; f->hprev = NULL; fb->head->hprev = f; fb->head = f; FlowReference(&p->flow, f); /* found our flow, lock & return */ FLOWLOCK_WRLOCK(f); FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return f; } } } /* lock & return */ FlowReference(&p->flow, f); FLOWLOCK_WRLOCK(f); FBLOCK_UNLOCK(fb); FlowHashCountUpdate; return f; } /** \internal * \brief Get a flow from the hash directly. * * Called in conditions where the spare queue is empty and memcap is reached. * * Walks the hash until a flow can be freed. Timeouts are disregarded, use_cnt * is adhered to. "flow_prune_idx" atomic int makes sure we don't start at the * top each time since that would clear the top of the hash leading to longer * and longer search times under high pressure (observed). * * \retval f flow or NULL */ static Flow *FlowGetUsedFlow(void) { uint32_t idx = SC_ATOMIC_GET(flow_prune_idx) % flow_config.hash_size; uint32_t cnt = flow_config.hash_size; while (cnt--) { if (++idx >= flow_config.hash_size) idx = 0; FlowBucket *fb = &flow_hash[idx]; if (FBLOCK_TRYLOCK(fb) != 0) continue; Flow *f = fb->tail; if (f == NULL) { FBLOCK_UNLOCK(fb); continue; } if (FLOWLOCK_TRYWRLOCK(f) != 0) { FBLOCK_UNLOCK(fb); continue; } /** never prune a flow that is used by a packet or stream msg * we are currently processing in one of the threads */ if (SC_ATOMIC_GET(f->use_cnt) > 0) { FBLOCK_UNLOCK(fb); FLOWLOCK_UNLOCK(f); continue; } /* remove from the hash */ if (f->hprev != NULL) f->hprev->hnext = f->hnext; if (f->hnext != NULL) f->hnext->hprev = f->hprev; if (fb->head == f) fb->head = f->hnext; if (fb->tail == f) fb->tail = f->hprev; f->hnext = NULL; f->hprev = NULL; f->fb = NULL; FBLOCK_UNLOCK(fb); FlowClearMemory (f, f->protomap); FLOWLOCK_UNLOCK(f); (void) SC_ATOMIC_ADD(flow_prune_idx, (flow_config.hash_size - cnt)); return f; } return NULL; } suricata-1.4.7/src/decode-tcp.c0000644000000000000000000004042012253546156013200 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Victor Julien * * Decode TCP */ #include "suricata-common.h" #include "decode.h" #include "decode-tcp.h" #include "decode-events.h" #include "util-unittest.h" #include "util-debug.h" #include "util-optimize.h" #include "flow.h" static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len) { uint16_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; } /* 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 (*(pkt+1) > plen || *(pkt+1) < 2) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); return -1; } 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 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) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.ws != NULL) { ENGINE_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) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.mss != NULL) { ENGINE_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) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.sackok != NULL) { ENGINE_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) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.ts != NULL) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { p->tcpvars.ts = &p->TCP_OPTS[p->TCP_OPTS_CNT]; } } break; case TCP_OPT_SACK: SCLogDebug("SACK option, len %u", p->TCP_OPTS[p->TCP_OPTS_CNT].len); if (p->TCP_OPTS[p->TCP_OPTS_CNT].len < TCP_OPT_SACK_MIN_LEN || p->TCP_OPTS[p->TCP_OPTS_CNT].len > TCP_OPT_SACK_MAX_LEN || !((p->TCP_OPTS[p->TCP_OPTS_CNT].len - 2) % 8 == 0)) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.sack != NULL) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { p->tcpvars.sack = &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 *tv, Packet *p, uint8_t *pkt, uint16_t len) { if (unlikely(len < TCP_HEADER_LEN)) { ENGINE_SET_EVENT(p, TCP_PKT_TOO_SMALL); return -1; } p->tcph = (TCPHdr *)pkt; uint8_t hlen = TCP_GET_HLEN(p); if (unlikely(len < hlen)) { ENGINE_SET_EVENT(p, TCP_HLEN_TOO_SMALL); return -1; } uint8_t tcp_opt_len = hlen - TCP_HEADER_LEN; if (unlikely(tcp_opt_len > TCP_OPTLENMAX)) { ENGINE_SET_EVENT(p, TCP_INVALID_OPTLEN); return -1; } if (likely(tcp_opt_len > 0)) { DecodeTCPOptions(p, pkt + TCP_HEADER_LEN, tcp_opt_len); } SET_TCP_SRC_PORT(p,&p->sp); SET_TCP_DST_PORT(p,&p->dp); p->proto = IPPROTO_TCP; p->payload = pkt + hlen; p->payload_len = len - hlen; return 0; } void DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_tcp, tv->sc_perf_pca); if (unlikely(DecodeTCPPacket(tv, p,pkt,len) < 0)) { SCLogDebug("invalid TCP packet"); p->tcph = NULL; return; } #ifdef DEBUG SCLogDebug("TCP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 " %s%s%s%s%s", GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_HLEN(p), len, p->tcpvars.sackok ? "SACKOK " : "", p->tcpvars.sack ? "SACK " : "", p->tcpvars.ws ? "WS " : "", p->tcpvars.ts ? "TS " : "", p->tcpvars.mss ? "MSS " : ""); #endif /* Flow is an integral part of us */ FlowHandlePacket(tv, p); return; } #ifdef UNITTESTS static int TCPCalculateValidChecksumtest01(void) { uint16_t csum = 0; uint8_t raw_ipshdr[] = { 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; uint8_t raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0xa0, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 02}; csum = *( ((uint16_t *)raw_tcp) + 8); return (csum == TCPCalculateChecksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_tcp, sizeof(raw_tcp))); } static int TCPCalculateInvalidChecksumtest02(void) { uint16_t csum = 0; uint8_t raw_ipshdr[] = { 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; uint8_t raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0xa0, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 03}; csum = *( ((uint16_t *)raw_tcp) + 8); return (csum == TCPCalculateChecksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_tcp, sizeof(raw_tcp))); } static int TCPV6CalculateValidChecksumtest03(void) { uint16_t csum = 0; static uint8_t raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, 0x0c, 0x7a, 0x08, 0x77, 0x80, 0x10, 0x21, 0x5c, 0xc2, 0xf1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x27}; csum = *( ((uint16_t *)(raw_ipv6 + 70))); return (csum == TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 32)); } static int TCPV6CalculateInvalidChecksumtest04(void) { uint16_t csum = 0; static uint8_t raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, 0x0c, 0x7a, 0x08, 0x77, 0x80, 0x10, 0x21, 0x5c, 0xc2, 0xf1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x28}; csum = *( ((uint16_t *)(raw_ipv6 + 70))); return (csum == TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 32)); } /** \test Get the wscale of 2 */ static int TCPGetWscaleTest01(void) { int retval = 0; static uint8_t raw_tcp[] = {0xda, 0xc1, 0x00, 0x50, 0xb6, 0x21, 0x7f, 0x58, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x8a, 0xaf, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x62, 0x88, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ip4h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip4h, 0, sizeof(IPV4Hdr)); p->src.family = AF_INET; p->dst.family = AF_INET; p->ip4h = &ip4h; FlowInitConfig(FLOW_QUIET); DecodeTCP(&tv, &dtv, p, raw_tcp, sizeof(raw_tcp), NULL); FlowShutdown(); if (p->tcph == NULL) { printf("tcp packet decode failed: "); goto end; } uint8_t wscale = TCP_GET_WSCALE(p); if (wscale != 2) { printf("wscale %"PRIu8", expected 2: ", wscale); goto end; } retval = 1; end: SCFree(p); return retval; } /** \test Get the wscale of 15, so see if return 0 properly */ static int TCPGetWscaleTest02(void) { int retval = 0; static uint8_t raw_tcp[] = {0xda, 0xc1, 0x00, 0x50, 0xb6, 0x21, 0x7f, 0x58, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x8a, 0xaf, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x62, 0x88, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x0f}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ip4h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip4h, 0, sizeof(IPV4Hdr)); p->src.family = AF_INET; p->dst.family = AF_INET; p->ip4h = &ip4h; FlowInitConfig(FLOW_QUIET); DecodeTCP(&tv, &dtv, p, raw_tcp, sizeof(raw_tcp), NULL); FlowShutdown(); if (p->tcph == NULL) { printf("tcp packet decode failed: "); goto end; } uint8_t wscale = TCP_GET_WSCALE(p); if (wscale != 0) { printf("wscale %"PRIu8", expected 0: ", wscale); goto end; } retval = 1; end: SCFree(p); return retval; } /** \test Get the wscale, but it's missing, so see if return 0 properly */ static int TCPGetWscaleTest03(void) { int retval = 0; static uint8_t raw_tcp[] = {0xda, 0xc1, 0x00, 0x50, 0xb6, 0x21, 0x7f, 0x59, 0xdd, 0xa3, 0x6f, 0xf8, 0x80, 0x10, 0x05, 0xb4, 0x7c, 0x70, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x62, 0x88, 0x9e, 0x00, 0x00, 0x00, 0x00}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ip4h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip4h, 0, sizeof(IPV4Hdr)); p->src.family = AF_INET; p->dst.family = AF_INET; p->ip4h = &ip4h; FlowInitConfig(FLOW_QUIET); DecodeTCP(&tv, &dtv, p, raw_tcp, sizeof(raw_tcp), NULL); FlowShutdown(); if (p->tcph == NULL) { printf("tcp packet decode failed: "); goto end; } uint8_t wscale = TCP_GET_WSCALE(p); if (wscale != 0) { printf("wscale %"PRIu8", expected 0: ", wscale); goto end; } retval = 1; end: SCFree(p); return retval; } static int TCPGetSackTest01(void) { int retval = 0; static uint8_t raw_tcp[] = { 0x00, 0x50, 0x06, 0xa6, 0xfa, 0x87, 0x0b, 0xf5, 0xf1, 0x59, 0x02, 0xe0, 0xa0, 0x10, 0x3e, 0xbc, 0x1d, 0xe7, 0x00, 0x00, 0x01, 0x01, 0x05, 0x12, 0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64, 0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 }; static uint8_t raw_tcp_sack[] = { 0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64, 0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ip4h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip4h, 0, sizeof(IPV4Hdr)); p->src.family = AF_INET; p->dst.family = AF_INET; p->ip4h = &ip4h; FlowInitConfig(FLOW_QUIET); DecodeTCP(&tv, &dtv, p, raw_tcp, sizeof(raw_tcp), NULL); FlowShutdown(); if (p->tcph == NULL) { printf("tcp packet decode failed: "); goto end; } if (p->tcpvars.sack == NULL) { printf("tcp packet sack not decoded: "); goto end; } int sack = TCP_GET_SACK_CNT(p); if (sack != 2) { printf("expected 2 sack records, got %u: ", TCP_GET_SACK_CNT(p)); goto end; } uint8_t *sackptr = TCP_GET_SACK_PTR(p); if (sackptr == NULL) { printf("no sack data: "); goto end; } if (memcmp(sackptr, raw_tcp_sack, 16) != 0) { printf("malformed sack data: "); goto end; } retval = 1; end: SCFree(p); return retval; } #endif /* UNITTESTS */ void DecodeTCPRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("TCPCalculateValidChecksumtest01", TCPCalculateValidChecksumtest01, 1); UtRegisterTest("TCPCalculateInvalidChecksumtest02", TCPCalculateInvalidChecksumtest02, 0); UtRegisterTest("TCPV6CalculateValidChecksumtest03", TCPV6CalculateValidChecksumtest03, 1); UtRegisterTest("TCPV6CalculateInvalidChecksumtest04", TCPV6CalculateInvalidChecksumtest04, 0); UtRegisterTest("TCPGetWscaleTest01", TCPGetWscaleTest01, 1); UtRegisterTest("TCPGetWscaleTest02", TCPGetWscaleTest02, 1); UtRegisterTest("TCPGetWscaleTest03", TCPGetWscaleTest03, 1); UtRegisterTest("TCPGetSackTest01", TCPGetSackTest01, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/util-binsearch.h0000644000000000000000000000203412253546156014106 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_BINSEARCH_H__ #define __UTIL_BINSEARCH_H__ void BinSearchInit (void); uint8_t *BinSearch(const uint8_t *, size_t, const uint8_t *, size_t); uint8_t *BinSearchNocase(const uint8_t *, size_t, const uint8_t *, size_t); #endif /* __UTIL_BINSEARCH_H__ */ suricata-1.4.7/src/detect-engine-alert.c0000644000000000000000000002242512253546156015016 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "detect.h" #include "detect-engine-alert.h" #include "detect-engine-threshold.h" #include "detect-engine-tag.h" #include "decode.h" #include "flow.h" #include "flow-private.h" /** tag signature we use for tag alerts */ static Signature g_tag_signature; /** tag packet alert structure for tag alerts */ static PacketAlert g_tag_pa; void PacketAlertTagInit(void) { memset(&g_tag_signature, 0x00, sizeof(g_tag_signature)); g_tag_signature.id = TAG_SIG_ID; g_tag_signature.gid = TAG_SIG_GEN; g_tag_signature.num = TAG_SIG_ID; g_tag_signature.rev = 1; g_tag_signature.prio = 2; memset(&g_tag_pa, 0x00, sizeof(g_tag_pa)); g_tag_pa.order_id = 1000; g_tag_pa.action = ACTION_ALERT; g_tag_pa.s = &g_tag_signature; } PacketAlert *PacketAlertGetTag(void) { return &g_tag_pa; } /** * \brief Handle a packet and check if needs a threshold logic * Also apply rule action if necessary. * * \param de_ctx Detection Context * \param sig Signature pointer * \param p Packet structure * * \retval 1 alert is not suppressed * \retval 0 alert is suppressed */ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, uint16_t pos) { SCEnter(); int ret = 1; DetectThresholdData *td = NULL; SigMatch *sm = NULL; if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) { SCReturnInt(1); } do { td = SigGetThresholdTypeIter(s, p, &sm); if (td != NULL) { SCLogDebug("td %p", td); /* PacketAlertThreshold returns 2 if the alert is suppressed but * we do need to apply rule actions to the packet. */ ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s); if (ret == 0 || ret == 2) { /* It doesn't match threshold, remove it */ SCReturnInt(ret); } } } while (sm != NULL); SCReturnInt(1); } /** * \brief Check if a certain sid alerted, this is used in the test functions * * \param p Packet on which we want to check if the signature alerted or not * \param sid Signature id of the signature that thas to be checked for a match * * \retval match A value > 0 on a match; 0 on no match */ int PacketAlertCheck(Packet *p, uint32_t sid) { uint16_t i = 0; int match = 0; for (i = 0; i < p->alerts.cnt; i++) { if (p->alerts.alerts[i].s == NULL) continue; if (p->alerts.alerts[i].s->id == sid) match++; } return match; } /** * \brief Remove alert from the p->alerts.alerts array at pos * \param p Pointer to the Packet * \param pos Position in the array * \retval 0 if the number of alerts is less than pos * 1 if all goes well */ int PacketAlertRemove(Packet *p, uint16_t pos) { uint16_t i = 0; int match = 0; if (pos > p->alerts.cnt) { SCLogDebug("removing %u failed, pos > cnt %u", pos, p->alerts.cnt); return 0; } for (i = pos; i <= p->alerts.cnt - 1; i++) { memcpy(&p->alerts.alerts[i], &p->alerts.alerts[i + 1], sizeof(PacketAlert)); } // Update it, since we removed 1 p->alerts.cnt--; return match; } /** \brief append a signature match to a packet * * \param det_ctx thread detection engine ctx * \param s the signature that matched * \param p packet * \param flags alert flags * \param alert_msg ptr to StreamMsg object that the signature matched on */ int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, uint8_t flags) { int i = 0; if (p->alerts.cnt == PACKET_ALERT_MAX) return 0; SCLogDebug("sid %"PRIu32"", s->id); /* It should be usually the last, so check it before iterating */ if (p->alerts.cnt == 0 || (p->alerts.cnt > 0 && p->alerts.alerts[p->alerts.cnt - 1].num < s->num)) { /* We just add it */ p->alerts.alerts[p->alerts.cnt].num = s->num; p->alerts.alerts[p->alerts.cnt].action = s->action; p->alerts.alerts[p->alerts.cnt].flags = flags; p->alerts.alerts[p->alerts.cnt].s = s; } else { /* We need to make room for this s->num (a bit ugly with memcpy but we are planning changes here)*/ for (i = p->alerts.cnt - 1; i >= 0 && p->alerts.alerts[i].num > s->num; i--) { memcpy(&p->alerts.alerts[i + 1], &p->alerts.alerts[i], sizeof(PacketAlert)); } i++; /* The right place to store the alert */ p->alerts.alerts[i].num = s->num; p->alerts.alerts[i].action = s->action; p->alerts.alerts[i].flags = flags; p->alerts.alerts[i].s = s; } /* Update the count */ p->alerts.cnt++; return 0; } /** * \brief Check the threshold of the sigs that match, set actions, break on pass action * This function iterate the packet alerts array, removing those that didn't match * the threshold, and those that match after a signature with the action "pass". * The array is sorted by action priority/order * \param de_ctx detection engine context * \param det_ctx detection engine thread context * \param p pointer to the packet */ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) { SCEnter(); int i = 0; Signature *s = NULL; SigMatch *sm = NULL; while (i < p->alerts.cnt) { SCLogDebug("Sig->num: %"PRIu16, p->alerts.alerts[i].num); s = de_ctx->sig_array[p->alerts.alerts[i].num]; int res = PacketAlertHandle(de_ctx, det_ctx, s, p, i); if (res > 0) { /* Now, if we have an alert, we have to check if we want * to tag this session or src/dst host */ sm = s->sm_lists[DETECT_SM_LIST_TMATCH]; while (sm) { /* tags are set only for alerts */ sigmatch_table[sm->type].Match(NULL, det_ctx, p, s, sm); sm = sm->next; } if (s->flags & SIG_FLAG_IPONLY) { if (((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) || ((p->flowflags & FLOW_PKT_TOCLIENT) && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) { SCLogDebug("testing against \"ip-only\" signatures"); if (p->flow != NULL) { /* Update flow flags for iponly */ FLOWLOCK_WRLOCK(p->flow); FlowSetIPOnlyFlagNoLock(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0); if (s->action & ACTION_DROP) p->flow->flags |= FLOW_ACTION_DROP; if (s->action & ACTION_REJECT) p->flow->flags |= FLOW_ACTION_DROP; if (s->action & ACTION_REJECT_DST) p->flow->flags |= FLOW_ACTION_DROP; if (s->action & ACTION_REJECT_BOTH) p->flow->flags |= FLOW_ACTION_DROP; if (s->action & ACTION_PASS) p->flow->flags |= FLOW_ACTION_PASS; FLOWLOCK_UNLOCK(p->flow); } } } /* set verdict on packet */ UPDATE_PACKET_ACTION(p, p->alerts.alerts[i].action); if (PACKET_TEST_ACTION(p, ACTION_PASS)) { /* Ok, reset the alert cnt to end in the previous of pass * so we ignore the rest with less prio */ p->alerts.cnt = i; break; /* if the signature wants to drop, check if the * PACKET_ALERT_FLAG_DROP_FLOW flag is set. */ } else if ((PACKET_TEST_ACTION(p, ACTION_DROP)) && ((p->alerts.alerts[i].flags & PACKET_ALERT_FLAG_DROP_FLOW) || (s->flags & SIG_FLAG_APPLAYER)) && p->flow != NULL) { FLOWLOCK_WRLOCK(p->flow); /* This will apply only on IPS mode (check StreamTcpPacket) */ p->flow->flags |= FLOW_ACTION_DROP; FLOWLOCK_UNLOCK(p->flow); } } /* Thresholding removes this alert */ if (res == 0 || res == 2) { PacketAlertRemove(p, i); if (p->alerts.cnt == 0) break; } else { i++; } } /* At this point, we should have all the new alerts. Now check the tag * keyword context for sessions and hosts */ if (!(p->flags & PKT_PSEUDO_STREAM_END)) TagHandlePacket(de_ctx, det_ctx, p); } suricata-1.4.7/src/tmqh-nfq.c0000644000000000000000000000265112253546156012730 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * NFQ Verdict Handler */ #include "suricata-common.h" #include "packet-queue.h" #include "decode.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" void TmqhOutputVerdictNfq(ThreadVars *t, Packet *p); void TmqhNfqRegister (void) { tmqh_table[TMQH_NFQ].name = "nfq"; tmqh_table[TMQH_NFQ].InHandler = NULL; tmqh_table[TMQH_NFQ].OutHandler = TmqhOutputVerdictNfq; } void TmqhOutputVerdictNfq(ThreadVars *t, Packet *p) { /* XXX not scaling */ #if 0 PacketQueue *q = &trans_q[p->verdict_q_id]; SCMutexLock(&q->mutex_q); PacketEnqueue(q, p); SCCondSignal(&q->cond_q); SCMutexUnlock(&q->mutex_q); #endif } suricata-1.4.7/src/detect-engine-state.c0000644000000000000000000016472612253546156015042 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \defgroup sigstate State support * * It is possible to do matching on reconstructed applicative flow. * This is done by this code. It uses the ::Flow structure to store * the list of signatures to match on the reconstructed stream. * * The Flow::de_state is a ::DetectEngineState structure. This is * basically a containter for storage item of type ::DeStateStore. * They contains an array of ::DeStateStoreItem which store the * state of match for an individual signature identified by * DeStateStoreItem::sid. * * The state is constructed by DeStateDetectStartDetection() which * also starts the matching. Work is continued by * DeStateDetectContinueDetection(). * * Once a transaction has been analysed DeStateRestartDetection() * is used to reset the structures. * * @{ */ /** * \file * * \author Victor Julien * * \brief State based signature handling * */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-hua.h" #include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" #include "detect-engine-dcepayload.h" #include "detect-engine-file.h" #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "app-layer-parser.h" #include "app-layer-protos.h" #include "app-layer-htp.h" #include "app-layer-smb.h" #include "app-layer-dcerpc-common.h" #include "app-layer-dcerpc.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-profiling.h" /** convert enum to string */ #define CASE_CODE(E) case E: return #E /* prototype */ static void DeStateResetFileInspection(Flow *f, uint16_t alproto, void *alstate); int DeStateStoreFilestoreSigsCantMatch(SigGroupHead *sgh, DetectEngineState *de_state, uint8_t direction) { if (direction & STREAM_TOSERVER) { if (de_state->toserver_filestore_cnt == sgh->filestore_cnt) { SCReturnInt(1); } } else if (direction & STREAM_TOCLIENT) { if (de_state->toclient_filestore_cnt == sgh->filestore_cnt) { SCReturnInt(1); } } SCReturnInt(0); } /** \brief get string for match enum */ const char *DeStateMatchResultToString(DeStateMatchResult res) { switch (res) { CASE_CODE (DE_STATE_MATCH_NOSTATE); CASE_CODE (DE_STATE_MATCH_FULL); CASE_CODE (DE_STATE_MATCH_PARTIAL); CASE_CODE (DE_STATE_MATCH_NEW); CASE_CODE (DE_STATE_MATCH_NOMATCH); } return NULL; } /** * \brief Alloc a DeStateStore object * \retval d alloc'd object */ DeStateStore *DeStateStoreAlloc(void) { SCEnter(); DeStateStore *d = SCMalloc(sizeof(DeStateStore)); if (unlikely(d == NULL)) { SCReturnPtr(NULL, "DeStateStore"); } memset(d, 0x00, sizeof(DeStateStore)); SCReturnPtr(d, "DeStateStore"); } /** * \brief free a DeStateStore object (recursively) * \param store DeStateStore object to free */ void DeStateStoreFree(DeStateStore *store) { SCEnter(); if (store == NULL) { SCReturn; } if (store->next != NULL) { DeStateStoreFree(store->next); } SCFree(store); SCReturn; } /** * \brief Alloc a DetectEngineState object * \param d alloc'd object */ DetectEngineState *DetectEngineStateAlloc(void) { SCEnter(); DetectEngineState *d = SCMalloc(sizeof(DetectEngineState)); if (unlikely(d == NULL)) { SCReturnPtr(NULL, "DetectEngineState"); } memset(d, 0x00, sizeof(DetectEngineState)); SCReturnPtr(d, "DetectEngineState"); } /** * \brief Free a DetectEngineState object * You must lock the flow mutex for de_state * (f->de_state_m) * \param state DetectEngineState object to free */ void DetectEngineStateFree(DetectEngineState *state) { DeStateStore *iter = NULL; DeStateStore *aux = NULL; if (state == NULL) return; iter = state->head; while (iter != NULL) { aux = iter; iter = iter->next; SCFree(aux); } state->head = NULL; state->tail = NULL; state->cnt = 0; SCFree(state); } /** * \brief reset a DetectEngineState state * \param state LOCKED state */ void DetectEngineStateReset(DetectEngineState *state) { SCEnter(); DeStateStore *iter = NULL; DeStateStore *aux = NULL; if (state == NULL) return; iter = state->head; while (iter != NULL) { aux = iter; iter = iter->next; SCFree(aux); } state->head = NULL; state->tail = NULL; state->cnt = 0; SCReturn; } /** * \brief update the transaction id * * \param f unlocked flow * \param direction STREAM_TOCLIENT / STREAM_TOSERVER * * \retval 2 current transaction done, new available * \retval 1 current transaction done, no new (yet) * \retval 0 current transaction is not done yet */ int DeStateUpdateInspectTransactionId(Flow *f, char direction) { SCEnter(); int r = 0; FLOWLOCK_WRLOCK(f); r = AppLayerTransactionUpdateInspectId(f, direction); FLOWLOCK_UNLOCK(f); SCReturnInt(r); } /** * \brief Append a signature to the detect engine state * * \param state the detect engine state * \param s signature * \param sm sigmatch * \param uri did uri already match (if any) * \param dce did dce already match (if any) * \param hcbd did http client body already match (if any) * * \todo Need to use an array to transfer all these args. Pushing so * many args is slow. */ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, SigMatch *sm, uint32_t match_flags) { DeStateStore *store = state->tail; if (store == NULL) { store = DeStateStoreAlloc(); if (store != NULL) { state->head = store; state->tail = store; } } else { if ((state->cnt % DE_STATE_CHUNK_SIZE) == 0) { store = DeStateStoreAlloc(); if (store != NULL) { state->tail->next = store; state->tail = store; } } } if (store == NULL) { return; } SigIntId idx = state->cnt % DE_STATE_CHUNK_SIZE; store->store[idx].sid = s->num; store->store[idx].flags = 0; store->store[idx].flags |= match_flags; store->store[idx].nm = sm; state->cnt++; SCLogDebug("store %p idx %"PRIuMAX" cnt %"PRIuMAX" sig id %"PRIuMAX"", store, (uintmax_t)idx, (uintmax_t)state->cnt, (uintmax_t)store->store[idx].sid); return; } /* on first detection run: for each (1) app layer signature (2a) at least one app layer sm match OR (2b) content/uri match AND other app layer sigmatches present Cases: multiple app layer sm's content + uricontent content + app layer sm uricontent + app layer sm */ uint16_t DeStateGetStateVersion(DetectEngineState *de_state, uint8_t direction) { if (direction & STREAM_TOSERVER) { SCReturnUInt(de_state->toserver_version); } else { SCReturnUInt(de_state->toclient_version); } } void DeStateStoreStateVersion(DetectEngineState *de_state, uint8_t direction, uint16_t alversion) { if (direction & STREAM_TOSERVER) { SCLogDebug("STREAM_TOSERVER updated to %"PRIu16, alversion); de_state->toserver_version = alversion; } else { SCLogDebug("STREAM_TOCLIENT updated to %"PRIu16, alversion); de_state->toclient_version = alversion; } } /** * \brief Increment de_state filestore_cnt in the proper direction. * * \param de_state flow's locked de_state * \param direction flags containing direction * \param file_no_match number of sigs that are identified as "can't match" * with filestore. */ void DeStateStoreFileNoMatch(DetectEngineState *de_state, uint8_t direction, uint16_t file_no_match) { if (direction & STREAM_TOSERVER) { SCLogDebug("STREAM_TOSERVER added %"PRIu16, file_no_match); de_state->toserver_filestore_cnt += file_no_match; } else { SCLogDebug("STREAM_TOCLIENT added %"PRIu16, file_no_match); de_state->toclient_filestore_cnt += file_no_match; } } /** * \brief Check if a flow already contains a flow detect state * * \retval 2 has state, but it's not updated * \retval 1 has state * \retval 0 has no state */ int DeStateFlowHasState(Flow *f, uint8_t flags, uint16_t alversion) { SCEnter(); int r = 0; SCMutexLock(&f->de_state_m); if (f->de_state == NULL || f->de_state->cnt == 0) { r = 0; } else if (DeStateGetStateVersion(f->de_state, flags) == alversion) r = 2; else r = 1; SCMutexUnlock(&f->de_state_m); SCReturnInt(r); } /** \brief Match app layer sig list against state. Set up state for non matches * and partial matches. * \retval 1 match * \retval 0 no or partial match */ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, uint16_t alproto, uint16_t alversion) { SCEnter(); SigMatch *sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; int match = 0; int r = 0; uint32_t inspect_flags = 0; uint32_t match_flags = 0; uint16_t file_no_match = 0; if (alstate == NULL) { SCReturnInt(0); } SCLogDebug("s->id %"PRIu32, s->id); /* Check the uricontent, http client body, http header keywords here */ if (alproto == ALPROTO_HTTP) { FLOWLOCK_WRLOCK(f); HtpState *htp_state = (HtpState *)alstate; if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); FLOWLOCK_UNLOCK(f); SCReturnInt(0); } int tx_id = AppLayerTransactionGetInspectId(f); if (tx_id == -1) { FLOWLOCK_UNLOCK(f); SCReturnInt(0); } int total_txs = (int)list_size(htp_state->connp->conn->transactions); for ( ; tx_id < total_txs; tx_id++) { DetectEngineAppInspectionEngine *engine = app_inspection_engine[ALPROTO_HTTP][(flags & STREAM_TOSERVER) ? 0 : 1]; while (engine != NULL) { if (s->sm_lists[engine->sm_list] != NULL) { inspect_flags |= engine->inspect_flags; int r = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, tx_id); if (r == 1) { match_flags |= engine->match_flags; } else if (r == 2) { match_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; } else if (r == 3) { match_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; file_no_match++; } } engine = engine->next; } if (inspect_flags == match_flags) break; } FLOWLOCK_UNLOCK(f); } else if (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { inspect_flags |= DE_STATE_FLAG_DCE_INSPECT; SCLogDebug("inspecting dce payload"); if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { SMBState *smb_state = (SMBState *)alstate; if (smb_state->dcerpc_present && DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, &smb_state->dcerpc) == 1) { SCLogDebug("dce payload matched"); match_flags |= DE_STATE_FLAG_DCE_MATCH; } else { SCLogDebug("dce payload inspected but no match"); } } else { if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, alstate) == 1) { SCLogDebug("dce payload matched"); match_flags |= DE_STATE_FLAG_DCE_MATCH; } else { SCLogDebug("dce payload inspected but no match"); } } } } if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { for ( ; sm != NULL; sm = sm->next) { SCLogDebug("sm %p, sm->next %p", sm, sm->next); if (sigmatch_table[sm->type].AppLayerMatch != NULL && (alproto == s->alproto || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2)) { if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { SMBState *smb_state = (SMBState *)alstate; if (smb_state->dcerpc_present) { match = sigmatch_table[sm->type]. AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); } } else { match = sigmatch_table[sm->type]. AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); } if (match == 0) { break; } else if (sm->next == NULL) { sm = NULL; /* set to NULL as we have a match */ if (inspect_flags == 0 || (inspect_flags == match_flags)) { match_flags |= DE_STATE_FLAG_FULL_MATCH; r = 1; } break; } } } } else { if (inspect_flags != 0 && (inspect_flags == match_flags)) { match_flags |= DE_STATE_FLAG_FULL_MATCH; r = 1; } } SCLogDebug("detection done, store results: sm %p, inspect_flags %04X, " "match_flags %04X", sm, inspect_flags, match_flags); SCMutexLock(&f->de_state_m); /* match or no match, we store the state anyway * "sm" here is either NULL (complete match) or * the last SigMatch that didn't match */ if (f->de_state == NULL) { f->de_state = DetectEngineStateAlloc(); } if (f->de_state != NULL) { /* \todo shift to an array to transfer these match values*/ DeStateSignatureAppend(f->de_state, s, sm, match_flags); DeStateStoreStateVersion(f->de_state, flags, alversion); DeStateStoreFileNoMatch(f->de_state, flags, file_no_match); if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, f->de_state, flags) == 1) { SCLogDebug("disabling file storage for transaction %u", det_ctx->tx_id); FLOWLOCK_WRLOCK(f); FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT|STREAM_TOSERVER), det_ctx->tx_id); FLOWLOCK_UNLOCK(f); f->de_state->flags |= DE_STATE_FILE_STORE_DISABLED; } } SCMutexUnlock(&f->de_state_m); SCReturnInt(r); } /** \brief Continue DeState detection of the signatures stored in the state. * * \retval 0 all is good */ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *alstate, uint16_t alproto, uint16_t alversion) { SCEnter(); SigIntId cnt = 0; SigIntId store_cnt = 0; DeStateStore *store = NULL; uint32_t inspect_flags = 0; uint32_t match_flags = 0; int match = 0; uint16_t file_no_match = 0; if (f == NULL || alstate == NULL || alproto == ALPROTO_UNKNOWN) { return 0; } SCMutexLock(&f->de_state_m); if (f->de_state == NULL || f->de_state->cnt == 0) goto end; DeStateResetFileInspection(f, alproto, alstate); /* loop through the stores */ for (store = f->de_state->head; store != NULL; store = store->next) { /* loop through the sigs in the stores */ for (store_cnt = 0; store_cnt < DE_STATE_CHUNK_SIZE && cnt < f->de_state->cnt; store_cnt++, cnt++) { DeStateStoreItem *item = &store->store[store_cnt]; inspect_flags = 0; match_flags = 0; match = 0; SCLogDebug("internal id of signature to inspect: %"PRIuMAX, (uintmax_t)item->sid); Signature *s = de_ctx->sig_array[item->sid]; SCLogDebug("id of signature to inspect: %"PRIuMAX, (uintmax_t)s->id); /* if we already fully matched previously, detect that here */ if (item->flags & DE_STATE_FLAG_FULL_MATCH) { /* check first if we have received new files in the livetime of * this de_state (this tx). */ if (item->flags & (DE_STATE_FLAG_FILE_TC_INSPECT|DE_STATE_FLAG_FILE_TS_INSPECT)) { if ((flags & STREAM_TOCLIENT) && (f->de_state->flags & DE_STATE_FILE_TC_NEW)) { item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; item->flags &= ~DE_STATE_FLAG_FULL_MATCH; } if ((flags & STREAM_TOSERVER) && (f->de_state->flags & DE_STATE_FILE_TS_NEW)) { item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; item->flags &= ~DE_STATE_FLAG_FULL_MATCH; } } if (item->flags & DE_STATE_FLAG_FULL_MATCH) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_FULL; SCLogDebug("full match state"); continue; } } /* if we know for sure we can't ever match, detect that here */ if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { if ((flags & STREAM_TOSERVER) && (item->flags & DE_STATE_FLAG_FILE_TS_INSPECT) && (f->de_state->flags & DE_STATE_FILE_TS_NEW)) { /* new file, fall through */ item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; } else if ((flags & STREAM_TOCLIENT) && (item->flags & DE_STATE_FLAG_FILE_TC_INSPECT) && (f->de_state->flags & DE_STATE_FILE_TC_NEW)) { /* new file, fall through */ item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; } else { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NOMATCH; continue; } } /* only inspect in the right direction here */ if ((flags & STREAM_TOSERVER) && !(s->flags & SIG_FLAG_TOSERVER)) continue; else if ((flags & STREAM_TOCLIENT) && !(s->flags & SIG_FLAG_TOCLIENT)) continue; RULE_PROFILING_START; /* let's continue detection */ /* first, check uricontent */ if (alproto == ALPROTO_HTTP) { FLOWLOCK_WRLOCK(f); HtpState *htp_state = (HtpState *)alstate; if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); FLOWLOCK_UNLOCK(f); goto end; } int tx_id = AppLayerTransactionGetInspectId(f); if (tx_id == -1) { FLOWLOCK_UNLOCK(f); goto end; } int total_txs = (int)list_size(htp_state->connp->conn->transactions); for ( ; tx_id < total_txs; tx_id++) { DetectEngineAppInspectionEngine *engine = app_inspection_engine[ALPROTO_HTTP][(flags & STREAM_TOSERVER) ? 0 : 1]; while (engine != NULL) { if (s->sm_lists[engine->sm_list] != NULL && !(item->flags & engine->match_flags)) { inspect_flags |= engine->inspect_flags; int r = engine->Callback(tv, de_ctx, det_ctx, s, f, flags, alstate, tx_id); if (r == 1) { match_flags |= engine->match_flags; } else if (r == 2) { match_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; } else if (r == 3) { match_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; file_no_match++; } } engine = engine->next; } if (inspect_flags == match_flags) break; } FLOWLOCK_UNLOCK(f); } else if (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { if (!(item->flags & DE_STATE_FLAG_DCE_MATCH)) { SCLogDebug("inspecting dce payload"); inspect_flags |= DE_STATE_FLAG_DCE_INSPECT; if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { SMBState *smb_state = (SMBState *)alstate; //DCERPCState dcerpc_state; //dcerpc_state.dcerpc = smb_state->dcerpc; if (smb_state->dcerpc_present && DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, &smb_state->dcerpc) == 1) { SCLogDebug("dce payload matched"); match_flags |= DE_STATE_FLAG_DCE_MATCH; } else { SCLogDebug("dce payload inspected but no match"); } } else { if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, flags, alstate) == 1) { SCLogDebug("dce payload matched"); match_flags |= DE_STATE_FLAG_DCE_MATCH; } else { SCLogDebug("dce payload inspected but no match"); } } } else { SCLogDebug("dce payload already inspected"); } } } /* next, check the other sig matches */ if (item->nm != NULL) { SigMatch *sm; for (sm = item->nm; sm != NULL; sm = sm->next) { if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { SMBState *smb_state = (SMBState *)alstate; //DCERPCState dcerpc_state; //dcerpc_state.dcerpc = smb_state->dcerpc; if (smb_state->dcerpc_present) { match = sigmatch_table[sm->type]. AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); } } else { match = sigmatch_table[sm->type]. AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); } /* no match, break out */ if (match == 0) { item->nm = sm; det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_PARTIAL; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_PARTIAL)); break; /* match, and no more sm's */ } else if (sm->next == NULL) { /* mark the sig as matched */ item->nm = NULL; SCLogDebug("inspect_flags %04x match_flags %04x", inspect_flags, match_flags); if (inspect_flags == 0 || (inspect_flags == match_flags)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NEW; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_NEW)); match_flags |= DE_STATE_FLAG_FULL_MATCH; } else { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_PARTIAL; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_PARTIAL)); } } } } else { SCLogDebug("inspect_flags %04x match_flags %04x", inspect_flags, match_flags); if (inspect_flags != 0 && (inspect_flags == match_flags)) { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NEW; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_NEW)); match_flags |= DE_STATE_FLAG_FULL_MATCH; } else { det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_PARTIAL; SCLogDebug("state set to %s", DeStateMatchResultToString(DE_STATE_MATCH_PARTIAL)); } } item->flags |= match_flags; SCLogDebug("signature %"PRIu32" match state %s", s->id, DeStateMatchResultToString(det_ctx->de_state_sig_array[item->sid])); RULE_PROFILING_END(det_ctx, s, match); } } DeStateStoreStateVersion(f->de_state, flags, alversion); DeStateStoreFileNoMatch(f->de_state, flags, file_no_match); if (!(f->de_state->flags & DE_STATE_FILE_STORE_DISABLED)) { if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, f->de_state, flags) == 1) { SCLogDebug("disabling file storage for transaction"); FLOWLOCK_WRLOCK(f); FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT|STREAM_TOSERVER), det_ctx->tx_id); FLOWLOCK_UNLOCK(f); f->de_state->flags |= DE_STATE_FILE_STORE_DISABLED; } } end: if (f->de_state != NULL) { if (flags & STREAM_TOCLIENT) f->de_state->flags &= ~DE_STATE_FILE_TC_NEW; else f->de_state->flags &= ~DE_STATE_FILE_TS_NEW; } SCMutexUnlock(&f->de_state_m); SCReturnInt(0); } /** * \brief Restart detection as we're going to inspect a new transaction */ int DeStateRestartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *alstate, uint16_t alproto) { SCEnter(); /* first clear the existing state as it belongs * to the previous transaction */ SCMutexLock(&f->de_state_m); if (f->de_state != NULL) { DetectEngineStateReset(f->de_state); } SCMutexUnlock(&f->de_state_m); SCReturnInt(0); } /** * \brief Act on HTTP new file in same tx flag. * * \param f flow with *LOCKED* de_state */ static void DeStateResetFileInspection(Flow *f, uint16_t alproto, void *alstate) { if (f == NULL || alproto != ALPROTO_HTTP || alstate == NULL || f->de_state == NULL) { SCReturn; } FLOWLOCK_WRLOCK(f); HtpState *htp_state = (HtpState *)alstate; if (htp_state->flags & HTP_FLAG_NEW_FILE_TX_TC) { SCLogDebug("new file in the TC direction"); htp_state->flags &= ~HTP_FLAG_NEW_FILE_TX_TC; f->de_state->flags |= DE_STATE_FILE_TC_NEW; } else if (htp_state->flags & HTP_FLAG_NEW_FILE_TX_TS) { SCLogDebug("new file in the TS direction"); htp_state->flags &= ~HTP_FLAG_NEW_FILE_TX_TS; f->de_state->flags |= DE_STATE_FILE_TS_NEW; } FLOWLOCK_UNLOCK(f); } #ifdef UNITTESTS #include "flow-util.h" static int DeStateTest01(void) { SCLogDebug("sizeof(DetectEngineState)\t\t%"PRIuMAX, (uintmax_t)sizeof(DetectEngineState)); SCLogDebug("sizeof(DeStateStore)\t\t\t%"PRIuMAX, (uintmax_t)sizeof(DeStateStore)); SCLogDebug("sizeof(DeStateStoreItem)\t\t%"PRIuMAX"", (uintmax_t)sizeof(DeStateStoreItem)); return 1; } static int DeStateTest02(void) { int result = 0; DetectEngineState *state = DetectEngineStateAlloc(); if (state == NULL) { printf("d == NULL: "); goto end; } Signature s; memset(&s, 0x00, sizeof(s)); s.num = 0; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 11; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 22; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 33; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 44; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 55; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 66; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 77; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 88; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 99; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 100; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 111; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 122; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 133; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 144; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 155; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 166; DeStateSignatureAppend(state, &s, NULL, 0); if (state->head == NULL) { goto end; } if (state->head->store[1].sid != 11) { goto end; } if (state->head->next == NULL) { goto end; } if (state->head->store[14].sid != 144) { goto end; } if (state->head->next->store[0].sid != 155) { goto end; } if (state->head->next->store[1].sid != 166) { goto end; } result = 1; end: if (state != NULL) { DetectEngineStateFree(state); } return result; } static int DeStateTest03(void) { int result = 0; DetectEngineState *state = DetectEngineStateAlloc(); if (state == NULL) { printf("d == NULL: "); goto end; } Signature s; memset(&s, 0x00, sizeof(s)); s.num = 11; DeStateSignatureAppend(state, &s, NULL, 0); s.num = 22; DeStateSignatureAppend(state, &s, NULL, DE_STATE_FLAG_URI_MATCH); if (state->head == NULL) { goto end; } if (state->head->store[0].sid != 11) { goto end; } if (state->head->store[0].flags & DE_STATE_FLAG_URI_MATCH) { goto end; } if (state->head->store[1].sid != 22) { goto end; } if (!(state->head->store[1].flags & DE_STATE_FLAG_URI_MATCH)) { goto end; } result = 1; end: if (state != NULL) { DetectEngineStateFree(state); } return result; } static int DeStateSigTest01(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\nContent-Length: 10\r\n\r\n"; uint8_t httpbuf4[] = "Http Body!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy\"; http_cookie; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("signature matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; result = 1; end: if (http_state != NULL) { HTPStateFree(http_state); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test multiple pipelined http transactions */ static int DeStateSigTest02(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Http Body!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nHttp Body!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("signature matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (5): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 2))) { printf("signature 2 didn't match, but should have: "); goto end; } p->alerts.cnt = 0; result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int DeStateSigTest03(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ ThreadVars th_v; TcpSession ssn; int result = 0; Flow *f = NULL; Packet *p = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&ssn, 0, sizeof(ssn)); DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; f->alproto = ALPROTO_HTTP; p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); if (p == NULL) goto end; p->flow = f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } if (http_state->files_ts == NULL) { printf("no files in state: "); goto end; } FileContainer *files = AppLayerGetFilesFromFlow(p->flow, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); goto end; } File *file = files->head; if (file == NULL) { printf("no file: "); goto end; } if (!(file->flags & FILE_STORE)) { printf("file is set to store, but sig didn't match: "); goto end; } result = 1; end: UTHFreeFlow(f); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); return result; } static int DeStateSigTest04(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ ThreadVars th_v; TcpSession ssn; int result = 0; Flow *f = NULL; Packet *p = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&ssn, 0, sizeof(ssn)); DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; f->alproto = ALPROTO_HTTP; p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); if (p == NULL) goto end; p->flow = f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } if (http_state->files_ts == NULL) { printf("no files in state: "); goto end; } FileContainer *files = AppLayerGetFilesFromFlow(p->flow, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); goto end; } File *file = files->head; if (file == NULL) { printf("no file: "); goto end; } if (file->flags & FILE_STORE) { printf("file is set to store, but sig didn't match: "); goto end; } result = 1; end: UTHFreeFlow(f); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); return result; } static int DeStateSigTest05(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ ThreadVars th_v; TcpSession ssn; int result = 0; Flow *f = NULL; Packet *p = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&ssn, 0, sizeof(ssn)); DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; f->alproto = ALPROTO_HTTP; p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); if (p == NULL) goto end; p->flow = f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } if (http_state->files_ts == NULL) { printf("no files in state: "); goto end; } FileContainer *files = AppLayerGetFilesFromFlow(p->flow, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); goto end; } File *file = files->head; if (file == NULL) { printf("no file: "); goto end; } if (!(file->flags & FILE_NOSTORE)) { printf("file is not set to \"no store\": "); goto end; } result = 1; end: UTHFreeFlow(f); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); return result; } static int DeStateSigTest06(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ ThreadVars th_v; TcpSession ssn; int result = 0; Flow *f = NULL; Packet *p = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&ssn, 0, sizeof(ssn)); DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; filestore; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; f->alproto = ALPROTO_HTTP; p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); if (p == NULL) goto end; p->flow = f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } if (http_state->files_ts == NULL) { printf("no files in state: "); goto end; } FileContainer *files = AppLayerGetFilesFromFlow(p->flow, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); goto end; } File *file = files->head; if (file == NULL) { printf("no file: "); goto end; } if (!(file->flags & FILE_NOSTORE)) { printf("file is not set to \"no store\": "); goto end; } result = 1; end: UTHFreeFlow(f); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); return result; } static int DeStateSigTest07(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ ThreadVars th_v; TcpSession ssn; int result = 0; Flow *f = NULL; Packet *p = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&ssn, 0, sizeof(ssn)); DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; f->alproto = ALPROTO_HTTP; p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); if (p == NULL) goto end; p->flow = f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } if (http_state->files_ts == NULL) { printf("no files in state: "); goto end; } FileContainer *files = AppLayerGetFilesFromFlow(p->flow, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); goto end; } File *file = files->head; if (file == NULL) { printf("no file: "); goto end; } if (file->flags & FILE_STORE) { printf("file is set to store, but sig didn't match: "); goto end; } result = 1; end: UTHFreeFlow(f); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); return result; } #endif void DeStateRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DeStateTest01", DeStateTest01, 1); UtRegisterTest("DeStateTest02", DeStateTest02, 1); UtRegisterTest("DeStateTest03", DeStateTest03, 1); UtRegisterTest("DeStateSigTest01", DeStateSigTest01, 1); UtRegisterTest("DeStateSigTest02", DeStateSigTest02, 1); UtRegisterTest("DeStateSigTest03", DeStateSigTest03, 1); UtRegisterTest("DeStateSigTest04", DeStateSigTest04, 1); UtRegisterTest("DeStateSigTest05", DeStateSigTest05, 1); UtRegisterTest("DeStateSigTest06", DeStateSigTest06, 1); UtRegisterTest("DeStateSigTest07", DeStateSigTest07, 1); #endif } /** * @} */ suricata-1.4.7/src/detect-engine-threshold.h0000644000000000000000000000267012253546156015710 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * \author Victor Julien */ #ifndef __DETECT_ENGINE_THRESHOLD_H__ #define __DETECT_ENGINE_THRESHOLD_H__ #include "detect.h" #include "host.h" DetectThresholdData *SigGetThresholdType(Signature *, Packet *); DetectThresholdData *SigGetThresholdTypeIter(Signature *, Packet *, SigMatch **); int PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, DetectThresholdData *, Packet *, Signature *); void ThresholdHashInit(DetectEngineCtx *); void ThresholdContextDestroy(DetectEngineCtx *); int ThresholdTimeoutCheck(Host *, struct timeval *); void ThresholdListFree(void *ptr); #endif /* __DETECT_ENGINE_THRESHOLD_H__ */ suricata-1.4.7/src/tmqh-packetpool.c0000644000000000000000000002353512253546156014311 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Packetpool queue handlers. Packet pool is implemented as a ringbuffer. * We're using a multi reader / multi writer version of the ringbuffer, * that is relatively expensive due to the CAS function. But it is necessary * because every thread can return packets to the pool and multiple parts * of the code retrieve packets (Decode, Defrag) and these can run in their * own threads as well. */ #include "suricata.h" #include "packet-queue.h" #include "decode.h" #include "detect.h" #include "detect-uricontent.h" #include "threads.h" #include "threadvars.h" #include "flow.h" #include "flow-util.h" #include "host.h" #include "stream.h" #include "stream-tcp-reassemble.h" #include "tm-queuehandlers.h" #include "pkt-var.h" #include "tmqh-packetpool.h" #include "util-ringbuffer.h" #include "util-debug.h" #include "util-error.h" #include "util-profiling.h" static RingBuffer16 *ringbuffer = NULL; /** * \brief TmqhPacketpoolRegister * \initonly */ void TmqhPacketpoolRegister (void) { tmqh_table[TMQH_PACKETPOOL].name = "packetpool"; tmqh_table[TMQH_PACKETPOOL].InHandler = TmqhInputPacketpool; tmqh_table[TMQH_PACKETPOOL].OutHandler = TmqhOutputPacketpool; ringbuffer = RingBufferInit(); if (ringbuffer == NULL) { SCLogError(SC_ERR_FATAL, "Error registering Packet pool handler (at ring buffer init)"); exit(EXIT_FAILURE); } } void TmqhPacketpoolDestroy (void) { /* doing this clean up PacketPoolDestroy now, * where we also clean the packets */ } int PacketPoolIsEmpty(void) { return RingBufferIsEmpty(ringbuffer); } uint16_t PacketPoolSize(void) { return RingBufferSize(ringbuffer); } void PacketPoolWait(void) { RingBufferWait(ringbuffer); } /** \brief a initialized packet * * \warning Use *only* at init, not at packet runtime */ void PacketPoolStorePacket(Packet *p) { if (RingBufferIsFull(ringbuffer)) { exit(1); } RingBufferMrMwPut(ringbuffer, (void *)p); SCLogDebug("buffersize %u", RingBufferSize(ringbuffer)); } /** \brief get a packet from the packet pool, but if the * pool is empty, don't wait, just return NULL */ Packet *PacketPoolGetPacket(void) { if (RingBufferIsEmpty(ringbuffer)) return NULL; Packet *p = RingBufferMrMwGetNoWait(ringbuffer); return p; } void PacketPoolInit(intmax_t max_pending_packets) { /* pre allocate packets */ SCLogDebug("preallocating packets... packet size %" PRIuMAX "", (uintmax_t)SIZE_OF_PACKET); int i = 0; for (i = 0; i < max_pending_packets; i++) { /* XXX pkt alloc function */ Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered while allocating a packet. Exiting..."); exit(EXIT_FAILURE); } PACKET_INITIALIZE(p); PacketPoolStorePacket(p); } SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"", max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET)); } void PacketPoolDestroy(void) { if (ringbuffer == NULL) { return; } Packet *p = NULL; while ((p = PacketPoolGetPacket()) != NULL) { PACKET_CLEANUP(p); SCFree(p); } RingBufferDestroy(ringbuffer); ringbuffer = NULL; } Packet *TmqhInputPacketpool(ThreadVars *t) { Packet *p = NULL; while (p == NULL && ringbuffer->shutdown == FALSE) { p = RingBufferMrMwGet(ringbuffer); } /* packet is clean */ return p; } void TmqhOutputPacketpool(ThreadVars *t, Packet *p) { int proot = 0; SCEnter(); SCLogDebug("Packet %p, p->root %p, alloced %s", p, p->root, p->flags & PKT_ALLOC ? "true" : "false"); /** \todo make this a callback * Release tcp segments. Done here after alerting can use them. */ if (p->flow != NULL && p->proto == IPPROTO_TCP) { SCMutexLock(&p->flow->m); StreamTcpPruneSession(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? STREAM_TOSERVER : STREAM_TOCLIENT); SCMutexUnlock(&p->flow->m); } if (IS_TUNNEL_PKT(p)) { SCLogDebug("Packet %p is a tunnel packet: %s", p,p->root ? "upper layer" : "tunnel root"); /* get a lock to access root packet fields */ SCMutex *m = p->root ? &p->root->tunnel_mutex : &p->tunnel_mutex; SCMutexLock(m); if (IS_TUNNEL_ROOT_PKT(p)) { SCLogDebug("IS_TUNNEL_ROOT_PKT == TRUE"); if (TUNNEL_PKT_TPR(p) == 0) { SCLogDebug("TUNNEL_PKT_TPR(p) == 0, no more tunnel packet " "depending on this root"); /* if this packet is the root and there are no * more tunnel packets, return it to the pool */ /* fall through */ } else { SCLogDebug("tunnel root Packet %p: TUNNEL_PKT_TPR(p) > 0, so " "packets are still depending on this root, setting " "p->tunnel_verdicted == 1", p); /* if this is the root and there are more tunnel * packets, return this to the pool. It's still referenced * by the tunnel packets, and we will return it * when we handle them */ SET_TUNNEL_PKT_VERDICTED(p); SCMutexUnlock(m); PACKET_PROFILING_END(p); SCReturn; } } else { SCLogDebug("NOT IS_TUNNEL_ROOT_PKT, so tunnel pkt"); /* the p->root != NULL here seems unnecessary: IS_TUNNEL_PKT checks * that p->tunnel_pkt == 1, IS_TUNNEL_ROOT_PKT checks that + * p->root == NULL. So when we are here p->root can only be * non-NULL, right? CLANG thinks differently. May be a FP, but * better safe than sorry. VJ */ if (p->root != NULL && IS_TUNNEL_PKT_VERDICTED(p->root) && TUNNEL_PKT_TPR(p) == 1) { SCLogDebug("p->root->tunnel_verdicted == 1 && TUNNEL_PKT_TPR(p) == 1"); /* the root is ready and we are the last tunnel packet, * lets enqueue them both. */ TUNNEL_DECR_PKT_TPR_NOLOCK(p); /* handle the root */ SCLogDebug("setting proot = 1 for root pkt, p->root %p " "(tunnel packet %p)", p->root, p); proot = 1; /* fall through */ } else { /* root not ready yet, so get rid of the tunnel pkt only */ SCLogDebug("NOT p->root->tunnel_verdicted == 1 && " "TUNNEL_PKT_TPR(p) == 1 (%" PRIu32 ")", TUNNEL_PKT_TPR(p)); TUNNEL_DECR_PKT_TPR_NOLOCK(p); /* fall through */ } } SCMutexUnlock(m); SCLogDebug("tunnel stuff done, move on (proot %d)", proot); } FlowDeReference(&p->flow); /* we're done with the tunnel root now as well */ if (proot == 1) { SCLogDebug("getting rid of root pkt... alloc'd %s", p->root->flags & PKT_ALLOC ? "true" : "false"); FlowDeReference(&p->root->flow); /* if p->root uses extended data, free them */ if (p->root->ReleaseData) { if (p->root->ReleaseData(t, p->root) == TM_ECODE_FAILED) { SCLogWarning(SC_ERR_INVALID_ACTION, "Unable to release packet data"); } } if (p->root->ext_pkt) { if (!(p->root->flags & PKT_ZERO_COPY)) { SCFree(p->root->ext_pkt); } p->root->ext_pkt = NULL; } if (p->root->flags & PKT_ALLOC) { PACKET_CLEANUP(p->root); SCFree(p->root); p->root = NULL; } else { PACKET_RECYCLE(p->root); RingBufferMrMwPut(ringbuffer, (void *)p->root); } } if (p->ReleaseData) { if (p->ReleaseData(t, p) == TM_ECODE_FAILED) { SCLogWarning(SC_ERR_INVALID_ACTION, "Unable to release packet data"); } } /* if p uses extended data, free them */ if (p->ext_pkt) { if (!(p->flags & PKT_ZERO_COPY)) { SCFree(p->ext_pkt); } p->ext_pkt = NULL; } PACKET_PROFILING_END(p); SCLogDebug("getting rid of tunnel pkt... alloc'd %s (root %p)", p->flags & PKT_ALLOC ? "true" : "false", p->root); if (p->flags & PKT_ALLOC) { PACKET_CLEANUP(p); SCFree(p); } else { PACKET_RECYCLE(p); RingBufferMrMwPut(ringbuffer, (void *)p); } SCReturn; } /** * \brief Release all the packets in the queue back to the packetpool. Mainly * used by threads that have failed, and wants to return the packets back * to the packetpool. * * \param pq Pointer to the packetqueue from which the packets have to be * returned back to the packetpool * * \warning this function assumes that the pq does not use locking */ void TmqhReleasePacketsToPacketPool(PacketQueue *pq) { Packet *p = NULL; if (pq == NULL) return; while ( (p = PacketDequeue(pq)) != NULL) TmqhOutputPacketpool(NULL, p); return; } suricata-1.4.7/src/detect-engine-proto.h0000644000000000000000000000327412253546156015060 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_PROTO_H__ #define __DETECT_PROTO_H__ #define DETECT_PROTO_ANY (1 << 0) /**< Indicate that given protocol is considered as IP */ #define DETECT_PROTO_ONLY_PKT (1 << 1) /**< Indicate that we only care about packet payloads. */ #define DETECT_PROTO_ONLY_STREAM (1 << 2) /**< Indicate that we only care about stream payloads. */ #define DETECT_PROTO_IPV4 (1 << 3) /**< IPv4 only */ #define DETECT_PROTO_IPV6 (1 << 4) /**< IPv6 only */ typedef struct DetectProto_ { uint8_t proto[256/8]; /**< bit array for 256 protocol bits */ uint8_t flags; } DetectProto; /* prototypes */ int DetectProtoParse(DetectProto *dp, char *str); int DetectProtoContainsProto(DetectProto *, int); void DetectProtoTests(void); #endif /* __DETECT_PROTO_H__ */ suricata-1.4.7/src/data-queue.c0000644000000000000000000000451412253546156013230 00000000000000/** * Copyright (c) 2009, 2010 Open Information Security Foundation. * * \author Anoop Saldanha */ #include "suricata-common.h" #include "data-queue.h" #include "threads.h" /** * \brief Enqueues data on the queue. * * \param q Pointer to the data queue. * \param data Pointer to the data to be queued. It should be a pointer to a * structure instance that implements the template structure * struct SCDQGenericQData_ defined in data-queue.h. */ void SCDQDataEnqueue(SCDQDataQueue *q, SCDQGenericQData *data) { /* we already have some data in queue */ if (q->top != NULL) { data->next = q->top; q->top->prev = data; q->top = data; /* the queue is empty */ } else { q->top = data; q->bot = data; } q->len++; #ifdef DBG_PERF if (q->len > q->dbg_maxlen) q->dbg_maxlen = q->len; #endif /* DBG_PERF */ return; } /** * \brief Dequeues and returns an entry from the queue. * * \param q Pointer to the data queue. * \param retval Pointer to the data that has been enqueued. The instance * returned is/should be a pointer to a structure instance that * implements the template structure struct SCDQGenericQData_ * defined in data-queue.h. */ SCDQGenericQData *SCDQDataDequeue(SCDQDataQueue *q) { SCDQGenericQData *data = NULL; /* if the queue is empty there are is no data left and we return NULL */ if (q->len == 0) { return NULL; } /* If we are going to get the last packet, set len to 0 * before doing anything else (to make the threads to follow * the SCondWait as soon as possible) */ q->len--; /* pull the bottom packet from the queue */ data = q->bot; #ifdef OS_DARWIN /* Weird issue in OS_DARWIN * Sometimes it looks that two thread arrive here at the same time * so the bot ptr is NULL */ if (data == NULL) { printf("No data to dequeue!\n"); return NULL; } #endif /* OS_DARWIN */ /* more data in queue */ if (q->bot->prev != NULL) { q->bot = q->bot->prev; q->bot->next = NULL; /* just the one we remove, so now empty */ } else { q->top = NULL; q->bot = NULL; } data->next = NULL; data->prev = NULL; return data; } suricata-1.4.7/src/util-device.c0000644000000000000000000001370612253546156013412 00000000000000/* Copyright (C) 2011-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "conf.h" #include "util-device.h" /** * \file * * \author Eric Leblond * * \brief Utility functions to handle device list */ /** private device list */ static TAILQ_HEAD(, LiveDevice_) live_devices = TAILQ_HEAD_INITIALIZER(live_devices); /** * \brief Add a pcap device for monitoring * * \param dev string with the device name * * \retval 0 on success. * \retval -1 on failure. */ int LiveRegisterDevice(char *dev) { LiveDevice *pd = SCMalloc(sizeof(LiveDevice)); if (unlikely(pd == NULL)) { return -1; } pd->dev = SCStrdup(dev); SC_ATOMIC_INIT(pd->pkts); SC_ATOMIC_INIT(pd->drop); SC_ATOMIC_INIT(pd->invalid_checksums); pd->ignore_checksum = 0; TAILQ_INSERT_TAIL(&live_devices, pd, next); SCLogDebug("Pcap device \"%s\" registered.", dev); return 0; } /** * \brief Get the number of registered devices * * \retval cnt the number of registered devices */ int LiveGetDeviceCount(void) { int i = 0; LiveDevice *pd; TAILQ_FOREACH(pd, &live_devices, next) { i++; } return i; } /** * \brief Get a pointer to the device name at idx * * \param number idx of the device in our list * * \retval ptr pointer to the string containing the device * \retval NULL on error */ char *LiveGetDeviceName(int number) { int i = 0; LiveDevice *pd; TAILQ_FOREACH(pd, &live_devices, next) { if (i == number) { return pd->dev; } i++; } return NULL; } /** * \brief Get a pointer to the device at idx * * \param number idx of the device in our list * * \retval ptr pointer to the string containing the device * \retval NULL on error */ LiveDevice *LiveGetDevice(char *name) { int i = 0; LiveDevice *pd; if (name == NULL) { SCLogWarning(SC_ERR_INVALID_VALUE, "Name of device should not be null"); return NULL; } TAILQ_FOREACH(pd, &live_devices, next) { if (!strcmp(name, pd->dev)) { return pd; } i++; } return NULL; } int LiveBuildDeviceList(char * runmode) { ConfNode *base = ConfGetNode(runmode); ConfNode *child; int i = 0; if (base == NULL) return 0; TAILQ_FOREACH(child, &base->head, next) { if (!strcmp(child->val, "interface")) { ConfNode *subchild; TAILQ_FOREACH(subchild, &child->head, next) { if ((!strcmp(subchild->name, "interface"))) { if (!strcmp(subchild->val, "default")) break; SCLogInfo("Adding interface %s from config file", subchild->val); LiveRegisterDevice(subchild->val); i++; } } } } return i; } #ifdef BUILD_UNIX_SOCKET TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *answer, void *data) { SCEnter(); LiveDevice *pd; const char * name = NULL; json_t *jarg = json_object_get(cmd, "iface"); if(!json_is_string(jarg)) { json_object_set_new(answer, "message", json_string("Iface is not a string")); SCReturnInt(TM_ECODE_FAILED); } name = json_string_value(jarg); if (name == NULL) { json_object_set_new(answer, "message", json_string("Iface name is NULL")); SCReturnInt(TM_ECODE_FAILED); } TAILQ_FOREACH(pd, &live_devices, next) { if (!strcmp(name, pd->dev)) { json_t *jdata = json_object(); if (jdata == NULL) { json_object_set_new(answer, "message", json_string("internal error at json object creation")); SCReturnInt(TM_ECODE_FAILED); } json_object_set_new(jdata, "pkts", json_integer(SC_ATOMIC_GET(pd->pkts))); json_object_set_new(jdata, "invalid-checksums", json_integer(SC_ATOMIC_GET(pd->invalid_checksums))); json_object_set_new(jdata, "drop", json_integer(SC_ATOMIC_GET(pd->drop))); json_object_set_new(answer, "message", jdata); SCReturnInt(TM_ECODE_OK); } } json_object_set_new(answer, "message", json_string("Iface does not exist")); SCReturnInt(TM_ECODE_FAILED); } TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *answer, void *data) { SCEnter(); json_t *jdata; json_t *jarray; LiveDevice *pd; int i = 0; jdata = json_object(); if (jdata == NULL) { json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } jarray = json_array(); if (jarray == NULL) { json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } TAILQ_FOREACH(pd, &live_devices, next) { json_array_append(jarray, json_string(pd->dev)); i++; } json_object_set_new(jdata, "count", json_integer(i)); json_object_set_new(jdata, "ifaces", jarray); json_object_set_new(answer, "message", jdata); SCReturnInt(TM_ECODE_OK); } #endif /* BUILD_UNIX_SOCKET */ suricata-1.4.7/src/stream-tcp-sack.h0000644000000000000000000000332412253546156014176 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __STREAM_TCP_SACK_H__ #define __STREAM_TCP_SACK_H__ #include "suricata-common.h" #include "util-optimize.h" /** * \brief Get the size of the SACKed ranges * * \param stream Stream to get the size for. * * \retval size the size * * Optimized for case where SACK is not in use in the * stream, as it *should* only be used in case of packet * loss. */ static inline uint32_t StreamTcpSackedSize(TcpStream *stream) { if (likely(stream->sack_head == NULL)) { SCReturnUInt(0U); } else { uint32_t size = 0; StreamTcpSackRecord *rec = NULL; for (rec = stream->sack_head; rec != NULL; rec = rec->next) { size += (rec->re - rec->le); } SCReturnUInt(size); } } int StreamTcpSackUpdatePacket(TcpStream *, Packet *); void StreamTcpSackPruneList(TcpStream *); void StreamTcpSackFreeList(TcpStream *); void StreamTcpSackRegisterTests (void); #endif /* __STREAM_TCP_SACK_H__*/ suricata-1.4.7/src/util-mpm-ac.c0000644000000000000000000022523312253546156013325 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * First iteration of aho-corasick MPM from - * * Efficient String Matching: An Aid to Bibliographic Search * Alfred V. Aho and Margaret J. Corasick * * - Uses the delta table for calculating transitions, instead of having * separate goto and failure transitions. * - If we cross 2 ** 16 states, we use 4 bytes in the transition table * to hold each state, otherwise we use 2 bytes. * - This version of the MPM is heavy on memory, but it performs well. * If you can fit the ruleset with this mpm on your box without hitting * swap, this is the MPM to go for. * * \todo - Do a proper analyis of our existing MPMs and suggest a good one based * on the pattern distribution and the expected traffic(say http). * - Tried out loop unrolling without any perf increase. Need to dig deeper. * - Irrespective of whether we cross 2 ** 16 states or not,shift to using * uint32_t for state type, so that we can integrate it's status as a * final state or not in the topmost byte. We are already doing it if * state_count is > 2 ** 16. * - Test case-senstive patterns if they have any ascii chars. If they * don't treat them as nocase. * - Carry out other optimizations we are working on. hashes, compression. */ #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "util-mpm-ac.h" #include "conf.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-memcmp.h" void SCACInitCtx(MpmCtx *, int); void SCACInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void SCACDestroyCtx(MpmCtx *); void SCACDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int SCACAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int SCACPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); void SCACPrintInfo(MpmCtx *mpm_ctx); void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACRegisterTests(void); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_FAIL (-1) /* size of the hash table used to speed up pattern insertions initially */ #define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 /** * \brief Helper structure used by AC during state table creation */ typedef struct StateQueue_ { int32_t store[STATE_QUEUE_CONTAINER_SIZE]; int top; int bot; } StateQueue; /** * \brief Register the aho-corasick mpm. */ void MpmACRegister(void) { mpm_table[MPM_AC].name = "ac"; /* don't need this. isn't that awesome? no more chopping and blah blah */ mpm_table[MPM_AC].max_pattern_length = 0; mpm_table[MPM_AC].InitCtx = SCACInitCtx; mpm_table[MPM_AC].InitThreadCtx = SCACInitThreadCtx; mpm_table[MPM_AC].DestroyCtx = SCACDestroyCtx; mpm_table[MPM_AC].DestroyThreadCtx = SCACDestroyThreadCtx; mpm_table[MPM_AC].AddPattern = SCACAddPatternCS; mpm_table[MPM_AC].AddPatternNocase = SCACAddPatternCI; mpm_table[MPM_AC].Prepare = SCACPreparePatterns; mpm_table[MPM_AC].Search = SCACSearch; mpm_table[MPM_AC].Cleanup = NULL; mpm_table[MPM_AC].PrintCtx = SCACPrintInfo; mpm_table[MPM_AC].PrintThreadCtx = SCACPrintSearchStats; mpm_table[MPM_AC].RegisterUnittests = SCACRegisterTests; return; } /** * \internal * \brief Initialize the AC context with user specified conf parameters. We * aren't retrieving anything for AC conf now, but we will certainly * need it, when we customize AC. */ static void SCACGetConfig() { //ConfNode *ac_conf; //const char *hash_val = NULL; //ConfNode *pm = ConfGetNode("pattern-matcher"); return; } /** * \internal * \brief Compares 2 patterns. We use it for the hashing process during the * the initial pattern insertion time, to cull duplicate sigs. * * \param p Pointer to the first pattern(SCACPattern). * \param pat Pointer to the second pattern(raw pattern array). * \param patlen Pattern length. * \param flags Flags. We don't need this. * * \retval hash A 32 bit unsigned hash. */ static inline int SCACCmpPattern(SCACPattern *p, uint8_t *pat, uint16_t patlen, char flags) { if (p->len != patlen) return 0; if (p->flags != flags) return 0; if (memcmp(p->cs, pat, patlen) != 0) return 0; return 1; } /** * \internal * \brief Creates a hash of the pattern. We use it for the hashing process * during the initial pattern insertion time, to cull duplicate sigs. * * \param pat Pointer to the pattern. * \param patlen Pattern length. * * \retval hash A 32 bit unsigned hash. */ static inline uint32_t SCACInitHashRaw(uint8_t *pat, uint16_t patlen) { uint32_t hash = patlen * pat[0]; if (patlen > 1) hash += pat[1]; return (hash % INIT_HASH_SIZE); } /** * \internal * \brief Looks up a pattern. We use it for the hashing process during the * the initial pattern insertion time, to cull duplicate sigs. * * \param ctx Pointer to the AC ctx. * \param pat Pointer to the pattern. * \param patlen Pattern length. * \param flags Flags. We don't need this. * * \retval hash A 32 bit unsigned hash. */ static inline SCACPattern *SCACInitHashLookup(SCACCtx *ctx, uint8_t *pat, uint16_t patlen, char flags, uint32_t pid) { uint32_t hash = SCACInitHashRaw(pat, patlen); if (ctx->init_hash == NULL || ctx->init_hash[hash] == NULL) { return NULL; } SCACPattern *t = ctx->init_hash[hash]; for ( ; t != NULL; t = t->next) { //if (SCACCmpPattern(t, pat, patlen, flags) == 1) if (t->flags == flags && t->id == pid) return t; } return NULL; } /** * \internal * \brief Allocs a new pattern instance. * * \param mpm_ctx Pointer to the mpm context. * * \retval p Pointer to the newly created pattern. */ static inline SCACPattern *SCACAllocPattern(MpmCtx *mpm_ctx) { SCACPattern *p = SCMalloc(sizeof(SCACPattern)); if (unlikely(p == NULL)) { exit(EXIT_FAILURE); } memset(p, 0, sizeof(SCACPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(SCACPattern); return p; } /** * \internal * \brief Used to free SCACPattern instances. * * \param mpm_ctx Pointer to the mpm context. * \param p Pointer to the SCACPattern instance to be freed. * \param free Free the above pointer or not. */ static inline void SCACFreePattern(MpmCtx *mpm_ctx, SCACPattern *p) { if (p != NULL && p->cs != NULL && p->cs != p->ci) { SCFree(p->cs); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL && p->ci != NULL) { SCFree(p->ci); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL && p->original_pat != NULL) { SCFree(p->original_pat); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL) { SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(SCACPattern); } return; } /** * \internal * \brief Does a memcpy of the input string to lowercase. * * \param d Pointer to the target area for memcpy. * \param s Pointer to the src string for memcpy. * \param len len of the string sent in s. */ static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) d[i] = u8_tolower(s[i]); return; } static inline uint32_t SCACInitHash(SCACPattern *p) { uint32_t hash = p->len * p->original_pat[0]; if (p->len > 1) hash += p->original_pat[1]; return (hash % INIT_HASH_SIZE); } static inline int SCACInitHashAdd(SCACCtx *ctx, SCACPattern *p) { uint32_t hash = SCACInitHash(p); if (ctx->init_hash == NULL) { return 0; } if (ctx->init_hash[hash] == NULL) { ctx->init_hash[hash] = p; return 0; } SCACPattern *tt = NULL; SCACPattern *t = ctx->init_hash[hash]; /* get the list tail */ do { tt = t; t = t->next; } while (t != NULL); tt->next = p; return 0; } /** * \internal * \brief Add a pattern to the mpm-ac context. * * \param mpm_ctx Mpm context. * \param pat Pointer to the pattern. * \param patlen Length of the pattern. * \param pid Pattern id * \param sid Signature id (internal id). * \param flags Pattern's MPM_PATTERN_* flags. * * \retval 0 On success. * \retval -1 On failure. */ static int SCACAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, ctx, patlen, pid); if (patlen == 0) { SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); return 0; } /* check if we have already inserted this pattern */ SCACPattern *p = SCACInitHashLookup(ctx, pat, patlen, flags, pid); if (p == NULL) { SCLogDebug("Allocing new pattern"); /* p will never be NULL */ p = SCACAllocPattern(mpm_ctx); p->len = patlen; p->flags = flags; p->id = pid; p->original_pat = SCMalloc(patlen); if (p->original_pat == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->original_pat, pat, patlen); p->ci = SCMalloc(patlen); if (p->ci == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy_tolower(p->ci, pat, patlen); /* setup the case sensitive part of the pattern */ if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* nocase means no difference between cs and ci */ p->cs = p->ci; } else { if (memcmp(p->ci, pat, p->len) == 0) { /* no diff between cs and ci: pat is lowercase */ p->cs = p->ci; } else { p->cs = SCMalloc(patlen); if (p->cs == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->cs, pat, patlen); } } /* put in the pattern hash */ SCACInitHashAdd(ctx, p); //if (mpm_ctx->pattern_cnt == 65535) { // SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " // "insert anymore. Exiting"); // exit(EXIT_FAILURE); //} mpm_ctx->pattern_cnt++; if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) { mpm_ctx->minlen = patlen; } else { if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } /* we need the max pat id */ if (pid > ctx->max_pat_id) ctx->max_pat_id = pid; } return 0; error: SCACFreePattern(mpm_ctx, p); return -1; } /** * \internal * \brief Initialize a new state in the goto and output tables. * * \param mpm_ctx Pointer to the mpm context. * * \retval The state id, of the newly created state. */ static inline int SCACInitNewState(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int ascii_code = 0; int size = 0; /* reallocate space in the goto table to include a new state */ size = (ctx->state_count + 1) * ctx->single_state_size; ctx->goto_table = SCRealloc(ctx->goto_table, size); if (ctx->goto_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } /* set all transitions for the newly assigned state as FAIL transitions */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_FAIL; } /* reallocate space in the output table for the new state */ size = (ctx->state_count + 1) * sizeof(SCACOutputTable); ctx->output_table = SCRealloc(ctx->output_table, size); if (ctx->output_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->output_table + ctx->state_count, 0, sizeof(SCACOutputTable)); /* \todo using it temporarily now during dev, since I have restricted * state var in SCACCtx->state_table to uint16_t. */ //if (ctx->state_count > 65536) { // printf("state count exceeded\n"); // exit(EXIT_FAILURE); //} return ctx->state_count++; } /** * \internal * \brief Adds a pid to the output table for a state. * * \param state The state to whose output table we should add the pid. * \param pid The pattern id to add. * \param mpm_ctx Pointer to the mpm context. */ static void SCACSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; SCACOutputTable *output_state = &ctx->output_table[state]; uint32_t i = 0; for (i = 0; i < output_state->no_of_entries; i++) { if (output_state->pids[i] == pid) return; } output_state->no_of_entries++; output_state->pids = SCRealloc(output_state->pids, output_state->no_of_entries * sizeof(uint32_t)); if (output_state->pids == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } output_state->pids[output_state->no_of_entries - 1] = pid; return; } /** * \brief Helper function used by SCACCreateGotoTable. Adds a pattern to the * goto table. * * \param pattern Pointer to the pattern. * \param pattern_len Pattern length. * \param pid The pattern id, that corresponds to this pattern. We * need it to updated the output table for this pattern. * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int32_t state = 0; int32_t newstate = 0; int i = 0; int p = 0; /* walk down the trie till we have a match for the pattern prefix */ state = 0; for (i = 0; i < pattern_len; i++) { if (ctx->goto_table[state][pattern[i]] != SC_AC_FAIL) { state = ctx->goto_table[state][pattern[i]]; } else { break; } } /* add the non-matching pattern suffix to the trie, from the last state * we left off */ for (p = i; p < pattern_len; p++) { newstate = SCACInitNewState(mpm_ctx); ctx->goto_table[state][pattern[p]] = newstate; state = newstate; } /* add this pattern id, to the output table of the last state, where the * pattern ends in the trie */ SCACSetOutputState(state, pid, mpm_ctx); return; } /** * \internal * \brief Create the goto table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACCreateGotoTable(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; uint32_t i = 0; /* add each pattern to create the goto table */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { SCACEnter(ctx->parray[i]->ci, ctx->parray[i]->len, ctx->parray[i]->id, mpm_ctx); } int ascii_code = 0; for (ascii_code = 0; ascii_code < 256; ascii_code++) { if (ctx->goto_table[0][ascii_code] == SC_AC_FAIL) { ctx->goto_table[0][ascii_code] = 0; } } return; } static inline int SCACStateQueueIsEmpty(StateQueue *q) { if (q->top == q->bot) return 1; else return 0; } static inline void SCACEnqueue(StateQueue *q, int32_t state) { int i = 0; /*if we already have this */ for (i = q->bot; i < q->top; i++) { if (q->store[i] == state) return; } q->store[q->top++] = state; if (q->top == STATE_QUEUE_CONTAINER_SIZE) q->top = 0; if (q->top == q->bot) { SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " "Fatal Error. Exiting. Please file a bug report on this"); exit(EXIT_FAILURE); } return; } static inline int32_t SCACDequeue(StateQueue *q) { if (q->bot == STATE_QUEUE_CONTAINER_SIZE) q->bot = 0; if (q->bot == q->top) { SCLogCritical(SC_ERR_AHO_CORASICK, "StateQueue behaving weirdly. " "Fatal Error. Exiting. Please file a bug report on this"); exit(EXIT_FAILURE); } return q->store[q->bot++]; } /* #define SCACStateQueueIsEmpty(q) (((q)->top == (q)->bot) ? 1 : 0) #define SCACEnqueue(q, state) do { \ int i = 0; \ \ for (i = (q)->bot; i < (q)->top; i++) { \ if ((q)->store[i] == state) \ return; \ } \ \ (q)->store[(q)->top++] = state; \ \ if ((q)->top == STATE_QUEUE_CONTAINER_SIZE) \ (q)->top = 0; \ \ if ((q)->top == (q)->bot) { \ SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " \ "Fatal Error. Exiting. Please file a bug report on this"); \ exit(EXIT_FAILURE); \ } \ } while (0) #define SCACDequeue(q) ( (((q)->bot == STATE_QUEUE_CONTAINER_SIZE)? ((q)->bot = 0): 0), \ (((q)->bot == (q)->top) ? \ (printf("StateQueue behaving " \ "weirdly. Fatal Error. Exiting. Please " \ "file a bug report on this"), \ exit(EXIT_FAILURE)) : 0), \ (q)->store[(q)->bot++]) \ */ /** * \internal * \brief Club the output data from 2 states and store it in the 1st state. * dst_state_data = {dst_state_data} UNION {src_state_data} * * \param dst_state First state(also the destination) for the union operation. * \param src_state Second state for the union operation. * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACClubOutputStates(int32_t dst_state, int32_t src_state, MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; uint32_t i = 0; uint32_t j = 0; SCACOutputTable *output_dst_state = &ctx->output_table[dst_state]; SCACOutputTable *output_src_state = &ctx->output_table[src_state]; for (i = 0; i < output_src_state->no_of_entries; i++) { for (j = 0; j < output_dst_state->no_of_entries; j++) { if (output_src_state->pids[i] == output_dst_state->pids[j]) { break; } } if (j == output_dst_state->no_of_entries) { output_dst_state->no_of_entries++; output_dst_state->pids = SCRealloc(output_dst_state->pids, (output_dst_state->no_of_entries * sizeof(uint32_t)) ); if (output_dst_state->pids == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } output_dst_state->pids[output_dst_state->no_of_entries - 1] = output_src_state->pids[i]; } } return; } /** * \internal * \brief Create the failure table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACCreateFailureTable(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int ascii_code = 0; int32_t state = 0; int32_t r_state = 0; StateQueue q; memset(&q, 0, sizeof(StateQueue)); /* allot space for the failure table. A failure entry in the table for * every state(SCACCtx->state_count) */ ctx->failure_table = SCMalloc(ctx->state_count * sizeof(int32_t)); if (ctx->failure_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->failure_table, 0, ctx->state_count * sizeof(int32_t)); /* add the failure transitions for the 0th state, and add every non-fail * transition from the 0th state to the queue for further processing * of failure states */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[0][ascii_code]; if (temp_state != 0) { SCACEnqueue(&q, temp_state); ctx->failure_table[temp_state] = 0; } } while (!SCACStateQueueIsEmpty(&q)) { /* pick up every state from the queue and add failure transitions */ r_state = SCACDequeue(&q); for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[r_state][ascii_code]; if (temp_state == SC_AC_FAIL) continue; SCACEnqueue(&q, temp_state); state = ctx->failure_table[r_state]; while(ctx->goto_table[state][ascii_code] == SC_AC_FAIL) state = ctx->failure_table[state]; ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code]; SCACClubOutputStates(temp_state, ctx->failure_table[temp_state], mpm_ctx); } } return; } /** * \internal * \brief Create the delta table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACCreateDeltaTable(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int ascii_code = 0; int32_t r_state = 0; if (ctx->state_count < 32767) { ctx->state_table_u16 = SCMalloc(ctx->state_count * sizeof(SC_AC_STATE_TYPE_U16) * 256); if (ctx->state_table_u16 == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->state_table_u16, 0, ctx->state_count * sizeof(SC_AC_STATE_TYPE_U16) * 256); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (ctx->state_count * sizeof(SC_AC_STATE_TYPE_U16) * 256); StateQueue q; memset(&q, 0, sizeof(StateQueue)); for (ascii_code = 0; ascii_code < 256; ascii_code++) { SC_AC_STATE_TYPE_U16 temp_state = ctx->goto_table[0][ascii_code]; ctx->state_table_u16[0][ascii_code] = temp_state; if (temp_state != 0) SCACEnqueue(&q, temp_state); } while (!SCACStateQueueIsEmpty(&q)) { r_state = SCACDequeue(&q); for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[r_state][ascii_code]; if (temp_state != SC_AC_FAIL) { SCACEnqueue(&q, temp_state); ctx->state_table_u16[r_state][ascii_code] = temp_state; } else { ctx->state_table_u16[r_state][ascii_code] = ctx->state_table_u16[ctx->failure_table[r_state]][ascii_code]; } } } } else { /* create space for the state table. We could have used the existing goto * table, but since we have it set to hold 32 bit state values, we will create * a new state table here of type SC_AC_STATE_TYPE(current set to uint16_t) */ ctx->state_table_u32 = SCMalloc(ctx->state_count * sizeof(SC_AC_STATE_TYPE_U32) * 256); if (ctx->state_table_u32 == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->state_table_u32, 0, ctx->state_count * sizeof(SC_AC_STATE_TYPE_U32) * 256); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (ctx->state_count * sizeof(SC_AC_STATE_TYPE_U32) * 256); StateQueue q; memset(&q, 0, sizeof(StateQueue)); for (ascii_code = 0; ascii_code < 256; ascii_code++) { SC_AC_STATE_TYPE_U32 temp_state = ctx->goto_table[0][ascii_code]; ctx->state_table_u32[0][ascii_code] = temp_state; if (temp_state != 0) SCACEnqueue(&q, temp_state); } while (!SCACStateQueueIsEmpty(&q)) { r_state = SCACDequeue(&q); for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[r_state][ascii_code]; if (temp_state != SC_AC_FAIL) { SCACEnqueue(&q, temp_state); ctx->state_table_u32[r_state][ascii_code] = temp_state; } else { ctx->state_table_u32[r_state][ascii_code] = ctx->state_table_u32[ctx->failure_table[r_state]][ascii_code]; } } } } return; } static inline void SCACClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int ascii_code = 0; uint32_t state = 0; uint32_t temp_state = 0; if (ctx->state_count < 32767) { for (state = 0; state < ctx->state_count; state++) { for (ascii_code = 0; ascii_code < 256; ascii_code++) { temp_state = ctx->state_table_u16[state & 0x7FFF][ascii_code]; if (ctx->output_table[temp_state & 0x7FFF].no_of_entries != 0) ctx->state_table_u16[state & 0x7FFF][ascii_code] |= (1 << 15); } } } else { for (state = 0; state < ctx->state_count; state++) { for (ascii_code = 0; ascii_code < 256; ascii_code++) { temp_state = ctx->state_table_u32[state & 0x00FFFFFF][ascii_code]; if (ctx->output_table[temp_state & 0x00FFFFFF].no_of_entries != 0) ctx->state_table_u32[state & 0x00FFFFFF][ascii_code] |= (1 << 24); } } } return; } static inline void SCACInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; uint32_t state = 0; uint32_t k = 0; for (state = 0; state < ctx->state_count; state++) { if (ctx->output_table[state].no_of_entries == 0) continue; for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { ctx->output_table[state].pids[k] &= 0x0000FFFF; ctx->output_table[state].pids[k] |= 1 << 16; } } } return; } #if 0 static void SCACPrintDeltaTable(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int i = 0, j = 0; printf("##############Delta Table##############\n"); for (i = 0; i < ctx->state_count; i++) { printf("%d: \n", i); for (j = 0; j < 256; j++) { if (SCACGetDelta(i, j, mpm_ctx) != 0) { printf(" %c -> %d\n", j, SCACGetDelta(i, j, mpm_ctx)); } } } return; } #endif /** * \brief Process the patterns and prepare the state table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACPrepareStateTable(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; /* create the 0th state in the goto table and output_table */ SCACInitNewState(mpm_ctx); /* create the goto table */ SCACCreateGotoTable(mpm_ctx); /* create the failure table */ SCACCreateFailureTable(mpm_ctx); /* create the final state(delta) table */ SCACCreateDeltaTable(mpm_ctx); /* club the output state presence with delta transition entries */ SCACClubOutputStatePresenceWithDeltaTable(mpm_ctx); /* club nocase entries */ SCACInsertCaseSensitiveEntriesForPatterns(mpm_ctx); #if 0 SCACPrintDeltaTable(mpm_ctx); #endif /* we don't need these anymore */ SCFree(ctx->goto_table); ctx->goto_table = NULL; SCFree(ctx->failure_table); ctx->failure_table = NULL; return; } /** * \brief Process the patterns added to the mpm, and create the internal tables. * * \param mpm_ctx Pointer to the mpm context. */ int SCACPreparePatterns(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ ctx->parray = (SCACPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); if (ctx->parray == NULL) goto error; memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; for (i = 0; i < INIT_HASH_SIZE; i++) { SCACPattern *node = ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; ctx->parray[p++] = node; node = nnode; } } /* we no longer need the hash, so free it's memory */ SCFree(ctx->init_hash); ctx->init_hash = NULL; /* the memory consumed by a single state in our goto table */ ctx->single_state_size = sizeof(int32_t) * 256; /* handle no case patterns */ ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACPatternList)); if (ctx->pid_pat_list == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACPatternList)); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE) { if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 0) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 1; else if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 1) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 1; else ctx->pid_pat_list[ctx->parray[i]->id].case_state = 3; } else { //if (memcmp(ctx->parray[i]->original_pat, ctx->parray[i]->ci, // ctx->parray[i]->len) != 0) { ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, ctx->parray[i]->original_pat, ctx->parray[i]->len); ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 0) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 2; else if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 2) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 2; else ctx->pid_pat_list[ctx->parray[i]->id].case_state = 3; //} } } /* prepare the state table required by AC */ SCACPrepareStateTable(mpm_ctx); /* free all the stored patterns. Should save us a good 100-200 mbs */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { SCACFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); return 0; error: return -1; } /** * \brief Init the mpm thread context. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. * \param matchsize We don't need this. */ void SCACInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); mpm_thread_ctx->ctx = SCMalloc(sizeof(SCACThreadCtx)); if (mpm_thread_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_thread_ctx->ctx, 0, sizeof(SCACThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(SCACThreadCtx); return; } /** * \brief Initialize the AC context. * * \param mpm_ctx Mpm context. * \param module_handle Cuda module handle from the cuda handler API. We don't * have to worry about this here. */ void SCACInitCtx(MpmCtx *mpm_ctx, int module_handle) { if (mpm_ctx->ctx != NULL) return; mpm_ctx->ctx = SCMalloc(sizeof(SCACCtx)); if (mpm_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_ctx->ctx, 0, sizeof(SCACCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(SCACCtx); /* initialize the hash we use to speed up pattern insertions */ SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; ctx->init_hash = SCMalloc(sizeof(SCACPattern *) * INIT_HASH_SIZE); if (ctx->init_hash == NULL) { exit(EXIT_FAILURE); } memset(ctx->init_hash, 0, sizeof(SCACPattern *) * INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ SCACGetConfig(); SCReturn; } /** * \brief Destroy the mpm thread context. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. */ void SCACDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { SCACPrintSearchStats(mpm_thread_ctx); if (mpm_thread_ctx->ctx != NULL) { SCFree(mpm_thread_ctx->ctx); mpm_thread_ctx->ctx = NULL; mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(SCACThreadCtx); } return; } /** * \brief Destroy the mpm context. * * \param mpm_ctx Pointer to the mpm context. */ void SCACDestroyCtx(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->init_hash != NULL) { SCFree(ctx->init_hash); ctx->init_hash = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACPattern *)); } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { SCACFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); } if (ctx->state_table_u16 != NULL) { SCFree(ctx->state_table_u16); ctx->state_table_u16 = NULL; mpm_ctx->memory_cnt++; mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_STATE_TYPE_U16) * 256); } else if (ctx->state_table_u32 != NULL) { SCFree(ctx->state_table_u32); ctx->state_table_u32 = NULL; mpm_ctx->memory_cnt++; mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_STATE_TYPE_U32) * 256); } if (ctx->output_table != NULL) { uint32_t state_count; for (state_count = 0; state_count < ctx->state_count; state_count++) { if (ctx->output_table[state_count].pids != NULL) { SCFree(ctx->output_table[state_count].pids); } } SCFree(ctx->output_table); } if (ctx->pid_pat_list != NULL) { int i; for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); } SCFree(ctx->pid_pat_list); } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(SCACCtx); return; } /** * \brief The aho corasick search function. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. * \param pmq Pointer to the Pattern Matcher Queue to hold * search matches. * \param buf Buffer to be searched. * \param buflen Buffer length. * * \retval matches Match count. */ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int i = 0; int matches = 0; /* \todo tried loop unrolling with register var, with no perf increase. Need * to dig deeper */ /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACPatternList *pid_pat_list = ctx->pid_pat_list; if (ctx->state_count < 32767) { register SC_AC_STATE_TYPE_U16 state = 0; SC_AC_STATE_TYPE_U16 (*state_table_u16)[256] = ctx->state_table_u16; for (i = 0; i < buflen; i++) { state = state_table_u16[state & 0x7FFF][u8_tolower(buf[i])]; if (state & 0x8000) { uint32_t no_of_entries = ctx->output_table[state & 0x7FFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { if ((i + 1) < pid_pat_list[pids[k] & 0x0000FFFF].patlen) continue; if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { /* inside loop */ if (pid_pat_list[pids[k] & 0x0000FFFF].case_state != 3) { continue; } } if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; } matches++; } else { if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; } matches++; } //loop1: //; } } } /* for (i = 0; i < buflen; i++) */ } else { register SC_AC_STATE_TYPE_U32 state = 0; SC_AC_STATE_TYPE_U32 (*state_table_u32)[256] = ctx->state_table_u32; for (i = 0; i < buflen; i++) { state = state_table_u32[state & 0x00FFFFFF][u8_tolower(buf[i])]; if (state & 0xFF000000) { uint32_t no_of_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { if ((i + 1) < pid_pat_list[pids[k] & 0x0000FFFF].patlen) continue; if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { /* inside loop */ if (pid_pat_list[pids[k] & 0x0000FFFF].case_state != 3) { continue; } } if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; } matches++; } else { if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; } matches++; } //loop1: //; } } } /* for (i = 0; i < buflen; i++) */ } return matches; } /** * \brief Add a case insensitive pattern. Although we have different calls for * adding case sensitive and insensitive patterns, we make a single call * for either case. No special treatment for either case. * * \param mpm_ctx Pointer to the mpm context. * \param pat The pattern to add. * \param patnen The pattern length. * \param offset Ignored. * \param depth Ignored. * \param pid The pattern id. * \param sid Ignored. * \param flags Flags associated with this pattern. * * \retval 0 On success. * \retval -1 On failure. */ int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return SCACAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } /** * \brief Add a case sensitive pattern. Although we have different calls for * adding case sensitive and insensitive patterns, we make a single call * for either case. No special treatment for either case. * * \param mpm_ctx Pointer to the mpm context. * \param pat The pattern to add. * \param patnen The pattern length. * \param offset Ignored. * \param depth Ignored. * \param pid The pattern id. * \param sid Ignored. * \param flags Flags associated with this pattern. * * \retval 0 On success. * \retval -1 On failure. */ int SCACAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return SCACAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef SC_AC_COUNTERS SCACThreadCtx *ctx = (SCACThreadCtx *)mpm_thread_ctx->ctx; printf("AC Thread Search stats (ctx %p)\n", ctx); printf("Total calls: %" PRIu32 "\n", ctx->total_calls); printf("Total matches: %" PRIu64 "\n", ctx->total_matches); #endif /* SC_AC_COUNTERS */ return; } void SCACPrintInfo(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; printf("MPM AC Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); printf(" Sizeof:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" SCACCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACCtx)); printf(" SCACPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACPattern)); printf(" SCACPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count); printf("\n"); return; } /*************************************Unittests********************************/ #ifdef UNITTESTS static int SCACTest01(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest02(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest03(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest04(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); SCACAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); SCACAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest05(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); SCACAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); SCACAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest06(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcd"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest07(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* should match 30 times */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 29 times */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 28 times */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* 26 */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 21 */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 1 */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); PmqSetup(&pmq, 0, 6); /* total matches: 135 */ SCACPreparePatterns(&mpm_ctx); char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest08(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest09(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest10(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "abcdefgh" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest11(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); if (SCACAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; if (SCACAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) goto end; if (SCACAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) goto end; if (SCACAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; PmqSetup(&pmq, 0, 5); if (SCACPreparePatterns(&mpm_ctx) == -1) goto end; result = 1; char *buf = "he"; result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); buf = "she"; result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); buf = "his"; result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); buf = "hers"; result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); end: SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest12(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest13(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; SCACAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest14(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; SCACAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest15(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; SCACAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest16(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; SCACAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABC"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest17(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; SCACAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzAB"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest18(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; SCACAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest19(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; SCACAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest20(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; SCACAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest21(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest22(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest23(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); if (cnt == 0) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest24(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest25(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); SCACAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); SCACAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACPreparePatterns(&mpm_ctx); char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest26(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); SCACAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACPreparePatterns(&mpm_ctx); char *buf = "works"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest27(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 0 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "tone"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest28(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC, -1); SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 0 match */ SCACAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACPreparePatterns(&mpm_ctx); char *buf = "tONE"; uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACDestroyCtx(&mpm_ctx); SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACTest29(void) { uint8_t *buf = (uint8_t *)"onetwothreefourfivesixseveneightnine"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); if (de_ctx->sig_list->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) != 1) { printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); goto end; } if (PacketAlertCheck(p, 2) != 1) { printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void SCACRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCACTest01", SCACTest01, 1); UtRegisterTest("SCACTest02", SCACTest02, 1); UtRegisterTest("SCACTest03", SCACTest03, 1); UtRegisterTest("SCACTest04", SCACTest04, 1); UtRegisterTest("SCACTest05", SCACTest05, 1); UtRegisterTest("SCACTest06", SCACTest06, 1); UtRegisterTest("SCACTest07", SCACTest07, 1); UtRegisterTest("SCACTest08", SCACTest08, 1); UtRegisterTest("SCACTest09", SCACTest09, 1); UtRegisterTest("SCACTest10", SCACTest10, 1); UtRegisterTest("SCACTest11", SCACTest11, 1); UtRegisterTest("SCACTest12", SCACTest12, 1); UtRegisterTest("SCACTest13", SCACTest13, 1); UtRegisterTest("SCACTest14", SCACTest14, 1); UtRegisterTest("SCACTest15", SCACTest15, 1); UtRegisterTest("SCACTest16", SCACTest16, 1); UtRegisterTest("SCACTest17", SCACTest17, 1); UtRegisterTest("SCACTest18", SCACTest18, 1); UtRegisterTest("SCACTest19", SCACTest19, 1); UtRegisterTest("SCACTest20", SCACTest20, 1); UtRegisterTest("SCACTest21", SCACTest21, 1); UtRegisterTest("SCACTest22", SCACTest22, 1); UtRegisterTest("SCACTest23", SCACTest23, 1); UtRegisterTest("SCACTest24", SCACTest24, 1); UtRegisterTest("SCACTest25", SCACTest25, 1); UtRegisterTest("SCACTest26", SCACTest26, 1); UtRegisterTest("SCACTest27", SCACTest27, 1); UtRegisterTest("SCACTest28", SCACTest28, 1); UtRegisterTest("SCACTest29", SCACTest29, 1); #endif return; } suricata-1.4.7/src/detect-uricontent.h0000644000000000000000000000252312253546156014640 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Gurvinder Singh */ #ifndef __DETECT_URICONTENT_H__ #define __DETECT_URICONTENT_H__ #include "detect-content.h" #include "util-spm-bm.h" #include "app-layer-htp.h" /* prototypes */ void DetectUricontentRegister (void); uint32_t DetectUricontentMaxId(DetectEngineCtx *); //uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, void *alstate); void DetectUricontentPrint(DetectContentData *); uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *, Flow *, HtpState *, uint8_t); #endif /* __DETECT_URICONTENT_H__ */ suricata-1.4.7/src/source-pfring.c0000644000000000000000000004544412253546156013767 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author William Metcalf * \author Eric Leblond * * PF_RING packet acquisition support * * \todo remove requirement for setting cluster so old 3.x versions are supported * \todo implement DNA support * \todo Allow ring options such as snaplen etc, to be user configurable. */ #ifdef HAVE_PFRING #include #endif /* HAVE_PFRING */ #include "suricata-common.h" #include "suricata.h" #include "conf.h" #include "decode.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "source-pfring.h" #include "util-debug.h" #include "util-checksum.h" #include "util-privs.h" #include "util-device.h" #include "runmodes.h" TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot); TmEcode ReceivePfringThreadInit(ThreadVars *, void *, void **); void ReceivePfringThreadExitStats(ThreadVars *, void *); TmEcode ReceivePfringThreadDeinit(ThreadVars *, void *); TmEcode DecodePfringThreadInit(ThreadVars *, void *, void **); TmEcode DecodePfring(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); extern int max_pending_packets; extern uint8_t suricata_ctl_flags; #ifndef HAVE_PFRING /*Handle cases where we don't have PF_RING support built-in*/ TmEcode NoPfringSupportExit(ThreadVars *, void *, void **); void TmModuleReceivePfringRegister (void) { tmm_modules[TMM_RECEIVEPFRING].name = "ReceivePfring"; tmm_modules[TMM_RECEIVEPFRING].ThreadInit = NoPfringSupportExit; tmm_modules[TMM_RECEIVEPFRING].Func = NULL; tmm_modules[TMM_RECEIVEPFRING].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVEPFRING].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEPFRING].RegisterTests = NULL; tmm_modules[TMM_RECEIVEPFRING].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | SC_CAP_NET_BIND_SERVICE | SC_CAP_NET_BROADCAST; tmm_modules[TMM_RECEIVEPFRING].flags = TM_FLAG_RECEIVE_TM; } void TmModuleDecodePfringRegister (void) { tmm_modules[TMM_DECODEPFRING].name = "DecodePfring"; tmm_modules[TMM_DECODEPFRING].ThreadInit = NoPfringSupportExit; tmm_modules[TMM_DECODEPFRING].Func = NULL; tmm_modules[TMM_DECODEPFRING].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEPFRING].ThreadDeinit = NULL; tmm_modules[TMM_DECODEPFRING].RegisterTests = NULL; tmm_modules[TMM_DECODEPFRING].cap_flags = 0; tmm_modules[TMM_DECODEPFRING].flags = TM_FLAG_DECODE_TM; } /** * \brief this funciton prints an error message and exits. * \param tv pointer to ThreadVars * \param initdata pointer to the interface passed from the user * \param data pointer gets populated with PfringThreadVars */ TmEcode NoPfringSupportExit(ThreadVars *tv, void *initdata, void **data) { SCLogError(SC_ERR_NO_PF_RING,"Error creating thread %s: you do not have support for pfring " "enabled please recompile with --enable-pfring", tv->name); exit(EXIT_FAILURE); } #else /* implied we do have PF_RING support */ /** protect pfring_set_bpf_filter, as it is not thread safe */ static SCMutex pfring_bpf_set_filter_lock = PTHREAD_MUTEX_INITIALIZER; /* XXX replace with user configurable options */ #define LIBPFRING_PROMISC 1 #define LIBPFRING_REENTRANT 0 #define LIBPFRING_WAIT_FOR_INCOMING 1 /** * \brief Structure to hold thread specific variables. */ typedef struct PfringThreadVars_ { /* thread specific handle */ pfring *pd; /* counters */ uint64_t bytes; uint32_t pkts; uint16_t capture_kernel_packets; uint16_t capture_kernel_drops; ThreadVars *tv; TmSlot *slot; /* threads count */ int threads; #ifdef HAVE_PFRING_CLUSTER_TYPE cluster_type ctype; #endif /* HAVE_PFRING_CLUSTER_TYPE */ uint8_t cluster_id; char *interface; LiveDevice *livedev; #ifdef HAVE_PFRING_SET_BPF_FILTER char *bpf_filter; #endif /* HAVE_PFRING_SET_BPF_FILTER */ ChecksumValidationMode checksum_mode; } PfringThreadVars; /** * \brief Registration Function for RecievePfring. * \todo Unit tests are needed for this module. */ void TmModuleReceivePfringRegister (void) { tmm_modules[TMM_RECEIVEPFRING].name = "ReceivePfring"; tmm_modules[TMM_RECEIVEPFRING].ThreadInit = ReceivePfringThreadInit; tmm_modules[TMM_RECEIVEPFRING].Func = NULL; tmm_modules[TMM_RECEIVEPFRING].PktAcqLoop = ReceivePfringLoop; tmm_modules[TMM_RECEIVEPFRING].ThreadExitPrintStats = ReceivePfringThreadExitStats; tmm_modules[TMM_RECEIVEPFRING].ThreadDeinit = ReceivePfringThreadDeinit; tmm_modules[TMM_RECEIVEPFRING].RegisterTests = NULL; tmm_modules[TMM_RECEIVEPFRING].flags = TM_FLAG_RECEIVE_TM; } /** * \brief Registration Function for DecodePfring. * \todo Unit tests are needed for this module. */ void TmModuleDecodePfringRegister (void) { tmm_modules[TMM_DECODEPFRING].name = "DecodePfring"; tmm_modules[TMM_DECODEPFRING].ThreadInit = DecodePfringThreadInit; tmm_modules[TMM_DECODEPFRING].Func = DecodePfring; tmm_modules[TMM_DECODEPFRING].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEPFRING].ThreadDeinit = NULL; tmm_modules[TMM_DECODEPFRING].RegisterTests = NULL; tmm_modules[TMM_DECODEPFRING].flags = TM_FLAG_DECODE_TM; } static inline void PfringDumpCounters(PfringThreadVars *ptv) { pfring_stat pfring_s; if (likely((pfring_stats(ptv->pd, &pfring_s) >= 0))) { SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, pfring_s.recv); SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, pfring_s.drop); SC_ATOMIC_SET(ptv->livedev->drop, pfring_s.drop); } } /** * \brief Pfring Packet Process function. * * This function fills in our packet structure from libpfring. * From here the packets are picked up by the DecodePfring thread. * * \param user pointer to PfringThreadVars * \param h pointer to pfring packet header * \param p pointer to the current packet */ static inline void PfringProcessPacket(void *user, struct pfring_pkthdr *h, Packet *p) { PfringThreadVars *ptv = (PfringThreadVars *)user; ptv->bytes += h->caplen; ptv->pkts++; (void) SC_ATOMIC_ADD(ptv->livedev->pkts, 1); p->livedev = ptv->livedev; /* PF_RING may fail to set timestamp */ if (h->ts.tv_sec == 0) { gettimeofday((struct timeval *)&h->ts, NULL); } p->ts.tv_sec = h->ts.tv_sec; p->ts.tv_usec = h->ts.tv_usec; /* PF_RING all packets are marked as a link type of ethernet * so that is what we do here. */ p->datalink = LINKTYPE_ETHERNET; switch (ptv->checksum_mode) { case CHECKSUM_VALIDATION_RXONLY: if (h->extended_hdr.rx_direction == 0) { p->flags |= PKT_IGNORE_CHECKSUM; } break; case CHECKSUM_VALIDATION_DISABLE: p->flags |= PKT_IGNORE_CHECKSUM; break; case CHECKSUM_VALIDATION_AUTO: if (ptv->livedev->ignore_checksum) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (ChecksumAutoModeCheck(ptv->pkts, SC_ATOMIC_GET(ptv->livedev->pkts), SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { ptv->livedev->ignore_checksum = 1; p->flags |= PKT_IGNORE_CHECKSUM; } break; default: break; } SET_PKT_LEN(p, h->caplen); } /** * \brief Recieves packets from an interface via libpfring. * * This function recieves packets from an interface and passes * the packet on to the pfring callback function. * * \param tv pointer to ThreadVars * \param data pointer that gets cast into PfringThreadVars for ptv * \param slot slot containing task information * \retval TM_ECODE_OK on success * \retval TM_ECODE_FAILED on failure */ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); uint16_t packet_q_len = 0; PfringThreadVars *ptv = (PfringThreadVars *)data; Packet *p = NULL; struct pfring_pkthdr hdr; TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; struct timeval current_time; ptv->slot = s->slot_next; while(1) { if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCReturnInt(TM_ECODE_FAILED); } PKT_SET_SRC(p, PKT_SRC_WIRE); /* Some flavours of PF_RING may fail to set timestamp - see PF-RING-enabled libpcap code*/ hdr.ts.tv_sec = hdr.ts.tv_usec = 0; /* Depending on what compile time options are used for pfring we either return 0 or -1 on error and always 1 for success */ #ifdef HAVE_PFRING_RECV_UCHAR int r = pfring_recv(ptv->pd, (u_char**)&GET_PKT_DIRECT_DATA(p), (u_int)GET_PKT_DIRECT_MAX_SIZE(p), &hdr, LIBPFRING_WAIT_FOR_INCOMING); #else int r = pfring_recv(ptv->pd, (char *)GET_PKT_DIRECT_DATA(p), (u_int)GET_PKT_DIRECT_MAX_SIZE(p), &hdr, LIBPFRING_WAIT_FOR_INCOMING); #endif /* HAVE_PFRING_RECV_UCHAR */ if (r == 1) { //printf("RecievePfring src %" PRIu32 " sport %" PRIu32 " dst %" PRIu32 " dstport %" PRIu32 "\n", // hdr.parsed_pkt.ipv4_src,hdr.parsed_pkt.l4_src_port, hdr.parsed_pkt.ipv4_dst,hdr.parsed_pkt.l4_dst_port); PfringProcessPacket(ptv, &hdr, p); if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(TM_ECODE_FAILED); } /* Trigger one dump of stats every second */ TimeGet(¤t_time); if (current_time.tv_sec != last_dump) { PfringDumpCounters(ptv); last_dump = current_time.tv_sec; } } else { SCLogError(SC_ERR_PF_RING_RECV,"pfring_recv error %" PRId32 "", r); TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(TM_ECODE_FAILED); } SCPerfSyncCountersIfSignalled(tv, 0); } return TM_ECODE_OK; } /** * \brief Init function for RecievePfring. * * This is a setup function for recieving packets * via libpfring. * * \param tv pointer to ThreadVars * \param initdata pointer to the interface passed from the user * \param data pointer gets populated with PfringThreadVars * \todo add a config option for setting cluster id * \todo Create a general pfring setup function. * \retval TM_ECODE_OK on success * \retval TM_ECODE_FAILED on error */ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) { int rc; u_int32_t version = 0; PfringIfaceConfig *pfconf = (PfringIfaceConfig *) initdata; if (pfconf == NULL) return TM_ECODE_FAILED; PfringThreadVars *ptv = SCMalloc(sizeof(PfringThreadVars)); if (unlikely(ptv == NULL)) { pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } memset(ptv, 0, sizeof(PfringThreadVars)); ptv->tv = tv; ptv->threads = 1; ptv->interface = SCStrdup(pfconf->iface); ptv->livedev = LiveGetDevice(pfconf->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); SCReturnInt(TM_ECODE_FAILED); } #ifdef HAVE_PFRING_OPEN_NEW ptv->pd = pfring_open(ptv->interface, (uint32_t)default_packet_size, PF_RING_REENTRANT | PF_RING_LONG_HEADER | PF_RING_PROMISC); #else ptv->pd = pfring_open(ptv->interface, LIBPFRING_PROMISC, (uint32_t)default_packet_size, LIBPFRING_REENTRANT); #endif if (ptv->pd == NULL) { SCLogError(SC_ERR_PF_RING_OPEN,"opening %s failed: pfring_open error", ptv->interface); pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } else { pfring_set_application_name(ptv->pd, PROG_NAME); pfring_version(ptv->pd, &version); } ptv->checksum_mode = pfconf->checksum_mode; /* We only set cluster info if the number of pfring threads is greater than 1 */ ptv->threads = pfconf->threads; ptv->cluster_id = pfconf->cluster_id; if ((ptv->threads == 1) && (strncmp(ptv->interface, "dna", 3) == 0)) { SCLogInfo("DNA interface detected, not adding thread to cluster"); } else { #ifdef HAVE_PFRING_CLUSTER_TYPE ptv->ctype = pfconf->ctype; rc = pfring_set_cluster(ptv->pd, ptv->cluster_id, ptv->ctype); #else rc = pfring_set_cluster(ptv->pd, ptv->cluster_id); #endif /* HAVE_PFRING_CLUSTER_TYPE */ if (rc != 0) { SCLogError(SC_ERR_PF_RING_SET_CLUSTER_FAILED, "pfring_set_cluster " "returned %d for cluster-id: %d", rc, ptv->cluster_id); pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } } if (ptv->threads > 1) { SCLogInfo("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, ptv->interface, ptv->cluster_id); } else { SCLogInfo("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d, single-pfring-thread", tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, ptv->interface, ptv->cluster_id); } #ifdef HAVE_PFRING_SET_BPF_FILTER if (pfconf->bpf_filter) { ptv->bpf_filter = SCStrdup(pfconf->bpf_filter); SCMutexLock(&pfring_bpf_set_filter_lock); rc = pfring_set_bpf_filter(ptv->pd, ptv->bpf_filter); SCMutexUnlock(&pfring_bpf_set_filter_lock); if (rc < 0) { SCLogInfo("Set PF_RING bpf filter \"%s\" failed.", ptv->bpf_filter); } } #endif /* HAVE_PFRING_SET_BPF_FILTER */ ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", ptv->tv, SC_PERF_TYPE_UINT64, "NULL"); ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", ptv->tv, SC_PERF_TYPE_UINT64, "NULL"); /* It seems that as of 4.7.1 this is required */ #ifdef HAVE_PFRING_ENABLE rc = pfring_enable_ring(ptv->pd); if (rc != 0) { SCLogError(SC_ERR_PF_RING_OPEN, "pfring_enable failed returned %d ", rc); pfconf->DerefFunc(pfconf); return TM_ECODE_FAILED; } #endif /* HAVE_PFRING_ENABLE */ *data = (void *)ptv; pfconf->DerefFunc(pfconf); return TM_ECODE_OK; } /** * \brief This function prints stats to the screen at exit. * \param tv pointer to ThreadVars * \param data pointer that gets cast into PfringThreadVars for ptv */ void ReceivePfringThreadExitStats(ThreadVars *tv, void *data) { PfringThreadVars *ptv = (PfringThreadVars *)data; PfringDumpCounters(ptv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->sc_perf_pca), (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->sc_perf_pca)); SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } /** * \brief DeInit function closes pd at exit. * \param tv pointer to ThreadVars * \param data pointer that gets cast into PfringThreadVars for ptvi * \retval TM_ECODE_OK is always returned */ TmEcode ReceivePfringThreadDeinit(ThreadVars *tv, void *data) { PfringThreadVars *ptv = (PfringThreadVars *)data; if (ptv->interface) SCFree(ptv->interface); pfring_remove_from_cluster(ptv->pd); #ifdef HAVE_PFRING_SET_BPF_FILTER if (ptv->bpf_filter) { pfring_remove_bpf_filter(ptv->pd); SCFree(ptv->bpf_filter); } #endif /* HAVE_PFRING_SET_BPF_FILTER */ pfring_close(ptv->pd); return TM_ECODE_OK; } /** * \brief This function passes off to link type decoders. * * DecodePfring reads packets from the PacketQueue. Inside of libpcap version of * PF_RING all packets are marked as a link type of ethernet so that is what we do here. * * \param tv pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into PfringThreadVars for ptv * \param pq pointer to the current PacketQueue * * \todo Verify that PF_RING only deals with ethernet traffic * * \warning This function bypasses the pkt buf and len macro's * * \retval TM_ECODE_OK is always returned */ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); return TM_ECODE_OK; } /** * \brief This an Init function for DecodePfring * * \param tv pointer to ThreadVars * \param initdata pointer to initilization data. * \param data pointer that gets cast into PfringThreadVars for ptv * \retval TM_ECODE_OK is returned on success * \retval TM_ECODE_FAILED is returned on error */ TmEcode DecodePfringThreadInit(ThreadVars *tv, void *initdata, void **data) { DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if (dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; return TM_ECODE_OK; } #endif /* HAVE_PFRING */ /* eof */ suricata-1.4.7/src/util-checksum.h0000644000000000000000000000215612253546156013757 00000000000000/* Copyright (C) 2011-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #ifndef __UTIL_CHECKSUM_H__ #define __UTIL_CHECKSUM_H__ int ReCalculateChecksum(Packet *p); int ChecksumAutoModeCheck(uint32_t thread_count, unsigned int iface_count, unsigned int iface_fail); /* constant linked with detection of interface with * invalid checksums */ #define CHECKSUM_SAMPLE_COUNT 1000 #define CHECKSUM_INVALID_RATIO 10 #endif suricata-1.4.7/src/reputation.c0000644000000000000000000016254312253546156013376 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * \author Victor Julien * Original Idea by Matt Jonkman * * IP Reputation Module, initial API for IPV4 and IPV6 feed */ #include "util-error.h" #include "util-debug.h" #include "util-radix-tree.h" #include "util-host-os-info.h" #include "util-unittest.h" #include "suricata-common.h" #include "threads.h" #include "util-print.h" #include "host.h" #include "conf.h" #include "detect.h" #include "reputation.h" /** effective reputation version, atomic as the host * time out code will use it to check if a host's * reputation info is outdated. */ SC_ATOMIC_DECLARE(uint32_t, srep_eversion); /** reputation version set to the host's reputation, * this will be set to 1 before rep files are loaded, * so hosts will always have a minial value of 1 */ static uint32_t srep_version = 0; static uint32_t SRepIncrVersion(void) { return ++srep_version; } static uint32_t SRepGetVersion(void) { return srep_version; } static uint32_t SRepGetEffectiveVersion(void) { return SC_ATOMIC_GET(srep_eversion); } /** \brief Increment effective reputation version after * a rule/reputatio reload is complete. */ void SRepReloadComplete(void) { (void) SC_ATOMIC_ADD(srep_eversion, 1); SCLogDebug("effective Reputation version %u", SRepGetEffectiveVersion()); } /** \brief Set effective reputation version after * reputation initialization is complete. */ void SRepInitComplete(void) { (void) SC_ATOMIC_SET(srep_eversion, 1); SCLogDebug("effective Reputation version %u", SRepGetEffectiveVersion()); } /** \brief Check if a Host is timed out wrt ip rep, meaning a new * version is in place. * * We clean up the old version here. * * \param h host * * \retval 0 not timed out * \retval 1 timed out */ int SRepHostTimedOut(Host *h) { BUG_ON(h == NULL); if (h->iprep == NULL) return 1; uint32_t eversion = SRepGetEffectiveVersion(); SReputation *r = h->iprep; if (r->version < eversion) { SCLogDebug("host %p has reputation version %u, " "effective version is %u", h, r->version, eversion); SCFree(h->iprep); h->iprep = NULL; HostDecrUsecnt(h); return 1; } return 0; } static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t shortname_len) { size_t line_len = strlen(line); char *ptrs[2] = {NULL,NULL}; int i = 0; int idx = 0; char *origline = line; while (i < (int)line_len) { if (line[i] == ',' || line[i] == '\n' || line[i] == '\0' || i == (int)(line_len - 1)) { line[i] = '\0'; ptrs[idx] = line; idx++; line += (i+1); i = 0; if (line >= origline + line_len) break; if (strlen(line) == 0) break; if (idx == 2) break; } else { i++; } } if (idx != 2) { return -1; } SCLogDebug("%s, %s", ptrs[0], ptrs[1]); int c = atoi(ptrs[0]); if (c < 0 || c >= SREP_MAX_CATS) { return -1; } *cat = (uint8_t)c; strlcpy(shortname, ptrs[1], shortname_len); return 0; } /** * \retval 0 valid * \retval 1 header * \retval -1 boo */ static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) { size_t line_len = strlen(line); char *ptrs[3] = {NULL,NULL,NULL}; int i = 0; int idx = 0; char *origline = line; while (i < (int)line_len) { if (line[i] == ',' || line[i] == '\n' || line[i] == '\0' || i == (int)(line_len - 1)) { line[i] = '\0'; ptrs[idx] = line; idx++; line += (i+1); i = 0; if (line >= origline + line_len) break; if (strlen(line) == 0) break; if (idx == 3) break; } else { i++; } } if (idx != 3) { return -1; } //SCLogInfo("%s, %s, %s", ptrs[0], ptrs[1], ptrs[2]); if (strcmp(ptrs[0], "ip") == 0) return 1; uint32_t addr; if (inet_pton(AF_INET, ptrs[0], &addr) <= 0) { return -1; } int c = atoi(ptrs[1]); if (c < 0 || c >= SREP_MAX_CATS) { return -1; } int v = atoi(ptrs[2]); if (v < 0 || v > 127) { return -1; } *ip = addr; *cat = c; *value = v; return 0; } #define SREP_SHORTNAME_LEN 32 static char srep_cat_table[SREP_MAX_CATS][SREP_SHORTNAME_LEN]; int SRepCatValid(uint8_t cat) { if (cat >= SREP_MAX_CATS) return 0; if (strlen(srep_cat_table[cat]) == 0) return 0; return 1; } uint8_t SRepCatGetByShortname(char *shortname) { uint8_t cat; for (cat = 0; cat < SREP_MAX_CATS; cat++) { if (strcmp(srep_cat_table[cat], shortname) == 0) return cat; } return 0; } int SRepLoadCatFile(char *filename) { char line[8192] = ""; Address a; memset(&a, 0x00, sizeof(a)); a.family = AF_INET; memset(&srep_cat_table, 0x00, sizeof(srep_cat_table)); BUG_ON(SRepGetVersion() > 0); FILE *fp = fopen(filename, "r"); if (fp == NULL) { SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); return -1; } while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) continue; /* ignore comments and empty lines */ if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') continue; while (isspace((unsigned char)line[--len])); /* Check if we have a trailing newline, and remove it */ len = strlen(line); if (len == 0) continue; if (line[len - 1] == '\n' || line[len - 1] == '\r') { line[len - 1] = '\0'; } uint8_t cat = 0; char shortname[SREP_SHORTNAME_LEN]; if (SRepCatSplitLine(line, &cat, shortname, sizeof(shortname)) == 0) { strlcpy(srep_cat_table[cat], shortname, SREP_SHORTNAME_LEN); } else { SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } } fclose(fp); fp = NULL; SCLogDebug("IP Rep categories:"); int i; for (i = 0; i < SREP_MAX_CATS; i++) { if (strlen(srep_cat_table[i]) == 0) continue; SCLogDebug("CAT %d, name %s", i, srep_cat_table[i]); } return 0; } static int SRepLoadFile(char *filename) { char line[8192] = ""; Address a; memset(&a, 0x00, sizeof(a)); a.family = AF_INET; FILE *fp = fopen(filename, "r"); if (fp == NULL) { SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file \"%s\": %s", filename, strerror(errno)); return -1; } while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) continue; /* ignore comments and empty lines */ if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') continue; while (isspace((unsigned char)line[--len])); /* Check if we have a trailing newline, and remove it */ len = strlen(line); if (len == 0) continue; if (line[len - 1] == '\n' || line[len - 1] == '\r') { line[len - 1] = '\0'; } uint32_t ip = 0; uint8_t cat = 0, value = 0; int r = SRepSplitLine(line, &ip, &cat, &value); if (r < 0) { SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } else if (r == 0) { char ipstr[16]; PrintInet(AF_INET, (const void *)&ip, ipstr, sizeof(ipstr)); SCLogDebug("%s %u %u", ipstr, cat, value); a.addr_data32[0] = ip; Host *h = HostGetHostFromHash(&a); if (h == NULL) { SCLogError(SC_ERR_NO_REPUTATION, "failed to get a host, increase host.memcap"); break; } else { //SCLogInfo("host %p", h); if (h->iprep == NULL) { h->iprep = SCMalloc(sizeof(SReputation)); if (h->iprep != NULL) { memset(h->iprep, 0x00, sizeof(SReputation)); HostIncrUsecnt(h); } } if (h->iprep != NULL) { SReputation *rep = h->iprep; /* if version is outdated, it's an older entry that we'll * now replace. */ if (rep->version != SRepGetVersion()) { memset(rep, 0x00, sizeof(SReputation)); } rep->version = SRepGetVersion(); rep->rep[cat] = value; SCLogDebug("host %p iprep %p setting cat %u to value %u", h, h->iprep, cat, value); #ifdef DEBUG if (SCLogDebugEnabled()) { int i; for (i = 0; i < SREP_MAX_CATS; i++) { if (rep->rep[i] == 0) continue; SCLogDebug("--> host %p iprep %p cat %d to value %u", h, h->iprep, i, rep->rep[i]); } } #endif } HostRelease(h); } } } fclose(fp); fp = NULL; return 0; } /** * \brief Create the path if default-rule-path was specified * \param sig_file The name of the file * \retval str Pointer to the string path + sig_file */ static char *SRepCompleteFilePath(char *file) { char *defaultpath = NULL; char *path = NULL; /* Path not specified */ if (PathIsRelative(file)) { if (ConfGet("default-reputation-path", &defaultpath) == 1) { SCLogDebug("Default path: %s", defaultpath); size_t path_len = sizeof(char) * (strlen(defaultpath) + strlen(file) + 2); path = SCMalloc(path_len); if (unlikely(path == NULL)) return NULL; strlcpy(path, defaultpath, path_len); #if defined OS_WIN32 || defined __CYGWIN__ if (path[strlen(path) - 1] != '\\') strlcat(path, "\\\\", path_len); #else if (path[strlen(path) - 1] != '/') strlcat(path, "/", path_len); #endif strlcat(path, file, path_len); } else { path = SCStrdup(file); if (unlikely(path == NULL)) return NULL; } } else { path = SCStrdup(file); if (unlikely(path == NULL)) return NULL; } return path; } /** \brief init reputation * * \param de_ctx detection engine ctx for tracking iprep version * * \retval 0 ok * \retval -1 error * * If this function is called more than once, the category file * is not reloaded. */ int SRepInit(DetectEngineCtx *de_ctx) { ConfNode *files; ConfNode *file = NULL; int r = 0; char *sfile = NULL; char *filename = NULL; int init = 0; if (SRepGetVersion() == 0) { SC_ATOMIC_INIT(srep_eversion); init = 1; } /* if both settings are missing, we assume the user doesn't want ip rep */ (void)ConfGet("reputation-categories-file", &filename); files = ConfGetNode("reputation-files"); if (filename == NULL && files == NULL) { SCLogInfo("IP reputation disabled"); return 0; } if (files == NULL) { SCLogError(SC_ERR_NO_REPUTATION, "\"reputation-files\" not set"); return -1; } if (init) { if (filename == NULL) { SCLogError(SC_ERR_NO_REPUTATION, "\"reputation-categories-file\" not set"); return -1; } /* init even if we have reputation files, so that when we * have a live reload, we have inited the cats */ if (SRepLoadCatFile(filename) < 0) { SCLogError(SC_ERR_NO_REPUTATION, "failed to load reputation " "categories file %s", filename); return -1; } } de_ctx->srep_version = SRepIncrVersion(); SCLogDebug("Reputation version %u", de_ctx->srep_version); /* ok, let's load signature files from the general config */ if (files != NULL) { TAILQ_FOREACH(file, &files->head, next) { sfile = SRepCompleteFilePath(file->val); SCLogInfo("Loading reputation file: %s", sfile); r = SRepLoadFile(sfile); if (r < 0){ if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); } } SCFree(sfile); } } /* Set effective rep version. * On live reload we will handle this after de_ctx has been swapped */ if (init) { SRepInitComplete(); } HostPrintStats(); return 0; } #ifdef UNITTESTS static int SRepTest01(void) { char str[] = "1.2.3.4,1,2"; uint32_t ip = 0; uint8_t cat = 0, value = 0; if (SRepSplitLine(str, &ip, &cat, &value) != 0) { return 0; } char ipstr[16]; PrintInet(AF_INET, (const void *)&ip, ipstr, sizeof(ipstr)); if (strcmp(ipstr, "1.2.3.4") != 0) return 0; if (cat != 1) return 0; if (value != 2) return 0; return 1; } static int SRepTest02(void) { char str[] = "1.1.1.1,"; uint32_t ip = 0; uint8_t cat = 0, value = 0; if (SRepSplitLine(str, &ip, &cat, &value) == 0) { return 0; } return 1; } static int SRepTest03(void) { char str[] = "1,Shortname,Long Name"; uint8_t cat = 0; char shortname[SREP_SHORTNAME_LEN]; if (SRepCatSplitLine(str, &cat, shortname, sizeof(shortname)) != 0) { printf("split failed: "); return 0; } if (strcmp(shortname, "Shortname") != 0) { printf("%s != Shortname: ", shortname); return 0; } if (cat != 1) { printf("cat 1 != %u: ", cat); return 0; } return 1; } #endif /** Global trees that hold host reputation for IPV4 and IPV6 hosts */ IPReputationCtx *rep_ctx; /** * \brief Initialization fuction for the Reputation Context (IPV4 and IPV6) * * \retval Pointer to the IPReputationCtx created * NULL Error initializing moule; */ IPReputationCtx *SCReputationInitCtx(void) { rep_ctx = (IPReputationCtx *)SCMalloc(sizeof(IPReputationCtx)); if (rep_ctx == NULL) return NULL; memset(rep_ctx,0,sizeof(IPReputationCtx)); rep_ctx->reputationIPV4_tree = SCRadixCreateRadixTree(SCReputationFreeData, NULL); if (rep_ctx->reputationIPV4_tree == NULL) { SCLogDebug("Error initializing Reputation IPV4 module"); return NULL; } SCLogDebug("Reputation IPV4 module initialized"); rep_ctx->reputationIPV6_tree = SCRadixCreateRadixTree(SCReputationFreeData, NULL); if (rep_ctx->reputationIPV6_tree == NULL) { SCLogDebug("Error initializing Reputation IPV6 module"); return NULL; } SCLogDebug("Reputation IPV6 module initialized"); if (SCMutexInit(&rep_ctx->reputationIPV4_lock, NULL) != 0) { SCLogError(SC_ERR_MUTEX, "Mutex not correctly initialized"); exit(EXIT_FAILURE); } if (SCMutexInit(&rep_ctx->reputationIPV6_lock, NULL) != 0) { SCLogError(SC_ERR_MUTEX, "Mutex not correctly initialized"); exit(EXIT_FAILURE); } return rep_ctx; } /** * \brief Allocates the Reputation structure for a host/netblock * * \retval rep_data On success, pointer to the rep_data that has to be sent * along with the key, to be added to the Radix tree */ Reputation *SCReputationAllocData(void) { Reputation *rep_data = NULL; if ( (rep_data = SCMalloc(sizeof(Reputation))) == NULL) return NULL; memset(rep_data,0, sizeof(Reputation)); rep_data->ctime = time(NULL); rep_data->mtime= time(NULL); return rep_data; } /** * \brief Used to SCFree the reputation data that is allocated by Reputation API * * \param Pointer to the data that has to be SCFreed */ void SCReputationFreeData(void *data) { if (data != NULL) SCFree(data); return; } /** * \brief Allocates the Reputation structure for a host/netblock * * \retval ReputationTransaction pointer On success */ ReputationTransaction *SCReputationTransactionAlloc(void) { ReputationTransaction *rtx = NULL; if ( (rtx = SCMalloc(sizeof(ReputationTransaction))) == NULL) return NULL; memset(rtx, 0, sizeof(ReputationTransaction)); return rtx; } /** * \brief Used to SCFree the transaction data * * \param Pointer to the data that has to be SCFreed */ void SCReputationTransactionFreeData(void *data) { if (data != NULL) SCFree(data); return; } /** * \brief Apply the transaction of changes to the reputation * We use transactions because we cant be locking/unlocking the * trees foreach update. This help for a better performance * * \param rep_data pointer to the reputation to update * \param rtx pointer to the transaction data */ void SCReputationApplyTransaction(Reputation *rep_data, ReputationTransaction *rtx) { int i = 0; /* No modification needed */ if ( !(rtx->flags & TRANSACTION_FLAG_NEEDSYNC)) return; /* Here we should apply a formula, a threshold or similar, * maybe values loaded from config */ for (; i < REPUTATION_NUMBER; i++) { if (rtx->flags & TRANSACTION_FLAG_INCS) { if (rep_data->reps[i] + rtx->inc[i] < 255) rep_data->reps[i] += rtx->inc[i]; else rep_data->reps[i] = 255; } if (rtx->flags & TRANSACTION_FLAG_DECS) { if (rep_data->reps[i] - rtx->dec[i] > 0) rep_data->reps[i] -= rtx->dec[i]; else rep_data->reps[i] = 0; } } rep_data->mtime = time(NULL); rep_data->flags |= REPUTATION_FLAG_NEEDSYNC; } /** * \brief Function that compare two reputation structs to determine if they are equal * * \param rep1 pointer to reputation 1 * \param rep2 pointer to reputation 2 * * \retval 1 if they are equal; 0 if not */ int SCReputationEqual(Reputation *rep1, Reputation *rep2) { return (memcmp(rep1->reps, rep2->reps, REPUTATION_NUMBER * sizeof(uint8_t)) == 0)? 1 : 0; } /** * \brief Helper function to print the Reputation structure * * \param Pointer rep_data to a Reputation structure */ void SCReputationPrint(Reputation *rep_data) { if (rep_data == NULL) { printf("No Reputation Data!\n"); return; } int i = 0; for (; i < REPUTATION_NUMBER; i++) printf("Rep_type %d = %d\n", i, rep_data->reps[i]); if (rep_data->flags & REPUTATION_FLAG_NEEDSYNC) printf("REPUTATION_FLAG_NEEDSYNC = 1\n"); } /** * \brief Clone all the data of a reputation * When you try to update the feed, if the data you have belongs * to a netblock, it will be cloned and inserted or a host, with * the modifications that you add * * \param orig Pointer to the original reputation (probably of a netblock) * * \retval Reputation Pointer to the reputation copy */ Reputation *SCReputationClone(Reputation *orig) { Reputation *rep = NULL; if (orig == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid arguments"); return NULL; } if ( (rep = SCMalloc(sizeof(Reputation))) == NULL) return NULL; memcpy(rep, orig, sizeof(Reputation)); return rep; } void SCReputationFreeCtx(IPReputationCtx *rep_ctx) { if (rep_ctx->reputationIPV4_tree != NULL) { SCRadixReleaseRadixTree(rep_ctx->reputationIPV4_tree); rep_ctx->reputationIPV4_tree = NULL; SCMutexDestroy(&rep_ctx->reputationIPV4_lock); } if (rep_ctx->reputationIPV6_tree != NULL) { SCRadixReleaseRadixTree(rep_ctx->reputationIPV6_tree); rep_ctx->reputationIPV6_tree = NULL; SCMutexDestroy(&rep_ctx->reputationIPV6_lock); } } /** * \brief Used to add a new reputation to the reputation module (only at the startup) * * \param ipv4addr pointer to the ipv4 address key * \param netmask_value of the ipv4 address (can be a subnet or a host (32)) * \param rep_data Reputation pointer to the Reputation associated to the host/net * * \retval NULL On failure; rep_data on success */ Reputation *SCReputationAddIPV4Data(uint8_t *ipv4addr, int netmask_value, Reputation *rep_data) { struct in_addr *ipv4_addr = (struct in_addr *) ipv4addr; if (ipv4_addr == NULL || rep_data == NULL || rep_ctx == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid arguments"); return NULL; } /* If the reputation tree is not initialized yet */ if (rep_ctx->reputationIPV4_tree == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Reputation trees not initialized"); return NULL; } if (netmask_value == 32) { /* Be careful with the mutex */ SCMutexLock(&rep_ctx->reputationIPV4_lock); SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, rep_ctx->reputationIPV4_tree, (void *)rep_data); SCMutexUnlock(&rep_ctx->reputationIPV4_lock); } else { if (netmask_value < 0 || netmask_value > 31) { SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Invalid IPV4 Netblock"); return NULL; } SCRadixChopIPAddressAgainstNetmask((uint8_t *)ipv4_addr, netmask_value, 32); /* Be careful with the mutex */ SCMutexLock(&rep_ctx->reputationIPV4_lock); SCRadixAddKeyIPV4Netblock((uint8_t *)ipv4_addr, rep_ctx->reputationIPV4_tree, (void *)rep_data, netmask_value); SCMutexUnlock(&rep_ctx->reputationIPV4_lock); } return rep_data; } /** * \brief Retrieves the Reputation of a host (exact match), given an ipv4 address in the raw * address format. * * \param ipv4_addr Pointer to a raw ipv4 address. * * \retval Pointer to a copy of the host Reputation on success; * NULL on failure, or on not finding the key; */ Reputation *SCReputationLookupIPV4ExactMatch(uint8_t *ipv4_addr) { Reputation *rep_data; /* Be careful with this (locking)*/ SCMutexLock(&rep_ctx->reputationIPV4_lock); SCRadixNode *node = SCRadixFindKeyIPV4ExactMatch(ipv4_addr, rep_ctx->reputationIPV4_tree); if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { rep_data = NULL; } else { /* Yes, we clone it because the pointer can be outdated * while another thread remove this reputation */ rep_data = SCReputationClone((Reputation *)node->prefix->user_data_result); } SCMutexUnlock(&rep_ctx->reputationIPV4_lock); return rep_data; } /** * \brief Retrieves the Reputation of a host (best match), given an ipv4 address in the raw * address format. * * \param ipv4_addr Pointer to a raw ipv4 address. * * \retval Pointer to a copy of the host Reputation on success; * NULL on failure, or on not finding the key; */ Reputation *SCReputationLookupIPV4BestMatch(uint8_t *ipv4_addr) { Reputation *rep_data; /* Be careful with this (locking)*/ SCMutexLock(&rep_ctx->reputationIPV4_lock); SCRadixNode *node = SCRadixFindKeyIPV4BestMatch(ipv4_addr, rep_ctx->reputationIPV4_tree); if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { rep_data = NULL; } else { /* Yes, we clone it because the pointer can be outdated * while another thread remove this reputation */ rep_data = SCReputationClone((Reputation *)node->prefix->user_data_result); } SCMutexUnlock(&rep_ctx->reputationIPV4_lock); return rep_data; } /** * \brief Retrieves the Reputation of a host (best match), given an ipv6 address in the raw * address format. * * \param Pointer to a raw ipv6 address. * * \retval Pointer to a copy of the host Reputation on success; * NULL on failure, or on not finding the key; */ Reputation *SCReputationLookupIPV6BestMatch(uint8_t *ipv6_addr) { Reputation *rep_data; /* Be careful with this (locking)*/ SCMutexLock(&rep_ctx->reputationIPV6_lock); SCRadixNode *node = SCRadixFindKeyIPV6BestMatch(ipv6_addr, rep_ctx->reputationIPV6_tree); if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { rep_data = NULL; } else { /* Yes, we clone it because the pointer can be outdated * while another thread remove this reputation */ rep_data = SCReputationClone((Reputation *)node->prefix->user_data_result); } SCMutexUnlock(&rep_ctx->reputationIPV6_lock); return rep_data; } /** * \brief Retrieves the Reputation of a host (exact match), given an ipv6 address in the raw * address format. * * \param Pointer to a raw ipv6 address. * * \retval Pointer to a copy of the host reputation on success; * NULL on failure, or on not finding the key; */ Reputation *SCReputationLookupIPV6ExactMatch(uint8_t *ipv6_addr) { Reputation *rep_data; /* Be careful with this (locking)*/ SCMutexLock(&rep_ctx->reputationIPV6_lock); SCRadixNode *node = SCRadixFindKeyIPV6ExactMatch(ipv6_addr, rep_ctx->reputationIPV6_tree); if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { rep_data = NULL; } else { /* Yes, we clone it because the pointer can be outdated * while another thread remove this reputation */ rep_data = SCReputationClone((Reputation *)node->prefix->user_data_result); } SCMutexUnlock(&rep_ctx->reputationIPV6_lock); return rep_data; } /** * \brief Retrieves the Real Reputation of a host (exact match), given an ipv4 address in the raw * address format. (Not thread safe!) * * \param ipv4_addr Pointer to a raw ipv4 address. * * \retval Pointer to the Reputation of the host on success; * NULL on failure, or on not finding the key; */ Reputation *SCReputationLookupIPV4ExactMatchReal(uint8_t *ipv4_addr) { SCRadixNode *node = SCRadixFindKeyIPV4ExactMatch(ipv4_addr, rep_ctx->reputationIPV4_tree); if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { return NULL; } else { return (Reputation *)node->prefix->user_data_result; } } /** * \brief Retrieves the Real Reputation of a host (best match), given an ipv4 address in the raw * address format. (Not thread safe!) * * \param ipv4_addr Pointer to a raw ipv4 address. * * \retval Pointer to the Reputation of the host on success; * NULL on failure, or on not finding the key; */ Reputation *SCReputationLookupIPV4BestMatchReal(uint8_t *ipv4_addr) { SCRadixNode *node = SCRadixFindKeyIPV4BestMatch(ipv4_addr, rep_ctx->reputationIPV4_tree); if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { return NULL; } else { return (Reputation *)node->prefix->user_data_result; } } /** * \brief Retrieves the Real Reputation of a host (best match), given an ipv6 address in the raw * address format. (Not thread safe!) * * \param Pointer to a raw ipv6 address. * * \retval Pointer to the Reputation of the host on success; * NULL on failure, or on not finding the key; */ Reputation *SCReputationLookupIPV6BestMatchReal(uint8_t *ipv6_addr) { SCRadixNode *node = SCRadixFindKeyIPV6BestMatch(ipv6_addr, rep_ctx->reputationIPV6_tree); if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { return NULL; } else { return (Reputation *)node->prefix->user_data_result; } } /** * \brief Retrieves the Real Reputation of a host (exact match), given an ipv6 address in the raw * address format. (Not thread safe!) * * \param Pointer to a raw ipv6 address. * * \retval Pointer to the Reputation of the host on success; * NULL on failure, or on not finding the key; */ Reputation *SCReputationLookupIPV6ExactMatchReal(uint8_t *ipv6_addr) { SCRadixNode *node = SCRadixFindKeyIPV6ExactMatch(ipv6_addr, rep_ctx->reputationIPV6_tree); if (node == NULL || node->prefix == NULL || node->prefix->user_data_result == NULL) { return NULL; } else { return (Reputation *)node->prefix->user_data_result; } } /** * \brief Remove the node of the reputation tree associated to the ipv4 address * * \param ipv4_addr Pointer to a raw ipv4 address * \param netmask_value netmask to apply to the address (32 for host) * */ void SCReputationRemoveIPV4Data(uint8_t * ipv4_addr, uint8_t netmask_value) { SCMutexLock(&rep_ctx->reputationIPV4_lock); SCRadixRemoveKeyIPV4Netblock(ipv4_addr, rep_ctx->reputationIPV4_tree, netmask_value); SCMutexUnlock(&rep_ctx->reputationIPV4_lock); } /** * \brief Remove the node of the reputation tree associated to the ipv6 address * * \param ipv6_addr Pointer to a raw ipv6 address * \param netmask_value netmask to apply to the address (128 for host) * */ void SCReputationRemoveIPV6Data(uint8_t * ipv6_addr, uint8_t netmask_value) { SCMutexLock(&rep_ctx->reputationIPV6_lock); SCRadixRemoveKeyIPV6Netblock(ipv6_addr, rep_ctx->reputationIPV6_tree, netmask_value); SCMutexUnlock(&rep_ctx->reputationIPV6_lock); } /** * \brief Used to add a new reputation to the reputation module (only at the startup) * * \param ipv6addr pointer to the ipv6 address key * \param netmask_value of the ipv6 address (can be a subnet) * \param rep_data Reputation pointer to the Reputation associated to the host/net * * \retval NULL On failure */ Reputation *SCReputationAddIPV6Data(uint8_t *ipv6addr, int netmask_value, Reputation *rep_data) { struct in_addr *ipv6_addr = (struct in_addr *) ipv6addr; if (ipv6_addr == NULL || rep_data == NULL || rep_ctx == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid arguments"); return NULL; } /* If the reputation tree is not initialized yet */ if (rep_ctx->reputationIPV6_tree == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Reputation trees not initialized"); return NULL; } if (netmask_value == 128) { /* Be careful with the mutex */ SCMutexLock(&rep_ctx->reputationIPV6_lock); SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, rep_ctx->reputationIPV6_tree, (void *)rep_data); SCMutexUnlock(&rep_ctx->reputationIPV6_lock); } else { if (netmask_value < 0 || netmask_value > 127) { SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Invalid IPV6 Netblock"); return NULL; } SCRadixChopIPAddressAgainstNetmask((uint8_t *)ipv6_addr, netmask_value, 128); /* Be careful with the mutex */ SCMutexLock(&rep_ctx->reputationIPV6_lock); SCRadixAddKeyIPV6Netblock((uint8_t *)ipv6_addr, rep_ctx->reputationIPV6_tree, (void *)rep_data, netmask_value); SCMutexUnlock(&rep_ctx->reputationIPV6_lock); } return rep_data; } /** * \brief Update a reputation or insert a new one. If it doesn't exist * it will try to search for the reputation of parent subnets to * create the new reputation data based on this one * * \param ipv6addr pointer to the ipv6 address key * \param rep_data Reputation pointer to the Reputation associated to the host/net * * \retval NULL On failure */ Reputation *SCReputationUpdateIPV4Data(uint8_t *ipv4addr, ReputationTransaction *rtx) { struct in_addr *ipv4_addr = (struct in_addr *) ipv4addr; Reputation *actual_rep; if (ipv4_addr == NULL || rtx == NULL || rep_ctx == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid arguments"); return NULL; } /* If the reputation tree is not initialized yet */ if (rep_ctx->reputationIPV4_tree == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Reputation trees not initialized"); return NULL; } /* Be careful with the mutex */ SCMutexLock(&rep_ctx->reputationIPV4_lock); /* Search exact match and update */ actual_rep = SCReputationLookupIPV4ExactMatchReal(ipv4addr); if (actual_rep == NULL) { /* else search best match (parent subnets) */ actual_rep =SCReputationLookupIPV4BestMatchReal(ipv4addr); if (actual_rep != NULL) { /* clone from parent and insert host */ actual_rep = SCReputationClone(actual_rep); } else { /* else insert a new reputation data for the host */ actual_rep = SCReputationAllocData(); /* If new, we only increment values */ rtx->flags = TRANSACTION_FLAG_INCS; rtx->flags |= TRANSACTION_FLAG_NEEDSYNC; } /* insert the reputation data in the tree */ SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, rep_ctx->reputationIPV4_tree, (void *)actual_rep); } /* Apply updates */ SCReputationApplyTransaction(actual_rep, rtx); /* Unlock! */ SCMutexUnlock(&rep_ctx->reputationIPV4_lock); return actual_rep; } /** * \brief Update a reputation or insert a new one. If it doesn't exist * it will try to search for the reputation of parent subnets to * create the new reputation data based on this one * * \param ipv6addr pointer to the ipv6 address key * \param rep_data Reputation pointer to the Reputation associated to the host/net * * \retval NULL On failure */ Reputation *SCReputationUpdateIPV6Data(uint8_t *ipv6addr, ReputationTransaction *rtx) { struct in_addr *ipv6_addr = (struct in_addr *) ipv6addr; Reputation *actual_rep; if (ipv6_addr == NULL || rtx == NULL || rep_ctx == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid arguments"); return NULL; } /* If the reputation tree is not initialized yet */ if (rep_ctx->reputationIPV6_tree == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Reputation trees not initialized"); return NULL; } /* Be careful with the mutex */ SCMutexLock(&rep_ctx->reputationIPV6_lock); /* Search exact match and update */ actual_rep = SCReputationLookupIPV6ExactMatchReal(ipv6addr); if (actual_rep == NULL) { /* else search best match (parent subnets) */ actual_rep =SCReputationLookupIPV6BestMatchReal(ipv6addr); if (actual_rep != NULL) { /* clone from parent and insert host */ actual_rep = SCReputationClone(actual_rep); } else { /* else insert a new reputation data for the host */ actual_rep = SCReputationAllocData(); /* If new, we only increment values */ rtx->flags = TRANSACTION_FLAG_INCS; rtx->flags |= TRANSACTION_FLAG_NEEDSYNC; } /* insert the reputation data in the tree */ SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, rep_ctx->reputationIPV6_tree, (void *)actual_rep); } /* Apply updates */ SCReputationApplyTransaction(actual_rep, rtx); /* Unlock! */ SCMutexUnlock(&rep_ctx->reputationIPV6_lock); return actual_rep; } /* ----------------- UNITTESTS-------------------- */ #ifdef UNITTESTS /** * \test Adding (from numeric ipv4) and removing host reputation in the Reputation context * tree. THe reputation data is the real one, no copies here. */ int SCReputationTestIPV4AddRemoveHost01(void) { int i = 0; struct in_addr in; SCReputationInitCtx(); if (rep_ctx == NULL) { SCLogInfo("Error initializing Reputation Module"); return 0; } Reputation *rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.6", &in) < 0) goto error; /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 6; rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); if (rep_orig == NULL) goto error; Reputation *rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_orig) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 7; rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); if (rep_orig == NULL) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_orig) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 7; rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 31, rep_orig); if (rep_orig == NULL) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); /* It should return the host info and not the subnet info */ if (rep_data == NULL || rep_data == rep_orig) goto error; if (inet_pton(AF_INET, "192.168.1.8", &in) < 0) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); /* It should return the host info and not the subnet info */ if (rep_data != NULL) goto error; /* Removing */ if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) goto error; SCReputationRemoveIPV4Data((uint8_t *) &in, 32); rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; if (inet_pton(AF_INET, "192.168.1.6", &in) < 0) goto error; SCReputationRemoveIPV4Data((uint8_t *) &in, 32); rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; SCRadixPrintTree(rep_ctx->reputationIPV4_tree); SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 1; error: SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 0; } /** * \test Adding (from numeric ipv6) and removing host reputation in the Reputation context * tree. THe reputation data is the real one, no copies here. */ int SCReputationTestIPV6AddRemoveHost01(void) { uint8_t in[16]; uint8_t i = 0; SCReputationInitCtx(); if (rep_ctx == NULL) { SCLogInfo("Error initializing Reputation Module"); return 0; } if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2362", &in) < 0) goto error; Reputation *rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 1; rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 128, rep_orig); if (rep_orig == NULL) goto error; Reputation *rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_orig) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 8; rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 128, rep_orig); if (rep_orig == NULL) goto error; rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_orig) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 7; rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 127, rep_orig); if (rep_orig == NULL) goto error; rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); /* It should return the host info and not the subnet info */ if (rep_data == NULL || rep_data == rep_orig) goto error; /* Removing */ if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) goto error; SCReputationRemoveIPV6Data((uint8_t *) &in, 128); rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2362", &in) < 0) goto error; SCReputationRemoveIPV6Data((uint8_t *) &in, 128); rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; SCRadixPrintTree(rep_ctx->reputationIPV6_tree); SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 1; error: SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 0; } /** * \test Adding (from numeric ipv4) and retrieving reputations * tree. The reputation data retireved are copies of the original. */ int SCReputationTestIPV4AddRemoveHost02(void) { int i = 0; struct in_addr in; SCReputationInitCtx(); if (rep_ctx == NULL) { SCLogInfo("Error initializing Reputation Module"); return 0; } Reputation *rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.6", &in) < 0) goto error; /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 6; rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); if (rep_orig == NULL) goto error; Reputation *rep_data = SCReputationLookupIPV4ExactMatch((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 0) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 7; rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); if (rep_orig == NULL) goto error; rep_data = SCReputationLookupIPV4ExactMatch((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 0) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.7", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 9; rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 31, rep_orig); if (rep_orig == NULL) goto error; rep_data = SCReputationLookupIPV4ExactMatch((uint8_t *) &in); /* It should return the host info and not the subnet info */ if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 1) goto error; SCRadixPrintTree(rep_ctx->reputationIPV4_tree); SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 1; error: SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 0; } /** * \test Adding (from numeric ipv6) and removing host reputation in the Reputation context * tree. The reputation data retireved are copies of the original. */ int SCReputationTestIPV6AddRemoveHost02(void) { int i = 0; uint8_t in[16]; SCReputationInitCtx(); if (rep_ctx == NULL) { SCLogInfo("Error initializing Reputation Module"); return 0; } Reputation *rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2362", &in) < 0) goto error; /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 6; rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 128, rep_orig); if (rep_orig == NULL) goto error; Reputation *rep_data = SCReputationLookupIPV6ExactMatch((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 0) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 7; rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 128, rep_orig); if (rep_orig == NULL) goto error; rep_data = SCReputationLookupIPV6ExactMatch((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 0) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2363", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 9; rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 127, rep_orig); if (rep_orig == NULL) goto error; rep_data = SCReputationLookupIPV6ExactMatch((uint8_t *) &in); /* It should return the host info and not the subnet info */ if (rep_data == NULL || SCReputationEqual(rep_data, rep_orig) == 1) goto error; if (inet_pton(AF_INET6, "aaaa:bbbb:cccc:dddd:1223:1722:3425:2364", &in) < 0) goto error; rep_data = SCReputationLookupIPV6ExactMatch((uint8_t *) &in); /* It should return the host info and not the subnet info */ if (rep_data != NULL) goto error; SCRadixPrintTree(rep_ctx->reputationIPV6_tree); SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 1; error: SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 0; } /** * \test Test searches (best and exact matches) */ int SCReputationTestIPV4BestExactMatch01(void) { int i = 0; struct in_addr in; SCReputationInitCtx(); if (rep_ctx == NULL) { SCLogInfo("Error initializing Reputation Module"); return 0; } Reputation *rep_origC = NULL; Reputation *rep_origB = NULL; Reputation *rep_origA = NULL; Reputation *rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.6", &in) < 0) goto error; /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 6; /* adding a host */ rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 32, rep_orig); if (rep_orig == NULL) goto error; Reputation *rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_orig) goto error; rep_orig = SCReputationAllocData(); if (rep_orig == NULL) goto error; /* Adding C subnet */ if (inet_pton(AF_INET, "192.168.1.0", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 7; rep_origC = SCReputationAddIPV4Data((uint8_t *) &in, 24, rep_orig); if (rep_origC == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.5", &in) < 0) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_origC) goto error; rep_orig = SCReputationAllocData(); /* Adding B subnet */ if (inet_pton(AF_INET, "192.168.0.0", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 7; rep_origB = SCReputationAddIPV4Data((uint8_t *) &in, 16, rep_orig); if (rep_origB == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.5", &in) < 0) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_origC) goto error; if (inet_pton(AF_INET, "192.168.2.5", &in) < 0) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_origB) goto error; rep_orig = SCReputationAllocData(); /* Adding A subnet */ if (inet_pton(AF_INET, "192.0.0.0", &in) < 0) goto error; for (i = 0; i < REPUTATION_NUMBER; i++) rep_orig->reps[i] = i * 10 + 7; rep_origA = SCReputationAddIPV4Data((uint8_t *) &in, 8, rep_orig); if (rep_origA == NULL) goto error; if (inet_pton(AF_INET, "192.168.1.5", &in) < 0) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_origC) goto error; if (inet_pton(AF_INET, "192.168.2.5", &in) < 0) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_origB) goto error; if (inet_pton(AF_INET, "192.167.2.5", &in) < 0) goto error; rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data != NULL) goto error; rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); if (rep_data == NULL || rep_data != rep_origA) goto error; SCRadixPrintTree(rep_ctx->reputationIPV4_tree); SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 1; error: SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 0; } /** * \test Update transactions */ int SCReputationTestIPV4Update01(void) { int i = 0; struct in_addr in; SCReputationInitCtx(); if (rep_ctx == NULL) { SCLogInfo("Error initializing Reputation Module"); return 0; } Reputation *rep_orig = SCReputationAllocData(); ReputationTransaction rtx; memset(&rtx, 0, sizeof(ReputationTransaction)); if (rep_orig == NULL) goto error; /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) { rep_orig->reps[i] = 10; } if (inet_pton(AF_INET, "192.168.0.0", &in) < 0) goto error; /* Add add it as net */ rep_orig = SCReputationAddIPV4Data((uint8_t *) &in, 16, rep_orig); if (rep_orig == NULL) goto error; rtx.dec[REPUTATION_DDOS] = 5; rtx.inc[REPUTATION_PHISH] = 50; rtx.inc[REPUTATION_MALWARE] = 30; rtx.flags |= TRANSACTION_FLAG_NEEDSYNC; rtx.flags |= TRANSACTION_FLAG_INCS; rtx.flags |= TRANSACTION_FLAG_DECS; if (inet_pton(AF_INET, "192.168.10.100", &in) < 0) goto error; /* Update (it will create the host entry with the data of the net) */ SCReputationUpdateIPV4Data((uint8_t *)&in, &rtx); /* Create the reputation that any host 192.168.* should have */ Reputation *rep_aux = SCReputationAllocData(); /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) { rep_aux->reps[i] = 10; } rep_aux->reps[REPUTATION_DDOS] = 5; rep_aux->reps[REPUTATION_PHISH] = 60; rep_aux->reps[REPUTATION_MALWARE] = 40; Reputation *rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) goto error; /* Now that is created, it should update only the host */ rtx.dec[REPUTATION_DDOS] = 50; rtx.inc[REPUTATION_PHISH] = 50; rtx.inc[REPUTATION_MALWARE] = 50; rep_aux->reps[REPUTATION_DDOS] = 0; rep_aux->reps[REPUTATION_PHISH] = 110; rep_aux->reps[REPUTATION_MALWARE] = 90; SCReputationUpdateIPV4Data((uint8_t *)&in, &rtx); rep_data = SCReputationLookupIPV4ExactMatchReal((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) goto error; /* So let's see if we add a host and get the parent data again */ if (inet_pton(AF_INET, "192.168.10.101", &in) < 0) goto error; rep_aux->reps[REPUTATION_DDOS] = 10; rep_aux->reps[REPUTATION_PHISH] = 10; rep_aux->reps[REPUTATION_MALWARE] = 10; rep_data = SCReputationLookupIPV4BestMatchReal((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) goto error; SCRadixPrintTree(rep_ctx->reputationIPV4_tree); SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 1; error: SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 0; } /** * \test Update transactions */ int SCReputationTestIPV6Update01(void) { int i = 0; uint8_t in[16]; SCReputationInitCtx(); if (rep_ctx == NULL) { SCLogInfo("Error initializing Reputation Module"); return 0; } Reputation *rep_orig = SCReputationAllocData(); ReputationTransaction rtx; memset(&rtx, 0, sizeof(ReputationTransaction)); if (rep_orig == NULL) goto error; /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) { rep_orig->reps[i] = 10; } if (inet_pton(AF_INET6, "8762:2352:6261:7265:EE23:21AD:2121:1DDD", &in) < 0) goto error; /* Add add it as net */ rep_orig = SCReputationAddIPV6Data((uint8_t *) &in, 98, rep_orig); if (rep_orig == NULL) goto error; rtx.dec[REPUTATION_DDOS] = 5; rtx.inc[REPUTATION_PHISH] = 50; rtx.inc[REPUTATION_MALWARE] = 30; rtx.flags |= TRANSACTION_FLAG_NEEDSYNC; rtx.flags |= TRANSACTION_FLAG_INCS; rtx.flags |= TRANSACTION_FLAG_DECS; if (inet_pton(AF_INET6, "8762:2352:6261:7265:EE23:21AD:2121:1ABA", &in) < 0) goto error; /* Update (it will create the host entry with the data of the net) */ SCReputationUpdateIPV6Data((uint8_t *)&in, &rtx); /* Create the reputation that any host 192.168.* should have */ Reputation *rep_aux = SCReputationAllocData(); /* Fill the reputation with some values.. */ for (i = 0; i < REPUTATION_NUMBER; i++) { rep_aux->reps[i] = 10; } rep_aux->reps[REPUTATION_DDOS] = 5; rep_aux->reps[REPUTATION_PHISH] = 60; rep_aux->reps[REPUTATION_MALWARE] = 40; Reputation *rep_data = SCReputationLookupIPV6BestMatchReal((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) goto error; /* Now that is created, it should update only the host */ rtx.dec[REPUTATION_DDOS] = 50; rtx.inc[REPUTATION_PHISH] = 50; rtx.inc[REPUTATION_MALWARE] = 50; rep_aux->reps[REPUTATION_DDOS] = 0; rep_aux->reps[REPUTATION_PHISH] = 110; rep_aux->reps[REPUTATION_MALWARE] = 90; SCReputationUpdateIPV6Data((uint8_t *)&in, &rtx); rep_data = SCReputationLookupIPV6ExactMatchReal((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) goto error; /* So let's see if we add a host and get the parent data again */ if (inet_pton(AF_INET6, "8762:2352:6261:7265:EE23:21AD:2121:1ACB", &in) < 0) goto error; rep_aux->reps[REPUTATION_DDOS] = 10; rep_aux->reps[REPUTATION_PHISH] = 10; rep_aux->reps[REPUTATION_MALWARE] = 10; rep_data = SCReputationLookupIPV6BestMatchReal((uint8_t *) &in); if (rep_data == NULL || SCReputationEqual(rep_data, rep_aux) != 1) goto error; SCRadixPrintTree(rep_ctx->reputationIPV6_tree); SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 1; error: SCReputationFreeCtx(rep_ctx); rep_ctx = NULL; return 0; } #endif /* UNITTESTS */ /** Register the following unittests for the Reputation module */ void SCReputationRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCReputationTestIPV4AddRemoveHost01", SCReputationTestIPV4AddRemoveHost01, 1); UtRegisterTest("SCReputationTestIPV6AddRemoveHost01", SCReputationTestIPV6AddRemoveHost01, 1); UtRegisterTest("SCReputationTestIPV4BestExactMatch01", SCReputationTestIPV4BestExactMatch01, 1); UtRegisterTest("SCReputationTestIPV4AddRemoveHost02", SCReputationTestIPV4AddRemoveHost02, 1); UtRegisterTest("SCReputationTestIPV6AddRemoveHost02", SCReputationTestIPV6AddRemoveHost02, 1); UtRegisterTest("SCReputationTestIPV4Update01", SCReputationTestIPV4Update01, 1); UtRegisterTest("SCReputationTestIPV6Update01", SCReputationTestIPV6Update01, 1); UtRegisterTest("SRepTest01", SRepTest01, 1); UtRegisterTest("SRepTest02", SRepTest02, 1); UtRegisterTest("SRepTest03", SRepTest03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-rpc.h0000644000000000000000000000334012253546156013230 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_RPC_H__ #define __DETECT_RPC_H__ /* At least we check the program, the version is optional, * and the procedure is optional if we are checking the version. * If we parse the wildcard "*" we will allow any value (no check) */ #define DETECT_RPC_CHECK_PROGRAM 0x01 #define DETECT_RPC_CHECK_VERSION 0x02 #define DETECT_RPC_CHECK_PROCEDURE 0x04 /** Simple struct for a rpc msg call */ typedef struct RpcMsg_ { uint32_t xid; uint32_t type; /**< CALL = 0 (We only search for CALLS */ uint32_t rpcvers; /**< must be equal to two (2) */ uint32_t prog; uint32_t vers; uint32_t proc; } RpcMsg; /* Extract uint32_t */ #define EXT_GET_UINT32T(buf) ((long)ntohl((long)*(buf)++)) typedef struct DetectRpcData_ { uint32_t program; uint32_t program_version; uint32_t procedure; uint8_t flags; } DetectRpcData; /* prototypes */ void DetectRpcRegister (void); #endif /* __DETECT_RPC_H__ */ suricata-1.4.7/src/threads.h0000644000000000000000000006631212253546156012640 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon Crespo * * Threading functions defined as macros */ #ifndef __THREADS_H__ #define __THREADS_H__ #if HAVE_CONFIG_H #include #endif /* need this for the _POSIX_SPIN_LOCKS define */ #if HAVE_UNISTD_H #include #endif #ifdef PROFILING #include "util-cpu.h" #include "util-profiling-locks.h" #endif #if defined OS_FREEBSD || __OpenBSD__ #if ! defined __OpenBSD__ #include #endif enum { PRIO_LOW = 2, PRIO_MEDIUM = 0, PRIO_HIGH = -2, }; #elif OS_DARWIN #include enum { PRIO_LOW = 2, PRIO_MEDIUM = 0, PRIO_HIGH = -2, }; #elif OS_WIN32 #include enum { PRIO_LOW = THREAD_PRIORITY_LOWEST, PRIO_MEDIUM = THREAD_PRIORITY_NORMAL, PRIO_HIGH = THREAD_PRIORITY_HIGHEST, }; #else /* LINUX */ #if HAVE_SYS_SYSCALL_H #include #endif #if HAVE_SYS_PRCTL_H #include #define THREAD_NAME_LEN 16 #endif enum { PRIO_LOW = 2, PRIO_MEDIUM = 0, PRIO_HIGH = -2, }; #endif /* OS_FREEBSD */ #include /** The mutex/spinlock/condition definitions and functions are used * in the same way as the POSIX definitionsr; Anyway we are centralizing * them here to make an easier portability process and debugging process; * Please, make sure you initialize mutex and spinlocks before using them * because, some OS doesn't initialize them for you :) */ //#define DBG_THREADS /** Suricata Mutex */ #define SCMutex pthread_mutex_t #define SCMutexAttr pthread_mutexattr_t #define SCMutexDestroy pthread_mutex_destroy /** Suricata RWLocks */ #define SCRWLock pthread_rwlock_t #define SCRWLockDestroy pthread_rwlock_destroy /** Get the Current Thread Id */ #ifdef OS_FREEBSD #include #define SCGetThreadIdLong(...) ({ \ long tmpthid; \ thr_self(&tmpthid); \ u_long tid = (u_long)tmpthid; \ tid; \ }) #elif __OpenBSD__ #define SCGetThreadIdLong(...) ({ \ pid_t tpid; \ tpid = getpid(); \ u_long tid = (u_long)tpid; \ tid; \ }) #elif __CYGWIN__ #define SCGetThreadIdLong(...) ({ \ u_long tid = (u_long)GetCurrentThreadId(); \ tid; \ }) #elif OS_WIN32 #define SCGetThreadIdLong(...) ({ \ u_long tid = (u_long)GetCurrentThreadId(); \ tid; \ }) #elif OS_DARWIN #define SCGetThreadIdLong(...) ({ \ thread_port_t tpid; \ tpid = mach_thread_self(); \ u_long tid = (u_long)tpid; \ tid; \ }) #else #define SCGetThreadIdLong(...) ({ \ pid_t tmpthid; \ tmpthid = syscall(SYS_gettid); \ u_long tid = (u_long)tmpthid; \ tid; \ }) #endif /* OS FREEBSD */ /** Mutex Functions */ #ifdef DBG_THREADS /** When dbg threads is defined, if a mutex fail to lock, it's * initialized, logged, and does a second try; This is to prevent the system to freeze; * It is for Mac OS X users; * If you see a mutex, spinlock or condiion not initialized, report it please! */ #define SCMutexLock_dbg(mut) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") locking mutex %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut); \ int retl = pthread_mutex_lock(mut); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); \ if (retl != 0) { \ switch (retl) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ retl = pthread_mutex_init(mut, NULL); \ if (retl != 0) \ exit(EXIT_FAILURE); \ retl = pthread_mutex_lock(mut); \ break; \ case EDEADLK: \ printf("A deadlock would occur if the thread blocked waiting for mutex\n"); \ break; \ } \ } \ retl; \ }) #define SCMutexTrylock_dbg(mut) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking mutex %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut); \ int rett = pthread_mutex_trylock(mut); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, rett); \ if (rett != 0) { \ switch (rett) { \ case EINVAL: \ printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ break; \ case EBUSY: \ printf("Mutex is already locked\n"); \ break; \ } \ } \ rett; \ }) #define SCMutexInit_dbg(mut, mutattr) ({ \ int ret; \ ret = pthread_mutex_init(mut, mutattr); \ if (ret != 0) { \ switch (ret) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") mutex %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, ret); \ break; \ case EAGAIN: \ printf("The system temporarily lacks the resources to create another mutex\n"); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") mutex %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, ret); \ break; \ case ENOMEM: \ printf("The process cannot allocate enough memory to create another mutex\n"); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") mutex %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, ret); \ break; \ } \ } \ ret; \ }) #define SCMutexUnlock_dbg(mut) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocking mutex %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut); \ int retu = pthread_mutex_unlock(mut); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retu); \ if (retu != 0) { \ switch (retu) { \ case EINVAL: \ printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ break; \ case EPERM: \ printf("The current thread does not hold a lock on mutex\n"); \ break; \ } \ } \ retu; \ }) #define SCMutexInit(mut, mutattrs) SCMutexInit_dbg(mut, mutattrs) #define SCMutexLock(mut) SCMutexLock_dbg(mut) #define SCMutexTrylock(mut) SCMutexTrylock_dbg(mut) #define SCMutexUnlock(mut) SCMutexUnlock_dbg(mut) #elif defined PROFILE_LOCKING #define SCMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) #define SCMutexUnlock(mut) pthread_mutex_unlock(mut) typedef struct ProfilingLock_ { char *file; char *func; int line; int type; uint32_t cont; uint64_t ticks; } ProfilingLock; extern __thread ProfilingLock locks[PROFILING_MAX_LOCKS]; extern __thread int locks_idx; extern __thread int record_locks; extern __thread uint64_t mutex_lock_contention; extern __thread uint64_t mutex_lock_wait_ticks; extern __thread uint64_t mutex_lock_cnt; //printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); #define SCMutexLock_profile(mut) ({ \ mutex_lock_cnt++; \ int retl = 0; \ int cont = 0; \ uint64_t mutex_lock_start = UtilCpuGetTicks(); \ if (pthread_mutex_trylock((mut)) != 0) { \ mutex_lock_contention++; \ cont = 1; \ retl = pthread_mutex_lock(mut); \ } \ uint64_t mutex_lock_end = UtilCpuGetTicks(); \ mutex_lock_wait_ticks += (uint64_t)(mutex_lock_end - mutex_lock_start); \ \ if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ locks[locks_idx].file = (char *)__FILE__; \ locks[locks_idx].func = (char *)__func__; \ locks[locks_idx].line = (int)__LINE__; \ locks[locks_idx].type = LOCK_MUTEX; \ locks[locks_idx].cont = cont; \ locks[locks_idx].ticks = (uint64_t)(mutex_lock_end - mutex_lock_start); \ locks_idx++; \ } \ retl; \ }) #define SCMutexLock(mut) SCMutexLock_profile(mut) #define SCMutexTrylock(mut) pthread_mutex_trylock(mut) #else #define SCMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) #define SCMutexLock(mut) pthread_mutex_lock(mut) #define SCMutexTrylock(mut) pthread_mutex_trylock(mut) #define SCMutexUnlock(mut) pthread_mutex_unlock(mut) #endif /** Conditions/Signals */ /* Here we don't need to do nothing atm */ #define SCCondT pthread_cond_t #define SCCondInit pthread_cond_init #define SCCondSignal pthread_cond_signal #define SCCondTimedwait pthread_cond_timedwait #define SCCondDestroy pthread_cond_destroy #ifdef DBG_THREAD #define SCCondWait_dbg(cond, mut) ({ \ int ret = pthread_cond_wait(cond, mut); \ switch (ret) { \ case EINVAL: \ printf("The value specified by attr is invalid (or a SCCondT not initialized!)\n"); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") failed SCCondWait %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retu); \ break; \ } \ ret; \ }) #define SCCondWait SCondWait_dbg #else #define SCCondWait(cond, mut) pthread_cond_wait(cond, mut) #endif /** Spinlocks */ /** If posix spin not supported, use mutex */ #if ((_POSIX_SPIN_LOCKS - 200112L) < 0L) || defined HELGRIND #define SCSpinlock SCMutex #define SCSpinLock(spin) SCMutexLock((spin)) #define SCSpinTrylock(spin) SCMutexTrylock((spin)) #define SCSpinUnlock(spin) SCMutexUnlock((spin)) #define SCSpinInit(spin, spin_attr) SCMutexInit((spin), NULL) #define SCSpinDestroy(spin) SCMutexDestroy((spin)) #elif defined DBG_THREADS #define SCSpinlock pthread_spinlock_t #define SCSpinLock_dbg(spin) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") locking spin %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ int ret = pthread_spin_lock(spin); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocked spin %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ switch (ret) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ break; \ case EDEADLK: \ printf("A deadlock would occur if the thread blocked waiting for spin\n"); \ break; \ } \ ret; \ }) #define SCSpinTrylock_dbg(spin) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking spin %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ int ret = pthread_spin_trylock(spin); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked spin %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ switch (ret) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ break; \ case EDEADLK: \ printf("A deadlock would occur if the thread blocked waiting for spin\n"); \ break; \ case EBUSY: \ printf("A thread currently holds the lock\n"); \ break; \ } \ ret; \ }) #define SCSpinUnlock_dbg(spin) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocking spin %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ int ret = pthread_spin_unlock(spin); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") unlockedspin %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ switch (ret) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ break; \ case EPERM: \ printf("The calling thread does not hold the lock\n"); \ break; \ } \ ret; \ }) #define SCSpinInit_dbg(spin, spin_attr) ({ \ int ret = pthread_spin_init(spin, spin_attr); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") spinlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ switch (ret) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ break; \ case EBUSY: \ printf("A thread currently holds the lock\n"); \ break; \ case ENOMEM: \ printf("The process cannot allocate enough memory to create another spin\n"); \ break; \ case EAGAIN: \ printf("The system temporarily lacks the resources to create another spin\n"); \ break; \ } \ ret; \ }) #define SCSpinDestroy_dbg(spin) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") condition %p waiting\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ int ret = pthread_spin_destroy(spin); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") condition %p passed %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ switch (ret) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ break; \ case EBUSY: \ printf("A thread currently holds the lock\n"); \ break; \ case ENOMEM: \ printf("The process cannot allocate enough memory to create another spin\n"); \ break; \ case EAGAIN: \ printf("The system temporarily lacks the resources to create another spin\n"); \ break; \ } \ ret; \ }) #define SCSpinLock SCSpinLock_dbg #define SCSpinTrylock SCSpinTrylock_dbg #define SCSpinUnlock SCSpinUnlock_dbg #define SCSpinInit SCSpinInit_dbg #define SCSpinDestroy SCSpinDestroy_dbg #elif defined PROFILE_LOCKING #define SCSpinlock pthread_spinlock_t extern __thread uint64_t spin_lock_contention; extern __thread uint64_t spin_lock_wait_ticks; extern __thread uint64_t spin_lock_cnt; //printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); #define SCSpinLock_profile(spin) ({ \ spin_lock_cnt++; \ int retl = 0; \ int cont = 0; \ uint64_t spin_lock_start = UtilCpuGetTicks(); \ if (pthread_spin_trylock((spin)) != 0) { \ spin_lock_contention++; \ cont = 1; \ retl = pthread_spin_lock((spin)); \ } \ uint64_t spin_lock_end = UtilCpuGetTicks(); \ spin_lock_wait_ticks += (uint64_t)(spin_lock_end - spin_lock_start); \ \ if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ locks[locks_idx].file = (char *)__FILE__; \ locks[locks_idx].func = (char *)__func__; \ locks[locks_idx].line = (int)__LINE__; \ locks[locks_idx].type = LOCK_SPIN; \ locks[locks_idx].cont = cont; \ locks[locks_idx].ticks = (uint64_t)(spin_lock_end - spin_lock_start); \ locks_idx++; \ } \ retl; \ }) #define SCSpinLock(mut) SCSpinLock_profile(mut) #define SCSpinTrylock(spin) pthread_spin_trylock(spin) #define SCSpinUnlock(spin) pthread_spin_unlock(spin) #define SCSpinInit(spin, spin_attr) pthread_spin_init(spin, spin_attr) #define SCSpinDestroy(spin) pthread_spin_destroy(spin) #else /* if no dbg threads defined... */ #define SCSpinlock pthread_spinlock_t #define SCSpinLock(spin) pthread_spin_lock(spin) #define SCSpinTrylock(spin) pthread_spin_trylock(spin) #define SCSpinUnlock(spin) pthread_spin_unlock(spin) #define SCSpinInit(spin, spin_attr) pthread_spin_init(spin, spin_attr) #define SCSpinDestroy(spin) pthread_spin_destroy(spin) #endif /* DBG_THREADS */ /* * OS specific macro's for setting the thread name. "top" can display * this name. */ #if defined OS_FREEBSD /* FreeBSD */ /** \todo Add implementation for FreeBSD */ #define SCSetThreadName(n) ({ \ char tname[16] = ""; \ if (strlen(n) > 16) \ SCLogDebug("Thread name is too long, truncating it..."); \ strlcpy(tname, n, 16); \ pthread_set_name_np(pthread_self(), tname); \ 0; \ }) #elif defined __OpenBSD__ /* OpenBSD */ /** \todo Add implementation for OpenBSD */ #define SCSetThreadName(n) (0) #elif defined OS_WIN32 /* Windows */ /** \todo Add implementation for Windows */ #define SCSetThreadName(n) (0) #elif defined OS_DARWIN /* Mac OS X */ /** \todo Add implementation for MacOS */ #define SCSetThreadName(n) (0) #elif defined PR_SET_NAME /*PR_SET_NAME */ /** * \brief Set the threads name */ #define SCSetThreadName(n) ({ \ char tname[THREAD_NAME_LEN + 1] = ""; \ if (strlen(n) > THREAD_NAME_LEN) \ SCLogDebug("Thread name is too long, truncating it..."); \ strlcpy(tname, n, THREAD_NAME_LEN); \ int ret = 0; \ if ((ret = prctl(PR_SET_NAME, tname, 0, 0, 0)) < 0) \ SCLogDebug("Error setting thread name \"%s\": %s", tname, strerror(errno)); \ ret; \ }) #else #define SCSetThreadName(n) (0) #endif /** RWLock Functions */ #ifdef DBG_THREADS /** When dbg threads is defined, if a rwlock fail to lock, it's * initialized, logged, and does a second try; This is to prevent the system to freeze; * If you see a rwlock, spinlock or condiion not initialized, report it please! */ #define SCRWLockRDLock_dbg(rwl) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") locking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ int retl = pthread_rwlock_rdlock(rwl); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") locked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retl); \ if (retl != 0) { \ switch (retl) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ retl = pthread_rwlock_init(rwl, NULL); \ if (retl != 0) \ exit(EXIT_FAILURE); \ retl = pthread_rwlock_rdlock(rwl); \ break; \ case EDEADLK: \ printf("A deadlock would occur if the thread blocked waiting for rwlock\n"); \ break; \ } \ } \ retl; \ }) #define SCRWLockWRLock_dbg(rwl) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") locking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ int retl = pthread_rwlock_wrlock(rwl); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") locked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retl); \ if (retl != 0) { \ switch (retl) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ retl = pthread_rwlock_init(rwl, NULL); \ if (retl != 0) \ exit(EXIT_FAILURE); \ retl = pthread_rwlock_wrlock(rwl); \ break; \ case EDEADLK: \ printf("A deadlock would occur if the thread blocked waiting for rwlock\n"); \ break; \ } \ } \ retl; \ }) #define SCRWLockTryWRLock_dbg(rwl) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ int rett = pthread_rwlock_trywrlock(rwl); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, rett); \ if (rett != 0) { \ switch (rett) { \ case EINVAL: \ printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ break; \ case EBUSY: \ printf("RWLock is already locked\n"); \ break; \ } \ } \ rett; \ }) #define SCRWLockTryRDLock_dbg(rwl) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ int rett = pthread_rwlock_tryrdlock(rwl); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, rett); \ if (rett != 0) { \ switch (rett) { \ case EINVAL: \ printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ break; \ case EBUSY: \ printf("RWLock is already locked\n"); \ break; \ } \ } \ rett; \ }) #define SCRWLockInit_dbg(rwl, rwlattr) ({ \ int ret; \ ret = pthread_rwlock_init(rwl, rwlattr); \ if (ret != 0) { \ switch (ret) { \ case EINVAL: \ printf("The value specified by attr is invalid\n"); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \ break; \ case EAGAIN: \ printf("The system temporarily lacks the resources to create another rwlock\n"); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \ break; \ case ENOMEM: \ printf("The process cannot allocate enough memory to create another rwlock\n"); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \ break; \ } \ } \ ret; \ }) #define SCRWLockUnlock_dbg(rwl) ({ \ printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ int retu = pthread_rwlock_unlock(rwl); \ printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retu); \ if (retu != 0) { \ switch (retu) { \ case EINVAL: \ printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ break; \ case EPERM: \ printf("The current thread does not hold a lock on rwlock\n"); \ break; \ } \ } \ retu; \ }) #define SCRWLockInit(rwl, rwlattrs) SCRWLockInit_dbg(rwl, rwlattrs) #define SCRWLockRDLock(rwl) SCRWLockRDLock_dbg(rwl) #define SCRWLockWRLock(rwl) SCRWLockWRLock_dbg(rwl) #define SCRWLockTryWRLock(rwl) SCRWLockTryWRLock_dbg(rwl) #define SCRWLockTryRDLock(rwl) SCRWLockTryRDLock_dbg(rwl) #define SCRWLockUnlock(rwl) SCRWLockUnlock_dbg(rwl) #elif defined PROFILE_LOCKING #define SCRWLockInit(rwl, rwlattr ) pthread_rwlock_init(rwl, rwlattr) #define SCRWLockUnlock(rwl) pthread_rwlock_unlock(rwl) extern __thread uint64_t rww_lock_contention; extern __thread uint64_t rww_lock_wait_ticks; extern __thread uint64_t rww_lock_cnt; #define SCRWLockWRLock_profile(mut) ({ \ rww_lock_cnt++; \ int retl = 0; \ int cont = 0; \ uint64_t rww_lock_start = UtilCpuGetTicks(); \ if (pthread_rwlock_trywrlock((mut)) != 0) { \ rww_lock_contention++; \ cont = 1; \ retl = pthread_rwlock_wrlock(mut); \ } \ uint64_t rww_lock_end = UtilCpuGetTicks(); \ rww_lock_wait_ticks += (uint64_t)(rww_lock_end - rww_lock_start); \ \ if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ locks[locks_idx].file = (char *)__FILE__; \ locks[locks_idx].func = (char *)__func__; \ locks[locks_idx].line = (int)__LINE__; \ locks[locks_idx].type = LOCK_RWW; \ locks[locks_idx].cont = cont; \ locks[locks_idx].ticks = (uint64_t)(rww_lock_end - rww_lock_start); \ locks_idx++; \ } \ retl; \ }) extern __thread uint64_t rwr_lock_contention; extern __thread uint64_t rwr_lock_wait_ticks; extern __thread uint64_t rwr_lock_cnt; #define SCRWLockRDLock_profile(mut) ({ \ rwr_lock_cnt++; \ int retl = 0; \ int cont = 0; \ uint64_t rwr_lock_start = UtilCpuGetTicks(); \ if (pthread_rwlock_tryrdlock((mut)) != 0) { \ rwr_lock_contention++; \ cont = 1; \ retl = pthread_rwlock_rdlock(mut); \ } \ uint64_t rwr_lock_end = UtilCpuGetTicks(); \ rwr_lock_wait_ticks += (uint64_t)(rwr_lock_end - rwr_lock_start); \ \ if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ locks[locks_idx].file = (char *)__FILE__; \ locks[locks_idx].func = (char *)__func__; \ locks[locks_idx].line = (int)__LINE__; \ locks[locks_idx].type = LOCK_RWR; \ locks[locks_idx].cont = cont; \ locks[locks_idx].ticks = (uint64_t)(rwr_lock_end - rwr_lock_start); \ locks_idx++; \ } \ retl; \ }) #define SCRWLockWRLock(mut) SCRWLockWRLock_profile(mut) #define SCRWLockRDLock(mut) SCRWLockRDLock_profile(mut) #define SCRWLockTryWRLock(rwl) pthread_rwlock_trywrlock(rwl) #define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl) #else #define SCRWLockInit(rwl, rwlattr ) pthread_rwlock_init(rwl, rwlattr) #define SCRWLockWRLock(rwl) pthread_rwlock_wrlock(rwl) #define SCRWLockRDLock(rwl) pthread_rwlock_rdlock(rwl) #define SCRWLockTryWRLock(rwl) pthread_rwlock_trywrlock(rwl) #define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl) #define SCRWLockUnlock(rwl) pthread_rwlock_unlock(rwl) #endif /** End of RWLock functions */ void ThreadMacrosRegisterTests(void); #endif /* __THREADS_H__ */ suricata-1.4.7/src/detect-filestore.c0000644000000000000000000003102412253546156014433 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the filestore keyword */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-spm-bm.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "stream-tcp.h" #include "detect-filestore.h" /** * \brief Regex for parsing our flow options */ #define PARSE_REGEX "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([A-z_]+))?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectFilestoreMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilestoreFree(void *); /** * \brief Registration function for keyword: filestore */ void DetectFilestoreRegister(void) { sigmatch_table[DETECT_FILESTORE].name = "filestore"; sigmatch_table[DETECT_FILESTORE].desc = "stores files to disk if the rule matched"; sigmatch_table[DETECT_FILESTORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filestore"; sigmatch_table[DETECT_FILESTORE].FileMatch = DetectFilestoreMatch; sigmatch_table[DETECT_FILESTORE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILESTORE].Setup = DetectFilestoreSetup; sigmatch_table[DETECT_FILESTORE].Free = DetectFilestoreFree; sigmatch_table[DETECT_FILESTORE].RegisterTests = NULL; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } SCLogDebug("registering filestore rule option"); return; error: /* XXX */ return; } /** * \brief apply the post match filestore with options */ static int FilestorePostMatchWithOptions(Packet *p, Flow *f, DetectFilestoreData *filestore, FileContainer *fc, uint16_t file_id, uint16_t tx_id) { if (filestore == NULL) { SCReturnInt(0); } int this_file = 0; int this_tx = 0; int this_flow = 0; int rule_dir = 0; int toserver_dir = 0; int toclient_dir = 0; switch (filestore->direction) { case FILESTORE_DIR_DEFAULT: rule_dir = 1; break; case FILESTORE_DIR_BOTH: toserver_dir = 1; toclient_dir = 1; break; case FILESTORE_DIR_TOSERVER: toserver_dir = 1; break; case FILESTORE_DIR_TOCLIENT: toclient_dir = 1; break; } switch (filestore->scope) { case FILESTORE_SCOPE_DEFAULT: if (rule_dir) { this_file = 1; } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && toclient_dir) { this_file = 1; } else if ((p->flowflags & FLOW_PKT_TOSERVER) && toserver_dir) { this_file = 1; } break; case FILESTORE_SCOPE_TX: this_tx = 1; break; case FILESTORE_SCOPE_SSN: this_flow = 1; break; } if (this_file) { FileStoreFileById(fc, file_id); } else if (this_tx) { /* flag tx all files will be stored */ if (f->alproto == ALPROTO_HTTP && f->alstate != NULL) { HtpState *htp_state = f->alstate; if (toserver_dir) { htp_state->flags |= HTP_FLAG_STORE_FILES_TX_TS; FileStoreAllFilesForTx(htp_state->files_ts, tx_id); } if (toclient_dir) { htp_state->flags |= HTP_FLAG_STORE_FILES_TX_TC; FileStoreAllFilesForTx(htp_state->files_tc, tx_id); } htp_state->store_tx_id = tx_id; } } else if (this_flow) { /* flag flow all files will be stored */ if (f->alproto == ALPROTO_HTTP && f->alstate != NULL) { HtpState *htp_state = f->alstate; if (toserver_dir) { htp_state->flags |= HTP_FLAG_STORE_FILES_TS; FileStoreAllFiles(htp_state->files_ts); } if (toclient_dir) { htp_state->flags |= HTP_FLAG_STORE_FILES_TC; FileStoreAllFiles(htp_state->files_tc); } } } else { FileStoreFileById(fc, file_id); } SCReturnInt(0); } /** * \brief post-match function for filestore * * \param t thread local vars * \param det_ctx pattern matcher thread local data * \param p packet * * The match function for filestore records store candidates in the det_ctx. * When we are sure all parts of the signature matched, we run this function * to finalize the filestore. */ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s) { uint8_t flags = 0; SCEnter(); if (det_ctx->filestore_cnt == 0) { SCReturnInt(0); } if (s->filestore_sm == NULL || p->flow == NULL) { #ifndef DEBUG SCReturnInt(0); #else BUG_ON(1); #endif } if (p->flowflags & FLOW_PKT_TOCLIENT) flags |= STREAM_TOCLIENT; else flags |= STREAM_TOSERVER; FLOWLOCK_WRLOCK(p->flow); FileContainer *ffc = AppLayerGetFilesFromFlow(p->flow, flags); /* filestore for single files only */ if (s->filestore_sm->ctx == NULL) { uint16_t u; for (u = 0; u < det_ctx->filestore_cnt; u++) { FileStoreFileById(ffc, det_ctx->filestore[u].file_id); } } else { DetectFilestoreData *filestore = s->filestore_sm->ctx; uint16_t u; for (u = 0; u < det_ctx->filestore_cnt; u++) { FilestorePostMatchWithOptions(p, p->flow, filestore, ffc, det_ctx->filestore[u].file_id, det_ctx->filestore[u].tx_id); } } FLOWLOCK_UNLOCK(p->flow); SCReturnInt(0); } /** * \brief match the specified filestore * * \param t thread local vars * \param det_ctx pattern matcher thread local data * \param f *LOCKED* flow * \param flags direction flags * \param file file being inspected * \param s signature being inspected * \param m sigmatch that we will cast into DetectFilestoreData * * \retval 0 no match * \retval 1 match * * \todo when we start supporting more protocols, the logic in this function * needs to be put behind a api. */ static int DetectFilestoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) { uint16_t file_id = 0; SCEnter(); if (det_ctx->filestore_cnt >= DETECT_FILESTORE_MAX) { SCReturnInt(1); } /* file can be NULL when a rule with filestore scope > file * matches. */ if (file != NULL) { file_id = file->file_id; } det_ctx->filestore[det_ctx->filestore_cnt].file_id = file_id; det_ctx->filestore[det_ctx->filestore_cnt].tx_id = det_ctx->tx_id; SCLogDebug("%u, file %u, tx %u", det_ctx->filestore_cnt, det_ctx->filestore[det_ctx->filestore_cnt].file_id, det_ctx->filestore[det_ctx->filestore_cnt].tx_id); det_ctx->filestore_cnt++; SCReturnInt(1); } /** * \brief this function is used to parse filestore options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param str pointer to the user provided "filestore" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); DetectFilestoreData *fd = NULL; SigMatch *sm = NULL; char *args[3] = {NULL,NULL,NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FILESTORE; if (str != NULL && strlen(str) > 0) { SCLogDebug("str %s", str); ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 ", string %s", ret, str); goto error; } if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[0] = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[1] = (char *)str_ptr; } if (ret > 3) { res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[2] = (char *)str_ptr; } } fd = SCMalloc(sizeof(DetectFilestoreData)); if (unlikely(fd == NULL)) goto error; memset(fd, 0x00, sizeof(DetectFilestoreData)); if (args[0] != NULL) { SCLogDebug("first arg %s", args[0]); if (strcasecmp(args[0], "request") == 0 || strcasecmp(args[0], "to_server") == 0) { fd->direction = FILESTORE_DIR_TOSERVER; fd->scope = FILESTORE_SCOPE_TX; } else if (strcasecmp(args[0], "response") == 0 || strcasecmp(args[0], "to_client") == 0) { fd->direction = FILESTORE_DIR_TOCLIENT; fd->scope = FILESTORE_SCOPE_TX; } else if (strcasecmp(args[0], "both") == 0) { fd->direction = FILESTORE_DIR_BOTH; fd->scope = FILESTORE_SCOPE_TX; } } else { fd->direction = FILESTORE_DIR_DEFAULT; } if (args[1] != NULL) { SCLogDebug("second arg %s", args[1]); if (strcasecmp(args[1], "file") == 0) { fd->scope = FILESTORE_SCOPE_DEFAULT; } else if (strcasecmp(args[1], "tx") == 0) { fd->scope = FILESTORE_SCOPE_TX; } else if (strcasecmp(args[1], "ssn") == 0 || strcasecmp(args[1], "flow") == 0) { fd->scope = FILESTORE_SCOPE_SSN; } } else { if (fd->scope == 0) fd->scope = FILESTORE_SCOPE_DEFAULT; } sm->ctx = fd; } else { sm->ctx = NULL; } SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); s->filestore_sm = sm; if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } AppLayerHtpNeedFileInspection(); s->alproto = ALPROTO_HTTP; s->flags |= SIG_FLAG_FILESTORE; return 0; error: if (sm != NULL) SCFree(sm); return -1; } static void DetectFilestoreFree(void *ptr) { if (ptr != NULL) { SCFree(ptr); } } suricata-1.4.7/src/detect-sameip.h0000644000000000000000000000163512253546156013727 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus */ #ifndef __DETECT_SAMEIP_H__ #define __DETECT_SAMEIP_H__ /* prototypes */ void DetectSameipRegister(void); #endif /* __DETECT_SAMEIP_H__ */ suricata-1.4.7/src/util-spm-bm.h0000644000000000000000000000361512253546156013351 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * */ #ifndef __UTIL_SPM_BM__ #define __UTIL_SPM_BM__ #include "suricata-common.h" #include "suricata.h" #define ALPHABET_SIZE 256 /* Context for booyer moore */ typedef struct BmCtx_ { uint16_t bmBc[ALPHABET_SIZE]; uint16_t *bmGs; // = SCMalloc(sizeof(int32_t)*(needlelen + 1)); } BmCtx; /** Prepare and return a Boyer Moore context */ BmCtx *BoyerMooreCtxInit(uint8_t *needle, uint16_t needle_len); void BoyerMooreCtxToNocase(BmCtx *, uint8_t *, uint16_t); void PreBmBc(const uint8_t *x, uint16_t m, uint16_t *bmBc); void BoyerMooreSuffixes(const uint8_t *x, uint16_t m, uint16_t *suff); int PreBmGs(const uint8_t *, uint16_t, uint16_t *); uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, uint16_t *bmGs, uint16_t *bmBc); void PreBmBcNocase(const uint8_t *x, uint16_t m, uint16_t *bmBc); void BoyerMooreSuffixesNocase(const uint8_t *x, uint16_t m, uint16_t *suff); void PreBmGsNocase(const uint8_t *x, uint16_t m, uint16_t *bmGs); uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, uint16_t *bmGs, uint16_t *bmBc); void BoyerMooreCtxDeInit(BmCtx *); #endif /* __UTIL_SPM_BM__ */ suricata-1.4.7/src/detect-bytejump.c0000644000000000000000000013062212253546156014302 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus * * Implements byte_jump keyword. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "app-layer.h" #include "detect-bytejump.h" #include "detect-byte-extract.h" #include "detect-content.h" #include "detect-uricontent.h" #include "util-byte.h" #include "util-unittest.h" #include "util-debug.h" #include "detect-pcre.h" /** * \brief Regex for parsing our options */ #define PARSE_REGEX "^\\s*" \ "([^\\s,]+\\s*,\\s*[^\\s,]+)" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ "\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; void DetectBytejumpRegisterTests(void); void DetectBytejumpRegister (void) { const char *eb; int eo; int opts = 0; sigmatch_table[DETECT_BYTEJUMP].name = "byte_jump"; sigmatch_table[DETECT_BYTEJUMP].Match = DetectBytejumpMatch; sigmatch_table[DETECT_BYTEJUMP].Setup = DetectBytejumpSetup; sigmatch_table[DETECT_BYTEJUMP].Free = DetectBytejumpFree; sigmatch_table[DETECT_BYTEJUMP].RegisterTests = DetectBytejumpRegisterTests; sigmatch_table[DETECT_BYTEJUMP].flags |= SIGMATCH_PAYLOAD; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed " "at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /** \brief Byte jump match function * \param det_ctx thread detect engine ctx * \param s signature * \param m byte jump sigmatch * \param payload ptr to the payload * \param payload_len length of the payload * \retval 1 match * \retval 0 no match */ int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *m, uint8_t *payload, uint32_t payload_len, uint8_t flags, int32_t offset) { SCEnter(); DetectBytejumpData *data = (DetectBytejumpData *)m->ctx; uint8_t *ptr = NULL; uint8_t *jumpptr = NULL; int32_t len = 0; uint64_t val = 0; int extbytes; if (payload_len == 0) { SCReturnInt(0); } /* Calculate the ptr value for the bytejump and length remaining in * the packet from that point. */ if (flags & DETECT_BYTEJUMP_RELATIVE) { ptr = payload + det_ctx->buffer_offset; len = payload_len - det_ctx->buffer_offset; ptr += offset; len -= offset; /* No match if there is no relative base */ if (ptr == NULL || len <= 0) { SCReturnInt(0); } } else { ptr = payload + offset; len = payload_len - offset; } /* Verify the to-be-extracted data is within the packet */ if (ptr < payload || data->nbytes > len) { SCLogDebug("Data not within payload " "pkt=%p, ptr=%p, len=%d, nbytes=%d", payload, ptr, len, data->nbytes); SCReturnInt(0); } /* Extract the byte data */ if (flags & DETECT_BYTEJUMP_STRING) { extbytes = ByteExtractStringUint64(&val, data->base, data->nbytes, (const char *)ptr); if(extbytes <= 0) { SCLogError(SC_ERR_BYTE_EXTRACT_FAILED,"Error extracting %d bytes " "of string data: %d", data->nbytes, extbytes); SCReturnInt(-1); } } else { int endianness = (flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, data->nbytes, ptr); if (extbytes != data->nbytes) { SCLogError(SC_ERR_BYTE_EXTRACT_FAILED,"Error extracting %d bytes " "of numeric data: %d", data->nbytes, extbytes); SCReturnInt(-1); } } //printf("VAL: (%" PRIu64 " x %" PRIu32 ") + %d + %" PRId32 "\n", val, data->multiplier, extbytes, data->post_offset); /* Adjust the jump value based on flags */ val *= data->multiplier; if (flags & DETECT_BYTEJUMP_ALIGN) { if ((val % 4) != 0) { val += 4 - (val % 4); } } val += data->post_offset; /* Calculate the jump location */ if (flags & DETECT_BYTEJUMP_BEGIN) { jumpptr = payload + val; //printf("NEWVAL: payload %p + %ld = %p\n", p->payload, val, jumpptr); } else { val += extbytes; jumpptr = ptr + val; //printf("NEWVAL: ptr %p + %ld = %p\n", ptr, val, jumpptr); } /* Validate that the jump location is still in the packet * \todo Should this validate it is still in the *payload*? */ if ((jumpptr < payload) || (jumpptr >= payload + payload_len)) { SCLogDebug("Jump location (%p) is not within " "payload (%p-%p)", jumpptr, payload, payload + payload_len - 1); SCReturnInt(0); } #ifdef DEBUG if (SCLogDebugEnabled()) { uint8_t *sptr = (flags & DETECT_BYTEJUMP_BEGIN) ? payload : ptr; SCLogDebug("jumping %" PRId64 " bytes from %p (%08x) to %p (%08x)", val, sptr, (int)(sptr - payload), jumpptr, (int)(jumpptr - payload)); } #endif /* DEBUG */ /* Adjust the detection context to the jump location. */ det_ctx->buffer_offset = jumpptr - payload; SCReturnInt(1); } int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectBytejumpData *data = (DetectBytejumpData *)m->ctx; uint8_t *ptr = NULL; uint8_t *jumpptr = NULL; uint16_t len = 0; uint64_t val = 0; int extbytes; if (p->payload_len == 0) { return 0; } /* Calculate the ptr value for the bytejump and length remaining in * the packet from that point. */ if (data->flags & DETECT_BYTEJUMP_RELATIVE) { ptr = p->payload + det_ctx->buffer_offset; len = p->payload_len - det_ctx->buffer_offset; /* No match if there is no relative base */ if (ptr == NULL || len == 0) { return 0; } ptr += data->offset; len -= data->offset; } else { ptr = p->payload + data->offset; len = p->payload_len - data->offset; } /* Verify the to-be-extracted data is within the packet */ if (ptr < p->payload || data->nbytes > len) { SCLogDebug("Data not within packet " "payload=%p, ptr=%p, len=%d, nbytes=%d", p->payload, ptr, len, data->nbytes); return 0; } /* Extract the byte data */ if (data->flags & DETECT_BYTEJUMP_STRING) { extbytes = ByteExtractStringUint64(&val, data->base, data->nbytes, (const char *)ptr); if(extbytes <= 0) { SCLogError(SC_ERR_BYTE_EXTRACT_FAILED,"Error extracting %d bytes " "of string data: %d", data->nbytes, extbytes); return -1; } } else { int endianness = (data->flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, data->nbytes, ptr); if (extbytes != data->nbytes) { SCLogError(SC_ERR_BYTE_EXTRACT_FAILED,"Error extracting %d bytes " "of numeric data: %d", data->nbytes, extbytes); return -1; } } //printf("VAL: (%" PRIu64 " x %" PRIu32 ") + %d + %" PRId32 "\n", val, data->multiplier, extbytes, data->post_offset); /* Adjust the jump value based on flags */ val *= data->multiplier; if (data->flags & DETECT_BYTEJUMP_ALIGN) { if ((val % 4) != 0) { val += 4 - (val % 4); } } val += data->post_offset; /* Calculate the jump location */ if (data->flags & DETECT_BYTEJUMP_BEGIN) { jumpptr = p->payload + val; //printf("NEWVAL: payload %p + %ld = %p\n", p->payload, val, jumpptr); } else { val += extbytes; jumpptr = ptr + val; //printf("NEWVAL: ptr %p + %ld = %p\n", ptr, val, jumpptr); } /* Validate that the jump location is still in the packet * \todo Should this validate it is still in the *payload*? */ if ((jumpptr < p->payload) || (jumpptr >= p->payload + p->payload_len)) { SCLogDebug("Jump location (%p) is not within " "packet (%p-%p)", jumpptr, p->payload, p->payload + p->payload_len - 1); return 0; } #ifdef DEBUG if (SCLogDebugEnabled()) { uint8_t *sptr = (data->flags & DETECT_BYTEJUMP_BEGIN) ? p->payload : ptr; SCLogDebug("jumping %" PRId64 " bytes from %p (%08x) to %p (%08x)", val, sptr, (int)(sptr - p->payload), jumpptr, (int)(jumpptr - p->payload)); } #endif /* DEBUG */ /* Adjust the detection context to the jump location. */ det_ctx->buffer_offset = jumpptr - p->payload; return 1; } DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset) { DetectBytejumpData *data = NULL; char *args[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int numargs = 0; int i = 0; uint32_t nbytes; char *str_ptr; char *end_ptr; /* Execute the regex and populate args with captures. */ ret = pcre_exec(parse_regex, parse_regex_study, optstr, strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2 || ret > 10) { SCLogError(SC_ERR_PCRE_PARSE,"parse error, ret %" PRId32 ", string \"%s\"", ret, optstr); goto error; } /* The first two arguments are stashed in the first PCRE substring. * This is because byte_jump can take 10 arguments, but PCRE only * supports 9 substrings, sigh. */ res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS, 1, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed " "for arg 1"); goto error; } /* Break up first substring into two parameters * * NOTE: Because of this, we cannot free args[1] as it is part of args[0], * and *yes* this *is* ugly. */ end_ptr = str_ptr; while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++; *(end_ptr++) = '\0'; args[0] = str_ptr; numargs++; str_ptr = end_ptr; while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++; end_ptr = str_ptr; while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0')) end_ptr++; *(end_ptr++) = '\0'; args[1] = str_ptr; numargs++; /* The remaining args are directly from PCRE substrings */ for (i = 1; i < (ret - 1); i++) { res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS, i + 1, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed for arg %d", i + 1); goto error; } args[i+1] = str_ptr; numargs++; } /* Initialize the data */ data = SCMalloc(sizeof(DetectBytejumpData)); if (unlikely(data == NULL)) goto error; data->base = DETECT_BYTEJUMP_BASE_UNSET; data->flags = 0; data->multiplier = 1; data->post_offset = 0; /* * The first two options are required and positional. The * remaining arguments are flags and are not positional. */ /* Number of bytes */ if (ByteExtractStringUint32(&nbytes, 10, strlen(args[0]), args[0]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed number of bytes: %s", optstr); goto error; } /* Offset */ if (args[1][0] != '-' && isalpha((unsigned char)args[1][0])) { if (offset == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_jump supplied with " "var name for offset. \"value\" argument supplied to " "this function has to be non-NULL"); goto error; } *offset = SCStrdup(args[1]); if (*offset == NULL) goto error; } else { if (ByteExtractStringInt32(&data->offset, 0, strlen(args[1]), args[1]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed offset: %s", optstr); goto error; } } /* The remaining options are flags. */ /** \todo Error on dups? */ for (i = 2; i < numargs; i++) { if (strcmp("relative", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_RELATIVE; } else if (strcasecmp("string", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_STRING; } else if (strcasecmp("dec", args[i]) == 0) { data->base |= DETECT_BYTEJUMP_BASE_DEC; } else if (strcasecmp("hex", args[i]) == 0) { data->base |= DETECT_BYTEJUMP_BASE_HEX; } else if (strcasecmp("oct", args[i]) == 0) { data->base |= DETECT_BYTEJUMP_BASE_OCT; } else if (strcasecmp("big", args[i]) == 0) { if (data->flags & DETECT_BYTEJUMP_LITTLE) { data->flags ^= DETECT_BYTEJUMP_LITTLE; } data->flags |= DETECT_BYTEJUMP_BIG; } else if (strcasecmp("little", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_LITTLE; } else if (strcasecmp("from_beginning", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_BEGIN; } else if (strcasecmp("align", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_ALIGN; } else if (strncasecmp("multiplier ", args[i], 11) == 0) { if (ByteExtractStringUint32(&data->multiplier, 10, strlen(args[i]) - 11, args[i] + 11) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed multiplier: %s", optstr); goto error; } } else if (strncasecmp("post_offset ", args[i], 12) == 0) { if (ByteExtractStringInt32(&data->post_offset, 10, strlen(args[i]) - 12, args[i] + 12) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed post_offset: %s", optstr); goto error; } } else if (strcasecmp("dce", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_DCE; } else { SCLogError(SC_ERR_INVALID_VALUE, "Unknown option: \"%s\"", args[i]); goto error; } } if (data->flags & DETECT_BYTEJUMP_STRING) { /* 23 - This is the largest string (octal, with a zero prefix) that * will not overflow uint64_t. The only way this length * could be over 23 and still not overflow is if it were zero * prefixed and we only support 1 byte of zero prefix for octal. * * "01777777777777777777777" = 0xffffffffffffffff */ if (nbytes > 23) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 23 bytes " "with \"string\": %s", optstr); goto error; } } else { if (nbytes > 8) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 8 bytes " "without \"string\": %s\n", optstr); goto error; } if (data->base != DETECT_BYTEJUMP_BASE_UNSET) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot use a base " "without \"string\": %s", optstr); goto error; } } /* This is max 23 so it will fit in a byte (see above) */ data->nbytes = (uint8_t)nbytes; for (i = 0; i < numargs; i++){ if (i == 1) continue; /* args[1] is part of args[0] */ if (args[i] != NULL) SCFree(args[i]); } return data; error: for (i = 0; i < numargs; i++){ if (i == 1) continue; /* args[1] is part of args[0] */ if (args[i] != NULL) SCFree(args[i]); } if (data != NULL) DetectBytejumpFree(data); return NULL; } int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { DetectBytejumpData *data = NULL; SigMatch *sm = NULL; char *offset = NULL; data = DetectBytejumpParse(optstr, &offset); if (data == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_BYTEJUMP; sm->ctx = (void *)data; /* check bytejump modifiers against the signature alproto. In case they conflict * chuck out invalid signature */ if (data->flags & DETECT_BYTEJUMP_DCE) { if (s->alproto != ALPROTO_DCERPC) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " "bytetest with dce enabled"); goto error; } if ( (data->flags & DETECT_BYTEJUMP_STRING) || (data->flags & DETECT_BYTEJUMP_LITTLE) || (data->flags & DETECT_BYTEJUMP_BIG) || (data->flags & DETECT_BYTEJUMP_BEGIN) || (data->base == DETECT_BYTEJUMP_BASE_DEC) || (data->base == DETECT_BYTEJUMP_BASE_HEX) || (data->base == DETECT_BYTEJUMP_BASE_OCT) ) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " "DCERPC rule holds an invalid modifier for bytejump."); goto error; } } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { if (data->flags & DETECT_BYTEJUMP_RELATIVE) { SigMatch *prev_sm = NULL; prev_sm = SigMatchGetLastSMFromLists(s, 8, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); if (prev_sm == NULL) { data->flags &= ~DETECT_BYTEJUMP_RELATIVE; } s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else { s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } } else if (s->alproto == ALPROTO_DCERPC && (data->flags & DETECT_BYTEJUMP_RELATIVE)) { SigMatch *pm = NULL; SigMatch *dm = NULL; pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (dm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (pm->idx > dm->idx) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } if (offset != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, SigMatchListSMBelongsTo(s, sm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in byte_jump - %s\n", offset); goto error; } DetectBytejumpData *bjd = sm->ctx; bjd->offset = ((DetectByteExtractData *)bed_sm->ctx)->local_id; bjd->flags |= DETECT_BYTEJUMP_OFFSET_BE; SCFree(offset); } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { return 0; } if ( !(data->flags & DETECT_BYTEJUMP_RELATIVE)) { return(0); } SigMatch *prev_sm = NULL; prev_sm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, sm->prev, DETECT_BYTEJUMP, sm->prev, DETECT_PCRE, sm->prev); if (prev_sm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is an alproto sig."); return 0; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "No preceding content " "or uricontent or pcre option"); return -1; } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (prev_sm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_sm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; break; case DETECT_PCRE: pe = (DetectPcreData *)prev_sm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: SCLogDebug("No setting relative_next for bytejump. We " "have no use for it"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } /* switch */ return 0; error: if (data != NULL) DetectBytejumpFree(data); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectBytejumpData * * \param data pointer to DetectBytejumpData */ void DetectBytejumpFree(void *ptr) { DetectBytejumpData *data = (DetectBytejumpData *)ptr; SCFree(data); } /* UNITTESTS */ #ifdef UNITTESTS #include "util-unittest-helper.h" /** * \test DetectBytejumpTestParse01 is a test to make sure that we return * "something" when given valid bytejump opt */ int DetectBytejumpTestParse01(void) { int result = 0; DetectBytejumpData *data = NULL; data = DetectBytejumpParse("4,0", NULL); if (data != NULL) { DetectBytejumpFree(data); result = 1; } return result; } /** * \test DetectBytejumpTestParse02 is a test for setting the required opts */ int DetectBytejumpTestParse02(void) { int result = 0; DetectBytejumpData *data = NULL; data = DetectBytejumpParse("4, 0", NULL); if (data != NULL) { if ( (data->nbytes == 4) && (data->offset == 0) && (data->multiplier == 1) && (data->post_offset == 0) && (data->flags == 0) && (data->base == DETECT_BYTEJUMP_BASE_UNSET)) { result = 1; } DetectBytejumpFree(data); } return result; } /** * \test DetectBytejumpTestParse03 is a test for setting the optional flags */ int DetectBytejumpTestParse03(void) { int result = 0; DetectBytejumpData *data = NULL; data = DetectBytejumpParse(" 4,0 , relative , little, string, " "dec, align, from_beginning", NULL); if (data != NULL) { if ( (data->nbytes == 4) && (data->offset == 0) && (data->multiplier == 1) && (data->post_offset == 0) && (data->flags == ( DETECT_BYTEJUMP_RELATIVE |DETECT_BYTEJUMP_LITTLE |DETECT_BYTEJUMP_STRING |DETECT_BYTEJUMP_ALIGN |DETECT_BYTEJUMP_BEGIN)) && (data->base == DETECT_BYTEJUMP_BASE_DEC)) { result = 1; } DetectBytejumpFree(data); } return result; } /** * \test DetectBytejumpTestParse04 is a test for setting the optional flags * with parameters * * \todo This fails becuase we can only have 9 captures and there are 10. */ int DetectBytejumpTestParse04(void) { int result = 0; DetectBytejumpData *data = NULL; data = DetectBytejumpParse(" 4,0 , relative , little, string, " "dec, align, from_beginning , " "multiplier 2 , post_offset -16 ", NULL); if (data != NULL) { if ( (data->nbytes == 4) && (data->offset == 0) && (data->multiplier == 2) && (data->post_offset == -16) && (data->flags == ( DETECT_BYTEJUMP_RELATIVE |DETECT_BYTEJUMP_LITTLE |DETECT_BYTEJUMP_ALIGN |DETECT_BYTEJUMP_STRING |DETECT_BYTEJUMP_BEGIN)) && (data->base == DETECT_BYTEJUMP_BASE_DEC)) { result = 1; } DetectBytejumpFree(data); } return result; } /** * \test DetectBytejumpTestParse05 is a test for setting base without string */ int DetectBytejumpTestParse05(void) { int result = 0; DetectBytejumpData *data = NULL; data = DetectBytejumpParse(" 4,0 , relative , little, dec, " "align, from_beginning", NULL); if (data == NULL) { result = 1; } return result; } /** * \test DetectBytejumpTestParse06 is a test for too many bytes to extract */ int DetectBytejumpTestParse06(void) { int result = 0; DetectBytejumpData *data = NULL; data = DetectBytejumpParse("9, 0", NULL); if (data == NULL) { result = 1; } return result; } /** * \test DetectBytejumpTestParse07 is a test for too many string bytes to extract */ int DetectBytejumpTestParse07(void) { int result = 0; DetectBytejumpData *data = NULL; data = DetectBytejumpParse("24, 0, string, dec", NULL); if (data == NULL) { result = 1; } return result; } /** * \test DetectBytejumpTestParse08 is a test for offset too big */ int DetectBytejumpTestParse08(void) { int result = 0; DetectBytejumpData *data = NULL; data = DetectBytejumpParse("4, 0xffffffffffffffff", NULL); if (data == NULL) { result = 1; } return result; } /** * \test Test dce option. */ int DetectBytejumpTestParse09(void) { Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 1; s->alproto = ALPROTO_DCERPC; result &= (DetectBytejumpSetup(NULL, s, "4,0, align, multiplier 2, " "post_offset -16,dce") == 0); result &= (DetectBytejumpSetup(NULL, s, "4,0, multiplier 2, " "post_offset -16,dce") == 0); result &= (DetectBytejumpSetup(NULL, s, "4,0,post_offset -16,dce") == 0); result &= (DetectBytejumpSetup(NULL, s, "4,0,dce") == 0); result &= (DetectBytejumpSetup(NULL, s, "4,0,dce") == 0); result &= (DetectBytejumpSetup(NULL, s, "4,0, string, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, big, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, little, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, string, dec, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, string, oct, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, string, hex, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, from_beginning, dce") == -1); result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); return result; } /** * \test Test dce option. */ int DetectBytejumpTestParse10(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; DetectBytejumpData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "byte_jump:4,0,align,multiplier 2, " "post_offset -16,relative,dce; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (!(bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && (bd->flags & DETECT_BYTEJUMP_BIG) && (bd->flags & DETECT_BYTEJUMP_LITTLE) ) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "byte_jump:4,0,align,multiplier 2, " "post_offset -16,relative,dce; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (!(bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && (bd->flags & DETECT_BYTEJUMP_BIG) && (bd->flags & DETECT_BYTEJUMP_LITTLE) ) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "byte_jump:4,0,align,multiplier 2, " "post_offset -16,relative; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if ((bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && (bd->flags & DETECT_BYTEJUMP_BIG) && (bd->flags & DETECT_BYTEJUMP_LITTLE) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test dce option. */ int DetectBytejumpTestParse11(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; byte_jump:4,0,align,multiplier 2, " "post_offset -16,string,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_sub_data; " "content:\"one\"; byte_jump:4,0,align,multiplier 2, " "post_offset -16,big,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; byte_jump:4,0,align,multiplier 2, " "post_offset -16,little,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; byte_jump:4,0,align,multiplier 2, " "post_offset -16,string,hex,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; byte_jump:4,0,align,multiplier 2, " "post_offset -16,string,dec,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; byte_jump:4,0,align,multiplier 2, " "post_offset -16,string,oct,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; byte_jump:4,0,align,multiplier 2, " "post_offset -16,from_beginning,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test file_data */ static int DetectBytejumpTestParse12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectBytejumpData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; byte_jump:4,0,align,multiplier 2, " "post_offset -16,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_BYTEJUMP) { goto end; } bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if ((bd->flags & DETECT_BYTEJUMP_DCE) && (bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && (bd->flags & DETECT_BYTEJUMP_BIG) && (bd->flags & DETECT_BYTEJUMP_LITTLE) ) { result = 0; goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectByteJumpTestPacket01 is a test to check matches of * byte_jump and byte_jump relative works if the previous keyword is pcre * (bug 142) */ int DetectByteJumpTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" "User-Agent: Wget/1.11.4" "Accept: */*" "Host: www.google.com" "Connection: Keep-Alive" "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"pcre + byte_test + " "relative\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\"; byte_jump:1,6," "relative,string,dec; content:\"0\"; sid:134; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } /** * \test DetectByteJumpTestPacket02 is a test to check matches of * byte_jump and byte_jump relative works if the previous keyword is byte_jump * (bug 165) */ int DetectByteJumpTestPacket02 (void) { int result = 0; uint8_t buf[] = { 0x00, 0x00, 0x00, 0x77, 0xff, 0x53, 0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x92, 0xa4, 0x01, 0x08, 0x17, 0x5c, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x01, 0x40, 0x48, 0x00, 0x00, 0x00, 0xff }; uint16_t buflen = sizeof(buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"byte_jump with byte_jump" " + relative\"; byte_jump:1,13; byte_jump:4,0,relative; " "content:\"|48 00 00|\"; within:3; sid:144; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } int DetectByteJumpTestPacket03(void) { int result = 0; uint8_t *buf = NULL; uint16_t buflen = 0; buf = SCMalloc(4); if (unlikely(buf == NULL)) { printf("malloc failed\n"); exit(EXIT_FAILURE); } memcpy(buf, "boom", 4); buflen = 4; Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"byte_jump\"; " "byte_jump:1,214748364; sid:1; rev:1;)"; result = !UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: if (buf != NULL) SCFree(buf); return result; } /** * \test check matches of with from_beginning (bug 626/627) */ int DetectByteJumpTestPacket04 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; content:\"ABCD\"; distance:0; within:4; sid:1; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } /** * \test check matches of with from_beginning (bug 626/627) */ int DetectByteJumpTestPacket05 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; content:\"cdABCD\"; within:6; sid:1; rev:1;)"; result = UTHPacketMatchSig(p, sig) ? 0 : 1; UTHFreePacket(p); end: return result; } /** * \test check matches of with from_beginning (bug 626/627) */ int DetectByteJumpTestPacket06 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XX04abcdABCD"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,relative,string,dec,from_beginning; content:\"ABCD\"; distance:4; within:4; sid:1; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } /** * \test check matches of with from_beginning (bug 626/627) */ int DetectByteJumpTestPacket07 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XX04abcdABCD"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,relative,string,dec,from_beginning; content:\"abcdABCD\"; distance:0; within:8; sid:1; rev:1;)"; result = UTHPacketMatchSig(p, sig) ? 1 : 0; UTHFreePacket(p); end: return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectBytejump */ void DetectBytejumpRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01, 1); UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02, 1); UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03, 1); UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04, 1); UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05, 1); UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06, 1); UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07, 1); UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08, 1); UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09, 1); UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10, 1); UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11, 1); UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12, 1); UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01, 1); UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02, 1); UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03, 1); UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04, 1); UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05, 1); UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06, 1); UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/runmode-unix-socket.c0000644000000000000000000002754312253546156015124 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-pcap-file.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "unix-manager.h" #include "flow-manager.h" #include "flow-timeout.h" #include "stream-tcp.h" #include "output.h" #include "host.h" #include "defrag.h" static const char *default_mode = NULL; int unix_socket_mode_is_running = 0; typedef struct PcapFiles_ { char *filename; char *output_dir; TAILQ_ENTRY(PcapFiles_) next; } PcapFiles; typedef struct PcapCommand_ { DetectEngineCtx *de_ctx; TAILQ_HEAD(, PcapFiles_) files; int running; char *currentfile; } PcapCommand; const char *RunModeUnixSocketGetDefaultMode(void) { return default_mode; } #ifdef BUILD_UNIX_SOCKET static int unix_manager_file_task_running = 0; static int unix_manager_file_task_failed = 0; /** * \brief return list of files in the queue * * \retval 0 in case of error, 1 in case of success */ static TmEcode UnixSocketPcapFilesList(json_t *cmd, json_t* answer, void *data) { PcapCommand *this = (PcapCommand *) data; int i = 0; PcapFiles *file; json_t *jdata; json_t *jarray; jdata = json_object(); if (jdata == NULL) { json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } jarray = json_array(); if (jarray == NULL) { json_decref(jdata); json_object_set_new(answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } TAILQ_FOREACH(file, &this->files, next) { json_array_append_new(jarray, json_string(file->filename)); i++; } json_object_set_new(jdata, "count", json_integer(i)); json_object_set_new(jdata, "files", jarray); json_object_set_new(answer, "message", jdata); return TM_ECODE_OK; } static TmEcode UnixSocketPcapFilesNumber(json_t *cmd, json_t* answer, void *data) { PcapCommand *this = (PcapCommand *) data; int i = 0; PcapFiles *file; TAILQ_FOREACH(file, &this->files, next) { i++; } json_object_set_new(answer, "message", json_integer(i)); return TM_ECODE_OK; } static TmEcode UnixSocketPcapCurrent(json_t *cmd, json_t* answer, void *data) { PcapCommand *this = (PcapCommand *) data; if (this->currentfile) { json_object_set_new(answer, "message", json_string(this->currentfile)); } else { json_object_set_new(answer, "message", json_string("None")); } return TM_ECODE_OK; } static void PcapFilesFree(PcapFiles *cfile) { if (cfile == NULL) return; if (cfile->filename) SCFree(cfile->filename); if (cfile->output_dir) SCFree(cfile->output_dir); SCFree(cfile); } /** * \brief Add file to file queue * * \param this a UnixCommand:: structure * \param filename absolute filename * \param output_dir absolute name of directory where log will be put * * \retval 0 in case of error, 1 in case of success */ TmEcode UnixListAddFile(PcapCommand *this, const char *filename, const char *output_dir) { PcapFiles *cfile = NULL; if (filename == NULL || this == NULL) return TM_ECODE_FAILED; cfile = SCMalloc(sizeof(PcapFiles)); if (unlikely(cfile == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate new file"); return TM_ECODE_FAILED; } memset(cfile, 0, sizeof(PcapFiles)); cfile->filename = SCStrdup(filename); if (unlikely(cfile->filename == NULL)) { SCFree(cfile); SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup filename"); return TM_ECODE_FAILED; } if (output_dir) { cfile->output_dir = SCStrdup(output_dir); if (unlikely(cfile->output_dir == NULL)) { SCFree(cfile->filename); SCFree(cfile); SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup output_dir"); return TM_ECODE_FAILED; } } TAILQ_INSERT_TAIL(&this->files, cfile, next); return TM_ECODE_OK; } /** * \brief Command to add a file to treatment list * * \param cmd the content of command Arguments as a json_t object * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data) { PcapCommand *this = (PcapCommand *) data; int ret; const char *filename; const char *output_dir; #ifdef OS_WIN32 struct _stat st; #else struct stat st; #endif /* OS_WIN32 */ json_t *jarg = json_object_get(cmd, "filename"); if(!json_is_string(jarg)) { SCLogInfo("error: command is not a string"); json_object_set_new(answer, "message", json_string("command is not a string")); return TM_ECODE_FAILED; } filename = json_string_value(jarg); #ifdef OS_WIN32 if(_stat(filename, &st) != 0) { #else if(stat(filename, &st) != 0) { #endif /* OS_WIN32 */ json_object_set_new(answer, "message", json_string("File does not exist")); return TM_ECODE_FAILED; } json_t *oarg = json_object_get(cmd, "output-dir"); if (oarg != NULL) { if(!json_is_string(oarg)) { SCLogInfo("error: output dir is not a string"); json_object_set_new(answer, "message", json_string("output dir is not a string")); return TM_ECODE_FAILED; } output_dir = json_string_value(oarg); } else { SCLogInfo("error: can't get output-dir"); json_object_set_new(answer, "message", json_string("output dir param is mandatory")); return TM_ECODE_FAILED; } #ifdef OS_WIN32 if(_stat(output_dir, &st) != 0) { #else if(stat(output_dir, &st) != 0) { #endif /* OS_WIN32 */ json_object_set_new(answer, "message", json_string("Output directory does not exist")); return TM_ECODE_FAILED; } ret = UnixListAddFile(this, filename, output_dir); switch(ret) { case TM_ECODE_FAILED: json_object_set_new(answer, "message", json_string("Unable to add file to list")); return TM_ECODE_FAILED; case TM_ECODE_OK: SCLogInfo("Added file '%s' to list", filename); json_object_set_new(answer, "message", json_string("Successfully added file to list")); return TM_ECODE_OK; } return TM_ECODE_OK; } /** * \brief Handle the file queue * * This function check if there is currently a file * being parse. If it is not the case, it will start to * work on a new file. This implies to start a new 'pcap-file' * running mode after having set the file and the output dir. * This function also handles the cleaning of the previous * running mode. * * \param this a UnixCommand:: structure * \retval 0 in case of error, 1 in case of success */ TmEcode UnixSocketPcapFilesCheck(void *data) { PcapCommand *this = (PcapCommand *) data; if (unix_manager_file_task_running == 1) { return TM_ECODE_OK; } if ((unix_manager_file_task_failed == 1) || (this->running == 1)) { if (unix_manager_file_task_failed) { SCLogInfo("Preceeding taks failed, cleaning the running mode"); } unix_manager_file_task_failed = 0; this->running = 0; if (this->currentfile) { SCFree(this->currentfile); } this->currentfile = NULL; TmThreadKillThreadsFamily(TVT_MGMT); TmThreadClearThreadsFamily(TVT_MGMT); TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM); FlowForceReassembly(); TmThreadKillThreadsFamily(TVT_PPT); TmThreadClearThreadsFamily(TVT_PPT); RunModeShutDown(); SCPerfReleaseResources(); /* thread killed, we can run non thread-safe shutdown functions */ FlowShutdown(); HostCleanup(); StreamTcpFreeConfig(STREAM_VERBOSE); DefragDestroy(); TmqResetQueues(); } if (!TAILQ_EMPTY(&this->files)) { PcapFiles *cfile = TAILQ_FIRST(&this->files); TAILQ_REMOVE(&this->files, cfile, next); SCLogInfo("Starting run for '%s'", cfile->filename); unix_manager_file_task_running = 1; this->running = 1; if (ConfSet("pcap-file.file", cfile->filename, 1) != 1) { SCLogInfo("Can not set working file to '%s'", cfile->filename); PcapFilesFree(cfile); return TM_ECODE_FAILED; } if (cfile->output_dir) { if (ConfSet("default-log-dir", cfile->output_dir, 1) != 1) { SCLogInfo("Can not set output dir to '%s'", cfile->output_dir); PcapFilesFree(cfile); return TM_ECODE_FAILED; } } this->currentfile = SCStrdup(cfile->filename); PcapFilesFree(cfile); SCPerfInitCounterApi(); DefragInit(); FlowInitConfig(FLOW_QUIET); StreamTcpInitConfig(STREAM_VERBOSE); RunModeInitializeOutputs(); RunModeDispatch(RUNMODE_PCAP_FILE, NULL, this->de_ctx); FlowManagerThreadSpawn(); SCPerfSpawnThreads(); /* Un-pause all the paused threads */ TmThreadContinueThreads(); } return TM_ECODE_OK; } #endif void RunModeUnixSocketRegister(void) { #ifdef BUILD_UNIX_SOCKET RunModeRegisterNewRunMode(RUNMODE_UNIX_SOCKET, "single", "Unix socket mode", RunModeUnixSocketSingle); default_mode = "single"; #endif return; } void UnixSocketPcapFile(TmEcode tm) { #ifdef BUILD_UNIX_SOCKET switch (tm) { case TM_ECODE_DONE: unix_manager_file_task_running = 0; break; case TM_ECODE_FAILED: unix_manager_file_task_running = 0; unix_manager_file_task_failed = 1; break; case TM_ECODE_OK: break; } #endif } /** * \brief Single thread version of the Pcap file processing. */ int RunModeUnixSocketSingle(DetectEngineCtx *de_ctx) { #ifdef BUILD_UNIX_SOCKET PcapCommand *pcapcmd = SCMalloc(sizeof(PcapCommand)); if (unlikely(pcapcmd == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can not allocate pcap command"); return 1; } pcapcmd->de_ctx = de_ctx; TAILQ_INIT(&pcapcmd->files); pcapcmd->currentfile = NULL; UnixManagerThreadSpawn(de_ctx, 1); unix_socket_mode_is_running = 1; UnixManagerRegisterCommand("pcap-file", UnixSocketAddPcapFile, pcapcmd, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("pcap-file-number", UnixSocketPcapFilesNumber, pcapcmd, 0); UnixManagerRegisterCommand("pcap-file-list", UnixSocketPcapFilesList, pcapcmd, 0); UnixManagerRegisterCommand("pcap-current", UnixSocketPcapCurrent, pcapcmd, 0); UnixManagerRegisterBackgroundTask(UnixSocketPcapFilesCheck, pcapcmd); #endif return 0; } int RunModeUnixSocketIsActive(void) { return unix_socket_mode_is_running; } suricata-1.4.7/src/cuda-ptxdump.h0000644000000000000000000073473312253546156013632 00000000000000/* Auto-generated by ptxdump.py DO NOT EDIT * * This file contains the ptx code of the Cuda kernels. * A kernel is identified by its name and the compute capability (e.g. _sm_10). */ #ifdef __SC_CUDA_SUPPORT__ #ifndef __ptxdump_h__ #define __ptxdump_h__ const unsigned char util_mpm_b2g_cuda_kernel_sm_10[6760] = { 0x09, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x34, 0x0a, 0x09, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x73, 0x6d, 0x5f, 0x31, 0x30, 0x2c, 0x20, 0x6d, 0x61, 0x70, 0x5f, 0x66, 0x36, 0x34, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x34, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x2f, 0x62, 0x65, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x6e, 0x76, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x63, 0x20, 0x33, 0x2e, 0x32, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x20, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x31, 0x31, 0x2d, 0x30, 0x33, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x36, 0x37, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x39, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x70, 0x70, 0x33, 0x2e, 0x69, 0x20, 0x28, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x63, 0x63, 0x42, 0x49, 0x23, 0x2e, 0x38, 0x63, 0x4c, 0x33, 0x78, 0x63, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3a, 0x70, 0x74, 0x78, 0x2c, 0x20, 0x49, 0x53, 0x41, 0x3a, 0x73, 0x6d, 0x5f, 0x31, 0x30, 0x2c, 0x20, 0x45, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x3a, 0x6c, 0x69, 0x74, 0x74, 0x6c, 0x65, 0x2c, 0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x53, 0x69, 0x7a, 0x65, 0x3a, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x4f, 0x33, 0x09, 0x28, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x67, 0x30, 0x09, 0x28, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x6d, 0x32, 0x09, 0x28, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x09, 0x22, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x3e, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x09, 0x22, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x36, 0x37, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x64, 0x61, 0x66, 0x65, 0x32, 0x2e, 0x67, 0x70, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x33, 0x09, 0x22, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x67, 0x63, 0x63, 0x2f, 0x69, 0x36, 0x38, 0x36, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x2f, 0x34, 0x2e, 0x34, 0x2e, 0x35, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x64, 0x64, 0x65, 0x66, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x31, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x32, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x33, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x69, 0x6e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x64, 0x62, 0x6c, 0x5f, 0x70, 0x74, 0x78, 0x31, 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x0a, 0x09, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x20, 0x28, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x0a, 0x09, 0x7b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x25, 0x72, 0x68, 0x3c, 0x36, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x25, 0x72, 0x3c, 0x36, 0x34, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x70, 0x72, 0x65, 0x64, 0x20, 0x25, 0x70, 0x3c, 0x31, 0x30, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x35, 0x33, 0x09, 0x30, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x31, 0x2c, 0x20, 0x25, 0x63, 0x74, 0x61, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x77, 0x69, 0x64, 0x65, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x31, 0x2c, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x09, 0x63, 0x76, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x74, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x31, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x32, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x39, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x39, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x38, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x34, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x32, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x31, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x37, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x39, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x37, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x32, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x39, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x39, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x33, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x72, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x34, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x34, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x35, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x77, 0x69, 0x64, 0x65, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x34, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x35, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x34, 0x36, 0x2b, 0x32, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x39, 0x33, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x37, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x36, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x34, 0x38, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x30, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x34, 0x38, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x33, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x35, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x6e, 0x64, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x30, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x31, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6e, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x31, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x37, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x39, 0x31, 0x34, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x38, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x39, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x32, 0x32, 0x2b, 0x30, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x31, 0x31, 0x09, 0x30, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x3b, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x65, 0x6e, 0x64, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x7d, 0x20, 0x2f, 0x2f, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x0a, 0x0a, 0x00 }; const unsigned char util_mpm_b2g_cuda_kernel_sm_11[6760] = { 0x09, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x34, 0x0a, 0x09, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x73, 0x6d, 0x5f, 0x31, 0x31, 0x2c, 0x20, 0x6d, 0x61, 0x70, 0x5f, 0x66, 0x36, 0x34, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x34, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x2f, 0x62, 0x65, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x6e, 0x76, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x63, 0x20, 0x33, 0x2e, 0x32, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x20, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x31, 0x31, 0x2d, 0x30, 0x33, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x38, 0x62, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x39, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x70, 0x70, 0x33, 0x2e, 0x69, 0x20, 0x28, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x63, 0x63, 0x42, 0x49, 0x23, 0x2e, 0x4b, 0x4b, 0x51, 0x68, 0x4d, 0x33, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3a, 0x70, 0x74, 0x78, 0x2c, 0x20, 0x49, 0x53, 0x41, 0x3a, 0x73, 0x6d, 0x5f, 0x31, 0x31, 0x2c, 0x20, 0x45, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x3a, 0x6c, 0x69, 0x74, 0x74, 0x6c, 0x65, 0x2c, 0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x53, 0x69, 0x7a, 0x65, 0x3a, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x4f, 0x33, 0x09, 0x28, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x67, 0x30, 0x09, 0x28, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x6d, 0x32, 0x09, 0x28, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x09, 0x22, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x3e, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x09, 0x22, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x38, 0x62, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x64, 0x61, 0x66, 0x65, 0x32, 0x2e, 0x67, 0x70, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x33, 0x09, 0x22, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x67, 0x63, 0x63, 0x2f, 0x69, 0x36, 0x38, 0x36, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x2f, 0x34, 0x2e, 0x34, 0x2e, 0x35, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x64, 0x64, 0x65, 0x66, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x31, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x32, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x33, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x69, 0x6e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x64, 0x62, 0x6c, 0x5f, 0x70, 0x74, 0x78, 0x31, 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x0a, 0x09, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x20, 0x28, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x0a, 0x09, 0x7b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x25, 0x72, 0x68, 0x3c, 0x36, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x25, 0x72, 0x3c, 0x36, 0x34, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x70, 0x72, 0x65, 0x64, 0x20, 0x25, 0x70, 0x3c, 0x31, 0x30, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x35, 0x33, 0x09, 0x30, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x31, 0x2c, 0x20, 0x25, 0x63, 0x74, 0x61, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x77, 0x69, 0x64, 0x65, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x31, 0x2c, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x09, 0x63, 0x76, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x74, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x31, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x32, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x39, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x39, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x38, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x34, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x32, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x31, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x37, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x39, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x37, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x32, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x39, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x39, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x33, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x72, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x34, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x34, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x35, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x77, 0x69, 0x64, 0x65, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x34, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x35, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x34, 0x36, 0x2b, 0x32, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x39, 0x33, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x37, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x36, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x34, 0x38, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x30, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x34, 0x38, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x33, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x35, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x6e, 0x64, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x30, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x31, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6e, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x31, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x37, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x39, 0x31, 0x34, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x38, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x39, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x32, 0x32, 0x2b, 0x30, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x31, 0x31, 0x09, 0x30, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x3b, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x65, 0x6e, 0x64, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x7d, 0x20, 0x2f, 0x2f, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x0a, 0x0a, 0x00 }; const unsigned char util_mpm_b2g_cuda_kernel_sm_12[6760] = { 0x09, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x34, 0x0a, 0x09, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x73, 0x6d, 0x5f, 0x31, 0x32, 0x2c, 0x20, 0x6d, 0x61, 0x70, 0x5f, 0x66, 0x36, 0x34, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x34, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x2f, 0x62, 0x65, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x6e, 0x76, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x63, 0x20, 0x33, 0x2e, 0x32, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x20, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x31, 0x31, 0x2d, 0x30, 0x33, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x61, 0x66, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x39, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x70, 0x70, 0x33, 0x2e, 0x69, 0x20, 0x28, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x63, 0x63, 0x42, 0x49, 0x23, 0x2e, 0x74, 0x48, 0x64, 0x42, 0x71, 0x54, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3a, 0x70, 0x74, 0x78, 0x2c, 0x20, 0x49, 0x53, 0x41, 0x3a, 0x73, 0x6d, 0x5f, 0x31, 0x32, 0x2c, 0x20, 0x45, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x3a, 0x6c, 0x69, 0x74, 0x74, 0x6c, 0x65, 0x2c, 0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x53, 0x69, 0x7a, 0x65, 0x3a, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x4f, 0x33, 0x09, 0x28, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x67, 0x30, 0x09, 0x28, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x6d, 0x32, 0x09, 0x28, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x09, 0x22, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x3e, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x09, 0x22, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x61, 0x66, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x64, 0x61, 0x66, 0x65, 0x32, 0x2e, 0x67, 0x70, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x33, 0x09, 0x22, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x67, 0x63, 0x63, 0x2f, 0x69, 0x36, 0x38, 0x36, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x2f, 0x34, 0x2e, 0x34, 0x2e, 0x35, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x64, 0x64, 0x65, 0x66, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x31, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x32, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x33, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x69, 0x6e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x64, 0x62, 0x6c, 0x5f, 0x70, 0x74, 0x78, 0x31, 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x0a, 0x09, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x20, 0x28, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x0a, 0x09, 0x7b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x25, 0x72, 0x68, 0x3c, 0x36, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x25, 0x72, 0x3c, 0x36, 0x34, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x70, 0x72, 0x65, 0x64, 0x20, 0x25, 0x70, 0x3c, 0x31, 0x30, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x35, 0x33, 0x09, 0x30, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x31, 0x2c, 0x20, 0x25, 0x63, 0x74, 0x61, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x77, 0x69, 0x64, 0x65, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x31, 0x2c, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x09, 0x63, 0x76, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x74, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x31, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x32, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x39, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x39, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x38, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x34, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x32, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x31, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x37, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x39, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x37, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x32, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x39, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x39, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x33, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x72, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x34, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x34, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x35, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x77, 0x69, 0x64, 0x65, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x34, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x35, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x34, 0x36, 0x2b, 0x32, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x39, 0x33, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x37, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x36, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x34, 0x38, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x30, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x34, 0x38, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x33, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x35, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x6e, 0x64, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x30, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x31, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6e, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x31, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x37, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x39, 0x31, 0x34, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x38, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x39, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x32, 0x32, 0x2b, 0x30, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x31, 0x31, 0x09, 0x30, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x3b, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x65, 0x6e, 0x64, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x7d, 0x20, 0x2f, 0x2f, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x0a, 0x0a, 0x00 }; const unsigned char util_mpm_b2g_cuda_kernel_sm_13[6744] = { 0x09, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x34, 0x0a, 0x09, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x73, 0x6d, 0x5f, 0x31, 0x33, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x34, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x2f, 0x62, 0x65, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x6e, 0x76, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x63, 0x20, 0x33, 0x2e, 0x32, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x20, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x31, 0x31, 0x2d, 0x30, 0x33, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x64, 0x33, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x39, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x70, 0x70, 0x33, 0x2e, 0x69, 0x20, 0x28, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x63, 0x63, 0x42, 0x49, 0x23, 0x2e, 0x6c, 0x5a, 0x6c, 0x54, 0x41, 0x51, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3a, 0x70, 0x74, 0x78, 0x2c, 0x20, 0x49, 0x53, 0x41, 0x3a, 0x73, 0x6d, 0x5f, 0x31, 0x33, 0x2c, 0x20, 0x45, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x3a, 0x6c, 0x69, 0x74, 0x74, 0x6c, 0x65, 0x2c, 0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x53, 0x69, 0x7a, 0x65, 0x3a, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x4f, 0x33, 0x09, 0x28, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x67, 0x30, 0x09, 0x28, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x6d, 0x32, 0x09, 0x28, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x09, 0x22, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x3e, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x09, 0x22, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x64, 0x33, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x64, 0x61, 0x66, 0x65, 0x32, 0x2e, 0x67, 0x70, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x33, 0x09, 0x22, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x67, 0x63, 0x63, 0x2f, 0x69, 0x36, 0x38, 0x36, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x2f, 0x34, 0x2e, 0x34, 0x2e, 0x35, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x64, 0x64, 0x65, 0x66, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x31, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x32, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x33, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x69, 0x6e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x64, 0x62, 0x6c, 0x5f, 0x70, 0x74, 0x78, 0x33, 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x0a, 0x09, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x20, 0x28, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x0a, 0x09, 0x7b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x25, 0x72, 0x68, 0x3c, 0x36, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x25, 0x72, 0x3c, 0x36, 0x34, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x70, 0x72, 0x65, 0x64, 0x20, 0x25, 0x70, 0x3c, 0x31, 0x30, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x35, 0x33, 0x09, 0x30, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x31, 0x2c, 0x20, 0x25, 0x63, 0x74, 0x61, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x77, 0x69, 0x64, 0x65, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x31, 0x2c, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x09, 0x63, 0x76, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x74, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x31, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x32, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x39, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x39, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x38, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x30, 0x2b, 0x34, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x32, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x31, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x37, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x39, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x37, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x32, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x39, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x39, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x33, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x72, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x34, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x34, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x35, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x77, 0x69, 0x64, 0x65, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x34, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x33, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x35, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x34, 0x36, 0x2b, 0x32, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x39, 0x33, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x37, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x36, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x34, 0x38, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x30, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x34, 0x38, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x33, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x35, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x6e, 0x64, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x30, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x31, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6e, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x31, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x37, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x39, 0x31, 0x34, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x38, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x25, 0x72, 0x68, 0x32, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x39, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x32, 0x32, 0x2b, 0x30, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x68, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x31, 0x31, 0x09, 0x30, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x3b, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x65, 0x6e, 0x64, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x7d, 0x20, 0x2f, 0x2f, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x0a, 0x0a, 0x00 }; const unsigned char util_mpm_b2g_cuda_kernel_sm_20[6506] = { 0x09, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x2e, 0x32, 0x0a, 0x09, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x34, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x2f, 0x62, 0x65, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x6e, 0x76, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x63, 0x20, 0x33, 0x2e, 0x32, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x20, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x31, 0x31, 0x2d, 0x30, 0x33, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x66, 0x37, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x39, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x70, 0x70, 0x33, 0x2e, 0x69, 0x20, 0x28, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x63, 0x63, 0x42, 0x49, 0x23, 0x2e, 0x41, 0x63, 0x44, 0x65, 0x43, 0x4c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3a, 0x70, 0x74, 0x78, 0x2c, 0x20, 0x49, 0x53, 0x41, 0x3a, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x2c, 0x20, 0x45, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x3a, 0x6c, 0x69, 0x74, 0x74, 0x6c, 0x65, 0x2c, 0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x53, 0x69, 0x7a, 0x65, 0x3a, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x4f, 0x33, 0x09, 0x28, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x67, 0x30, 0x09, 0x28, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x6d, 0x32, 0x09, 0x28, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x09, 0x22, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x3e, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x09, 0x22, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x66, 0x37, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x64, 0x61, 0x66, 0x65, 0x32, 0x2e, 0x67, 0x70, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x33, 0x09, 0x22, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x67, 0x63, 0x63, 0x2f, 0x69, 0x36, 0x38, 0x36, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x2f, 0x34, 0x2e, 0x34, 0x2e, 0x35, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x64, 0x64, 0x65, 0x66, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x31, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x32, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x33, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x69, 0x6e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x64, 0x62, 0x6c, 0x5f, 0x70, 0x74, 0x78, 0x33, 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x0a, 0x09, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x20, 0x28, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x0a, 0x09, 0x7b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x25, 0x72, 0x3c, 0x36, 0x38, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x70, 0x72, 0x65, 0x64, 0x20, 0x25, 0x70, 0x3c, 0x31, 0x30, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x35, 0x33, 0x09, 0x30, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x2c, 0x20, 0x25, 0x63, 0x74, 0x61, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x2c, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x25, 0x74, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x31, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x32, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x31, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x31, 0x2b, 0x38, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x31, 0x2b, 0x34, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x38, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x39, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x31, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x32, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x31, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x39, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x31, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x39, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x34, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x36, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x37, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x39, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x31, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x33, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x72, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x36, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x36, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x34, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x35, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x38, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x63, 0x76, 0x74, 0x2e, 0x75, 0x31, 0x36, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x38, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x39, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x35, 0x30, 0x2b, 0x32, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x39, 0x33, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x31, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x36, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x32, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x35, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x34, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x32, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x38, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x39, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x30, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x31, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x36, 0x32, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x6e, 0x64, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x35, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6e, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x35, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x37, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x39, 0x31, 0x34, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x36, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x38, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x39, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x32, 0x33, 0x2b, 0x30, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x38, 0x3b, 0x0a, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x31, 0x31, 0x09, 0x30, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x3b, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x65, 0x6e, 0x64, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x7d, 0x20, 0x2f, 0x2f, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x0a, 0x0a, 0x00 }; const unsigned char util_mpm_b2g_cuda_kernel_sm_21[6506] = { 0x09, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x2e, 0x32, 0x0a, 0x09, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x34, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x2f, 0x62, 0x65, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x6e, 0x76, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x63, 0x20, 0x33, 0x2e, 0x32, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x20, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x30, 0x2d, 0x31, 0x31, 0x2d, 0x30, 0x33, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x64, 0x31, 0x62, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x39, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x70, 0x70, 0x33, 0x2e, 0x69, 0x20, 0x28, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x63, 0x63, 0x42, 0x49, 0x23, 0x2e, 0x75, 0x73, 0x58, 0x37, 0x67, 0x42, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3a, 0x70, 0x74, 0x78, 0x2c, 0x20, 0x49, 0x53, 0x41, 0x3a, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x2c, 0x20, 0x45, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x3a, 0x6c, 0x69, 0x74, 0x74, 0x6c, 0x65, 0x2c, 0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x53, 0x69, 0x7a, 0x65, 0x3a, 0x33, 0x32, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x4f, 0x33, 0x09, 0x28, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x67, 0x30, 0x09, 0x28, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x20, 0x2d, 0x6d, 0x32, 0x09, 0x28, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x29, 0x0a, 0x09, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x09, 0x22, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x3e, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x09, 0x22, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x74, 0x6d, 0x70, 0x78, 0x66, 0x74, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x64, 0x31, 0x62, 0x5f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x38, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x64, 0x61, 0x66, 0x65, 0x32, 0x2e, 0x67, 0x70, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x33, 0x09, 0x22, 0x75, 0x74, 0x69, 0x6c, 0x2d, 0x6d, 0x70, 0x6d, 0x2d, 0x62, 0x32, 0x67, 0x2d, 0x63, 0x75, 0x64, 0x61, 0x2d, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2e, 0x63, 0x75, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x67, 0x63, 0x63, 0x2f, 0x69, 0x36, 0x38, 0x36, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x2f, 0x34, 0x2e, 0x34, 0x2e, 0x35, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x64, 0x64, 0x65, 0x66, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x62, 0x69, 0x74, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x31, 0x39, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x30, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x31, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x32, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x31, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x33, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x32, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x34, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x31, 0x33, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x35, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x36, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x6d, 0x5f, 0x32, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x69, 0x6e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x37, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x73, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x22, 0x0a, 0x09, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x32, 0x38, 0x09, 0x22, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x63, 0x75, 0x64, 0x61, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2e, 0x2e, 0x2f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x64, 0x62, 0x6c, 0x5f, 0x70, 0x74, 0x78, 0x33, 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x0a, 0x09, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x20, 0x28, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x2c, 0x0a, 0x09, 0x09, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x0a, 0x09, 0x7b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x25, 0x72, 0x3c, 0x36, 0x38, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x72, 0x65, 0x67, 0x20, 0x2e, 0x70, 0x72, 0x65, 0x64, 0x20, 0x25, 0x70, 0x3c, 0x31, 0x30, 0x3e, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x35, 0x33, 0x09, 0x30, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x2c, 0x20, 0x25, 0x63, 0x74, 0x61, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x2c, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x25, 0x74, 0x69, 0x64, 0x2e, 0x78, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x6e, 0x6f, 0x70, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x31, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x35, 0x36, 0x33, 0x34, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x32, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x39, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x38, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x30, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x30, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x31, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x31, 0x2b, 0x38, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x31, 0x2b, 0x34, 0x5d, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x36, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x37, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x38, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x31, 0x39, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x31, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x32, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x33, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x74, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x32, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x31, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x37, 0x2c, 0x20, 0x5b, 0x5f, 0x5f, 0x63, 0x75, 0x64, 0x61, 0x70, 0x61, 0x72, 0x6d, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x5f, 0x67, 0x5f, 0x75, 0x38, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x39, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x32, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x31, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x32, 0x39, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x34, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x35, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x36, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x37, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x33, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x33, 0x38, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x33, 0x39, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x31, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x31, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x33, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x3b, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x38, 0x37, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x33, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x72, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x35, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x36, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x36, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x34, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6c, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x34, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x35, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x37, 0x30, 0x36, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x39, 0x35, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x73, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x38, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x63, 0x76, 0x74, 0x2e, 0x75, 0x31, 0x36, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x38, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x37, 0x2c, 0x20, 0x32, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x39, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x35, 0x30, 0x2b, 0x32, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x38, 0x34, 0x35, 0x30, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x39, 0x33, 0x38, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x30, 0x09, 0x30, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x31, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x65, 0x71, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x31, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x36, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3b, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x33, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x32, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x32, 0x2b, 0x31, 0x32, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x35, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x34, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x32, 0x2b, 0x31, 0x31, 0x5d, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x37, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x38, 0x20, 0x09, 0x25, 0x72, 0x35, 0x38, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x35, 0x37, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x35, 0x39, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x38, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x6f, 0x72, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x35, 0x2c, 0x20, 0x25, 0x72, 0x35, 0x39, 0x3b, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x2e, 0x6c, 0x6f, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x31, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x30, 0x2c, 0x20, 0x34, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x31, 0x3b, 0x0a, 0x09, 0x6c, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x33, 0x2c, 0x20, 0x5b, 0x25, 0x72, 0x36, 0x32, 0x2b, 0x30, 0x5d, 0x3b, 0x0a, 0x09, 0x73, 0x68, 0x6c, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x61, 0x6e, 0x64, 0x2e, 0x62, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x33, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x34, 0x3b, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x35, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x6e, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x37, 0x2c, 0x20, 0x25, 0x72, 0x34, 0x30, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x35, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x37, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x37, 0x36, 0x38, 0x32, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x32, 0x35, 0x38, 0x3a, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x39, 0x31, 0x34, 0x3a, 0x0a, 0x20, 0x2f, 0x2f, 0x3c, 0x6c, 0x6f, 0x6f, 0x70, 0x3e, 0x20, 0x50, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x38, 0x33, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x64, 0x20, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x36, 0x09, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x36, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x32, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x3b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x31, 0x36, 0x2c, 0x20, 0x25, 0x72, 0x36, 0x36, 0x2c, 0x20, 0x31, 0x3b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x70, 0x2e, 0x67, 0x65, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x70, 0x38, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x34, 0x2c, 0x20, 0x25, 0x72, 0x31, 0x36, 0x3b, 0x0a, 0x09, 0x40, 0x25, 0x70, 0x38, 0x20, 0x62, 0x72, 0x61, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x36, 0x35, 0x38, 0x3b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x2e, 0x75, 0x6e, 0x69, 0x20, 0x09, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x39, 0x34, 0x37, 0x34, 0x3a, 0x0a, 0x09, 0x6d, 0x6f, 0x76, 0x2e, 0x75, 0x33, 0x32, 0x20, 0x09, 0x25, 0x72, 0x32, 0x38, 0x2c, 0x20, 0x30, 0x3b, 0x0a, 0x24, 0x4c, 0x74, 0x5f, 0x30, 0x5f, 0x36, 0x31, 0x34, 0x36, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x30, 0x39, 0x09, 0x30, 0x0a, 0x09, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x75, 0x31, 0x36, 0x20, 0x09, 0x5b, 0x25, 0x72, 0x32, 0x33, 0x2b, 0x30, 0x5d, 0x2c, 0x20, 0x25, 0x72, 0x32, 0x38, 0x3b, 0x0a, 0x24, 0x4c, 0x42, 0x42, 0x31, 0x37, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x2e, 0x6c, 0x6f, 0x63, 0x09, 0x33, 0x09, 0x31, 0x31, 0x31, 0x09, 0x30, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x3b, 0x0a, 0x24, 0x4c, 0x44, 0x57, 0x65, 0x6e, 0x64, 0x5f, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x3a, 0x0a, 0x09, 0x7d, 0x20, 0x2f, 0x2f, 0x20, 0x42, 0x32, 0x67, 0x43, 0x75, 0x64, 0x61, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x4e, 0x44, 0x4d, 0x71, 0x0a, 0x0a, 0x00 }; const unsigned char* SCCudaPtxDumpGetModule(const char* module){ if (!strcmp(module, "util-mpm-b2g-cuda-kernel_sm_10")) return util_mpm_b2g_cuda_kernel_sm_10; if (!strcmp(module, "util-mpm-b2g-cuda-kernel_sm_11")) return util_mpm_b2g_cuda_kernel_sm_11; if (!strcmp(module, "util-mpm-b2g-cuda-kernel_sm_12")) return util_mpm_b2g_cuda_kernel_sm_12; if (!strcmp(module, "util-mpm-b2g-cuda-kernel_sm_13")) return util_mpm_b2g_cuda_kernel_sm_13; if (!strcmp(module, "util-mpm-b2g-cuda-kernel_sm_20")) return util_mpm_b2g_cuda_kernel_sm_20; if (!strcmp(module, "util-mpm-b2g-cuda-kernel_sm_21")) return util_mpm_b2g_cuda_kernel_sm_21; SCLogError(SC_ERR_FATAL, "Error in SCCudaPtxDumpGetModule, module %s not found. Exiting...",module); exit(EXIT_FAILURE); }; #endif /* __ptxdump_h__ */ #endif /* __SC_CUDA_SUPPORT__ */ suricata-1.4.7/src/detect-id.c0000644000000000000000000002433612253546156013043 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * Implements the id keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-id.h" #include "flow.h" #include "flow-var.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" /** * \brief Regex for parsing "id" option, matching number or "number" */ #define PARSE_REGEX "^\\s*([0-9]{1,5}|\"[0-9]{1,5}\")\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectIdMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectIdSetup (DetectEngineCtx *, Signature *, char *); void DetectIdRegisterTests(void); void DetectIdFree(void *); /** * \brief Registration function for keyword: id */ void DetectIdRegister (void) { sigmatch_table[DETECT_ID].name = "id"; sigmatch_table[DETECT_ID].desc = "match on a specific IP ID value"; sigmatch_table[DETECT_ID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Id"; sigmatch_table[DETECT_ID].Match = DetectIdMatch; sigmatch_table[DETECT_ID].Setup = DetectIdSetup; sigmatch_table[DETECT_ID].Free = DetectIdFree; sigmatch_table[DETECT_ID].RegisterTests = DetectIdRegisterTests; const char *eb; int eo; int opts = 0; SCLogDebug("registering id rule option"); parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief This function is used to match the specified id on a packet * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectIdData * * \retval 0 no match * \retval 1 match */ int DetectIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectIdData *id_d = (DetectIdData *)m->ctx; /** * To match a ipv4 packet with a "id" rule */ if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) { return 0; } if (id_d->id == IPV4_GET_IPID(p)) { SCLogDebug("IPV4 Proto and matched with ip_id: %u.\n", id_d->id); return 1; } return 0; } /** * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" * * \param idstr Pointer to the user provided id option * * \retval id_d pointer to DetectIdData on success * \retval NULL on failure */ DetectIdData *DetectIdParse (char *idstr) { uint32_t temp; DetectIdData *id_d = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, idstr, strlen(idstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 3) { SCLogError(SC_ERR_PCRE_MATCH, "invalid id option. The id option value must be" " in the range %u - %u", DETECT_IPID_MIN, DETECT_IPID_MAX); goto error; } if (ret > 1) { const char *str_ptr; char *orig; char *tmp_str; res = pcre_get_substring((char *)idstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct id option */ id_d = SCMalloc(sizeof(DetectIdData)); if (unlikely(id_d == NULL)) goto error; orig = SCStrdup((char*)str_ptr); if (unlikely(orig == NULL)) { goto error; } tmp_str=orig; /* Let's see if we need to scape "'s */ if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } /* ok, fill the id data */ temp = atoi((char *)tmp_str); if (temp > DETECT_IPID_MAX) { SCLogError(SC_ERR_INVALID_VALUE, "\"id\" option must be in " "the range %u - %u", DETECT_IPID_MIN, DETECT_IPID_MAX); SCFree(orig); goto error; } id_d->id = temp; SCFree(orig); SCLogDebug("detect-id: will look for ip_id: %u\n", id_d->id); } return id_d; error: if (id_d != NULL) DetectIdFree(id_d); return NULL; } /** * \brief this function is used to add the parsed "id" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "id" option * * \retval 0 on Success * \retval -1 on Failure */ int DetectIdSetup (DetectEngineCtx *de_ctx, Signature *s, char *idstr) { DetectIdData *id_d = NULL; SigMatch *sm = NULL; id_d = DetectIdParse(idstr); if (id_d == 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_ID; sm->ctx = (void *)id_d; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (id_d != NULL) DetectIdFree(id_d); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectIdData * * \param id_d pointer to DetectIdData */ void DetectIdFree(void *ptr) { DetectIdData *id_d = (DetectIdData *)ptr; SCFree(id_d); } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectIdTestParse01 is a test to make sure that we parse the "id" * option correctly when given valid id option */ int DetectIdTestParse01 (void) { DetectIdData *id_d = NULL; id_d = DetectIdParse(" 35402 "); if (id_d != NULL &&id_d->id==35402) { DetectIdFree(id_d); return 1; } return 0; } /** * \test DetectIdTestParse02 is a test to make sure that we parse the "id" * option correctly when given an invalid id option * it should return id_d = NULL */ int DetectIdTestParse02 (void) { DetectIdData *id_d = NULL; id_d = DetectIdParse("65537"); if (id_d == NULL) { DetectIdFree(id_d); return 1; } return 0; } /** * \test DetectIdTestParse03 is a test to make sure that we parse the "id" * option correctly when given an invalid id option * it should return id_d = NULL */ int DetectIdTestParse03 (void) { DetectIdData *id_d = NULL; id_d = DetectIdParse("12what?"); if (id_d == NULL) { DetectIdFree(id_d); return 1; } return 0; } /** * \test DetectIdTestParse04 is a test to make sure that we parse the "id" * option correctly when given valid id option but wrapped with "'s */ int DetectIdTestParse04 (void) { DetectIdData *id_d = NULL; /* yep, look if we trim blank spaces correctly and ignore "'s */ id_d = DetectIdParse(" \"35402\" "); if (id_d != NULL &&id_d->id==35402) { DetectIdFree(id_d); return 1; } return 0; } /** * \test DetectIdTestSig01 * \brief Test to check "id" keyword with constructed packets */ int DetectIdTestMatch01(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_UDP); p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; /* TCP IP id = 1234 */ p[0]->ip4h->ip_id = htons(1234); /* UDP IP id = 5678 */ p[1]->ip4h->ip_id = htons(5678); /* UDP IP id = 91011 */ p[2]->ip4h->ip_id = htons(5101); char *sigs[3]; sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; id:1234; sid:1;)"; sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; id:5678; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; id:5101; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { /* packet 0 match sid 1 but should not match sid 2 */ {1, 0, 0}, /* packet 1 should not match */ {0, 1, 0}, /* packet 2 should not match */ {0, 0, 1} }; result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 3); UTHFreePackets(p, 3); end: return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectId */ void DetectIdRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectIdTestParse01", DetectIdTestParse01, 1); UtRegisterTest("DetectIdTestParse02", DetectIdTestParse02, 1); UtRegisterTest("DetectIdTestParse03", DetectIdTestParse03, 1); UtRegisterTest("DetectIdTestParse04", DetectIdTestParse04, 1); UtRegisterTest("DetectIdTestMatch01", DetectIdTestMatch01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/flow-manager.h0000644000000000000000000000220012253546156013547 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __FLOW_MANAGER_H__ #define __FLOW_MANAGER_H__ /** flow manager scheduling condition */ SCCondT flow_manager_cond; SCMutex flow_manager_mutex; #define FlowWakeupFlowManagerThread() SCCondSignal(&flow_manager_cond) void FlowManagerThreadSpawn(void); void FlowKillFlowManagerThread(void); void FlowMgrRegisterTests (void); #endif /* __FLOW_MANAGER_H__ */ suricata-1.4.7/src/detect-flowint.h0000644000000000000000000000430612253546156014131 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_FLOWINT_H__ #define __DETECT_FLOWINT_H__ /** Flowint operations allowed */ enum { /** Changing integer values */ FLOWINT_MODIFIER_SET, FLOWINT_MODIFIER_ADD, FLOWINT_MODIFIER_SUB, /** Comparing integer values */ FLOWINT_MODIFIER_LT, FLOWINT_MODIFIER_LE, FLOWINT_MODIFIER_EQ, FLOWINT_MODIFIER_NE, FLOWINT_MODIFIER_GE, FLOWINT_MODIFIER_GT, /** Checking if a var is set (keyword isset/notset)*/ FLOWINT_MODIFIER_ISSET, FLOWINT_MODIFIER_NOTSET, FLOWINT_MODIFIER_UNKNOWN }; /** The target can be a value, or another variable arleady declared */ enum { FLOWINT_TARGET_VAL, FLOWINT_TARGET_VAR, FLOWINT_TARGET_SELF, FLOWINT_TARGET_UNKNOWN }; /** If the target is another var, get the name and the idx */ typedef struct TargetVar_ { uint16_t idx; char *name; } TargetVar; /** Context data for flowint vars */ typedef struct DetectFlowintData_ { /* This is the main var we are going to use * against the target */ char *name; /* Internal id of the var */ uint16_t idx; /* The modifier/operation/condition we are * going to execute */ uint8_t modifier; uint8_t targettype; union { /* the target value */ uint32_t value; /* or the target var */ TargetVar tvar; } target; } DetectFlowintData; /* prototypes */ void DetectFlowintRegister (void); #endif /* __DETECT_FLOWINT_H__ */ suricata-1.4.7/src/detect-flowint.c0000644000000000000000000023044012253546156014124 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * * Flowvar management for integer types, part of the detection engine * Keyword: flowint */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "threads.h" #include "flow.h" #include "flow-var.h" #include "detect-flowint.h" #include "util-spm.h" #include "util-var-name.h" #include "util-debug.h" #include "util-unittest.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" /* name modifiers value */ #define PARSE_REGEX "^\\s*([a-zA-Z][\\w\\d_.]+)\\s*,\\s*([+=-]{1}|==|!=|<|<=|>|>=|isset|notset)\\s*,?\\s*([a-zA-Z][\\w\\d]+|[\\d]{1,10})?\\s*$" /* Varnames must begin with a letter */ static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectFlowintMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectFlowintSetup(DetectEngineCtx *, Signature *, char *); void DetectFlowintFree(void *); void DetectFlowintRegisterTests(void); void DetectFlowintRegister(void) { sigmatch_table[DETECT_FLOWINT].name = "flowint"; sigmatch_table[DETECT_FLOWINT].desc = "operate on a per-flow integer"; sigmatch_table[DETECT_FLOWINT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flowint"; sigmatch_table[DETECT_FLOWINT].Match = DetectFlowintMatch; sigmatch_table[DETECT_FLOWINT].Setup = DetectFlowintSetup; sigmatch_table[DETECT_FLOWINT].Free = DetectFlowintFree; sigmatch_table[DETECT_FLOWINT].RegisterTests = DetectFlowintRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: SCLogInfo("Error registering flowint detection plugin"); return; } /** * \brief This function is used to create a flowint, add/substract values, * compare it with other flowints, etc * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param s pointer to the current Signature * \param m pointer to the sigmatch that we will cast into DetectFlowintData * * \retval 0 no match, when a var doesn't exist * \retval 1 match, when a var is initialized well, add/substracted, or a true * condition */ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectFlowintData *sfd =(DetectFlowintData *) m->ctx; FlowVar *fv; FlowVar *fvt; uint32_t targetval; /** ATM If we are going to compare the current var with another * that doesn't exist, the default value will be zero; * if you don't want this behaviour, you can use the keyword * "isset" to make it match or not before using the default * value of zero; * But it is mandatory that the current var exist, otherwise, it will * return zero(not match). */ if (sfd->targettype == FLOWINT_TARGET_VAR) { sfd->target.tvar.idx = VariableNameGetIdx(det_ctx->de_ctx, sfd->target.tvar.name, DETECT_FLOWINT); fvt = FlowVarGet(p->flow, sfd->target.tvar.idx); /* We don't have that variable initialized yet */ if (fvt == NULL) targetval = 0; else targetval = fvt->data.fv_int.value; } else { targetval = sfd->target.value; } SCLogDebug("Our var %s is at idx: %"PRIu16"", sfd->name, sfd->idx); if (sfd->modifier == FLOWINT_MODIFIER_SET) { FlowVarAddInt(p->flow, sfd->idx, targetval); SCLogDebug("Setting %s = %u", sfd->name, targetval); return 1; } fv = FlowVarGet(p->flow, sfd->idx); if (sfd->modifier == FLOWINT_MODIFIER_ISSET) { SCLogDebug(" Isset %s? = %u", sfd->name,(fv) ? 1 : 0); if (fv != NULL) return 1; else return 0; } if (sfd->modifier == FLOWINT_MODIFIER_NOTSET) { SCLogDebug(" Not set %s? = %u", sfd->name,(fv) ? 0 : 1); if (fv != NULL) return 0; else return 1; } if (fv != NULL && fv->datatype == FLOWVAR_TYPE_INT) { if (sfd->modifier == FLOWINT_MODIFIER_ADD) { SCLogDebug("Adding %u to %s", targetval, sfd->name); FlowVarAddInt(p->flow, sfd->idx, fv->data.fv_int.value + targetval); return 1; } if (sfd->modifier == FLOWINT_MODIFIER_SUB) { SCLogDebug("Substracting %u to %s", targetval, sfd->name); FlowVarAddInt(p->flow, sfd->idx, fv->data.fv_int.value - targetval); return 1; } switch(sfd->modifier) { case FLOWINT_MODIFIER_EQ: SCLogDebug("( %u EQ %u )", fv->data.fv_int.value, targetval); return fv->data.fv_int.value == targetval; break; case FLOWINT_MODIFIER_NE: SCLogDebug("( %u NE %u )", fv->data.fv_int.value, targetval); return fv->data.fv_int.value != targetval; break; case FLOWINT_MODIFIER_LT: SCLogDebug("( %u LT %u )", fv->data.fv_int.value, targetval); return fv->data.fv_int.value < targetval; break; case FLOWINT_MODIFIER_LE: SCLogDebug("( %u LE %u )", fv->data.fv_int.value, targetval); return fv->data.fv_int.value <= targetval; break; case FLOWINT_MODIFIER_GT: SCLogDebug("( %u GT %u )", fv->data.fv_int.value, targetval); return fv->data.fv_int.value > targetval; break; case FLOWINT_MODIFIER_GE: SCLogDebug("( %u GE %u )", fv->data.fv_int.value, targetval); return fv->data.fv_int.value >= targetval; break; default: SCLogDebug("Unknown Modifier!"); exit(EXIT_FAILURE); } } else { /* allow a add on a non-existing var, it will init to the "add" value, * so implying a 0 set. */ if (sfd->modifier == FLOWINT_MODIFIER_ADD) { SCLogDebug("Adding %u to %s (new var)", targetval, sfd->name); FlowVarAddInt(p->flow, sfd->idx, targetval); return 1; } else { SCLogDebug("Var not found!"); /* It doesn't exist because it wasn't set * or it is a string var, that we don't compare here */ return 0; } } } /** * \brief This function is used to parse a flowint option * * \param de_ctx pointer to the engine context * \param rawstr pointer to the string holding the options * * \retval NULL if invalid option * \retval DetectFlowintData pointer with the flowint parsed */ DetectFlowintData *DetectFlowintParse(DetectEngineCtx *de_ctx, char *rawstr) { DetectFlowintData *sfd = NULL; char *str = rawstr; char *varname = NULL; char *varval = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; uint8_t modifier = FLOWINT_MODIFIER_UNKNOWN; unsigned long long value_long = 0; const char *str_ptr; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowint(ret = %d).", rawstr, ret); return NULL; } /* Get our flowint varname */ res = pcre_get_substring((char *) rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return NULL; } varname =(char *) str_ptr; res = pcre_get_substring((char *) rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return NULL; } /* Get the modifier */ if (strcmp("=", str_ptr) == 0) modifier = FLOWINT_MODIFIER_SET; if (strcmp("+", str_ptr) == 0) modifier = FLOWINT_MODIFIER_ADD; if (strcmp("-", str_ptr) == 0) modifier = FLOWINT_MODIFIER_SUB; if (strcmp("<", str_ptr) == 0) modifier = FLOWINT_MODIFIER_LT; if (strcmp("<=", str_ptr) == 0) modifier = FLOWINT_MODIFIER_LE; if (strcmp("!=", str_ptr) == 0) modifier = FLOWINT_MODIFIER_NE; if (strcmp("==", str_ptr) == 0) modifier = FLOWINT_MODIFIER_EQ; if (strcmp(">=", str_ptr) == 0) modifier = FLOWINT_MODIFIER_GE; if (strcmp(">", str_ptr) == 0) modifier = FLOWINT_MODIFIER_GT; if (strcmp("isset", str_ptr) == 0) modifier = FLOWINT_MODIFIER_ISSET; if (strcmp("notset", str_ptr) == 0) modifier = FLOWINT_MODIFIER_NOTSET; if (modifier == FLOWINT_MODIFIER_UNKNOWN) { SCLogError(SC_ERR_UNKNOWN_VALUE, "Unknown modifier"); goto error; } sfd = SCMalloc(sizeof(DetectFlowintData)); if (unlikely(sfd == NULL)) goto error; /* If we need another arg, check it out(isset doesn't need another arg) */ if (modifier != FLOWINT_MODIFIER_ISSET && modifier != FLOWINT_MODIFIER_NOTSET) { if (ret < 4) goto error; res = pcre_get_substring((char *) rawstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); varval =(char *) str_ptr; if (res < 0 || strcmp(varval,"") == 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); SCFree(sfd); return NULL; } /* get the target value to operate with *(it should be a value or another var) */ str = SCStrdup(varval); if (unlikely(str == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "malloc from strdup failed"); goto error; } if (str[0] >= '0' && str[0] <= '9') { /* is digit, look at the regexp */ sfd->targettype = FLOWINT_TARGET_VAL; value_long = atoll(str); if (value_long > UINT32_MAX) { SCLogDebug("DetectFlowintParse: Cannot load this value." " Values should be between 0 and %"PRIu32, UINT32_MAX); goto error; } } else { sfd->targettype = FLOWINT_TARGET_VAR; sfd->target.tvar.name = str; } } else { sfd->targettype = FLOWINT_TARGET_SELF; } /* Set the name of the origin var to modify/compared with the target */ sfd->name = SCStrdup(varname); if (de_ctx != NULL) sfd->idx = VariableNameGetIdx(de_ctx, varname, DETECT_FLOWINT); sfd->target.value =(uint32_t) value_long; sfd->modifier = modifier; return sfd; error: if (sfd != NULL) SCFree(sfd); return NULL; } /** * \brief This function is used to set up the SigMatch holding the flowint opt * * \param de_ctx pointer to the engine context * \param s pointer to the current Signature * \param rawstr pointer to the string holding the options * * \retval 0 if all is ok * \retval -1 if we find any problem */ static int DetectFlowintSetup(DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectFlowintData *sfd = NULL; SigMatch *sm = NULL; sfd = DetectFlowintParse(de_ctx, rawstr); if (sfd == 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_FLOWINT; sm->ctx = (void *)sfd; switch (sfd->modifier) { case FLOWINT_MODIFIER_SET: case FLOWINT_MODIFIER_ADD: case FLOWINT_MODIFIER_SUB: SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); break; case FLOWINT_MODIFIER_LT: case FLOWINT_MODIFIER_LE: case FLOWINT_MODIFIER_NE: case FLOWINT_MODIFIER_EQ: case FLOWINT_MODIFIER_GE: case FLOWINT_MODIFIER_GT: case FLOWINT_MODIFIER_ISSET: case FLOWINT_MODIFIER_NOTSET: SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); break; } return 0; error: if (sfd) DetectFlowintFree(sfd); if (sm) SCFree(sm); return -1; } /** * \brief This function is used to free the data of DetectFlowintData */ void DetectFlowintFree(void *tmp) { DetectFlowintData *sfd =(DetectFlowintData*) tmp; if (sfd != NULL) { if (sfd->name != NULL) SCFree(sfd->name); if (sfd->targettype == FLOWINT_TARGET_VAR) if (sfd->target.tvar.name != NULL) SCFree(sfd->target.tvar.name); SCFree(sfd); } } /** * \brief This is a helper funtion used for debugging purposes */ void DetectFlowintPrintData(DetectFlowintData *sfd) { if (sfd == NULL) { SCLogDebug("DetectFlowintPrintData: Error, DetectFlowintData == NULL!"); return; } SCLogDebug("Varname: %s, modifier: %"PRIu8", idx: %"PRIu16" Target: ", sfd->name, sfd->modifier, sfd->idx); switch(sfd->targettype) { case FLOWINT_TARGET_VAR: SCLogDebug("target_var: %s, target_idx: %"PRIu16, sfd->target.tvar.name, sfd->target.tvar.idx); break; case FLOWINT_TARGET_VAL: SCLogDebug("Value: %"PRIu32"; ", sfd->target.value); break; default : SCLogDebug("DetectFlowintPrintData: Error, Targettype not known!"); } } #ifdef UNITTESTS /** * \test DetectFlowintTestParseVal01 is a test to make sure that we set the * DetectFlowint correctly for setting a valid target value */ int DetectFlowintTestParseVal01(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,=,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_SET) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar01 is a test to make sure that we set the * DetectFlowint correctly for setting a valid target variable */ int DetectFlowintTestParseVar01(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,=,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_SET) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVal02 is a test to make sure that we set the * DetectFlowint correctly for adding a valid target value */ int DetectFlowintTestParseVal02(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,+,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_ADD) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar02 is a test to make sure that we set the * DetectFlowint correctly for adding a valid target variable */ int DetectFlowintTestParseVar02(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,+,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_ADD) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVal03 is a test to make sure that we set the * DetectFlowint correctly for substract a valid target value */ int DetectFlowintTestParseVal03(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,-,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_SUB) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar03 is a test to make sure that we set the * DetectFlowint correctly for substract a valid target variable */ int DetectFlowintTestParseVar03(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,-,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_SUB) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVal04 is a test to make sure that we set the * DetectFlowint correctly for checking if equal to a valid target value */ int DetectFlowintTestParseVal04(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,==,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_EQ) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar04 is a test to make sure that we set the * DetectFlowint correctly for checking if equal to a valid target variable */ int DetectFlowintTestParseVar04(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,==,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_EQ) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVal05 is a test to make sure that we set the * DetectFlowint correctly for cheking if not equal to a valid target value */ int DetectFlowintTestParseVal05(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,!=,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_NE) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar05 is a test to make sure that we set the * DetectFlowint correctly for checking if not equal to a valid target variable */ int DetectFlowintTestParseVar05(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,!=,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_NE) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVal06 is a test to make sure that we set the * DetectFlowint correctly for cheking if greater than a valid target value */ int DetectFlowintTestParseVal06(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, >,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_GT) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar06 is a test to make sure that we set the * DetectFlowint correctly for checking if greater than a valid target variable */ int DetectFlowintTestParseVar06(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, >,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_GT) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVal07 is a test to make sure that we set the * DetectFlowint correctly for cheking if greater or equal than a valid target value */ int DetectFlowintTestParseVal07(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, >= ,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_GE) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar07 is a test to make sure that we set the * DetectFlowint correctly for checking if greater or equal than a valid target variable */ int DetectFlowintTestParseVar07(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, >= ,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_GE) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVal08 is a test to make sure that we set the * DetectFlowint correctly for cheking if lower or equal than a valid target value */ int DetectFlowintTestParseVal08(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, <= ,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_LE) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar08 is a test to make sure that we set the * DetectFlowint correctly for checking if lower or equal than a valid target variable */ int DetectFlowintTestParseVar08(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, <= ,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_LE) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVal09 is a test to make sure that we set the * DetectFlowint correctly for cheking if lower than a valid target value */ int DetectFlowintTestParseVal09(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, < ,35"); DetectFlowintPrintData(sfd); if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && sfd->modifier == FLOWINT_MODIFIER_LT) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar09 is a test to make sure that we set the * DetectFlowint correctly for checking if lower than a valid target variable */ int DetectFlowintTestParseVar09(void) { int result = 0; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, < ,targetvar"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && sfd->modifier == FLOWINT_MODIFIER_LT) { result = 1; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseVar09 is a test to make sure that handle the * isset keyword correctly */ int DetectFlowintTestParseIsset10(void) { int result = 1; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar, isset"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_SELF && sfd->modifier == FLOWINT_MODIFIER_ISSET) { result &= 1; } else { result = 0; } if (sfd) DetectFlowintFree(sfd); sfd = DetectFlowintParse(de_ctx, "myvar, notset"); DetectFlowintPrintData(sfd); if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_SELF && sfd->modifier == FLOWINT_MODIFIER_NOTSET) { result &= 1; } else { result = 0; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectFlowintTestParseInvalidSyntaxis01 is a test to make sure that we dont set the * DetectFlowint for a invalid input option */ int DetectFlowintTestParseInvalidSyntaxis01(void) { int result = 1; DetectFlowintData *sfd = NULL; DetectEngineCtx *de_ctx; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto error; de_ctx->flags |= DE_QUIET; sfd = DetectFlowintParse(de_ctx, "myvar,=,9999999999"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,=,9532458716234857"); result = 0; } if (sfd) DetectFlowintFree(sfd); sfd = DetectFlowintParse(de_ctx, "myvar,=,45targetvar"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,=,45targetvar "); result = 0; } if (sfd) DetectFlowintFree(sfd); sfd = DetectFlowintParse(de_ctx, "657myvar,=,targetvar"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at 657myvar,=,targetvar "); result = 0; } if (sfd) DetectFlowintFree(sfd); sfd = DetectFlowintParse(de_ctx, "myvar,=<,targetvar"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,=<,targetvar "); result = 0; } if (sfd) DetectFlowintFree(sfd); sfd = DetectFlowintParse(de_ctx, "myvar,===,targetvar"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,===,targetvar "); result = 0; } if (sfd) DetectFlowintFree(sfd); sfd = DetectFlowintParse(de_ctx, "myvar,=="); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,=="); result = 0; } if (sfd) DetectFlowintFree(sfd); sfd = DetectFlowintParse(de_ctx, "myvar,"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,"); result = 0; } if (sfd) DetectFlowintFree(sfd); sfd = DetectFlowintParse(de_ctx, "myvar"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar"); result = 0; } if (sfd) DetectFlowintFree(sfd); DetectEngineCtxFree(de_ctx); return result; error: if (de_ctx) DetectEngineCtxFree(de_ctx); return result; } /** \test DetectFlowintTestPacket01Real * \brief Set a counter when we see a content:"GET" * and increment it by 2 if we match a "Unauthorized" * When it reach 3(with the last +2), another counter starts * and when that counter reach 6 packets. * * All the Signatures generate an alert(its for testing) * but the ignature that increment the second counter +1, that has * a "noalert", so we can do all increments * silently until we reach 6 next packets counted */ int DetectFlowintTestPacket01Real() { int result = 1; uint8_t pkt1[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 }; uint8_t pkt2[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, 0x03, 0x07 }; uint8_t pkt3[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, 0x23, 0x63 }; uint8_t pkt4[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a }; uint8_t pkt5[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, 0x40, 0x93 }; uint8_t pkt6[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0a }; uint8_t pkt7[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt8[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, 0x40, 0x93 }; uint8_t pkt9[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt10[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt11[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, 0x43, 0x8a }; uint8_t *pkts[] = { pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, pkt9, pkt10, pkt11 }; uint16_t pktssizes[] = { sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), sizeof(pkt11) }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; /* Now that we have the array of packets for the flow, prepare the signatures */ de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint:myvar,=,1; flowint:maxvar,=,6; sid:101;)"); de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint: myvar,+,2; sid:102;)"); de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar,==,3; flowint: cntpackets, =, 0; sid:103;)"); de_ctx->sig_list->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: myvar,==,3; flowint: cntpackets, +, 1; noalert;sid:104;)"); /* comparation of myvar with maxvar */ de_ctx->sig_list->next->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, ==, maxvar; sid:105;)"); /* I know it's a bit ugly, */ de_ctx->sig_list->next->next->next->next->next = NULL; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); /* Decode the packets, and test the matches*/ int i; for (i = 0;i < 11;i++) { memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); switch(i) { case 3: if (PacketAlertCheck(p, 101) == 0) { SCLogDebug("Not declared/initialized!"); result = 0; } break; case 5: if (PacketAlertCheck(p, 102) == 0) { SCLogDebug("Not incremented!"); result = 0; } if (PacketAlertCheck(p, 103) == 0) { SCLogDebug("myvar is not 3 or bad cmp!!"); result = 0; } break; case 10: if (PacketAlertCheck(p, 105) == 0) { SCLogDebug("Not declared/initialized/or well incremented the" " second var!"); result = 0; } break; } SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; end: if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx) DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); if (de_ctx) DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; } /** * \test DetectFlowintTestPacket02Real * \brief like DetectFlowintTestPacket01Real but using isset/notset keywords */ int DetectFlowintTestPacket02Real() { int result = 1; uint8_t pkt1[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 }; uint8_t pkt2[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, 0x03, 0x07 }; uint8_t pkt3[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, 0x23, 0x63 }; uint8_t pkt4[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a }; uint8_t pkt5[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, 0x40, 0x93 }; uint8_t pkt6[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0a }; uint8_t pkt7[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt8[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, 0x40, 0x93 }; uint8_t pkt9[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt10[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt11[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, 0x43, 0x8a }; uint8_t *pkts[] = { pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, pkt9, pkt10, pkt11 }; uint16_t pktssizes[] = { sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), sizeof(pkt11) }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; /* Now that we have the array of packets for the flow, prepare the signatures */ de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint: myvar, notset; flowint:maxvar,notset; flowint: myvar,=,1; flowint: maxvar,=,6; sid:101;)"); de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: myvar,+,2; sid:102;)"); de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar, isset; flowint: myvar,==,3; flowint:cntpackets,notset; flowint: cntpackets, =, 0; sid:103;)"); de_ctx->sig_list->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: cntpackets,isset; flowint: cntpackets, +, 1; noalert;sid:104;)"); /* comparation of myvar with maxvar */ de_ctx->sig_list->next->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, isset; flowint: maxvar,isset; flowint: cntpackets, ==, maxvar; sid:105;)"); /* I know it's a bit ugly, */ de_ctx->sig_list->next->next->next->next->next = NULL; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); int i; /* Decode the packets, and test the matches*/ for (i = 0;i < 11;i++) { memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); switch(i) { case 3: if (PacketAlertCheck(p, 101) == 0) { SCLogDebug("Not declared/initialized!"); result = 0; } break; case 5: if (PacketAlertCheck(p, 102) == 0) { SCLogDebug("Not incremented!"); result = 0; } if (PacketAlertCheck(p, 103) == 0) { SCLogDebug("myvar is not 3 or bad cmp!!"); result = 0; } break; case 10: if (PacketAlertCheck(p, 105) == 0) { SCLogDebug("Not declared/initialized/or well incremented the" " second var!"); result = 0; } break; } SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; end: if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx) DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); //PatternMatchDestroy(mpm_ctx); if (de_ctx) DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; } /** * \test DetectFlowintTestPacket03Real * \brief Check the behaviour of isset/notset */ int DetectFlowintTestPacket03Real() { int result = 1; uint8_t pkt1[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 }; uint8_t pkt2[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, 0x03, 0x07 }; uint8_t pkt3[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, 0x23, 0x63 }; uint8_t pkt4[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a }; uint8_t pkt5[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, 0x40, 0x93 }; uint8_t pkt6[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0a }; uint8_t pkt7[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt8[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, 0x40, 0x93 }; uint8_t pkt9[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt10[] = { 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, 0x23, 0x6a }; uint8_t pkt11[] = { 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, 0x43, 0x8a }; uint8_t *pkts[] = { pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, pkt9, pkt10, pkt11 }; uint16_t pktssizes[] = { sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), sizeof(pkt11) }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; /* Now that we have the array of packets for the flow, prepare the signatures */ de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check notset\"; content:\"GET\"; flowint: myvar, notset; flowint: myvar,=,0; flowint: other,=,10; sid:101;)"); de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check isset\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: other,isset; sid:102;)"); de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check notset\"; content:\"Unauthorized\"; flowint:lala,isset; sid:103;)"); de_ctx->sig_list->next->next->next = NULL; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); int i; /* Decode the packets, and test the matches*/ for (i = 0;i < 11;i++) { memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); switch(i) { case 3: if (PacketAlertCheck(p, 101) == 0) { SCLogDebug("Not declared/initialized but match!"); result = 0; } if (PacketAlertCheck(p, 103) != 0) { SCLogDebug(" var lala is never set, it should NOT match!!"); result = 0; } break; case 5: if (PacketAlertCheck(p, 102) == 0) { SCLogDebug("Not incremented!"); result = 0; } if (PacketAlertCheck(p, 103) != 0) { SCLogDebug(" var lala is never set, it should NOT match!!"); result = 0; } break; } SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; end: if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx) DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); //PatternMatchDestroy(mpm_ctx); if (de_ctx) DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectFlowint */ void DetectFlowintRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectFlowintTestParseVal01", DetectFlowintTestParseVal01, 1); UtRegisterTest("DetectFlowintTestParseVar01", DetectFlowintTestParseVar01, 1); UtRegisterTest("DetectFlowintTestParseVal02", DetectFlowintTestParseVal02, 1); UtRegisterTest("DetectFlowintTestParseVar02", DetectFlowintTestParseVar02, 1); UtRegisterTest("DetectFlowintTestParseVal03", DetectFlowintTestParseVal03, 1); UtRegisterTest("DetectFlowintTestParseVar03", DetectFlowintTestParseVar03, 1); UtRegisterTest("DetectFlowintTestParseVal04", DetectFlowintTestParseVal04, 1); UtRegisterTest("DetectFlowintTestParseVar04", DetectFlowintTestParseVar04, 1); UtRegisterTest("DetectFlowintTestParseVal05", DetectFlowintTestParseVal05, 1); UtRegisterTest("DetectFlowintTestParseVar05", DetectFlowintTestParseVar05, 1); UtRegisterTest("DetectFlowintTestParseVal06", DetectFlowintTestParseVal06, 1); UtRegisterTest("DetectFlowintTestParseVar06", DetectFlowintTestParseVar06, 1); UtRegisterTest("DetectFlowintTestParseVal07", DetectFlowintTestParseVal07, 1); UtRegisterTest("DetectFlowintTestParseVar07", DetectFlowintTestParseVar07, 1); UtRegisterTest("DetectFlowintTestParseVal08", DetectFlowintTestParseVal08, 1); UtRegisterTest("DetectFlowintTestParseVar08", DetectFlowintTestParseVar08, 1); UtRegisterTest("DetectFlowintTestParseVal09", DetectFlowintTestParseVal09, 1); UtRegisterTest("DetectFlowintTestParseVar09", DetectFlowintTestParseVar09, 1); UtRegisterTest("DetectFlowintTestParseIsset10", DetectFlowintTestParseIsset10, 1); UtRegisterTest("DetectFlowintTestParseInvalidSyntaxis01", DetectFlowintTestParseInvalidSyntaxis01, 1); UtRegisterTest("DetectFlowintTestPacket01Real", DetectFlowintTestPacket01Real, 1); UtRegisterTest("DetectFlowintTestPacket02Real", DetectFlowintTestPacket02Real, 1); UtRegisterTest("DetectFlowintTestPacket03Real", DetectFlowintTestPacket03Real, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-noalert.h0000644000000000000000000000164312253546156014114 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_NOALERT_H__ #define __DETECT_NOALERT_H__ /* prototypes */ void DetectNoalertRegister (void); #endif /* __DETECT_NOALERT_H__ */ suricata-1.4.7/src/decode-icmpv6.c0000644000000000000000000011114112253546156013615 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Victor Julien * * Decode ICMPv6 */ #include "suricata-common.h" #include "decode-icmpv6.h" #include "decode.h" #include "decode-tcp.h" #include "decode-sctp.h" #include "decode-udp.h" #include "decode-events.h" #include "util-unittest.h" #include "flow.h" #include "util-debug.h" #include "util-print.h" /** * \brief Get variables and do some checks of the embedded IPV6 packet * * \param p Pointer to the packet we are filling * \param partial_packet Pointer to the raw packet buffer * \param len the len of the rest of the packet not processed yet * * \retval void No return value */ void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) { /** Check the sizes, the header must fit at least */ if (len < IPV6_HEADER_LEN) { SCLogDebug("ICMPV6_IPV6_TRUNC_PKT"); ENGINE_SET_EVENT(p, ICMPV6_IPV6_TRUNC_PKT); return; } IPV6Hdr *icmp6_ip6h = (IPV6Hdr*)partial_packet; /** Check the embedded version */ if(((icmp6_ip6h->s_ip6_vfc & 0xf0) >> 4) != 6) { SCLogDebug("ICMPv6 contains Unknown IPV6 version " "ICMPV6_IPV6_UNKNOWN_VER"); ENGINE_SET_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER); return; } /** We need to fill icmpv6vars */ p->icmpv6vars.emb_ipv6h = icmp6_ip6h; /** Get the IP6 address */ p->icmpv6vars.emb_ip6_src[0] = icmp6_ip6h->s_ip6_src[0]; p->icmpv6vars.emb_ip6_src[1] = icmp6_ip6h->s_ip6_src[1]; p->icmpv6vars.emb_ip6_src[2] = icmp6_ip6h->s_ip6_src[2]; p->icmpv6vars.emb_ip6_src[3] = icmp6_ip6h->s_ip6_src[3]; p->icmpv6vars.emb_ip6_dst[0] = icmp6_ip6h->s_ip6_dst[0]; p->icmpv6vars.emb_ip6_dst[1] = icmp6_ip6h->s_ip6_dst[1]; p->icmpv6vars.emb_ip6_dst[2] = icmp6_ip6h->s_ip6_dst[2]; p->icmpv6vars.emb_ip6_dst[3] = icmp6_ip6h->s_ip6_dst[3]; /** Get protocol and ports inside the embedded ipv6 packet and set the pointers */ p->icmpv6vars.emb_ip6_proto_next = icmp6_ip6h->s_ip6_nxt; switch (icmp6_ip6h->s_ip6_nxt) { case IPPROTO_TCP: if (len >= IPV6_HEADER_LEN + TCP_HEADER_LEN ) { p->icmpv6vars.emb_tcph = (TCPHdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = p->icmpv6vars.emb_tcph->th_sport; p->icmpv6vars.emb_dport = p->icmpv6vars.emb_tcph->th_dport; SCLogDebug("ICMPV6->IPV6->TCP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv6vars.emb_sport, p->icmpv6vars.emb_dport); } else { SCLogDebug("Warning, ICMPV6->IPV6->TCP " "header Didn't fit in the packet!"); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; } break; case IPPROTO_UDP: if (len >= IPV6_HEADER_LEN + UDP_HEADER_LEN ) { p->icmpv6vars.emb_udph = (UDPHdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = p->icmpv6vars.emb_udph->uh_sport; p->icmpv6vars.emb_dport = p->icmpv6vars.emb_udph->uh_dport; SCLogDebug("ICMPV6->IPV6->UDP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv6vars.emb_sport, p->icmpv6vars.emb_dport); } else { SCLogDebug("Warning, ICMPV6->IPV6->UDP " "header Didn't fit in the packet!"); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; } break; case IPPROTO_ICMPV6: p->icmpv6vars.emb_icmpv6h = (ICMPV6Hdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; SCLogDebug("ICMPV6->IPV6->ICMP header"); break; } /* debug print */ #ifdef DEBUG char s[46], d[46]; PrintInet(AF_INET6, (const void *)p->icmpv6vars.emb_ip6_src, s, sizeof(s)); PrintInet(AF_INET6, (const void *)p->icmpv6vars.emb_ip6_dst, d, sizeof(d)); SCLogDebug("ICMPv6 embedding IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: " "%" PRIu32 " NH: %" PRIu32 " PLEN: %" PRIu32 " HLIM: %" PRIu32, s, d, IPV6_GET_RAW_CLASS(icmp6_ip6h), IPV6_GET_RAW_FLOW(icmp6_ip6h), IPV6_GET_RAW_NH(icmp6_ip6h), IPV6_GET_RAW_PLEN(icmp6_ip6h), IPV6_GET_RAW_HLIM(icmp6_ip6h)); #endif return; } /** * \brief Decode ICMPV6 packets and fill the Packet with the decoded info * * \param tv Pointer to the thread variables * \param dtv Pointer to the decode thread variables * \param p Pointer to the packet we are filling * \param pkt Pointer to the raw packet buffer * \param len the len of the rest of the packet not processed yet * \param pq the packet queue were this packet go * * \retval void No return value */ void DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int full_hdr = 0; SCPerfCounterIncr(dtv->counter_icmpv6, tv->sc_perf_pca); if (len < ICMPV6_HEADER_LEN) { SCLogDebug("ICMPV6_PKT_TOO_SMALL"); ENGINE_SET_EVENT(p, ICMPV6_PKT_TOO_SMALL); return; } p->icmpv6h = (ICMPV6Hdr *)pkt; p->proto = IPPROTO_ICMPV6; p->type = p->icmpv6h->type; p->code = p->icmpv6h->code; p->payload_len = len - ICMPV6_HEADER_LEN; p->payload = pkt + ICMPV6_HEADER_LEN; SCLogDebug("ICMPV6 TYPE %" PRIu32 " CODE %" PRIu32 "", p->icmpv6h->type, p->icmpv6h->code); switch (ICMPV6_GET_TYPE(p)) { case ICMP6_DST_UNREACH: SCLogDebug("ICMP6_DST_UNREACH"); if (ICMPV6_GET_CODE(p) > ICMP6_DST_UNREACH_REJECTROUTE) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { DecodePartialIPV6(p, (uint8_t*) (pkt + ICMPV6_HEADER_LEN), len - ICMPV6_HEADER_LEN ); full_hdr = 1; } break; case ICMP6_PACKET_TOO_BIG: SCLogDebug("ICMP6_PACKET_TOO_BIG"); if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.mtu = ICMPV6_GET_MTU(p); DecodePartialIPV6(p, (uint8_t*) (pkt + ICMPV6_HEADER_LEN), len - ICMPV6_HEADER_LEN ); full_hdr = 1; } break; case ICMP6_TIME_EXCEEDED: SCLogDebug("ICMP6_TIME_EXCEEDED"); if (ICMPV6_GET_CODE(p) > ICMP6_TIME_EXCEED_REASSEMBLY) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { DecodePartialIPV6(p, (uint8_t*) (pkt + ICMPV6_HEADER_LEN), len - ICMPV6_HEADER_LEN ); full_hdr = 1; } break; case ICMP6_PARAM_PROB: SCLogDebug("ICMP6_PARAM_PROB"); if (ICMPV6_GET_CODE(p) > ICMP6_PARAMPROB_OPTION) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.error_ptr= ICMPV6_GET_ERROR_PTR(p); DecodePartialIPV6(p, (uint8_t*) (pkt + ICMPV6_HEADER_LEN), len - ICMPV6_HEADER_LEN ); full_hdr = 1; } break; case ICMP6_ECHO_REQUEST: SCLogDebug("ICMP6_ECHO_REQUEST id: %u seq: %u", p->icmpv6h->icmpv6b.icmpv6i.id, p->icmpv6h->icmpv6b.icmpv6i.seq); if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.id = p->icmpv6h->icmpv6b.icmpv6i.id; p->icmpv6vars.seq = p->icmpv6h->icmpv6b.icmpv6i.seq; full_hdr = 1; } break; case ICMP6_ECHO_REPLY: SCLogDebug("ICMP6_ECHO_REPLY id: %u seq: %u", p->icmpv6h->icmpv6b.icmpv6i.id, p->icmpv6h->icmpv6b.icmpv6i.seq); if (p->icmpv6h->code != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.id = p->icmpv6h->icmpv6b.icmpv6i.id; p->icmpv6vars.seq = p->icmpv6h->icmpv6b.icmpv6i.seq; full_hdr = 1; } break; default: SCLogDebug("ICMPV6 Message type %" PRIu8 " not " "implemented yet", ICMPV6_GET_TYPE(p)); ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_TYPE); } /* for a info message the header is just 4 bytes */ if (!full_hdr) { if (p->payload_len >= 4) { p->payload_len -= 4; p->payload = pkt + 4; } else { p->payload_len = 0; p->payload = NULL; } } #ifdef DEBUG if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) SCLogDebug("Unknown Code, ICMPV6_UNKNOWN_CODE"); if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_TYPE)) SCLogDebug("Unknown Type, ICMPV6_UNKNOWN_TYPE"); #endif /* Flow is an integral part of us */ FlowHandlePacket(tv, p); return; } #ifdef UNITTESTS static int ICMPV6CalculateValidChecksumtest01(void) { uint16_t csum = 0; uint8_t raw_ipv6[] = { 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, 0x08, 0x00}; csum = *( ((uint16_t *)(raw_ipv6 + 56))); return (csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); } static int ICMPV6CalculateInvalidChecksumtest02(void) { uint16_t csum = 0; uint8_t raw_ipv6[] = { 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, 0x08, 0x01}; csum = *( ((uint16_t *)(raw_ipv6 + 56))); return (csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); } /** \test icmpv6 message type: parameter problem, valid packet * * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6ParamProbTest01(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0xcc, 0x2a, 0x6d, 0x93, 0x0b, 0xdf, 0x69, 0x70, 0x12, 0xb7, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x08, 0xb5, 0x99, 0xc3, 0xde, 0x40 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; uint32_t *ipv6src; uint32_t *ipv6dst; ipv6src = (uint32_t*) &raw_ipv6[8]; ipv6dst = (uint32_t*) &raw_ipv6[24]; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->icmpv6h == NULL) { SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); retval = 0; goto end; } if (ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0 || ICMPV6_GET_EMB_PROTO(p) != IPPROTO_ICMPV6) { SCLogDebug("ICMPv6 not processed at all"); retval = 0; goto end; } /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " "the src and dest ip addresses correctly"); retval = 0; goto end; } } retval = 1; end: SCFree(p); return retval; } /** \test icmpv6 message type: packet too big, valid packet * * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6PktTooBigTest01(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x5c, 0x7a, 0x00, 0x00, 0x05, 0x00, 0x64, 0x14, 0xfd, 0xff, 0x00, 0x00, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; uint32_t *ipv6src; uint32_t *ipv6dst; ipv6src = (uint32_t*) &raw_ipv6[8]; ipv6dst = (uint32_t*) &raw_ipv6[24]; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->icmpv6h == NULL) { SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); retval = 0; goto end; } /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ if (ICMPV6_GET_TYPE(p) != 2 || ICMPV6_GET_CODE(p) != 0 ) { SCLogDebug("ICMPv6 Not processed at all"); retval = 0; goto end; } /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " "the src and dest ip addresses correctly"); retval = 0; goto end; } } SCLogDebug("ICMPV6 IPV6 src and dst properly set"); retval = 1; end: SCFree(p); return retval; } /** \test icmpv6 message type: time exceed, valid packet * * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6TimeExceedTest01(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x56, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x23, 0xff, 0x3d, 0x00, 0x00, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; uint32_t *ipv6src; uint32_t *ipv6dst; ipv6src = (uint32_t*) &raw_ipv6[8]; ipv6dst = (uint32_t*) &raw_ipv6[24]; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->icmpv6h == NULL) { SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); retval = 0; goto end; } /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ if (ICMPV6_GET_TYPE(p) != 3 || ICMPV6_GET_CODE(p) != 0 || ICMPV6_GET_EMB_IPV6(p)==NULL || ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE ) { SCLogDebug("ICMPv6 Not processed at all"); retval = 0; goto end; } /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " "the src and dest ip addresses correctly"); retval = 0; goto end; } } SCLogDebug("ICMPV6 IPV6 src and dst properly set"); retval = 1; end: SCFree(p); return retval; } /** \test icmpv6 message type: destination unreach, valid packet * * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6DestUnreachTest01(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x7b, 0x85, 0x00, 0x00, 0x00, 0x00, 0x60, 0x4b, 0xe8, 0xbd, 0x00, 0x00, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; uint32_t *ipv6src; uint32_t *ipv6dst; ipv6src = (uint32_t*) &raw_ipv6[8]; ipv6dst = (uint32_t*) &raw_ipv6[24]; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->icmpv6h == NULL) { SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); retval = 0; goto end; } /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ if (ICMPV6_GET_TYPE(p) != 1 || ICMPV6_GET_CODE(p) != 0 || ICMPV6_GET_EMB_IPV6(p) == NULL || ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE ) { SCLogDebug("ICMPv6 Not processed at all"); retval = 0; goto end; } /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " "the src and dest ip addresses correctly"); retval = 0; goto end; } } retval = 1; end: SCFree(p); return retval; } /**\test icmpv6 message type: echo request, valid packet * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6EchoReqTest01(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->icmpv6h == NULL) { SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); goto end; } SCLogDebug("ID: %u seq: %u", ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); if (ICMPV6_GET_TYPE(p) != 128 || ICMPV6_GET_CODE(p) != 0 || ntohs(ICMPV6_GET_ID(p)) != 9712 || ntohs(ICMPV6_GET_SEQ(p)) != 29987) { printf("ICMPv6 Echo reply decode failed TYPE %u CODE %u ID %04x(%u) SEQ %04x(%u): ", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ntohs(ICMPV6_GET_ID(p)), ICMPV6_GET_SEQ(p), ntohs(ICMPV6_GET_SEQ(p))); goto end; } retval = 1; end: SCFree(p); return retval; } /**\test icmpv6 message type: echo reply, valid packet * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6EchoRepTest01(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x81, 0x00, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->icmpv6h == NULL) { SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); goto end; } SCLogDebug("type: %u code %u ID: %u seq: %u", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p),ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); if (ICMPV6_GET_TYPE(p) != 129 || ICMPV6_GET_CODE(p) != 0 || ntohs(ICMPV6_GET_ID(p)) != 9712 || ntohs(ICMPV6_GET_SEQ(p)) != 29987) { printf("ICMPv6 Echo reply decode failed TYPE %u CODE %u ID %04x(%u) SEQ %04x(%u): ", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ntohs(ICMPV6_GET_ID(p)), ICMPV6_GET_SEQ(p), ntohs(ICMPV6_GET_SEQ(p))); goto end; } retval = 1; end: SCFree(p); return retval; } /** \test icmpv6 message type: parameter problem, invalid packet * \brief set the event ICMPV6_IPV6_UNKNOWN_VER properly when the embedded packet has an unknown version * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6ParamProbTest02(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0xcc, 0x2a, 0x6d, 0x93, 0x0b, 0xdf, 0x38, 0x70, 0x12, 0xb7, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x08, 0xb5, 0x99, 0xc3, 0xde, 0x40 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->icmpv6h == NULL) { SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); retval = 0; goto end; } if (ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0) { SCLogDebug("ICMPv6 Not processed at all"); retval = 0; goto end; } if (!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER)) { SCLogDebug("ICMPv6 Error: Unknown embedded ipv6 version event not set"); retval = 0; goto end; } retval = 1; end: SCFree(p); return retval; } /** \test icmpv6 message type: packet too big, invalid packet * \brief Set the event ICMPV6_UNKNOWN_CODE if code is invalid for this type * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6PktTooBigTest02(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x10, 0x5c, 0x7a, 0x00, 0x00, 0x05, 0x00, 0x64, 0x14, 0xfd, 0xff, 0x00, 0x00, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->icmpv6h == NULL) { SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); retval = 0; goto end; } if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { SCLogDebug("ICMPv6 Error: Unknown code event not set"); retval = 0; goto end; } retval = 1; end: SCFree(p); return retval; } /** \test icmpv6 message type: time exceed, invalid packet * \brief set the event ICMPV6_PKT_TOO_SMALL properly * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6TimeExceedTest02(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x10, 0x5c }; /* The icmpv6 header is broken in the checksum (so we dont have a complete header) */ Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (!ENGINE_ISSET_EVENT(p, ICMPV6_PKT_TOO_SMALL)) { SCLogDebug("ICMPv6 Error: event packet too small not set"); retval = 0; goto end; } retval = 1; end: SCFree(p); return retval; } /**\test icmpv6 message type: destination unreach, invalid packet * \brief The embedded packet header (ipv6) is truncated * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6DestUnreachTest02(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x7b, 0x85, 0x00, 0x00, 0x00, 0x00, 0x60, 0x4b, 0xe8, 0xbd, 0x00, 0x00, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_TRUNC_PKT)) { SCLogDebug("ICMPv6 Error: embedded ipv6 truncated packet event not set"); retval = 0; goto end; } retval = 1; end: SCFree(p); return retval; } /**\test icmpv6 message type: echo request, invalid packet * \brief unknown code * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6EchoReqTest02(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { SCLogDebug("ICMPv6 Error: Unknown code event not set"); retval = 0; goto end; } retval = 1; end: SCFree(p); return retval; } /**\test icmpv6 message type: echo reply, invalid packet * \brief unknown code * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6EchoRepTest02(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x81, 0x01, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { SCLogDebug("ICMPv6 Error: Unknown code event not set"); retval = 0; goto end; } retval = 1; end: SCFree(p); return retval; } /**\test icmpv6 packet decoding and setting up of payload_len and payload buufer * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6PayloadTest01(void) { int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x7b, 0x85, 0x00, 0x00, 0x00, 0x00, 0x60, 0x4b, 0xe8, 0xbd, 0x00, 0x00, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); FlowShutdown(); if (p->payload == NULL) { printf("payload == NULL, expected non-NULL: "); goto end; } if (p->payload_len != 37) { printf("payload_len %"PRIu16", expected 37: ", p->payload_len); goto end; } retval = 1; end: SCFree(p); return retval; } #endif /* UNITTESTS */ /** * \brief Registers ICMPV6 unit tests * \todo More ICMPv6 tests */ void DecodeICMPV6RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("ICMPV6CalculateValidChecksumtest01", ICMPV6CalculateValidChecksumtest01, 1); UtRegisterTest("ICMPV6CalculateInValidChecksumtest02", ICMPV6CalculateInvalidChecksumtest02, 0); UtRegisterTest("ICMPV6ParamProbTest01 (Valid)", ICMPV6ParamProbTest01, 1); UtRegisterTest("ICMPV6DestUnreachTest01 (Valid)", ICMPV6DestUnreachTest01, 1); UtRegisterTest("ICMPV6PktTooBigTest01 (Valid)", ICMPV6PktTooBigTest01, 1); UtRegisterTest("ICMPV6TimeExceedTest01 (Valid)", ICMPV6TimeExceedTest01, 1); UtRegisterTest("ICMPV6EchoReqTest01 (Valid)", ICMPV6EchoReqTest01, 1); UtRegisterTest("ICMPV6EchoRepTest01 (Valid)", ICMPV6EchoRepTest01, 1); UtRegisterTest("ICMPV6ParamProbTest02 (Invalid)", ICMPV6ParamProbTest02, 1); UtRegisterTest("ICMPV6DestUnreachTest02 (Invalid)", ICMPV6DestUnreachTest02, 1); UtRegisterTest("ICMPV6PktTooBigTest02 (Invalid)", ICMPV6PktTooBigTest02, 1); UtRegisterTest("ICMPV6TimeExceedTest02 (Invalid)", ICMPV6TimeExceedTest02, 1); UtRegisterTest("ICMPV6EchoReqTest02 (Invalid)", ICMPV6EchoReqTest02, 1); UtRegisterTest("ICMPV6EchoRepTest02 (Invalid)", ICMPV6EchoRepTest02, 1); UtRegisterTest("ICMPV6PayloadTest01", ICMPV6PayloadTest01, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/app-layer-protos.c0000644000000000000000000000307212253546156014411 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #include "suricata-common.h" #define CASE_CODE(E) case E: return #E /** * \brief Maps the ALPROTO_*, to its string equivalent * * \param proto app layer protocol id * * \retval string equivalent for the alproto */ const char *TmModuleAlprotoToString(int proto) { switch (proto) { CASE_CODE (ALPROTO_UNKNOWN); CASE_CODE (ALPROTO_HTTP); CASE_CODE (ALPROTO_FTP); CASE_CODE (ALPROTO_SMTP); CASE_CODE (ALPROTO_TLS); CASE_CODE (ALPROTO_SSH); CASE_CODE (ALPROTO_IMAP); CASE_CODE (ALPROTO_MSN); CASE_CODE (ALPROTO_JABBER); CASE_CODE (ALPROTO_SMB); CASE_CODE (ALPROTO_SMB2); CASE_CODE (ALPROTO_DCERPC); CASE_CODE (ALPROTO_DCERPC_UDP); default: return "ALPROTO_UNDEFINED"; } } suricata-1.4.7/src/win32-misc.h0000644000000000000000000000231512253546156013072 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Jan Jezek */ #ifndef __WIN32_MISC_H__ #define __WIN32_MISC_H__ #define index strchr #define rindex strrchr #define bzero(s, n) memset(s, 0, n) #ifndef O_NOFOLLOW #define O_NOFOLLOW 0 #endif /* O_NOFOLLOW */ void setenv(const char *name, const char *value, int overwrite); void unsetenv(const char *name); const char* inet_ntop(int af, const void *src, char *dst, uint32_t cnt); int inet_pton(int af, const char *src, void *dst); #define geteuid() (0) #endif suricata-1.4.7/src/util-checksum.c0000644000000000000000000000622412253546156013752 00000000000000/* Copyright (C) 2011-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond * * Util functions for checskum. */ #include "suricata-common.h" #include "util-checksum.h" int ReCalculateChecksum(Packet *p) { if (PKT_IS_IPV4(p)) { if (PKT_IS_TCP(p)) { /* TCP */ p->tcph->th_sum = 0; p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; p->udph->uh_sum = UDPV4CalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN)); } /* IPV4 */ p->ip4h->ip_csum = 0; p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h)); } else if (PKT_IS_IPV6(p)) { /* just TCP for IPV6 */ if (PKT_IS_TCP(p)) { p->tcph->th_sum = 0; p->tcph->th_sum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; p->udph->uh_sum = UDPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN)); } } return 0; } /** * \brief Check if the number of invalid checksums indicate checksum * offloading in place. * * \retval 1 yes, offloading in place * \retval 0 no, no offloading used */ int ChecksumAutoModeCheck(uint32_t thread_count, unsigned int iface_count, unsigned int iface_fail) { if (thread_count == CHECKSUM_SAMPLE_COUNT) { if (iface_fail != 0) { if ((iface_count / iface_fail) < CHECKSUM_INVALID_RATIO) { SCLogInfo("More than 1/%dth of packets have an invalid " "checksum, assuming checksum offloading is used (%d/%d)", CHECKSUM_INVALID_RATIO, iface_fail, iface_count); return 1; } else { SCLogInfo("Less than 1/%dth of packets have an invalid " "checksum, assuming checksum offloading is NOT used (%d/%d)", CHECKSUM_INVALID_RATIO, iface_fail, iface_count); } } else { SCLogInfo("No packets with invalid checksum, assuming checksum offloading is NOT used"); } } return 0; } suricata-1.4.7/src/detect-offset.c0000644000000000000000000001704112253546156013730 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * * Implements the offset keyword. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-byte-extract.h" #include "app-layer.h" #include "flow-var.h" #include "util-debug.h" static int DetectOffsetSetup (DetectEngineCtx *, Signature *, char *); void DetectOffsetRegister (void) { sigmatch_table[DETECT_OFFSET].name = "offset"; sigmatch_table[DETECT_OFFSET].desc = "designate from which byte in the payload will be checked to find a match"; sigmatch_table[DETECT_OFFSET].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#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; sigmatch_table[DETECT_OFFSET].flags |= SIGMATCH_PAYLOAD; } int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) { char *str = offsetstr; char dubbed = 0; SigMatch *pm = NULL; /* strip "'s */ if (offsetstr[0] == '\"' && offsetstr[strlen(offsetstr)-1] == '\"') { str = SCStrdup(offsetstr+1); if (unlikely(str == NULL)) goto error; str[strlen(offsetstr)-2] = '\0'; dubbed = 1; } switch (s->alproto) { case ALPROTO_DCERPC: /* add to the latest "content" keyword from either dmatch or pmatch */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " "preceding content option for dcerpc sig"); if (dubbed) SCFree(str); return -1; } break; default: pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " "preceding content or uricontent option, http_client_body, " "http_header, http_raw_header, http_method, " "http_cookie, http_raw_uri, http_stat_msg, " "http_stat_code, http_user_agent, " "http_host or http_raw_host option"); if (dubbed) SCFree(str); return -1; } break; } /* we can remove this switch now with the unified structure */ DetectContentData *cd = NULL; switch (pm->type) { case DETECT_CONTENT: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); if (dubbed) SCFree(str); return -1; } if (cd->flags & DETECT_CONTENT_NEGATED) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a fast_pattern"); goto error; } } else { if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "keyword set along with a fast_pattern:only;"); goto error; } } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative keyword " "with a non-relative keyword for the same content." ); goto error; } if (cd->flags & DETECT_CONTENT_OFFSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple offsets for the same content. "); goto error; } if (str[0] != '-' && isalpha((unsigned char)str[0])) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var " "seen in offset - %s\n", str); goto error; } cd->offset = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_OFFSET_BE; } else { cd->offset = (uint32_t)atoi(str); if (cd->depth != 0) { if (cd->depth < cd->content_len) { SCLogDebug("depth increased to %"PRIu32" to match pattern len", cd->content_len); cd->depth = cd->content_len; } /* Updating the depth as is relative to the offset */ cd->depth += cd->offset; } } cd->flags |= DETECT_CONTENT_OFFSET; break; default: SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs a preceding" " content keyword"); goto error; } if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; } suricata-1.4.7/src/queue.h0000644000000000000000000004420012253546156012322 00000000000000/* $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ #if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) #define _Q_INVALIDATE(a) ((a) = ((void *)-1)) #else #define _Q_INVALIDATE(a) #endif /* * Singly-linked List definitions. */ /* * The following macros are not used and are in conflict with Win32 API */ #if 0 #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List access methods. */ #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_END(head) NULL #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = SLIST_FIRST(head); \ (var) != SLIST_END(head); \ (var) = SLIST_NEXT(var, field)) #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ for ((varp) = &SLIST_FIRST((head)); \ ((var) = *(varp)) != SLIST_END(head); \ (varp) = &SLIST_NEXT((var), field)) /* * Singly-linked List functions. */ #define SLIST_INIT(head) { \ SLIST_FIRST(head) = SLIST_END(head); \ } #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) #define SLIST_REMOVE_NEXT(head, elm, field) do { \ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->slh_first; \ \ while (curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ _Q_INVALIDATE((elm)->field.sle_next); \ } \ } while (0) #endif /* 0 */ /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List access methods */ #define LIST_FIRST(head) ((head)->lh_first) #define LIST_END(head) NULL #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_FOREACH(var, head, field) \ for((var) = LIST_FIRST(head); \ (var)!= LIST_END(head); \ (var) = LIST_NEXT(var, field)) /* * List functions. */ #define LIST_INIT(head) do { \ LIST_FIRST(head) = LIST_END(head); \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) #define LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue access methods. */ #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) #define SIMPLEQ_FOREACH(var, head, field) \ for((var) = SIMPLEQ_FIRST(head); \ (var) != SIMPLEQ_END(head); \ (var) = SIMPLEQ_NEXT(var, field)) /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * tail queue access methods */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) NULL #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) /* XXX */ #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_EMPTY(head) \ (TAILQ_FIRST(head) == TAILQ_END(head)) #define TAILQ_FOREACH(var, head, field) \ for((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head); \ (var) = TAILQ_NEXT(var, field)) /* removal safe iterator using a temprary element has last param */ #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ for((var) = TAILQ_FIRST(head), \ (tvar) = TAILQ_FIRST(head) ? TAILQ_NEXT(TAILQ_FIRST(head), field): NULL ; \ (var) != TAILQ_END(head); \ (var = tvar), (tvar) = var ? TAILQ_NEXT(var, field): NULL) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for((var) = TAILQ_LAST(head, headname); \ (var) != TAILQ_END(head); \ (var) = TAILQ_PREV(var, headname, field)) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) #define TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ else \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue access methods */ #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_END(head) ((void *)(head)) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) #define CIRCLEQ_EMPTY(head) \ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) #define CIRCLEQ_FOREACH(var, head, field) \ for((var) = CIRCLEQ_FIRST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_NEXT(var, field)) #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ for((var) = CIRCLEQ_LAST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_PREV(var, field)) /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = CIRCLEQ_END(head); \ (head)->cqh_last = CIRCLEQ_END(head); \ } while (0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = CIRCLEQ_END(head); \ if ((head)->cqh_last == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = CIRCLEQ_END(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ CIRCLEQ_END(head)) \ (head).cqh_last = (elm2); \ else \ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ CIRCLEQ_END(head)) \ (head).cqh_first = (elm2); \ else \ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #endif /* !_SYS_QUEUE_H_ */ suricata-1.4.7/src/util-mpm-b2g.c0000644000000000000000000040370312253546156013414 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implementation of the SBNDMq pattern matching algorithm. * * Ideas: * - B2g does a full match in the search of up to 'm' characters, * in case of a case insensitive search we could say it's match if * the pattern is of len 'm' or just compare the rest of the chars. * * \todo Try to get the S0 calculation right. */ //#define PRINTMATCH #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "util-bloomfilter.h" #include "util-mpm-b2g.h" #include "util-print.h" #include "util-debug.h" #include "util-unittest.h" #include "util-memcmp.h" #include "conf.h" #define INIT_HASH_SIZE 65536 #ifdef B2G_COUNTERS #define COUNT(counter) \ (counter) #else #define COUNT(counter) #endif /* B2G_COUNTERS */ static uint32_t b2g_hash_size = 0; static uint32_t b2g_bloom_size = 0; static uint8_t b2g_hash_shift = 0; static void *b2g_func; #define B2G_HASH16(a,b) (((a) << b2g_hash_shift) | (b)) void B2gInitCtx (MpmCtx *, int); void B2gThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void B2gDestroyCtx(MpmCtx *); void B2gThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); int B2gAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B2gAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B2gPreparePatterns(MpmCtx *mpm_ctx); uint32_t B2gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); #ifdef B2G_SEARCH2 uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); #endif uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); void B2gPrintInfo(MpmCtx *mpm_ctx); void B2gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void B2gRegisterTests(void); void MpmB2gRegister (void) { mpm_table[MPM_B2G].name = "b2g"; mpm_table[MPM_B2G].max_pattern_length = B2G_WORD_SIZE; mpm_table[MPM_B2G].InitCtx = B2gInitCtx; mpm_table[MPM_B2G].InitThreadCtx = B2gThreadInitCtx; mpm_table[MPM_B2G].DestroyCtx = B2gDestroyCtx; mpm_table[MPM_B2G].DestroyThreadCtx = B2gThreadDestroyCtx; mpm_table[MPM_B2G].AddPattern = B2gAddPatternCS; mpm_table[MPM_B2G].AddPatternNocase = B2gAddPatternCI; mpm_table[MPM_B2G].Prepare = B2gPreparePatterns; mpm_table[MPM_B2G].Search = B2gSearchWrap; mpm_table[MPM_B2G].Cleanup = NULL; mpm_table[MPM_B2G].PrintCtx = B2gPrintInfo; mpm_table[MPM_B2G].PrintThreadCtx = B2gPrintSearchStats; mpm_table[MPM_B2G].RegisterUnittests = B2gRegisterTests; } #ifdef PRINTMATCH static void prt (uint8_t *buf, uint16_t buflen) { uint16_t i; for (i = 0; i < buflen; i++) { if (isprint(buf[i])) printf("%c", buf[i]); else printf("\\x%02X", buf[i]); } //printf("\n"); } #endif void B2gPrintInfo(MpmCtx *mpm_ctx) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; printf("MPM B2g Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); printf(" Sizeofs:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" B2gCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gCtx)); printf(" B2gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gPattern)); printf(" B2gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Hash size: %" PRIu32 "\n", ctx->hash_size); printf("\n"); } /** * \brief B2gAllocPattern allocates a new pattern structure * and initialize the data * \initonly */ static inline B2gPattern *B2gAllocPattern(MpmCtx *mpm_ctx) { B2gPattern *p = SCMalloc(sizeof(B2gPattern)); if (unlikely(p == NULL)) return NULL; memset(p,0,sizeof(B2gPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gPattern); return p; } static inline B2gPattern * B2gAllocHashItem(MpmCtx *mpm_ctx) { B2gPattern *hi = SCMalloc(sizeof(B2gPattern)); if (unlikely(hi == NULL)) return NULL; memset(hi,0,sizeof(B2gPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gPattern); return hi; } static void B2gHashFree(MpmCtx *mpm_ctx, B2gPattern *hi) { if (hi == NULL) return; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gPattern); B2gPattern *t = hi->next; SCFree(hi); B2gHashFree(mpm_ctx, t); } static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) { d[i] = u8_tolower(s[i]); } } /* * INIT HASH START */ static inline uint32_t B2gInitHash(B2gPattern *p) { uint32_t hash = p->len * p->original_pat[0]; if (p->len > 1) hash += p->original_pat[1]; return (hash % INIT_HASH_SIZE); } static inline uint32_t B2gInitHashRaw(uint8_t *pat, uint16_t patlen) { uint32_t hash = patlen * pat[0]; if (patlen > 1) hash += pat[1]; return (hash % INIT_HASH_SIZE); } static inline int B2gInitHashAdd(B2gCtx *ctx, B2gPattern *p) { uint32_t hash = B2gInitHash(p); //printf("B2gInitHashAdd: %" PRIu32 "\n", hash); if (ctx->init_hash[hash] == NULL) { ctx->init_hash[hash] = p; //printf("B2gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); return 0; } B2gPattern *tt = NULL; B2gPattern *t = ctx->init_hash[hash]; /* get the list tail */ do { tt = t; t = t->next; } while (t != NULL); tt->next = p; //printf("B2gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); return 0; } static inline int B2gCmpPattern(B2gPattern *p, uint8_t *pat, uint16_t patlen, char flags); static inline B2gPattern *B2gInitHashLookup(B2gCtx *ctx, uint8_t *pat, uint16_t patlen, char flags, uint32_t pid) { uint32_t hash = B2gInitHashRaw(pat,patlen); //printf("B2gInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); if (ctx->init_hash[hash] == NULL) { return NULL; } B2gPattern *t = ctx->init_hash[hash]; for ( ; t != NULL; t = t->next) { //if (B2gCmpPattern(t,pat,patlen,flags) == 1) if (t->flags == flags && t->id == pid) return t; } return NULL; } static inline int B2gCmpPattern(B2gPattern *p, uint8_t *pat, uint16_t patlen, char flags) { if (p->len != patlen) return 0; if (p->flags != flags) return 0; if (SCMemcmp(p->cs, pat, patlen) != 0) return 0; return 1; } /* * INIT HASH END */ void B2gFreePattern(MpmCtx *mpm_ctx, B2gPattern *p) { if (p && p->cs && p->cs != p->ci) { SCFree(p->cs); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p && p->ci) { SCFree(p->ci); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p) { SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gPattern); } } /** \internal * \brief add a pattern to the mpm/b2g context * * \param pat ptr to the pattern * \param patlen length of the pattern * \param pid pattern id * \param sid signature id (internal id) * \param flags pattern MPM_PATTERN_* flags * * \initonly */ static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); if (patlen == 0) return 0; /* get a memory piece */ B2gPattern *p = B2gInitHashLookup(ctx, pat, patlen, flags, pid); if (p == NULL) { SCLogDebug("allocing new pattern"); p = B2gAllocPattern(mpm_ctx); if (p == NULL) goto error; p->len = patlen; p->flags = flags; p->id = pid; p->original_pat = SCMalloc(patlen); if (p->original_pat == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->original_pat, pat, patlen); /* setup the case insensitive part of the pattern */ p->ci = SCMalloc(patlen); if (p->ci == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy_tolower(p->ci, pat, patlen); /* setup the case sensitive part of the pattern */ if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* nocase means no difference between cs and ci */ p->cs = p->ci; } else { if (SCMemcmp(p->ci,pat,p->len) == 0) { /* no diff between cs and ci: pat is lowercase */ p->cs = p->ci; } else { p->cs = SCMalloc(patlen); if (p->cs == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->cs, pat, patlen); } } //printf("B2gAddPattern: ci \""); prt(p->ci,p->len); //printf("\" cs \""); prt(p->cs,p->len); //printf("\"\n"); /* put in the pattern hash */ B2gInitHashAdd(ctx, p); if (mpm_ctx->pattern_cnt == 65535) { printf("Max search words reached\n"); exit(1); } mpm_ctx->pattern_cnt++; if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } return 0; error: B2gFreePattern(mpm_ctx, p); return -1; } int B2gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return B2gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int B2gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return B2gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } static inline uint32_t B2gBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint16_t i; uint32_t hash = (uint32_t)u8_tolower(*d); for (i = 1; i < datalen; i++) { d++; hash += (u8_tolower(*d)) ^ i; } hash <<= (iter+1); hash %= hash_size; return hash; } static void B2gPrepareHash(MpmCtx *mpm_ctx) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; uint16_t i; uint16_t idx = 0; uint8_t idx8 = 0; ctx->hash = (B2gPattern **)SCMalloc(sizeof(B2gPattern *) * ctx->hash_size); if (ctx->hash == NULL) goto error; memset(ctx->hash, 0, sizeof(B2gPattern *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B2gPattern *) * ctx->hash_size); #ifdef B2G_SEARCH2 ctx->hash2 = (B2gPattern **)SCMalloc(sizeof(B2gPattern *) * ctx->hash_size); if (ctx->hash2 == NULL) goto error; memset(ctx->hash2, 0, sizeof(B2gPattern *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B2gPattern *) * ctx->hash_size); #endif /* alloc the pminlen array */ ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); if (ctx->pminlen == NULL) goto error; memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if(ctx->parray[i]->len == 1) { idx8 = (uint8_t)ctx->parray[i]->ci[0]; if (ctx->hash1[idx8].flags == 0) { ctx->hash1[idx8].flags |= MPM_PATTERN_ONE_BYTE; B2gPattern *hi = &ctx->hash1[idx8]; hi->len = ctx->parray[i]->len; hi->flags |= ctx->parray[i]->flags; hi->id = ctx->parray[i]->id; hi->ci = ctx->parray[i]->ci; hi->cs = ctx->parray[i]->cs; } else { B2gPattern *hi = B2gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->flags |= MPM_PATTERN_ONE_BYTE; hi->len = ctx->parray[i]->len; hi->flags |= ctx->parray[i]->flags; hi->id = ctx->parray[i]->id; hi->ci = ctx->parray[i]->ci; hi->cs = ctx->parray[i]->cs; /* Append this HashItem to the list */ B2gPattern *thi = &ctx->hash1[idx8]; while (thi->next) thi = thi->next; thi->next = hi; } ctx->pat_1_cnt++; #ifdef B2G_SEARCH2 } else if(ctx->parray[i]->len == 2) { idx = B2G_HASH16(ctx->parray[i]->ci[0],ctx->parray[i]->ci[1]); if (ctx->hash2[idx] == NULL) { B2gPattern *hi = B2gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= MPM_PATTERN_ONE_BYTE; ctx->hash2[idx] = hi; } else { B2gPattern *hi = B2gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= MPM_PATTERN_ONE_BYTE; /* Append this HashItem to the list */ B2gPattern *thi = ctx->hash2[idx]; while (thi->next) thi = thi->next; thi->next = hi; } ctx->pat_2_cnt++; #endif } else { idx = B2G_HASH16(ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); SCLogDebug("idx %" PRIu32 ", %c.%c", idx, ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); if (ctx->hash[idx] == NULL) { B2gPattern *hi = B2gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; ctx->pminlen[idx] = ctx->parray[i]->len; hi->len = ctx->parray[i]->len; hi->flags |= ctx->parray[i]->flags; hi->id = ctx->parray[i]->id; hi->ci = ctx->parray[i]->ci; hi->cs = ctx->parray[i]->cs; ctx->hash[idx] = hi; } else { B2gPattern *hi = B2gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->flags |= MPM_PATTERN_ONE_BYTE; hi->len = ctx->parray[i]->len; hi->flags |= ctx->parray[i]->flags; hi->id = ctx->parray[i]->id; hi->ci = ctx->parray[i]->ci; hi->cs = ctx->parray[i]->cs; if (ctx->parray[i]->len < ctx->pminlen[idx]) ctx->pminlen[idx] = ctx->parray[i]->len; /* Append this HashItem to the list */ B2gPattern *thi = ctx->hash[idx]; while (thi->next) thi = thi->next; thi->next = hi; } ctx->pat_x_cnt++; } } /* alloc the bloom array */ ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); if (ctx->bloom == NULL) goto error; memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); uint32_t h; for (h = 0; h < ctx->hash_size; h++) { B2gPattern *hi = ctx->hash[h]; if (hi == NULL) continue; ctx->bloom[h] = BloomFilterInit(b2g_bloom_size, 2, B2gBloomHash); if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); if (ctx->pminlen[h] > 8) ctx->pminlen[h] = 8; B2gPattern *thi = hi; do { SCLogDebug("adding \"%c%c\" to the bloom", thi->ci[0], thi->ci[1]); BloomFilterAdd(ctx->bloom[h], thi->ci, ctx->pminlen[h]); thi = thi->next; } while (thi != NULL); } return; error: return; } int B2gBuildMatchArray(MpmCtx *mpm_ctx) { SCEnter(); B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; ctx->B2G = SCMalloc(sizeof(B2G_TYPE) * ctx->hash_size); if (ctx->B2G == NULL) return -1; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B2G_TYPE) * ctx->hash_size); memset(ctx->B2G,0, b2g_hash_size * sizeof(B2G_TYPE)); uint32_t j; uint32_t a; /* fill the match array */ for (j = 0; j <= (ctx->m - B2G_Q); j++) { for (a = 0; a < mpm_ctx->pattern_cnt; a++) { if (ctx->parray[a]->len < ctx->m) continue; uint16_t h = B2G_HASH16(u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1])); ctx->B2G[h] = ctx->B2G[h] | (1 << (ctx->m - j)); SCLogDebug("h %"PRIu16", ctx->B2G[h] %"PRIu32"", h, ctx->B2G[h]); } } ctx->s0 = 1; SCReturnInt(0); } int B2gPreparePatterns(MpmCtx *mpm_ctx) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; /* alloc the pattern array */ ctx->parray = (B2gPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); if (ctx->parray == NULL) goto error; memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; for (i = 0; i < INIT_HASH_SIZE; i++) { B2gPattern *node = ctx->init_hash[i], *nnode = NULL; for ( ; node != NULL; ) { nnode = node->next; node->next = NULL; ctx->parray[p] = node; p++; node = nnode; } } /* we no longer need the hash, so free it's memory */ SCFree(ctx->init_hash); ctx->init_hash = NULL; /* set 'm' to the smallest pattern size */ ctx->m = mpm_ctx->minlen; /* make sure 'm' stays in bounds m can be max WORD_SIZE - 1 */ if (ctx->m >= B2G_WORD_SIZE) { ctx->m = B2G_WORD_SIZE - 1; } if (ctx->m < 2) ctx->m = 2; ctx->hash_size = b2g_hash_size; B2gPrepareHash(mpm_ctx); B2gBuildMatchArray(mpm_ctx); SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); if (ctx->pat_1_cnt) { ctx->Search = B2gSearch1; #ifdef B2G_SEARCH2 ctx->Search = B2gSearch2; if (ctx->pat_2_cnt) { ctx->MBSearch2 = B2gSearch2; } #endif ctx->MBSearch = b2g_func; #ifdef B2G_SEARCH2 } else if (ctx->pat_2_cnt) { ctx->Search = B2gSearch2; ctx->MBSearch = b2g_func; #endif } return 0; error: return -1; } void B2gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef B2G_COUNTERS B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; printf("B2g Thread Search stats (tctx %p)\n", tctx); printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); printf("Avg pminlen: %0.2f\n\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); #endif /* B2G_COUNTERS */ } /** * \brief Function to get the user defined values for b2g algorithm from the * config file 'suricata.yaml' */ static void B2gGetConfig() { ConfNode *b2g_conf; const char *hash_val = NULL; const char *bloom_val = NULL; const char *algo = NULL; /* init defaults */ b2g_hash_size = HASHSIZE_LOW; b2g_bloom_size = BLOOMSIZE_MEDIUM; b2g_hash_shift = B2G_HASHSHIFT_LOW; b2g_func = B2G_SEARCHFUNC; ConfNode *pm = ConfGetNode("pattern-matcher"); if (pm != NULL) { TAILQ_FOREACH(b2g_conf, &pm->head, next) { if (strcmp(b2g_conf->val, "b2g") == 0) { algo = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "algo"); hash_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "hash_size"); bloom_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "bf_size"); if (algo != NULL) { if (strcmp(algo, "B2gSearch") == 0) { b2g_func = B2gSearch; } else if (strcmp(algo, "B2gSearchBNDMq") == 0) { b2g_func = B2gSearchBNDMq; } } if (hash_val != NULL) { b2g_hash_size = MpmGetHashSize(hash_val); switch (b2g_hash_size) { case HASHSIZE_LOWEST: b2g_hash_shift = B2G_HASHSHIFT_LOWEST; break; case HASHSIZE_LOW: b2g_hash_shift = B2G_HASHSHIFT_LOW; break; case HASHSIZE_MEDIUM: b2g_hash_shift = B2G_HASHSHIFT_MEDIUM; break; case HASHSIZE_HIGH: b2g_hash_shift = B2G_HASHSHIFT_HIGH; break; case HASHSIZE_HIGHER: b2g_hash_shift = B2G_HASHSHIFT_HIGHER; break; case HASHSIZE_MAX: b2g_hash_shift = B2G_HASHSHIFT_MAX; break; } } if (bloom_val != NULL) b2g_bloom_size = MpmGetBloomSize(bloom_val); SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", b2g_hash_size, b2g_bloom_size); } } } } void B2gInitCtx (MpmCtx *mpm_ctx, int module_handle) { SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); if (mpm_ctx->ctx != NULL) return; //BUG_ON(mpm_ctx->ctx != NULL); mpm_ctx->ctx = SCMalloc(sizeof(B2gCtx)); if (mpm_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_ctx->ctx, 0, sizeof(B2gCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gCtx); /* initialize the hash we use to speed up pattern insertions */ B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; ctx->init_hash = SCMalloc(sizeof(B2gPattern *) * INIT_HASH_SIZE); if (ctx->init_hash == NULL) { exit(EXIT_FAILURE); } memset(ctx->init_hash, 0, sizeof(B2gPattern *) * INIT_HASH_SIZE); /* Initialize the defaults value from the config file. The given check make sure that we query config file only once for config values */ if (b2g_hash_size == 0) B2gGetConfig(); /* init defaults search functions */ ctx->Search = b2g_func; SCReturn; } void B2gDestroyCtx(MpmCtx *mpm_ctx) { SCLogDebug("mpm_ctx %p", mpm_ctx); B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->init_hash) { SCFree(ctx->init_hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B2gPattern *)); } if (ctx->parray) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { B2gFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gPattern)); } if (ctx->B2G) { SCFree(ctx->B2G); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B2G_TYPE) * ctx->hash_size); } if (ctx->bloom) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); BloomFilterFree(ctx->bloom[h]); } SCFree(ctx->bloom); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); } if (ctx->hash) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->hash[h] == NULL) continue; B2gHashFree(mpm_ctx, ctx->hash[h]); } SCFree(ctx->hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B2gPattern) * ctx->hash_size); } if (ctx->pminlen) { SCFree(ctx->pminlen); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gCtx); } void B2gThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); if (sizeof(B2gThreadCtx) > 0) { /* size can be null when optimized */ mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gThreadCtx)); if (mpm_thread_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_thread_ctx->ctx, 0, sizeof(B2gThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(B2gThreadCtx); } } void B2gThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { B2gThreadCtx *ctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; B2gPrintSearchStats(mpm_thread_ctx); if (ctx != NULL) { /* can be NULL if B2gThreadCtx is optimized to 0 */ mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(B2gThreadCtx); SCFree(mpm_thread_ctx->ctx); } } uint32_t B2gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; } uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; #ifdef B2G_COUNTERS B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = ctx->m - B2G_Q + 1, matches = 0; B2G_TYPE d; //printf("\n"); //PrintRawDataFp(stdout, buf, buflen); SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32"", buflen, ctx->m, pos); COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (uint32_t)(buflen - B2G_Q + 1)) { uint16_t h = B2G_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); d = ctx->B2G[h]; if (d != 0) { COUNT(tctx->stat_d0++); uint32_t j = pos; uint32_t first = pos - (ctx->m - B2G_Q + 1); do { j = j - 1; if (d >= (uint32_t)(1 << (ctx->m - 1))) { if (j > first) pos = j; else { /* get our patterns from the hash */ h = B2G_HASH16(u8_tolower(buf[j + ctx->m - 2]),u8_tolower(buf[j + ctx->m - 1])); if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((buflen - j) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf+j, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); SCLogDebug("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); goto skip_loop; } } } B2gPattern *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->next) { COUNT(tctx->stat_d0_hashloop++); if ((buflen - j) < thi->len) { continue; } if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { //if (memcmp_lowercase(thi->ci, buf+j, thi->len) == 0) { if (SCMemcmpLowercase(thi->ci, buf+j, thi->len) == 0) { #ifdef PRINTMATCH printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); #endif COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (SCMemcmp(thi->cs, buf+j, thi->len) == 0) { //if (memcmp(thi->cs, buf+j, thi->len) == 0) { #ifdef PRINTMATCH printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); #endif COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } } skip_loop: SCLogDebug("skipped"); //SCLogDebug("output at pos %" PRIu32 ": ", j); prt(buf + (j), ctx->m); printf("\n"); ; } } if (j == 0) { break; } h = B2G_HASH16(u8_tolower(buf[j - 1]),u8_tolower(buf[j])); d = (d << 1) & ctx->B2G[h]; } while (d != 0); } COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (ctx->m - B2G_Q + 1)); pos = pos + ctx->m - B2G_Q + 1; SCLogDebug("pos %"PRIu32"", pos); } SCLogDebug("matches %"PRIu32"", matches); return matches; } uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; #ifdef B2G_COUNTERS B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = 0, matches = 0; B2G_TYPE d; uint32_t j; COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (buflen - ctx->m)) { j = ctx->m - 1; d = ~0; do { uint16_t h = B2G_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); d = ((d << 1) & ctx->B2G[h]); j = j - 1; } while (d != 0 && j != 0); /* (partial) match, move on to verification */ if (d != 0) { COUNT(tctx->stat_d0++); //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); /* get our patterns from the hash */ uint16_t h = B2G_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((buflen - pos) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf+pos, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); goto skip_loop; } } } B2gPattern *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->next) { COUNT(tctx->stat_d0_hashloop++); //B2gPattern *p = ctx->parray[thi->idx]; if (buflen - pos < thi->len) continue; if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { if (SCMemcmpLowercase(thi->ci, buf+pos, thi->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (SCMemcmp(thi->cs, buf+pos, thi->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } } skip_loop: //pos = pos + ctx->s0; pos = pos + 1; } else { COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (j + 1)); pos = pos + j + 1; } } //printf("Total matches %" PRIu32 "\n", matches); return matches; } #ifdef B2G_SEARCH2 uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; B2gPattern *p; B2gPattern *thi, *hi; if (buflen < 2) return 0; //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint8_t h8 = u8_tolower(*buf); hi = &ctx->hash1[h8]; if (hi->flags & MPM_PATTERN_ONE_BYTE) { for (thi = hi; thi != NULL; thi = thi->next) { p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } else { if (*buf == p->cs[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } } } /* save one conversion by reusing h8 */ uint16_t h16 = B2G_HASH16(h8, u8_tolower(*(buf+1))); hi = ctx->hash2[h16]; for (thi = hi; thi != NULL; thi = thi->next) { p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); // for (em = p->em; em; em = em->next) { if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) cnt++; // } } } else { if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); // for (em = p->em; em; em = em->next) { if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) cnt++; // } } } } buf += 1; } //printf("B2gSearch2: after 2byte cnt %" PRIu32 "\n", cnt); if (ctx->pat_x_cnt > 0) { /* Pass bufmin on because buf no longer points to the * start of the buffer. */ cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); //printf("B2gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); } return cnt; } #endif uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { SCEnter(); B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; // B2gPattern *p; B2gPattern *thi, *hi; if (buflen == 0) SCReturnUInt(0); //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint8_t h = u8_tolower(*buf); hi = &ctx->hash1[h]; for (thi = hi; thi != NULL; thi = thi->next) { if (hi->flags & MPM_PATTERN_ONE_BYTE) { if (thi->len != 1) continue; if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { if (u8_tolower(*buf) == thi->ci[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } } else { if (*buf == thi->cs[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } } } } buf += 1; } //printf("B2gSearch1: after 1byte cnt %" PRIu32 "\n", cnt); #ifdef B2G_SEARCH2 if (ctx->pat_2_cnt) { /* Pass bufmin on because buf no longer points to the * start of the buffer. */ cnt += ctx->MBSearch2(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); //printf("B2gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); } else #endif if (ctx->pat_x_cnt) { cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); } SCReturnUInt(cnt); } /* * TESTS */ #ifdef UNITTESTS static int B2gTestInit01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); if (ctx->m == 4) result = 1; else printf("4 != %" PRIu32 " ", ctx->m); B2gDestroyCtx(&mpm_ctx); return result; } #if 0 static int B2gTestS0Init01 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); if (ctx->s0 == 4) result = 1; else printf("4 != %" PRIu32 " ", ctx->s0); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestS0Init02 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); if (ctx->s0 == 2) result = 1; else printf("2 != %" PRIu32 " ", ctx->s0); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestS0Init03 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); if (ctx->s0 == 1) result = 1; else printf("1 != %" PRIu32 " ", ctx->s0); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestS0Init04 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); if (ctx->s0 == 2) result = 1; else printf("2 != %" PRIu32 " ", ctx->s0); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestS0Init05 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); if (ctx->s0 == 3) result = 1; else printf("3 != %" PRIu32 " ", ctx->s0); B2gDestroyCtx(&mpm_ctx); return result; } #endif static int B2gTestSearch01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } /* test patterns longer than 'm'. M is 4 here. */ static int B2gTestSearch04 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } /* case insensitive test patterns longer than 'm'. M is 4 here. */ static int B2gTestSearch05 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch05a (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ B2gAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ B2gAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 5) result = 1; else printf("5 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch06 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch07 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch08 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch09 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch10 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); char *buf = "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "abcdefgh" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789"; uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch11 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch13 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch17 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch18 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch19 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch20 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ //B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } static int B2gTestSearch21 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; B2gAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); return result; } #endif /* UNITTESTS */ #if 0 static int B2gTestSearchXX (void) { MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2G, -1); B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; FILE *fp = fopen("/usr/share/dict/words", "r"); if (fp == NULL) exit(1); char *word; char line[128]; int w = 0; int w_max = 4000; while((word = fgets(line, sizeof(line), fp)) != NULL) { word[strlen(word) - 1] = '\0'; B2gAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); w++; if (w_max == w) break; } B2gPreparePatterns(&mpm_ctx); B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; uint32_t len = strlen(text) - 1; int i; uint32_t cnt; for (i = 0; i < 100; i++) { cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); } printf("cnt %u ", cnt); B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gDestroyCtx(&mpm_ctx); fclose(fp); return 1; } #endif void B2gRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("B2gTestInit01", B2gTestInit01, 1); /* UtRegisterTest("B2gTestS0Init01", B2gTestS0Init01, 1); UtRegisterTest("B2gTestS0Init02", B2gTestS0Init02, 1); UtRegisterTest("B2gTestS0Init03", B2gTestS0Init03, 1); UtRegisterTest("B2gTestS0Init04", B2gTestS0Init04, 1); UtRegisterTest("B2gTestS0Init05", B2gTestS0Init05, 1); */ UtRegisterTest("B2gTestSearch01", B2gTestSearch01, 1); UtRegisterTest("B2gTestSearch02", B2gTestSearch02, 1); UtRegisterTest("B2gTestSearch03", B2gTestSearch03, 1); UtRegisterTest("B2gTestSearch04", B2gTestSearch04, 1); UtRegisterTest("B2gTestSearch05", B2gTestSearch05, 1); UtRegisterTest("B2gTestSearch05a", B2gTestSearch05a, 1); UtRegisterTest("B2gTestSearch06", B2gTestSearch06, 1); UtRegisterTest("B2gTestSearch07", B2gTestSearch07, 1); UtRegisterTest("B2gTestSearch08", B2gTestSearch08, 1); UtRegisterTest("B2gTestSearch09", B2gTestSearch09, 1); UtRegisterTest("B2gTestSearch10", B2gTestSearch10, 1); UtRegisterTest("B2gTestSearch11", B2gTestSearch11, 1); UtRegisterTest("B2gTestSearch12", B2gTestSearch12, 1); UtRegisterTest("B2gTestSearch13", B2gTestSearch13, 1); UtRegisterTest("B2gTestSearch14", B2gTestSearch14, 1); UtRegisterTest("B2gTestSearch15", B2gTestSearch15, 1); UtRegisterTest("B2gTestSearch16", B2gTestSearch16, 1); UtRegisterTest("B2gTestSearch17", B2gTestSearch17, 1); UtRegisterTest("B2gTestSearch18", B2gTestSearch18, 1); UtRegisterTest("B2gTestSearch19", B2gTestSearch19, 1); UtRegisterTest("B2gTestSearch20", B2gTestSearch20, 1); UtRegisterTest("B2gTestSearch21", B2gTestSearch21, 1); // UtRegisterTest("B2gTestSearchXX", B2gTestSearchXX, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-buffer.h0000644000000000000000000001552512253546156013432 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_BUFFER_H__ #define __UTIL_BUFFER_H__ typedef struct MemBuffer_ { uint8_t *buffer; uint32_t size; uint32_t offset; } MemBuffer; MemBuffer *MemBufferCreateNew(uint32_t size); void MemBufferFree(MemBuffer *buffer); /** * \brief Reset the mem buffer. * * \param mem_buffer Pointer to the mem buffer instance. */ #define MemBufferReset(mem_buffer) do { \ (mem_buffer)->buffer[0] = 0; \ (mem_buffer)->offset = 0; \ } while (0) /** * \brief Write a buffer to the file pointer. * * Accepted buffers can contain both printable and non-printable * characters. Printable characters are written in the printable * format and the non-printable chars are written in hex codes * using the |XX| format. * * For example this would be the kind of output in the file - * onetwo|EF|three|ED|five * * \param buffer Pointer to the src MemBuffer instance to write. * \param fp Pointer to the file file instance to write to. */ #define MemBufferPrintToFP(buffer, fp) do { \ uint32_t i; \ \ for (i = 0; i < (buffer)->offset; i++) { \ if (isprint(buffer->buffer[i])) \ fprintf(fp, "%c", (buffer)->buffer[i]); \ else \ fprintf(fp, "|%02X|", (buffer)->buffer[i]); \ } \ } while (0) /** * \brief Write a buffer to the file pointer as a printable char string. * * \param buffer Pointer to the src MemBuffer instance to write. * \param fp Pointer to the file file instance to write to. */ #define MemBufferPrintToFPAsString(mem_buffer, fp) ({ \ fwrite((mem_buffer)->buffer, sizeof(uint8_t), (mem_buffer)->offset, fp); \ }) /** * \brief Write a buffer in hex format. * * \param buffer Pointer to the src MemBuffer instance to write. * \param fp Pointer to the file file instance to write to. */ #define MemBufferPrintToFPAsHex(buffer, fp) do { \ uint32_t i; \ \ for (i = 0; i < (buffer)->offset; i++) { \ if (((buffer)->offset % 8) == 0) \ fprintf(fp, "\n"); \ fprintf(fp, " %02X", (buffer)->buffer[i]); \ } \ } while (0) /** * \brief Write a raw buffer to the MemBuffer dst. * * When we say raw buffer it indicates a buffer that need not be * purely a string buffer. It can be a pure string buffer or not or * a mixture of both. Hence we don't accept any format strings. * * If the remaining space on the buffer is lesser than the length of * the buffer to write, it is truncated to fit into the empty space. * * Also after every write a '\0' is appended. This would indicate * that the total available space to write in the buffer is * MemBuffer->size - 1 and not Membuffer->size. The reason we * append the '\0' is for supporting writing pure string buffers * as well, that can later be used by other string handling funcs. * * \param raw_buffer The buffer to write. * \param raw_buffer_len Length of the above buffer. */ #define MemBufferWriteRaw(dst, raw_buffer, raw_buffer_len) do { \ uint32_t write_len; \ \ if (((raw_buffer_len) >= (dst)->size - (dst)->offset)) { \ SCLogDebug("Truncating data write since it exceeded buffer limit of " \ "- %"PRIu32"\n", (dst)->size); \ write_len = ((dst)->size - (dst)->offset) - 1; \ } else { \ write_len = (raw_buffer_len); \ } \ \ memcpy((dst)->buffer + (dst)->offset, (raw_buffer), write_len); \ (dst)->offset += write_len; \ dst->buffer[dst->offset] = '\0'; \ \ return; \ } while (0) /** * \brief Write a string buffer to the Membuffer dst. * * This function takes a format string and arguments for the format * string like sprintf. * * An example usage of this is - * MemBufferWriteString(mem_buffer_instance, \"%d - %s\", 10, \"one\"); * * \param dst The dst MemBuffer instance. * \param format The format string. * \param ... Variable arguments. */ #define MemBufferWriteString(dst, ...) do { \ int cw = snprintf((char *)(dst)->buffer + (dst)->offset, \ (dst)->size - (dst)->offset, \ __VA_ARGS__); \ if (cw >= 0) { \ if ( ((dst)->offset + cw) >= (dst)->size) { \ SCLogDebug("Truncating data write since it exceeded buffer " \ "limit of - %"PRIu32"\n", (dst)->size); \ (dst)->offset = (dst)->size - 1; \ } else { \ (dst->offset) += cw; \ } \ } \ } while (0) #endif /* __UTIL_BUFFER_H__ */ suricata-1.4.7/src/util-fmemopen.c0000644000000000000000000001147412253546156013761 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * Based on FMem.c of Alexandre Flori (2008/10/17 AF) */ #include "suricata-common.h" #include "util-fmemopen.h" #ifdef OS_DARWIN #define USE_FMEM_WRAPPER 1 #endif #ifdef OS_FREEBSD #define USE_FMEM_WRAPPER 1 #endif #ifdef __OpenBSD__ #define USE_FMEM_WRAPPER 1 #endif #ifdef USE_FMEM_WRAPPER #ifdef OS_WIN32 /** * \brief portable version of SCFmemopen for Windows works on top of real temp files * \param buffer that holds the file content * \param size of the file buffer * \param mode mode of the file to open * \retval pointer to the file; NULL if something is wrong */ FILE *SCFmemopen(void *buf, size_t size, const char *mode) { char temppath[MAX_PATH - 13]; if (0 == GetTempPath(sizeof(temppath), temppath)) return NULL; char filename[MAX_PATH + 1]; if (0 == GetTempFileName(temppath, "SC", 0, filename)) return NULL; FILE *f = fopen(filename, "wb"); if (NULL == f) return NULL; fwrite(buf, size, 1, f); fclose(f); return fopen(filename, mode); } #else typedef struct SCFmem_ { size_t pos; size_t size; char *buffer; } SCFmem; /** * \brief Seek the mem file from offset and whence * \param handler pointer to the memfile * \param osffset number of bytes to move from whence * \param whence SEEK_SET, SEEK_CUR, SEEK_END * \retval pos the position by the last operation, -1 if sizes are out of bounds */ static fpos_t SeekFn(void *handler, fpos_t offset, int whence) { size_t pos = 0; SCFmem *mem = handler; switch (whence) { case SEEK_SET: if (offset >= 0 && (size_t)offset <= mem->size) { return mem->pos = offset; } break; case SEEK_CUR: if (mem->pos + offset <= mem->size) return mem->pos += offset; break; case SEEK_END: /* must be negative */ if (mem->size + offset <= mem->size) return pos = mem->size + offset; break; } return -1; } /** * \brief Read from the buffer looking for the available memory limits * \param handler pointer to the memfile * \param buf buffer to read from the handler * \param number of bytes to read * \retval count , the number of bytes read */ static int ReadFn(void *handler, char *buf, int size) { size_t count = 0; SCFmem *mem = handler; size_t available = mem->size - mem->pos; int is_eof = 0; if (size < 0) return - 1; if ((size_t)size > available) { size = available; } else { is_eof = 1; } while (count < (size_t)size) buf[count++] = mem->buffer[mem->pos++]; if (is_eof == 1) return 0; return count; } /** * \brief Write into the buffer looking for the available memory limits * \param handler pointer to the memfile * \param buf buffer to write in the handler * \param number of bytes to write * \retval count , the number of bytes writen */ static int WriteFn(void *handler, const char *buf, int size) { size_t count = 0; SCFmem *mem = handler; size_t available = mem->size - mem->pos; if (size < 0) return - 1; if ((size_t)size > available) size = available; while (count < (size_t)size) mem->buffer[mem->pos++] = buf[count++]; return count; } /** * \brief close the mem file handler * \param handler pointer to the memfile * \retval 0 on succesful */ static int CloseFn(void *handler) { SCFree(handler); return 0; } /** * \brief portable version of SCFmemopen for OS X / BSD built on top of funopen() * \param buffer that holds the file content * \param size of the file buffer * \param mode mode of the file to open * \retval pointer to the file; NULL if something is wrong */ FILE *SCFmemopen(void *buf, size_t size, const char *mode) { SCFmem *mem = (SCFmem *) SCMalloc(sizeof(SCFmem)); if (mem == NULL) return NULL; memset(mem, 0, sizeof(SCFmem)); mem->size = size, mem->buffer = buf; return funopen(mem, ReadFn, WriteFn, SeekFn, CloseFn); } #endif /* OS_WIN32 */ #endif /* USE_FMEM_WRAPPER */ suricata-1.4.7/src/alert-syslog.c0000644000000000000000000003710312253546156013622 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * Logs alerts in a line based text format in to syslog. * */ #include "suricata-common.h" #include "debug.h" #include "flow.h" #include "conf.h" #include "threads.h" #include "tm-threads.h" #include "threadvars.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-reference.h" #include "output.h" #include "alert-syslog.h" #include "util-classification-config.h" #include "util-debug.h" #include "util-print.h" #include "util-proto-name.h" #include "util-syslog.h" #include "util-optimize.h" #define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" #define DEFAULT_ALERT_SYSLOG_FACILITY LOG_LOCAL0 #define DEFAULT_ALERT_SYSLOG_LEVEL LOG_ERR #define MODULE_NAME "AlertSyslog" extern uint8_t engine_mode; #ifndef OS_WIN32 static int alert_syslog_level = DEFAULT_ALERT_SYSLOG_LEVEL; #endif /* OS_WIN32 */ typedef struct AlertSyslogThread_ { /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ LogFileCtx* file_ctx; } AlertSyslogThread; TmEcode AlertSyslog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertSyslogIPv4(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertSyslogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertSyslogThreadInit(ThreadVars *, void *, void **); TmEcode AlertSyslogThreadDeinit(ThreadVars *, void *); void AlertSyslogExitPrintStats(ThreadVars *, void *); void AlertSyslogRegisterTests(void); OutputCtx *AlertSyslogInitCtx(ConfNode *); #ifndef OS_WIN32 static void AlertSyslogDeInitCtx(OutputCtx *); #endif /* OS_WIN32 */ /** \brief Function to register the AlertSyslog module */ void TmModuleAlertSyslogRegister (void) { #ifndef OS_WIN32 tmm_modules[TMM_ALERTSYSLOG].name = MODULE_NAME; tmm_modules[TMM_ALERTSYSLOG].ThreadInit = AlertSyslogThreadInit; tmm_modules[TMM_ALERTSYSLOG].Func = AlertSyslog; tmm_modules[TMM_ALERTSYSLOG].ThreadExitPrintStats = AlertSyslogExitPrintStats; tmm_modules[TMM_ALERTSYSLOG].ThreadDeinit = AlertSyslogThreadDeinit; tmm_modules[TMM_ALERTSYSLOG].RegisterTests = NULL; tmm_modules[TMM_ALERTSYSLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "syslog", AlertSyslogInitCtx); #endif /* !OS_WIN32 */ } /** \brief Function to register the AlertSyslog module for IPv4 */ void TmModuleAlertSyslogIPv4Register (void) { #ifndef OS_WIN32 tmm_modules[TMM_ALERTSYSLOG4].name = "AlertSyslogIPv4"; tmm_modules[TMM_ALERTSYSLOG4].ThreadInit = AlertSyslogThreadInit; tmm_modules[TMM_ALERTSYSLOG4].Func = AlertSyslogIPv4; tmm_modules[TMM_ALERTSYSLOG4].ThreadExitPrintStats = AlertSyslogExitPrintStats; tmm_modules[TMM_ALERTSYSLOG4].ThreadDeinit = AlertSyslogThreadDeinit; tmm_modules[TMM_ALERTSYSLOG4].RegisterTests = NULL; #endif /* !OS_WIN32 */ } /** \brief Function to register the AlertSyslog module for IPv6 */ void TmModuleAlertSyslogIPv6Register (void) { #ifndef OS_WIN32 tmm_modules[TMM_ALERTSYSLOG6].name = "AlertSyslogIPv6"; tmm_modules[TMM_ALERTSYSLOG6].ThreadInit = AlertSyslogThreadInit; tmm_modules[TMM_ALERTSYSLOG6].Func = AlertSyslogIPv6; tmm_modules[TMM_ALERTSYSLOG6].ThreadExitPrintStats = AlertSyslogExitPrintStats; tmm_modules[TMM_ALERTSYSLOG6].ThreadDeinit = AlertSyslogThreadDeinit; tmm_modules[TMM_ALERTSYSLOG6].RegisterTests = NULL; #endif /* !OS_WIN32 */ } #ifndef OS_WIN32 /** * \brief Create a new LogFileCtx for "syslog" output style. * * \param conf The configuration node for this output. * \return A OutputCtx pointer on success, NULL on failure. */ OutputCtx *AlertSyslogInitCtx(ConfNode *conf) { const char *facility_s = ConfNodeLookupChildValue(conf, "facility"); if (facility_s == NULL) { facility_s = DEFAULT_ALERT_SYSLOG_FACILITY_STR; } LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("AlertSyslogInitCtx: Could not create new LogFileCtx"); return NULL; } int facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap()); if (facility == -1) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid syslog facility: \"%s\"," " now using \"%s\" as syslog facility", facility_s, DEFAULT_ALERT_SYSLOG_FACILITY_STR); facility = DEFAULT_ALERT_SYSLOG_FACILITY; } const char *level_s = ConfNodeLookupChildValue(conf, "level"); if (level_s != NULL) { int level = SCMapEnumNameToValue(level_s, SCSyslogGetLogLevelMap()); if (level != -1) { alert_syslog_level = level; } } const char *ident = ConfNodeLookupChildValue(conf, "identity"); /* if null we just pass that to openlog, which will then * figure it out by itself. */ openlog(ident, LOG_PID|LOG_NDELAY, facility); OutputCtx *output_ctx = SCMalloc(sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { SCLogDebug("AlertSyslogInitCtx: Could not create new OutputCtx"); return NULL; } memset(output_ctx, 0x00, sizeof(OutputCtx)); output_ctx->data = logfile_ctx; output_ctx->DeInit = AlertSyslogDeInitCtx; SCLogInfo("Syslog output initialized"); return output_ctx; } /** * \brief Function to clear the memory of the output context and closes the * syslog interface * * \param output_ctx pointer to the output context to be cleared */ static void AlertSyslogDeInitCtx(OutputCtx *output_ctx) { if (output_ctx != NULL) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; if (logfile_ctx != NULL) { LogFileFreeCtx(logfile_ctx); } SCFree(output_ctx); } closelog(); } /** * \brief Function to initialize the AlertSystlogThread and sets the output * context pointer * * \param tv Pointer to the threadvars * \param initdata Pointer to the output context * \param data pointer to pointer to point to the AlertSyslogThread */ TmEcode AlertSyslogThreadInit(ThreadVars *t, void *initdata, void **data) { if(initdata == NULL) { SCLogDebug("Error getting context for AlertSyslog. \"initdata\" " "argument NULL"); return TM_ECODE_FAILED; } AlertSyslogThread *ast = SCMalloc(sizeof(AlertSyslogThread)); if (unlikely(ast == NULL)) return TM_ECODE_FAILED; memset(ast, 0, sizeof(AlertSyslogThread)); /** Use the Ouptut Context (file pointer and mutex) */ ast->file_ctx = ((OutputCtx *)initdata)->data; *data = (void *)ast; return TM_ECODE_OK; } /** * \brief Function to deinitialize the AlertSystlogThread * * \param tv Pointer to the threadvars * \param data pointer to the AlertSyslogThread to be cleared */ TmEcode AlertSyslogThreadDeinit(ThreadVars *t, void *data) { AlertSyslogThread *ast = (AlertSyslogThread *)data; if (ast == NULL) { return TM_ECODE_OK; } /* clear memory */ memset(ast, 0, sizeof(AlertSyslogThread)); SCFree(ast); return TM_ECODE_OK; } /** * \brief Function which is called to print the IPv4 alerts to the syslog * * \param tv Pointer to the threadvars * \param p Pointer to the packet * \param data pointer to the AlertSyslogThread * \param pq pointer the to packet queue * \param postpq pointer to the post processed packet queue * * \return On succes return TM_ECODE_OK */ TmEcode AlertSyslogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertSyslogThread *ast = (AlertSyslogThread *)data; int i; char *action = ""; if (p->alerts.cnt == 0) return TM_ECODE_OK; SCMutexLock(&ast->file_ctx->fp_mutex); ast->file_ctx->alerts += p->alerts.cnt; for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; } char srcip[16], dstip[16]; PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { action = "[Drop] "; } else if (pa->action & ACTION_DROP) { action = "[wDrop] "; } if (SCProtoNameValid(IPV4_GET_IPPROTO(p)) == TRUE) { syslog(alert_syslog_level, "%s[%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [Classification: %s] [Priority: %"PRIu32"]" " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "", action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio, known_proto[IPV4_GET_IPPROTO(p)], srcip, p->sp, dstip, p->dp); } else { syslog(alert_syslog_level, "%s[%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [Classification: %s] [Priority: %"PRIu32"]" " {PROTO:%03" PRIu32 "} %s:%" PRIu32 " -> %s:%" PRIu32 "", action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio, IPV4_GET_IPPROTO(p), srcip, p->sp, dstip, p->dp); } } SCMutexUnlock(&ast->file_ctx->fp_mutex); return TM_ECODE_OK; } /** * \brief Function which is called to print the IPv6 alerts to the syslog * * \param tv Pointer to the threadvars * \param p Pointer to the packet * \param data pointer to the AlertSyslogThread * \param pq pointer the to packet queue * \param postpq pointer to the post processed packet queue * * \return On succes return TM_ECODE_OK */ TmEcode AlertSyslogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertSyslogThread *ast = (AlertSyslogThread *)data; int i; char *action = ""; if (p->alerts.cnt == 0) return TM_ECODE_OK; SCMutexLock(&ast->file_ctx->fp_mutex); ast->file_ctx->alerts += p->alerts.cnt; for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; } char srcip[46], dstip[46]; PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { action = "[Drop] "; } else if (pa->action & ACTION_DROP) { action = "[wDrop] "; } if (SCProtoNameValid(IPV6_GET_L4PROTO(p)) == TRUE) { syslog(alert_syslog_level, "%s[%" PRIu32 ":%" PRIu32 ":%" "" PRIu32 "] %s [Classification: %s] [Priority: %" "" PRIu32 "] {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "", action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio, known_proto[IPV6_GET_L4PROTO(p)], srcip, p->sp, dstip, p->dp); } else { syslog(alert_syslog_level, "%s[%" PRIu32 ":%" PRIu32 ":%" "" PRIu32 "] %s [Classification: %s] [Priority: %" "" PRIu32 "] {PROTO:%03" PRIu32 "} %s:%" PRIu32 " -> %s:%" PRIu32 "", action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio, IPV6_GET_L4PROTO(p), srcip, p->sp, dstip, p->dp); } } SCMutexUnlock(&ast->file_ctx->fp_mutex); return TM_ECODE_OK; } /** * \brief Function which is called to print the decode alerts to the syslog * * \param tv Pointer to the threadvars * \param p Pointer to the packet * \param data pointer to the AlertSyslogThread * \param pq pointer the to packet queue * \param postpq pointer to the post processed packet queue * * \return On succes return TM_ECODE_OK */ TmEcode AlertSyslogDecoderEvent(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertSyslogThread *ast = (AlertSyslogThread *)data; int i; char *action = ""; if (p->alerts.cnt == 0) return TM_ECODE_OK; SCMutexLock(&ast->file_ctx->fp_mutex); ast->file_ctx->alerts += p->alerts.cnt; char temp_buf_hdr[512]; char temp_buf_pkt[65] = ""; char temp_buf_tail[32]; char alert[2048] = ""; for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; } if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { action = "[Drop] "; } else if (pa->action & ACTION_DROP) { action = "[wDrop] "; } snprintf(temp_buf_hdr, sizeof(temp_buf_hdr), "%s[%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [Classification: %s] [Priority: %" PRIu32 "] [**] [Raw pkt: ", action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio); strlcpy(alert, temp_buf_hdr, sizeof(alert)); PrintRawLineHexBuf(temp_buf_pkt, sizeof(temp_buf_pkt), GET_PKT_DATA(p), GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32); strlcat(alert, temp_buf_pkt, sizeof(alert)); if (p->pcap_cnt != 0) { snprintf(temp_buf_tail, sizeof(temp_buf_tail), "] [pcap file packet: %"PRIu64"]", p->pcap_cnt); } else { temp_buf_tail[0] = ']'; temp_buf_tail[1] = '\0'; } strlcat(alert, temp_buf_tail, sizeof(alert)); syslog(alert_syslog_level, "%s", alert); } SCMutexUnlock(&ast->file_ctx->fp_mutex); return TM_ECODE_OK; } /** * \brief Function which is called to print the alerts to the syslog * * \param tv Pointer to the threadvars * \param p Pointer to the packet * \param data pointer to the AlertSyslogThread * \param pq pointer the to packet queue * \param postpq pointer to the post processed packet queue * * \return On succes return TM_ECODE_OK */ TmEcode AlertSyslog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { if (PKT_IS_IPV4(p)) { return AlertSyslogIPv4(tv, p, data, pq, NULL); } else if (PKT_IS_IPV6(p)) { return AlertSyslogIPv6(tv, p, data, pq, NULL); } else if (p->events.cnt > 0) { return AlertSyslogDecoderEvent(tv, p, data, pq, NULL); } return TM_ECODE_OK; } /** * \brief Function to print the total alert while closing the engine * * \param tv Pointer to the output threadvars * \param data Pointer to the AlertSyslogThread data */ void AlertSyslogExitPrintStats(ThreadVars *tv, void *data) { AlertSyslogThread *ast = (AlertSyslogThread *)data; if (ast == NULL) { return; } SCLogInfo("(%s) Alerts %" PRIu64 "", tv->name, ast->file_ctx->alerts); } #endif /* !OS_WIN32 */ suricata-1.4.7/src/util-error.c0000644000000000000000000002475012253546156013305 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Error utility functions * * \todo Needs refining of the error codes. Renaming with a prefix of SC_ERR, * removal of duplicates and entries have to be made in util-error.c */ #include "util-error.h" #define CASE_CODE(E) case E: return #E /** * \brief Maps the error code, to its string equivalent * * \param The error code * * \retval The string equivalent for the error code */ const char * SCErrorToString(SCError err) { switch (err) { CASE_CODE (SC_OK); CASE_CODE (SC_ERR_MEM_ALLOC); CASE_CODE (SC_ERR_ACTION_ORDER); CASE_CODE (SC_ERR_PCRE_MATCH); CASE_CODE (SC_ERR_PCRE_GET_SUBSTRING); CASE_CODE (SC_ERR_PCRE_COMPILE); CASE_CODE (SC_ERR_PCRE_STUDY); CASE_CODE (SC_ERR_PCRE_PARSE); CASE_CODE (SC_ERR_LOG_MODULE_NOT_INIT); CASE_CODE (SC_ERR_LOG_FG_FILTER_MATCH); CASE_CODE (SC_ERR_PCAP_DISPATCH); CASE_CODE (SC_ERR_PCAP_CREATE); CASE_CODE (SC_ERR_PCAP_SET_SNAPLEN); CASE_CODE (SC_ERR_PCAP_SET_PROMISC); CASE_CODE (SC_ERR_PCAP_SET_TIMEOUT); CASE_CODE (SC_ERR_PCAP_OPEN_LIVE); CASE_CODE (SC_ERR_PCAP_OPEN_OFFLINE); CASE_CODE (SC_ERR_PCAP_ACTIVATE_HANDLE); CASE_CODE (SC_ERR_PCAP_SET_BUFF_SIZE); CASE_CODE (SC_ERR_NO_PCAP_SET_BUFFER_SIZE); CASE_CODE (SC_ERR_NO_PF_RING); CASE_CODE (SC_ERR_PF_RING_RECV); CASE_CODE (SC_ERR_PF_RING_GET_CLUSTERID_FAILED); CASE_CODE (SC_ERR_PF_RING_GET_INTERFACE_FAILED); CASE_CODE (SC_ERR_PF_RING_OPEN); CASE_CODE (SC_ERR_GET_CLUSTER_TYPE_FAILED); CASE_CODE (SC_ERR_INVALID_CLUSTER_TYPE); CASE_CODE (SC_ERR_PF_RING_SET_CLUSTER_FAILED); CASE_CODE (SC_ERR_DATALINK_UNIMPLEMENTED); CASE_CODE (SC_ERR_INVALID_SIGNATURE); CASE_CODE (SC_ERR_OPENING_FILE); CASE_CODE (SC_ERR_OPENING_RULE_FILE); CASE_CODE (SC_ERR_NO_RULES); CASE_CODE (SC_ERR_NO_RULES_LOADED); CASE_CODE (SC_ERR_COUNTER_EXCEEDED); CASE_CODE (SC_ERR_INVALID_CHECKSUM); CASE_CODE (SC_ERR_SPRINTF); CASE_CODE (SC_ERR_FATAL); CASE_CODE (SC_ERR_INVALID_ARGUMENT); CASE_CODE (SC_ERR_SPINLOCK); CASE_CODE (SC_ERR_INVALID_ENUM_MAP); CASE_CODE (SC_ERR_INVALID_IP_NETBLOCK); CASE_CODE (SC_ERR_INVALID_IPV4_ADDR); CASE_CODE (SC_ERR_INVALID_IPV6_ADDR); CASE_CODE (SC_ERR_INVALID_RUNMODE); CASE_CODE (SC_ERR_COMPLETE_PORT_SPACE_NEGATED); CASE_CODE (SC_ERR_NO_PORTS_LEFT_AFTER_MERGE); CASE_CODE (SC_ERR_NEGATED_VALUE_IN_PORT_RANGE); CASE_CODE (SC_ERR_PORT_PARSE_INSERT_STRING); CASE_CODE (SC_ERR_UNREACHABLE_CODE_REACHED); CASE_CODE (SC_ERR_INVALID_NUMERIC_VALUE); CASE_CODE (SC_ERR_NUMERIC_VALUE_ERANGE); CASE_CODE (SC_ERR_INVALID_NUM_BYTES); CASE_CODE (SC_ERR_ARG_LEN_LONG); CASE_CODE (SC_ERR_ALPARSER); CASE_CODE (SC_ERR_POOL_EMPTY); CASE_CODE (SC_ERR_REASSEMBLY); CASE_CODE (SC_ERR_POOL_INIT); CASE_CODE (SC_ERR_UNIMPLEMENTED); CASE_CODE (SC_ERR_ADDRESS_ENGINE_GENERIC); CASE_CODE (SC_ERR_PORT_ENGINE_GENERIC); CASE_CODE (SC_ERR_FAST_LOG_GENERIC); CASE_CODE (SC_ERR_IPONLY_RADIX); CASE_CODE (SC_ERR_DEBUG_LOG_GENERIC); CASE_CODE (SC_ERR_UNIFIED_LOG_GENERIC); CASE_CODE (SC_ERR_HTTP_LOG_GENERIC); CASE_CODE (SC_ERR_UNIFIED_ALERT_GENERIC); CASE_CODE (SC_ERR_UNIFIED2_ALERT_GENERIC); CASE_CODE (SC_ERR_FWRITE); CASE_CODE (SC_ERR_FOPEN); CASE_CODE (SC_ERR_THREAD_NICE_PRIO); CASE_CODE (SC_ERR_THREAD_SPAWN); CASE_CODE (SC_ERR_THREAD_CREATE); CASE_CODE (SC_ERR_THREAD_INIT); CASE_CODE (SC_ERR_THRESHOLD_HASH_ADD); CASE_CODE (SC_ERR_UNDEFINED_VAR); CASE_CODE (SC_ERR_RULE_KEYWORD_UNKNOWN); CASE_CODE (SC_ERR_FLAGS_MODIFIER); CASE_CODE (SC_ERR_DISTANCE_MISSING_CONTENT); CASE_CODE (SC_ERR_BYTETEST_MISSING_CONTENT); CASE_CODE (SC_ERR_BYTEJUMP_MISSING_CONTENT); CASE_CODE (SC_ERR_WITHIN_MISSING_CONTENT); CASE_CODE (SC_ERR_WITHIN_INVALID); CASE_CODE (SC_ERR_DEPTH_MISSING_CONTENT); CASE_CODE (SC_ERR_OFFSET_MISSING_CONTENT); CASE_CODE (SC_ERR_NOCASE_MISSING_PATTERN); CASE_CODE (SC_ERR_RAWBYTES_MISSING_CONTENT); CASE_CODE (SC_ERR_NO_URICONTENT_NEGATION); CASE_CODE (SC_ERR_HASH_TABLE_INIT); CASE_CODE (SC_ERR_STAT); CASE_CODE (SC_ERR_LOGDIR_CONFIG); CASE_CODE (SC_ERR_LOGDIR_CMDLINE); CASE_CODE (SC_ERR_RADIX_TREE_GENERIC); CASE_CODE (SC_ERR_MISSING_QUOTE); CASE_CODE (SC_ERR_UNKNOWN_PROTOCOL); CASE_CODE (SC_ERR_UNKNOWN_RUN_MODE); CASE_CODE (SC_ERR_IPFW_NOSUPPORT); CASE_CODE (SC_ERR_IPFW_BIND); CASE_CODE (SC_ERR_IPFW_SOCK); CASE_CODE (SC_ERR_IPFW_SETSOCKOPT); CASE_CODE (SC_ERR_IPFW_NOPORT); CASE_CODE (SC_WARN_IPFW_RECV); CASE_CODE (SC_WARN_IPFW_XMIT); CASE_CODE (SC_WARN_IPFW_SETSOCKOPT); CASE_CODE (SC_WARN_IPFW_UNBIND); CASE_CODE (SC_ERR_MULTIPLE_RUN_MODE); CASE_CODE (SC_ERR_BPF); CASE_CODE (SC_ERR_MISSING_CONFIG_PARAM); CASE_CODE (SC_ERR_UNKNOWN_VALUE); CASE_CODE (SC_ERR_INVALID_VALUE); CASE_CODE (SC_ERR_UNKNOWN_REGEX_MOD); CASE_CODE (SC_ERR_INVALID_OPERATOR); CASE_CODE (SC_ERR_PCAP_RECV_INIT); CASE_CODE (SC_ERR_NFQ_NOSUPPORT); CASE_CODE (SC_ERR_NFQ_UNBIND); CASE_CODE (SC_ERR_NFQ_BIND); CASE_CODE (SC_ERR_NFQ_HANDLE_PKT); CASE_CODE (SC_ERR_CUDA_ERROR); CASE_CODE (SC_ERR_CUDA_HANDLER_ERROR); CASE_CODE (SC_ERR_TM_THREADS_ERROR); CASE_CODE (SC_ERR_TM_MODULES_ERROR); CASE_CODE (SC_ERR_B2G_CUDA_ERROR); CASE_CODE (SC_ERR_INVALID_YAML_CONF_ENTRY); CASE_CODE (SC_ERR_TMQ_ALREADY_REGISTERED); CASE_CODE (SC_ERR_CONFLICTING_RULE_KEYWORDS); CASE_CODE (SC_ERR_INITIALIZATION); CASE_CODE (SC_ERR_INVALID_ACTION); CASE_CODE (SC_ERR_LIBNET_REQUIRED_FOR_ACTION); CASE_CODE (SC_ERR_LIBNET_INIT); CASE_CODE (SC_ERR_LIBNET_INVALID_DIR); CASE_CODE (SC_ERR_LIBNET_BUILD_FAILED); CASE_CODE (SC_ERR_LIBNET_WRITE_FAILED); CASE_CODE (SC_ERR_LIBNET_NOT_ENABLED); CASE_CODE (SC_ERR_UNIFIED_LOG_FILE_HEADER); CASE_CODE (SC_ERR_REFERENCE_UNKNOWN); CASE_CODE (SC_ERR_PIDFILE_SNPRINTF); CASE_CODE (SC_ERR_PIDFILE_OPEN); CASE_CODE (SC_ERR_PIDFILE_WRITE); CASE_CODE (SC_ERR_PIDFILE_DAEMON); CASE_CODE (SC_ERR_UID_FAILED); CASE_CODE (SC_ERR_GID_FAILED); CASE_CODE (SC_ERR_CHANGING_CAPS_FAILED); CASE_CODE (SC_ERR_LIBCAP_NG_REQUIRED); CASE_CODE (SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG); CASE_CODE (SC_WARN_FLOW_EMERGENCY); CASE_CODE (SC_ERR_SVC); CASE_CODE (SC_ERR_ERF_DAG_OPEN_FAILED); CASE_CODE (SC_ERR_ERF_DAG_STREAM_OPEN_FAILED); CASE_CODE (SC_ERR_ERF_DAG_STREAM_START_FAILED); CASE_CODE (SC_ERR_ERF_DAG_STREAM_SET_FAILED); CASE_CODE (SC_ERR_ERF_DAG_STREAM_READ_FAILED); CASE_CODE (SC_WARN_ERF_DAG_REC_LEN_CHANGED); CASE_CODE (SC_ERR_NAPATECH_OPEN_FAILED); CASE_CODE (SC_ERR_NAPATECH_STREAM_NEXT_FAILED); CASE_CODE (SC_ERR_NAPATECH_NOSUPPORT); CASE_CODE (SC_ERR_NAPATECH_REQUIRED); CASE_CODE (SC_ERR_NAPATECH_TIMESTAMP_TYPE_NOT_SUPPORTED); CASE_CODE (SC_ERR_NAPATECH_INIT_FAILED); CASE_CODE (SC_ERR_NAPATECH_CONFIG_STREAM); CASE_CODE (SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED); CASE_CODE (SC_ERR_NAPATECH_STAT_DROPS_FAILED); CASE_CODE (SC_ERR_NAPATECH_PARSE_CONFIG); CASE_CODE (SC_WARN_COMPATIBILITY); CASE_CODE (SC_ERR_DCERPC); CASE_CODE (SC_ERR_DETECT_PREPARE); CASE_CODE (SC_ERR_AHO_CORASICK); CASE_CODE (SC_ERR_REFERENCE_CONFIG); CASE_CODE (SC_ERR_DUPLICATE_SIG); CASE_CODE (SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL); CASE_CODE (SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT); CASE_CODE (SC_ERR_HTTP_METHOD_NEEDS_PRECEEDING_CONTENT); CASE_CODE (SC_ERR_HTTP_METHOD_INCOMPATIBLE_WITH_RAWBYTES); CASE_CODE (SC_ERR_HTTP_METHOD_RELATIVE_MISSING); CASE_CODE (SC_ERR_HTTP_COOKIE_NEEDS_PRECEEDING_CONTENT); CASE_CODE (SC_ERR_HTTP_COOKIE_INCOMPATIBLE_WITH_RAWBYTES); CASE_CODE (SC_ERR_HTTP_COOKIE_RELATIVE_MISSING); CASE_CODE (SC_ERR_LOGPCAP_SGUIL_BASE_DIR_MISSING); CASE_CODE (SC_ERR_UNKNOWN_DECODE_EVENT); CASE_CODE (SC_ERR_RUNMODE); CASE_CODE (SC_ERR_SHUTDOWN); CASE_CODE (SC_ERR_INVALID_DIRECTION); CASE_CODE (SC_ERR_AFP_CREATE); CASE_CODE (SC_ERR_AFP_READ); CASE_CODE (SC_ERR_AFP_DISPATCH); CASE_CODE (SC_ERR_CMD_LINE); CASE_CODE (SC_ERR_SIZE_PARSE); CASE_CODE (SC_ERR_RAWBYTES_FILE_DATA); CASE_CODE (SC_ERR_SOCKET); CASE_CODE (SC_ERR_PCAP_TRANSLATE); CASE_CODE (SC_WARN_OUTDATED_LIBHTP); CASE_CODE (SC_WARN_DEPRECATED); CASE_CODE (SC_WARN_PROFILE); CASE_CODE (SC_ERR_FLOW_INIT); CASE_CODE (SC_ERR_HOST_INIT); CASE_CODE (SC_ERR_MEM_BUFFER_API); CASE_CODE (SC_ERR_INVALID_MD5); CASE_CODE (SC_ERR_NO_MD5_SUPPORT); CASE_CODE (SC_ERR_EVENT_ENGINE); CASE_CODE (SC_ERR_NO_LUAJIT_SUPPORT); CASE_CODE (SC_ERR_LUAJIT_ERROR); CASE_CODE (SC_ERR_NO_GEOIP_SUPPORT); CASE_CODE (SC_ERR_GEOIP_ERROR); CASE_CODE (SC_ERR_DEFRAG_INIT); CASE_CODE (SC_ERR_NO_REPUTATION); CASE_CODE (SC_ERR_NOT_SUPPORTED); CASE_CODE (SC_WARN_UNCOMMON); CASE_CODE (SC_ERR_THRESHOLD_SETUP); default: return "UNKNOWN_ERROR"; } } suricata-1.4.7/src/util-buffer.c0000644000000000000000000000304112253546156013413 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "suricata.h" #include "util-debug.h" #include "util-buffer.h" /* 10 mb */ #define MAX_LIMIT 10485760 MemBuffer *MemBufferCreateNew(uint32_t size) { if (size > MAX_LIMIT) { SCLogWarning(SC_ERR_MEM_BUFFER_API, "Mem buffer asked to create " "buffer with size greater than API limit - %d", MAX_LIMIT); return NULL; } uint32_t total_size = size + sizeof(MemBuffer); MemBuffer *buffer = SCMalloc(total_size); if (unlikely(buffer == NULL)) { return NULL; } memset(buffer, 0, total_size); buffer->size = size; buffer->buffer = (uint8_t *)buffer + sizeof(MemBuffer); return buffer; } void MemBufferFree(MemBuffer *buffer) { SCFree(buffer); return; } suricata-1.4.7/src/detect-http-header.h0000644000000000000000000000172012253546156014651 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_HTTP_HEADER_H__ #define __DETECT_HTTP_HEADER_H__ void DetectHttpHeaderRegister(void); void DetectHttpRawHeaderRegister(void); #endif /* __DETECT_HTTP_HEADER_H__ */ suricata-1.4.7/src/output.h0000644000000000000000000000247212253546156012543 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited, Jason Ish */ #ifndef __OUTPUT_H__ #define __OUTPUT_H__ #include "suricata.h" #include "tm-threads.h" #define DEFAULT_LOG_MODE_APPEND "yes" #define DEFAULT_LOG_FILETYPE "regular" typedef struct OutputModule_ { char *name; char *conf_name; OutputCtx *(*InitFunc)(ConfNode *); TAILQ_ENTRY(OutputModule_) entries; } OutputModule; void OutputRegisterModule(char *, char *, OutputCtx *(*)(ConfNode *)); OutputModule *OutputGetModuleByConfName(char *name); void OutputDeregisterAll(void); #endif /* ! __OUTPUT_H__ */ suricata-1.4.7/src/detect-engine-sigorder.c0000644000000000000000000020250112253546156015520 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Signature ordering part of the detection engine. */ #include "suricata-common.h" #include "detect.h" #include "detect-flowbits.h" #include "detect-flowint.h" #include "detect-parse.h" #include "detect-engine-sigorder.h" #include "detect-pcre.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "util-action.h" #include "action-globals.h" #include "flow-util.h" #define DETECT_FLOWVAR_NOT_USED 1 #define DETECT_FLOWVAR_TYPE_READ 2 #define DETECT_FLOWVAR_TYPE_SET_READ 3 #define DETECT_FLOWVAR_TYPE_SET 4 #define DETECT_PKTVAR_NOT_USED 1 #define DETECT_PKTVAR_TYPE_READ 2 #define DETECT_PKTVAR_TYPE_SET_READ 3 #define DETECT_PKTVAR_TYPE_SET 4 #define DETECT_FLOWBITS_NOT_USED 1 #define DETECT_FLOWBITS_TYPE_READ 2 #define DETECT_FLOWBITS_TYPE_SET_READ 3 #define DETECT_FLOWBITS_TYPE_SET 4 #define DETECT_FLOWINT_NOT_USED 1 #define DETECT_FLOWINT_TYPE_READ 2 #define DETECT_FLOWINT_TYPE_SET_READ 3 #define DETECT_FLOWINT_TYPE_SET 4 /** * \brief Registers a keyword-based, signature ordering function * * \param de_ctx Pointer to the detection engine context from which the * signatures have to be ordered. * \param FuncPtr Pointer to the signature ordering function. The prototype of * the signature ordering function should accept a pointer to a * SCSigSignatureWrapper as its argument and shouldn't return * anything */ static void SCSigRegisterSignatureOrderingFunc(DetectEngineCtx *de_ctx, int (*SWCompare)(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2)) { SCSigOrderFunc *curr = NULL; SCSigOrderFunc *prev = NULL; SCSigOrderFunc *temp = NULL; curr = de_ctx->sc_sig_order_funcs; prev = curr; while (curr != NULL) { prev = curr; if (curr->SWCompare == SWCompare) break; curr = curr->next; } if (curr != NULL) return; if ( (temp = SCMalloc(sizeof(SCSigOrderFunc))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCSigRegisterSignatureOrderingFunc. Exiting..."); exit(EXIT_FAILURE); } memset(temp, 0, sizeof(SCSigOrderFunc)); temp->SWCompare = SWCompare; if (prev == NULL) de_ctx->sc_sig_order_funcs = temp; else prev->next = temp; return; } /** * \brief Returns the flowbit type set for this signature. If more than one * flowbit has been set for the same rule, we return the flowbit type of * the maximum priority/value, where priority/value is maximum for the * ones that set the value and the lowest for ones that read the value. * If no flowbit has been set for the rule, we return 0, which indicates * the least value amongst flowbit types. * * \param sig Pointer to the Signature from which the flowbit value has to be * returned. * * \retval flowbits The flowbits type for this signature if it is set; if it is * not set, return 0 */ static inline int SCSigGetFlowbitsType(Signature *sig) { DetectFlowbitsData *fb = NULL; int flowbits_user_type = DETECT_FLOWBITS_NOT_USED; int read = 0; int write = 0; SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWBITS) { fb = (DetectFlowbitsData *)sm->ctx; if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET || fb->cmd == DETECT_FLOWBITS_CMD_ISSET) { read++; } else { #ifdef DEBUG BUG_ON(1); #endif } } sm = sm->next; } sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWBITS) { fb = (DetectFlowbitsData *)sm->ctx; if (fb->cmd == DETECT_FLOWBITS_CMD_SET || fb->cmd == DETECT_FLOWBITS_CMD_UNSET || fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) { write++; } else { #ifdef DEBUG BUG_ON(1); #endif } } sm = sm->next; } if (read > 0 && write == 0) { flowbits_user_type = DETECT_FLOWBITS_TYPE_READ; } else if (read == 0 && write > 0) { flowbits_user_type = DETECT_FLOWBITS_TYPE_SET; } else if (read > 0 && write > 0) { flowbits_user_type = DETECT_FLOWBITS_TYPE_SET_READ; } SCLogDebug("Sig %s typeval %d", sig->msg, flowbits_user_type); return flowbits_user_type; } static inline int SCSigGetFlowintType(Signature *sig) { DetectFlowintData *fi = NULL; int flowint_user_type = DETECT_FLOWINT_NOT_USED; int read = 0; int write = 0; SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWINT) { fi = (DetectFlowintData *)sm->ctx; if (fi->modifier == FLOWINT_MODIFIER_LT || fi->modifier == FLOWINT_MODIFIER_LE || fi->modifier == FLOWINT_MODIFIER_EQ || fi->modifier == FLOWINT_MODIFIER_NE || fi->modifier == FLOWINT_MODIFIER_GE || fi->modifier == FLOWINT_MODIFIER_GT || fi->modifier == FLOWINT_MODIFIER_ISSET) { read++; } else { #ifdef DEBUG BUG_ON(1); #endif } } sm = sm->next; } sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWINT) { fi = (DetectFlowintData *)sm->ctx; if (fi->modifier == FLOWINT_MODIFIER_SET || fi->modifier == FLOWINT_MODIFIER_ADD || fi->modifier == FLOWINT_MODIFIER_SUB) { write++; } else { #ifdef DEBUG BUG_ON(1); #endif } } sm = sm->next; } if (read > 0 && write == 0) { flowint_user_type = DETECT_FLOWINT_TYPE_READ; } else if (read == 0 && write > 0) { flowint_user_type = DETECT_FLOWINT_TYPE_SET; } else if (read > 0 && write > 0) { flowint_user_type = DETECT_FLOWINT_TYPE_SET_READ; } SCLogDebug("Sig %s typeval %d", sig->msg, flowint_user_type); return flowint_user_type; } /** * \brief Returns whether the flowvar set for this rule, sets the flowvar or * reads the flowvar. If the rule sets the flowvar the function returns * DETECT_FLOWVAR_TYPE_SET(3), if it reads the flowvar the function * returns DETECT_FLOWVAR_TYPE_READ(2), and if flowvar is not used in this * rule the function returns DETECT_FLOWVAR_NOT_USED(1) * * \param sig Pointer to the Signature from which the flowvar type has to be * returned. * * \retval type DETECT_FLOWVAR_TYPE_SET(3) if the rule sets the flowvar, * DETECT_FLOWVAR_TYPE_READ(2) if it reads, and * DETECT_FLOWVAR_NOT_USED(1) if flowvar is not used. */ static inline int SCSigGetFlowvarType(Signature *sig) { DetectPcreData *pd = NULL; int type = DETECT_FLOWVAR_NOT_USED; int read = 0; int write = 0; SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { pd = (DetectPcreData *)sm->ctx; if (sm->type == DETECT_PCRE && (pd->flags & DETECT_PCRE_CAPTURE_FLOW)) { write++; } sm = sm->next; } sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; pd = NULL; while (sm != NULL) { if (sm->type == DETECT_FLOWVAR) { read++; } sm = sm->next; } if (read > 0 && write == 0) { type = DETECT_FLOWVAR_TYPE_READ; } else if (read == 0 && write > 0) { type = DETECT_FLOWVAR_TYPE_SET; } else if (read > 0 && write > 0) { type = DETECT_FLOWVAR_TYPE_SET_READ; } return type; } /** * \brief Returns whether the pktvar set for this rule, sets the flowvar or * reads the pktvar. If the rule sets the pktvar the function returns * DETECT_PKTVAR_TYPE_SET(3), if it reads the pktvar the function * returns DETECT_PKTVAR_TYPE_READ(2), and if pktvar is not used in this * rule the function returns DETECT_PKTVAR_NOT_USED(1) * * \param sig Pointer to the Signature from which the pktvar type has to be * returned. * * \retval type DETECT_PKTVAR_TYPE_SET(3) if the rule sets the flowvar, * DETECT_PKTVAR_TYPE_READ(2) if it reads, and * DETECT_PKTVAR_NOT_USED(1) if pktvar is not used. */ static inline int SCSigGetPktvarType(Signature *sig) { DetectPcreData *pd = NULL; int type = DETECT_PKTVAR_NOT_USED; int read = 0; int write = 0; SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { pd = (DetectPcreData *)sm->ctx; if (sm->type == DETECT_PCRE && (pd->flags & DETECT_PCRE_CAPTURE_PKT)) { write++; } sm = sm->next; } sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; pd = NULL; while (sm != NULL) { if (sm->type == DETECT_PKTVAR) { read++; } sm = sm->next; } if (read > 0 && write == 0) { type = DETECT_PKTVAR_TYPE_READ; } else if (read == 0 && write > 0) { type = DETECT_PKTVAR_TYPE_SET; } else if (read > 0 && write > 0) { type = DETECT_PKTVAR_TYPE_SET_READ; } return type; } /** * \brief Processes the flowbits data for this signature and caches it for * future use. This is needed to optimize the sig_ordering module. * * \param sw The sigwrapper/signature for which the flowbits data has to be * cached */ static inline void SCSigProcessUserDataForFlowbits(SCSigSignatureWrapper *sw) { *((int *)(sw->user[SC_RADIX_USER_DATA_FLOWBITS])) = SCSigGetFlowbitsType(sw->sig); return; } /** * \brief Processes the flowvar data for this signature and caches it for * future use. This is needed to optimize the sig_ordering module. * * \param sw The sigwrapper/signature for which the flowvar data has to be * cached */ static inline void SCSigProcessUserDataForFlowvar(SCSigSignatureWrapper *sw) { *((int *)(sw->user[SC_RADIX_USER_DATA_FLOWVAR])) = SCSigGetFlowvarType(sw->sig); return; } static inline void SCSigProcessUserDataForFlowint(SCSigSignatureWrapper *sw) { *((int *)(sw->user[SC_RADIX_USER_DATA_FLOWINT])) = SCSigGetFlowintType(sw->sig); return; } /** * \brief Processes the pktvar data for this signature and caches it for * future use. This is needed to optimize the sig_ordering module. * * \param sw The sigwrapper/signature for which the pktvar data has to be * cached */ static inline void SCSigProcessUserDataForPktvar(SCSigSignatureWrapper *sw) { *((int *)(sw->user[SC_RADIX_USER_DATA_PKTVAR])) = SCSigGetPktvarType(sw->sig); return; } static void SCSigOrder(DetectEngineCtx *de_ctx, SCSigSignatureWrapper *sw, int (*SWCompare)(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2)) { SCSigSignatureWrapper *min = NULL; SCSigSignatureWrapper *max = NULL; SCSigSignatureWrapper *prev = NULL; if (sw == NULL) return; if (de_ctx->sc_sig_sig_wrapper == NULL) { de_ctx->sc_sig_sig_wrapper = sw; sw->min = NULL; sw->max = NULL; return; } min = sw->min; max = sw->max; if (min == NULL) min = de_ctx->sc_sig_sig_wrapper; else min = min->next; while (min != max) { prev = min; /* the sorting logic */ if (SWCompare(sw, min) <= 0) { min = min->next; continue; } if (min->prev == sw) break; if (sw->next != NULL) sw->next->prev = sw->prev; if (sw->prev != NULL) sw->prev->next = sw->next; if (de_ctx->sc_sig_sig_wrapper == sw) de_ctx->sc_sig_sig_wrapper = sw->next; sw->next = min; sw->prev = min->prev; if (min->prev != NULL) min->prev->next = sw; else de_ctx->sc_sig_sig_wrapper = sw; min->prev = sw; break; } if (min == max && prev != sw) { if (sw->next != NULL) { sw->next->prev = sw->prev; } if (sw->prev != NULL) { sw->prev->next = sw->next; } if (min == NULL) { if (prev != NULL) prev->next = sw; sw->prev = prev; sw->next = NULL; } else { sw->prev = min->prev; sw->next = min; if (min->prev != NULL) min->prev->next = sw; min->prev = sw; } } /* set the min signature for this keyword, for the next ordering function */ min = sw; while (min != NULL && min != sw->min) { if (SWCompare(sw, min) != 0) break; min = min->prev; } sw->min = min; /* set the max signature for this keyword + 1, for the next ordering func */ max = sw; while (max != NULL && max != sw->max) { if (SWCompare(max, sw) != 0) break; max = max->next; } sw->max = max; return; } /** * \brief Orders an incoming Signature based on its action * * \param de_ctx Pointer to the detection engine context from which the * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its action */ static int SCSigOrderByActionCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { return ActionOrderVal(sw2->sig->action) - ActionOrderVal(sw1->sig->action); } /** * \brief Orders an incoming Signature based on its flowbits type * * \param de_ctx Pointer to the detection engine context from which the * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its flowbits */ static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { return *((int *)sw1->user[SC_RADIX_USER_DATA_FLOWBITS]) - *((int *)sw2->user[SC_RADIX_USER_DATA_FLOWBITS]); } /** * \brief Orders an incoming Signature based on its flowvar type * * \param de_ctx Pointer to the detection engine context from which the * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its flowvar */ static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { return *((int *)sw1->user[SC_RADIX_USER_DATA_FLOWVAR]) - *((int *)sw2->user[SC_RADIX_USER_DATA_FLOWVAR]); } /** * \brief Orders an incoming Signature based on its pktvar type * * \param de_ctx Pointer to the detection engine context from which the * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its pktvar */ static int SCSigOrderByPktvarCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { return *((int *)sw1->user[SC_RADIX_USER_DATA_PKTVAR]) - *((int *)sw2->user[SC_RADIX_USER_DATA_PKTVAR]); } static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { return *((int *)sw1->user[SC_RADIX_USER_DATA_FLOWINT]) - *((int *)sw2->user[SC_RADIX_USER_DATA_FLOWINT]); } /** * \brief Orders an incoming Signature based on its priority type * * \param de_ctx Pointer to the detection engine context from which the * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its priority */ static int SCSigOrderByPriorityCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { return sw2->sig->prio - sw1->sig->prio; } /** * \brief Creates a Wrapper around the Signature * * \param Pointer to the Signature to be wrapped * * \retval sw Pointer to the wrapper that holds the signature */ static inline SCSigSignatureWrapper *SCSigAllocSignatureWrapper(Signature *sig) { SCSigSignatureWrapper *sw = NULL; int i = 0; if ( (sw = SCMalloc(sizeof(SCSigSignatureWrapper))) == NULL) return NULL; memset(sw, 0, sizeof(SCSigSignatureWrapper)); sw->sig = sig; if ( (sw->user = SCMalloc(SC_RADIX_USER_DATA_MAX * sizeof(int *))) == NULL) { SCFree(sw); return NULL; } memset(sw->user, 0, SC_RADIX_USER_DATA_MAX * sizeof(int *)); for (i = 0; i < SC_RADIX_USER_DATA_MAX; i++) { if ( (sw->user[i] = SCMalloc(sizeof(int))) == NULL) { SCFree(sw); return NULL; } memset(sw->user[i], 0, sizeof(int)); } /* Process data from the signature into a cache for further use by the * sig_ordering module */ SCSigProcessUserDataForFlowbits(sw); SCSigProcessUserDataForFlowvar(sw); SCSigProcessUserDataForFlowint(sw); SCSigProcessUserDataForPktvar(sw); return sw; } /** * \brief Orders the signatures * * \param de_ctx Pointer to the Detection Engine Context that holds the * signatures to be ordered */ void SCSigOrderSignatures(DetectEngineCtx *de_ctx) { SCSigOrderFunc *funcs = NULL; Signature *sig = NULL; SCSigSignatureWrapper *sigw = NULL; int i = 0; SCLogDebug("ordering signatures in memory"); sig = de_ctx->sig_list; while (sig != NULL) { i++; sigw = SCSigAllocSignatureWrapper(sig); funcs = de_ctx->sc_sig_order_funcs; while (funcs != NULL) { SCSigOrder(de_ctx, sigw, funcs->SWCompare); funcs = funcs->next; } sig = sig->next; } SCLogDebug("Total Signatures to be processed by the" "sigordering module: %d", i); /* Re-order it in the Detection Engine Context sig_list */ de_ctx->sig_list = NULL; sigw = de_ctx->sc_sig_sig_wrapper; i = 0; while (sigw != NULL) { i++; if (de_ctx->sig_list == NULL) { sigw->sig->next = NULL; de_ctx->sig_list = sigw->sig; sig = de_ctx->sig_list; sigw = sigw->next; continue; } sigw->sig->next = NULL; sig->next = sigw->sig; sig = sig->next; sigw = sigw->next; } SCLogDebug("total signatures reordered by the sigordering module: %d", i); return; } /** * \brief Lets you register the Signature ordering functions. The order in * which the functions are registered, show the priority. The first * function registered provides more priority than the function * registered after it. To add a new registration function, register * it by listing it in the correct position in the below sequence, * based on the priority you would want to offer to that keyword. * * \param de_ctx Pointer to the detection engine context from which the * signatures have to be ordered. */ void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *de_ctx) { SCLogDebug("registering signature ordering functions"); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowintCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); return; } /** * \brief De-registers all the signature ordering functions registered * * \param de_ctx Pointer to the detection engine context from which the * signatures were ordered. */ void SCSigSignatureOrderingModuleCleanup(DetectEngineCtx *de_ctx) { SCSigOrderFunc *funcs = NULL; SCSigSignatureWrapper *sigw = NULL; SCSigSignatureWrapper *prev = NULL; void *temp = NULL; uint8_t i; /* clean the memory alloted to the signature ordering funcs */ funcs = de_ctx->sc_sig_order_funcs; while (funcs != NULL) { temp = funcs; funcs = funcs->next; SCFree(temp); } de_ctx->sc_sig_order_funcs = NULL; /* clean the memory alloted to the signature wrappers */ sigw = de_ctx->sc_sig_sig_wrapper; while (sigw != NULL) { prev = sigw; sigw = sigw->next; for (i = 0; i < SC_RADIX_USER_DATA_MAX; i++) { if (prev->user[i] != NULL) { SCFree(prev->user[i]); } } SCFree(prev->user); SCFree(prev); } de_ctx->sc_sig_sig_wrapper = NULL; return; } /**********Unittests**********/ DetectEngineCtx *DetectEngineCtxInit(void); Signature *SigInit(DetectEngineCtx *, char *); void SigFree(Signature *); void DetectEngineCtxFree(DetectEngineCtx *); #ifdef UNITTESTS static int SCSigOrderingTest01(void) { SCSigOrderFunc *temp = NULL; int i = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); temp = de_ctx->sc_sig_order_funcs; while (temp != NULL) { i++; temp = temp->next; } DetectEngineCtxFree(de_ctx); return (i == 5); end: return 0; } static int SCSigOrderingTest02(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:1;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; flowvar:http_host,\"www.oisf.net\"; rev:4; priority:1; sid:4;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:1; sid:5;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; content:\"220\"; offset:10; depth:4; rev:4; priority:3; sid:6;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:7;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:8;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; rev:4; priority:3; flowbits:set,TEST.one; flowbits:noalert; sid:9;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:10;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:11;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:12;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; pktvar:http_host,\"www.oisf.net\"; priority:2; flowbits:isnotset,TEST.two; sid:13;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; flowbits:set,TEST.two; sid:14;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; /* pass */ result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 4); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 7); sig = sig->next; result &= (sig->id == 10); sig = sig->next; /* drops */ result &= (sig->id == 9); sig = sig->next; result &= (sig->id == 13); sig = sig->next; result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 3); sig = sig->next; /* alerts */ result &= (sig->id == 14); sig = sig->next; result &= (sig->id == 5); sig = sig->next; result &= (sig->id == 1); sig = sig->next; result &= (sig->id == 11); sig = sig->next; result &= (sig->id == 12); sig = sig->next; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } static int SCSigOrderingTest03(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:1;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; flowbits:unset,TEST.one; rev:4; priority:2; sid:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; flowbits:isset,TEST.one; rev:4; priority:1; sid:4;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; priority:2; sid:5;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; flowbits:isnotset,TEST.one; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; rev:4; sid:6;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; flowbits:unset,TEST.one; rev:4; priority:3; sid:7;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; flowbits:toggle,TEST.one; rev:4; priority:1; pktvar:http_host,\"www.oisf.net\"; sid:8;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; rev:4; flowbits:set,TEST.one; flowbits:noalert; pktvar:http_host,\"www.oisf.net\"; sid:9;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:10;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:11;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:12;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; flowbits:isnotset,TEST.one; sid:13;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; flowbits:set,TEST.one; sid:14;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; result &= (sig->id == 3); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 9); sig = sig->next; result &= (sig->id == 7); sig = sig->next; result &= (sig->id == 14); sig = sig->next; result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 4); sig = sig->next; result &= (sig->id == 13); sig = sig->next; result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 5); sig = sig->next; result &= (sig->id == 1); sig = sig->next; result &= (sig->id == 10); sig = sig->next; result &= (sig->id == 11); sig = sig->next; result &= (sig->id == 12); sig = sig->next; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } static int SCSigOrderingTest04(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:1;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; content:\"220\"; offset:10; rev:4; priority:3; sid:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; rev:4; priority:3; sid:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; rev:4; priority:3; flowvar:http_host,\"www.oisf.net\"; sid:4;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:5;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; pktvar:http_host,\"www.oisf.net\"; rev:4; priority:1; sid:6;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; flowvar:http_host,\"www.oisf.net\"; pktvar:http_host,\"www.oisf.net\"; priority:1; sid:7;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; flowvar:http_host,\"www.oisf.net\"; sid:8;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; flowvar:http_host,\"www.oisf.net\"; sid:9;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; /* flowvar set */ result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 3); sig = sig->next; result &= (sig->id == 4); sig = sig->next; result &= (sig->id == 7); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 9); sig = sig->next; /* pktvar */ result &= (sig->id == 5); sig = sig->next; result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 1); sig = sig->next; end: if (de_ctx) DetectEngineCtxFree(de_ctx); return result; } static int SCSigOrderingTest05(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:1;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; content:\"220\"; offset:10; rev:4; priority:3; sid:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; rev:4; priority:3; sid:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; rev:4; priority:3; pktvar:http_host,\"www.oisf.net\"; sid:4;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:5;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:6;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; pktvar:http_host,\"www.oisf.net\"; sid:7;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; pktvar:http_host,\"www.oisf.net\"; sid:8;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; //#ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } //#endif sig = de_ctx->sig_list; /* pktvar set */ result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 3); sig = sig->next; result &= (sig->id == 4); sig = sig->next; /* pktvar read */ result &= (sig->id == 7); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 1); sig = sig->next; result &= (sig->id == 5); sig = sig->next; result &= (sig->id == 6); sig = sig->next; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } static int SCSigOrderingTest06(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:1;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; rev:4; priority:2; sid:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; rev:4; priority:3; sid:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; rev:4; priority:2; sid:4;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:5;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:1; sid:6;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:7;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:8;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 4); sig = sig->next; result &= (sig->id == 5); sig = sig->next; result &= (sig->id == 7); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 1); sig = sig->next; result &= (sig->id == 3); sig = sig->next; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } static int SCSigOrderingTest07(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:1; rev:4;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:10; sid:2; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:10; depth:4; sid:3; rev:4; priority:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:10; depth:4; sid:4; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; sid:5; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering drop\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; sid:6; rev:4; priority:1;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering reject\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; sid:7; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; sid:8; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 4); sig = sig->next; result &= (sig->id == 5); sig = sig->next; result &= (sig->id == 7); sig = sig->next; result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 1); sig = sig->next; result &= (sig->id == 3); sig = sig->next; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Order with a different Action priority * (as specified from config) */ static int SCSigOrderingTest08(void) { #ifdef HAVE_LIBNET11 int result = 0; Signature *prevsig = NULL, *sig = NULL; extern uint8_t action_order_sigs[4]; /* Let's change the order. Default is pass, drop, reject, alert (pass has highest prio) */ action_order_sigs[0] = ACTION_REJECT; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_ALERT; action_order_sigs[3] = ACTION_PASS; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:1; rev:4;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:10; sid:2; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:10; depth:4; sid:3; rev:4; priority:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:10; depth:4; sid:4; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; sid:5; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "reject tcp any !21:902 -> any any (msg:\"Testing sigordering drop\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; sid:6; rev:4; priority:1;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering reject\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; sid:7; rev:4;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; sid:8; rev:4; priority:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 1); sig = sig->next; result &= (sig->id == 3); sig = sig->next; result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 4); sig = sig->next; result &= (sig->id == 5); sig = sig->next; result &= (sig->id == 7); sig = sig->next; end: /* Restore the default pre-order definition */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; #else return 1; #endif } /** * \test Order with a different Action priority * (as specified from config) */ static int SCSigOrderingTest09(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; extern uint8_t action_order_sigs[4]; /* Let's change the order. Default is pass, drop, reject, alert (pass has highest prio) */ action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_REJECT; action_order_sigs[2] = ACTION_ALERT; action_order_sigs[3] = ACTION_PASS; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:1;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:10; priority:2; sid:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:10; depth:4; priority:3; sid:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:10; depth:4; rev:4; priority:2; sid:4;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:5;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering drop\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:1; sid:6;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering reject\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:7;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:8;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 7); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 1); sig = sig->next; result &= (sig->id == 3); sig = sig->next; result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 4); sig = sig->next; result &= (sig->id == 5); sig = sig->next; end: /* Restore the default pre-order definition */ action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_REJECT; action_order_sigs[2] = ACTION_PASS; action_order_sigs[3] = ACTION_ALERT; if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Order with a different Action priority * (as specified from config) */ static int SCSigOrderingTest10(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; extern uint8_t action_order_sigs[4]; /* Let's change the order. Default is pass, drop, reject, alert (pass has highest prio) */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_ALERT; action_order_sigs[2] = ACTION_DROP; action_order_sigs[3] = ACTION_REJECT; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:1;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:10; rev:4; priority:2; sid:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:10; depth:4; rev:4; priority:3; sid:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:10; depth:4; rev:4; priority:2; sid:4;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "pass tcp any !21:902 -> any any (msg:\"Testing sigordering pass\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:5;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering drop\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:1; sid:6;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "drop tcp any !21:902 -> any any (msg:\"Testing sigordering reject\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:7;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering alert\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:8;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 4); sig = sig->next; result &= (sig->id == 5); sig = sig->next; result &= (sig->id == 8); sig = sig->next; result &= (sig->id == 1); sig = sig->next; result &= (sig->id == 3); sig = sig->next; result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 7); sig = sig->next; end: /* Restore the default pre-order definition */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } static int SCSigOrderingTest11(void) { int result = 0; Signature *prevsig = NULL, *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering set\"; flowbits:isnotset,myflow1; rev:4; sid:1;)"); if (sig == NULL) { goto end; } prevsig = sig; de_ctx->sig_list = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering toggle\"; flowbits:toggle,myflow2; rev:4; sid:2;)"); if (sig == NULL) { goto end; } prevsig->next = sig; prevsig = sig; sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"Testing sigordering unset\"; flowbits:isset, myflow1; flowbits:unset,myflow2; rev:4; priority:3; sid:3;)"); if (sig == NULL) { goto end; } prevsig->next = sig; SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); SCSigOrderSignatures(de_ctx); result = 1; sig = de_ctx->sig_list; #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; result &= (sig->id == 2); sig = sig->next; result &= (sig->id == 3); sig = sig->next; result &= (sig->id == 1); sig = sig->next; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } static int SCSigOrderingTest12(void) { Signature *sig = NULL; Packet *p = NULL; uint8_t buf[] = "test message"; int result = 0; Flow f; FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; f.alproto = ALPROTO_UNKNOWN; f.proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; char *sigs[2]; sigs[0] = "alert tcp any any -> any any (content:\"test\"; dsize:>0; flowbits:isset,one; flowbits:set,two; sid:1;)"; sigs[1] = "alert tcp any any -> any any (content:\"test\"; dsize:>0; flowbits:set,one; sid:2;)"; UTHAppendSigs(de_ctx, sigs, 2); sig = de_ctx->sig_list; if (sig == NULL) goto end; if (sig->next == NULL) goto end; if (sig->next->next != NULL) goto end; if (de_ctx->signum != 2) goto end; FlowInitConfig(FLOW_QUIET); p = UTHBuildPacket(buf, sizeof(buf), IPPROTO_TCP); if (p == NULL) { printf("Error building packet."); goto end; } p->flow = &f; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; UTHMatchPackets(de_ctx, &p, 1); uint32_t sids[2] = {1, 2}; uint32_t results[2] = {1, 1}; result = UTHCheckPacketMatchResults(p, sids, results, 2); end: if (p != NULL) SCFree(p); if (de_ctx != NULL) { SigCleanSignatures(de_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowShutdown(); return result; } /** \test Bug 1061 */ static int SCSigOrderingTest13(void) { int result = 0; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flowbits:isset,bit1; flowbits:set,bit2; flowbits:set,bit3; sid:6;)"); if (sig == NULL) { goto end; } sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flowbits:set,bit1; flowbits:set,bit2; sid:7;)"); if (sig == NULL) { goto end; } sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flowbits:isset,bit1; flowbits:isset,bit2; flowbits:isset,bit3; sid:5;)"); if (sig == NULL) { goto end; } SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); SCSigOrderSignatures(de_ctx); result = 1; #ifdef DEBUG sig = de_ctx->sig_list; while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } #endif sig = de_ctx->sig_list; result &= (sig->id == 7); sig = sig->next; result &= (sig->id == 6); sig = sig->next; result &= (sig->id == 5); sig = sig->next; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } #endif void SCSigRegisterSignatureOrderingTests(void) { #ifdef UNITTESTS UtRegisterTest("SCSigOrderingTest01", SCSigOrderingTest01, 1); UtRegisterTest("SCSigOrderingTest02", SCSigOrderingTest02, 1); UtRegisterTest("SCSigOrderingTest03", SCSigOrderingTest03, 1); UtRegisterTest("SCSigOrderingTest04", SCSigOrderingTest04, 1); UtRegisterTest("SCSigOrderingTest05", SCSigOrderingTest05, 1); UtRegisterTest("SCSigOrderingTest06", SCSigOrderingTest06, 1); UtRegisterTest("SCSigOrderingTest07", SCSigOrderingTest07, 1); UtRegisterTest("SCSigOrderingTest08", SCSigOrderingTest08, 1); UtRegisterTest("SCSigOrderingTest09", SCSigOrderingTest09, 1); UtRegisterTest("SCSigOrderingTest10", SCSigOrderingTest10, 1); UtRegisterTest("SCSigOrderingTest11", SCSigOrderingTest11, 1); UtRegisterTest("SCSigOrderingTest12", SCSigOrderingTest12, 1); UtRegisterTest("SCSigOrderingTest13", SCSigOrderingTest13, 1); #endif return; } suricata-1.4.7/src/detect-http-raw-uri.h0000644000000000000000000000163612253546156015015 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * */ #ifndef __DETECT_HTTP_URI_H__ #define __DETECT_HTTP_URI_H__ void DetectHttpRawUriRegister(void); #endif /* __DETECT_HTTP_URI_H__ */ suricata-1.4.7/src/respond-reject.h0000644000000000000000000000210612253546156014121 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author William Metcalf */ #ifndef __RESPOND_REJECT_H__ #define __RESPOND_REJECT_H__ #include "tm-threads.h" #define REJECT_DIR_SRC 0 #define REJECT_DIR_DST 1 void TmModuleRespondRejectRegister (void); TmEcode RespondRejectFunc(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); #endif /* __RESPOND_REJECT_H__ */ suricata-1.4.7/src/decode-gre.h0000644000000000000000000000441712253546156013202 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DECODE_GRE_H__ #define __DECODE_GRE_H__ #ifndef IPPROTO_GRE #define IPPROTO_GRE 47 #endif #include "decode.h" #include "threadvars.h" typedef struct GREHdr_ { uint8_t flags; /**< GRE packet flags */ uint8_t version; /**< GRE version */ uint16_t ether_type; /**< ether type of the encapsulated traffic */ } GREHdr; typedef struct GRESreHdr_ { uint16_t af; /**< Address family */ uint8_t sre_offset; uint8_t sre_length; uint8_t *routing; } GRESreHdr; #define GRE_VERSION_0 0x0000 #define GRE_VERSION_1 0x0001 #define GRE_HDR_LEN 4 #define GRE_CHKSUM_LEN 2 #define GRE_OFFSET_LEN 2 #define GRE_KEY_LEN 4 #define GRE_SEQ_LEN 4 #define GRE_SRE_HDR_LEN 4 #define GRE_PROTO_PPP 0x880b #define GRE_FLAG_ISSET_CHKSUM(r) (r->flags & 0x80) #define GRE_FLAG_ISSET_ROUTE(r) (r->flags & 0x40) #define GRE_FLAG_ISSET_KY(r) (r->flags & 0x20) #define GRE_FLAG_ISSET_SQ(r) (r->flags & 0x10) #define GRE_FLAG_ISSET_SSR(r) (r->flags & 0x08) #define GRE_FLAG_ISSET_RECUR(r) (r->flags & 0x07) #define GRE_GET_VERSION(r) (r->version & 0x07) #define GRE_GET_FLAGS(r) (r->version & 0xF8) #define GRE_GET_PROTO(r) ntohs(r->ether_type) #define GREV1_HDR_LEN 8 #define GREV1_ACK_LEN 4 #define GREV1_FLAG_ISSET_FLAGS(r) (r->version & 0x78) #define GREV1_FLAG_ISSET_ACK(r) (r->version & 0x80) void DecodeGRERegisterTests(void); #endif /* __DECODE_GRE_H__ */ suricata-1.4.7/src/decode-ppp.h0000644000000000000000000000624412253546156013224 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva Pinto */ #ifndef __DECODE_PPP_H__ #define __DECODE_PPP_H__ /** Point to Point Protocol RFC1331 - Supported tyes */ #define PPP_IP 0x0021 /* Internet Protocol */ #define PPP_IPV6 0x0057 /* Internet Protocol version 6 */ #define PPP_VJ_UCOMP 0x002f /* VJ uncompressed TCP/IP */ /** Unsupported PPP types (libpcap source reference) */ #define PPP_IPX 0x002b /* Novell IPX Protocol */ #define PPP_VJ_COMP 0x002d /* VJ compressed TCP/IP */ #define PPP_IPX 0x002b /* Novell IPX Protocol */ #define PPP_OSI 0x0023 /* OSI Network Layer */ #define PPP_NS 0x0025 /* Xerox NS IDP */ #define PPP_DECNET 0x0027 /* DECnet Phase IV */ #define PPP_APPLE 0x0029 /* Appletalk */ #define PPP_BRPDU 0x0031 /* Bridging PDU */ #define PPP_STII 0x0033 /* Stream Protocol (ST-II) */ #define PPP_VINES 0x0035 /* Banyan Vines */ #define PPP_HELLO 0x0201 /* 802.1d Hello Packets */ #define PPP_LUXCOM 0x0231 /* Luxcom */ #define PPP_SNS 0x0233 /* Sigma Network Systems */ #define PPP_MPLS_UCAST 0x0281 /* rfc 3032 */ #define PPP_MPLS_MCAST 0x0283 /* rfc 3022 */ #define PPP_IPCP 0x8021 /* IP Control Protocol */ #define PPP_OSICP 0x8023 /* OSI Network Layer Control Protocol */ #define PPP_NSCP 0x8025 /* Xerox NS IDP Control Protocol */ #define PPP_DECNETCP 0x8027 /* DECnet Control Protocol */ #define PPP_APPLECP 0x8029 /* Appletalk Control Protocol */ #define PPP_IPXCP 0x802b /* Novell IPX Control Protocol */ #define PPP_STIICP 0x8033 /* Strean Protocol Control Protocol */ #define PPP_VINESCP 0x8035 /* Banyan Vines Control Protocol */ #define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ #define PPP_MPLSCP 0x8281 /* rfc 3022 */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_LQM 0xc025 /* Link Quality Monitoring */ #define PPP_CHAP 0xc223 /* Challenge Handshake Authentication Protocol */ /** PPP Packet header */ typedef struct PPPHdr_ { uint8_t address; uint8_t control; uint16_t protocol; } PPPHdr; /** PPP Packet header length */ #define PPP_HEADER_LEN 4 void DecodePPPRegisterTests(void); #endif /* __DECODE_PPP_H__ */ suricata-1.4.7/src/detect-engine-hua.h0000644000000000000000000000232712253546156014470 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HUA_H__ #define __DETECT_ENGINE_HUA_H__ #include "app-layer-htp.h" int DetectEngineInspectHttpUA(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *, Flow *, HtpState *, uint8_t); void DetectEngineHttpUARegisterTests(void); #endif /* __DETECT_ENGINE_HUA_H__ */ suricata-1.4.7/src/runmode-erf-file.c0000644000000000000000000002042212253546156014331 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-erf-file.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" static const char *default_mode; const char *RunModeErfFileGetDefaultMode(void) { return default_mode; } void RunModeErfFileRegister(void) { default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_ERF_FILE, "single", "Single threaded ERF file mode", RunModeErfFileSingle); RunModeRegisterNewRunMode(RUNMODE_ERF_FILE, "autofp", "Multi threaded ERF file mode. Packets from " "each flow are assigned to a single detect thread", RunModeErfFileAutoFp); return; } int RunModeErfFileSingle(DetectEngineCtx *de_ctx) { char *file; SCEnter(); if (ConfGet("erf-file.file", &file) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed to get erf-file.file from config."); exit(EXIT_FAILURE); } RunModeInitialize(); TimeModeSetOffline(); /* Basically the same setup as PCAP files. */ ThreadVars *tv = TmThreadCreatePacketHandler("ErfFile", "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); if (tv == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName("ReceiveErfFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName failed for ReceiveErfFile\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, file); tm_module = TmModuleGetByName("DecodeErfFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName DecodeErfFile failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName StreamTcp failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); SetupOutputs(tv); if (TmThreadSpawn(tv) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } SCLogInfo("RunModeErfFileSingle initialised"); SCReturnInt(0); } int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); char tname[12]; char qname[12]; uint16_t cpu = 0; char queues[2048] = ""; RunModeInitialize(); /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); /* start with cpu 1 so that if we're creating an odd number of detect * threads we're not creating the most on CPU0. */ if (ncpus > 0) cpu = 1; /* always create at least one thread */ int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) thread_max = 1; int thread; for (thread = 0; thread < thread_max; thread++) { if (strlen(queues) > 0) strlcat(queues, ",", sizeof(queues)); snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); strlcat(queues, qname, sizeof(queues)); } SCLogDebug("queues %s", queues); char *file = NULL; if (ConfGet("erf-file.file", &file) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving erf-file.file from config"); exit(EXIT_FAILURE); } TimeModeSetOffline(); /* create the threads */ ThreadVars *tv = TmThreadCreatePacketHandler("ReceiveErfFile", "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName("ReceiveErfFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName failed for ReceiveErfFile\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, file); tm_module = TmModuleGetByName("DecodeErfFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName DecodeErfFile failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); if (threading_set_cpu_affinity) { TmThreadSetCPUAffinity(tv, 0); if (ncpus > 1) TmThreadSetThreadPriority(tv, PRIO_MEDIUM); } if (TmThreadSpawn(tv) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } for (thread = 0; thread < thread_max; thread++) { snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); SCLogDebug("tname %s, qname %s", tname, qname); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { printf("ERROR: Can't allocate thread name\n"); exit(EXIT_FAILURE); } SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name, qname, "flow", "packetpool", "packetpool", "varslot"); if (tv_detect_ncpu == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName StreamTcp failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); if (threading_set_cpu_affinity) { TmThreadSetCPUAffinity(tv_detect_ncpu, (int)cpu); /* If we have more than one core/cpu, the first Detect thread * (at cpu 0) will have less priority (higher 'nice' value) * In this case we will set the thread priority to +10 (default is 0) */ if (cpu == 0 && ncpus > 1) { TmThreadSetThreadPriority(tv_detect_ncpu, PRIO_LOW); } else if (ncpus > 1) { TmThreadSetThreadPriority(tv_detect_ncpu, PRIO_MEDIUM); } } char *thread_group_name = SCStrdup("Detect"); if (unlikely(thread_group_name == NULL)) { printf("Error allocating memory\n"); exit(EXIT_FAILURE); } tv_detect_ncpu->thread_group_name = thread_group_name; /* add outputs as well */ SetupOutputs(tv_detect_ncpu); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } if ((cpu + 1) == ncpus) cpu = 0; else cpu++; } SCLogInfo("RunModeErfFileAutoFp initialised"); SCReturnInt(0); } suricata-1.4.7/src/util-radix-tree.c0000644000000000000000000042717212253546156014225 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implementation of radix trees */ #include "suricata-common.h" #include "util-radix-tree.h" #include "util-debug.h" #include "util-error.h" #include "util-unittest.h" #include "util-memcmp.h" /** * \brief Validates an IPV4 address and returns the network endian arranged * version of the IPV4 address * * \param addr Pointer to a character string containing an IPV4 address. A * valid IPV4 address is a character string containing a dotted * format of "ddd.ddd.ddd.ddd" * * \retval Pointer to an in_addr instance containing the network endian format * of the IPV4 address * \retval NULL if the IPV4 address is invalid */ struct in_addr *SCRadixValidateIPV4Address(const char *addr_str) { struct in_addr *addr = NULL; if ( (addr = SCMalloc(sizeof(struct in_addr))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixValidateIPV4Address. Exiting..."); exit(EXIT_FAILURE); } if (inet_pton(AF_INET, addr_str, addr) <= 0) { SCFree(addr); return NULL; } return addr; } /** * \brief Validates an IPV6 address and returns the network endian arranged * version of the IPV6 addresss * * \param addr Pointer to a character string containing an IPV6 address * * \retval Pointer to a in6_addr instance containing the network endian format * of the IPV6 address * \retval NULL if the IPV6 address is invalid */ struct in6_addr *SCRadixValidateIPV6Address(const char *addr_str) { struct in6_addr *addr = NULL; if ( (addr = SCMalloc(sizeof(struct in6_addr))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixValidateIPV6Address. Exiting..."); exit(EXIT_FAILURE); } if (inet_pton(AF_INET6, addr_str, addr) <= 0) { SCFree(addr); return NULL; } return addr; } /** * \brief Chops an ip address against a netmask. For example an ip address * 192.168.240.1 would be chopped to 192.168.224.0 against a netmask * value of 19. * * \param stream Pointer the ip address that has to be chopped. * \param netmask The netmask value (cidr) to which the ip address has to be chopped. */ void SCRadixChopIPAddressAgainstNetmask(uint8_t *stream, uint8_t netmask, uint16_t key_bitlen) { int mask = 0; int i = 0; int bytes = key_bitlen / 8; for (i = 0; i < bytes; i++) { mask = -1; if ( ((i + 1) * 8) > netmask) { if ( ((i + 1) * 8 - netmask) < 8) mask = -1 << ((i + 1) * 8 - netmask); else mask = 0; } stream[i] &= mask; } return; } /** * \brief Allocates and returns a new instance of SCRadixUserData. * * \param netmask The netmask entry (cidr) that has to be made in the new * SCRadixUserData instance * \param user The user data that has to be set for the above * netmask in the newly created SCRadixUserData instance. * * \retval user_data Pointer to a new instance of SCRadixUserData. */ static SCRadixUserData *SCRadixAllocSCRadixUserData(uint8_t netmask, void *user) { SCRadixUserData *user_data = SCMalloc(sizeof(SCRadixUserData)); if (unlikely(user_data == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); return NULL; } memset(user_data, 0, sizeof(SCRadixUserData)); user_data->netmask = netmask; user_data->user = user; return user_data; } /** * \brief Deallocates an instance of SCRadixUserData. * * \param user_data Pointer to the instance of SCRadixUserData that has to be * freed. */ static void SCRadixDeAllocSCRadixUserData(SCRadixUserData *user_data) { SCFree(user_data); return; } /** * \brief Appends a user_data instance(SCRadixUserData) to a * user_data(SCRadixUserData) list. We add the new entry in descending * order with respect to the netmask contained in the SCRadixUserData. * * \param new Pointer to the SCRadixUserData to be added to the list. * \param list Pointer to the SCRadixUserData list head, to which "new" has to * be appended. */ static void SCRadixAppendToSCRadixUserDataList(SCRadixUserData *new, SCRadixUserData **list) { SCRadixUserData *temp = NULL; SCRadixUserData *prev = NULL; if (new == NULL || list == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "new or list supplied as NULL"); exit(EXIT_FAILURE); } /* add to the list in descending order. The reason we do this is for * optimizing key retrieval for a ip key under a netblock */ prev = temp = *list; while (temp != NULL) { if (new->netmask > temp->netmask) break; prev = temp; temp = temp->next; } if (temp == *list) { new->next = *list; *list = new; } else { new->next = prev->next; prev->next = new; } return; } /** * \brief Creates a new Prefix for a key. Used internally by the API. * * \param key_stream Data that has to be wrapped in a SCRadixPrefix instance to * be processed for insertion/lookup/removal of a node by the * radix tree * \param key_bitlen The bitlen of the the above stream. For example if the * stream holds the ipv4 address(4 bytes), bitlen would be 32 * \param user Pointer to the user data that has to be associated with * this key * * \retval prefix The newly created prefix instance on success; NULL on failure */ static SCRadixPrefix *SCRadixCreatePrefix(uint8_t *key_stream, uint16_t key_bitlen, void *user, uint8_t netmask) { SCRadixPrefix *prefix = NULL; if ((key_bitlen % 8 != 0)) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid argument bitlen - %d", key_bitlen); return NULL; } if (key_stream == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Argument \"stream\" NULL"); return NULL; } if ( (prefix = SCMalloc(sizeof(SCRadixPrefix))) == NULL) goto error; memset(prefix, 0, sizeof(SCRadixPrefix)); if ( (prefix->stream = SCMalloc(key_bitlen / 8)) == NULL) goto error; memset(prefix->stream, 0, key_bitlen / 8); memcpy(prefix->stream, key_stream, key_bitlen / 8); prefix->bitlen = key_bitlen; prefix->user_data = SCRadixAllocSCRadixUserData(netmask, user); if (prefix->user_data == NULL) { goto error; } return prefix; error: if (prefix != NULL) { if (prefix->stream != NULL) { SCFree(prefix->stream); } SCFree(prefix); } return NULL; } /** * \brief Adds a netmask and its user_data for a particular prefix stream. * * \param prefix The prefix stream to which the netmask and its corresponding * user data has to be added. * \param netmask The netmask value (cidr) that has to be added to the prefix. * \param user The pointer to the user data corresponding to the above * netmask. */ static void SCRadixAddNetmaskUserDataToPrefix(SCRadixPrefix *prefix, uint8_t netmask, void *user) { if (prefix == NULL || user == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "prefix or user NULL"); exit(EXIT_FAILURE); } SCRadixAppendToSCRadixUserDataList(SCRadixAllocSCRadixUserData(netmask, user), &prefix->user_data); return; } /** * \brief Removes a particular user_data corresponding to a particular netmask * entry, from a prefix. * * \param prefix Pointer to the prefix from which the user_data/netmask entry * has to be removed. * \param netmask The netmask value (cidr) whose user_data has to be deleted. */ static void SCRadixRemoveNetmaskUserDataFromPrefix(SCRadixPrefix *prefix, uint8_t netmask) { SCRadixUserData *temp = NULL, *prev = NULL; if (prefix == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "prefix NULL"); exit(EXIT_FAILURE); } prev = temp = prefix->user_data; while (temp != NULL) { if (temp->netmask == netmask) { if (temp == prefix->user_data) prefix->user_data = temp->next; else prev->next = temp->next; SCRadixDeAllocSCRadixUserData(temp); break; } prev = temp; temp = temp->next; } return; } /** * \brief Indicates if prefix contains an entry for an ip with a specific netmask. * * \param prefix Pointer to the ip prefix that is being checked. * \param netmask The netmask value (cidr) that has to be checked for * presence in the prefix. * * \retval 1 On match. * \retval 0 On no match. */ static int SCRadixPrefixContainNetmask(SCRadixPrefix *prefix, uint8_t netmask) { SCRadixUserData *user_data = NULL; if (prefix == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "prefix is NULL"); goto no_match; } user_data = prefix->user_data; while (user_data != NULL) { if (user_data->netmask == netmask) return 1; user_data = user_data->next; } no_match: return 0; } /** * \brief Returns the total netmask count for this prefix. * * \param prefix Pointer to the prefix * * \retval count The total netmask count for this prefix. */ static int SCRadixPrefixNetmaskCount(SCRadixPrefix *prefix) { SCRadixUserData *user_data = NULL; uint32_t count = 0; if (prefix == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "prefix is NULL"); return 0; } user_data = prefix->user_data; while (user_data != NULL) { count++; user_data = user_data->next; } return count; } /** * \brief Indicates if prefix contains an entry for an ip with a specific netmask * and if it does, it sets the user data field * SCRadixPrefix->user_data_result to the netmask user_data entry. * * \param prefix Pointer to the ip prefix that is being checked. * \param netmask The netmask value for which we will have to return the user_data * \param exact_match Bool flag which indicates if we should check if the prefix * holds proper netblock(< 32 for ipv4 and < 128 for ipv6) or not. * * \retval 1 On match. * \retval 0 On no match. */ static int SCRadixPrefixContainNetmaskAndSetUserData(SCRadixPrefix *prefix, uint16_t netmask, int exact_match) { SCRadixUserData *user_data = NULL; if (prefix == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "prefix is NULL"); goto no_match; } user_data = prefix->user_data; /* Check if we have a match for an exact ip. An exact ip as in not a proper * netblock, i.e. an ip with a netmask of 32(ipv4) or 128(ipv6) */ if (exact_match) { if (user_data->netmask == netmask) { prefix->user_data_result = user_data->user; return 1; } else { goto no_match; } } /* Check for the user_data entry for this netmask_value */ while (user_data != NULL) { if (user_data->netmask == netmask) { prefix->user_data_result = user_data->user; return 1; } user_data = user_data->next; } no_match: return 0; } /** * \brief Frees a SCRadixPrefix instance * * \param prefix Pointer to a prefix instance * \param tree Pointer to the Radix tree to which this prefix belongs */ static void SCRadixReleasePrefix(SCRadixPrefix *prefix, SCRadixTree *tree) { SCRadixUserData *user_data_temp1 = NULL; SCRadixUserData *user_data_temp2 = NULL; if (prefix != NULL) { if (prefix->stream != NULL) SCFree(prefix->stream); user_data_temp1 = prefix->user_data; if (tree->Free != NULL) { while (user_data_temp1 != NULL) { user_data_temp2 = user_data_temp1; user_data_temp1 = user_data_temp1->next; tree->Free(user_data_temp2->user); SCRadixDeAllocSCRadixUserData(user_data_temp2); } } else if (user_data_temp1 != NULL) { SCFree(user_data_temp1); } SCFree(prefix); } return; } /** * \brief Creates a new node for the Radix tree * * \retval node The newly created node for the radix tree */ static inline SCRadixNode *SCRadixCreateNode() { SCRadixNode *node = NULL; if ( (node = SCMalloc(sizeof(SCRadixNode))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixCreateNode. Mem not allocated..."); return NULL; } memset(node, 0, sizeof(SCRadixNode)); return node; } /** * \brief Frees a Radix tree node * * \param node Pointer to a Radix tree node * \param tree Pointer to the Radix tree to which this node belongs */ static void SCRadixReleaseNode(SCRadixNode *node, SCRadixTree *tree) { if (node != NULL) { SCRadixReleasePrefix(node->prefix, tree); if (node->netmasks != NULL) SCFree(node->netmasks); SCFree(node); } return; } /** * \brief Creates a new Radix tree * * \param Free Function pointer supplied by the user to be used by the Radix * cleanup API to free the user suppplied data * * \retval tree The newly created radix tree on success * * \initonly (all radix trees should be created at init) */ SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void*), void (*PrintData)(void*)) { SCRadixTree *tree = NULL; if ( (tree = SCMalloc(sizeof(SCRadixTree))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixCreateRadixTree. Exiting..."); exit(EXIT_FAILURE); } memset(tree, 0, sizeof(SCRadixTree)); tree->Free = Free; tree->PrintData = PrintData; return tree; } /** * \brief Internal helper function used by SCRadixReleaseRadixTree to free a * subtree * * \param node Pointer to the root of the subtree that has to be freed * \param tree Pointer to the Radix tree to which this subtree belongs */ static void SCRadixReleaseRadixSubtree(SCRadixNode *node, SCRadixTree *tree) { if (node != NULL) { SCRadixReleaseRadixSubtree(node->left, tree); SCRadixReleaseRadixSubtree(node->right, tree); SCRadixReleaseNode(node, tree); } return; } /** * \brief Frees a Radix tree and all its nodes * * \param tree Pointer to the Radix tree that has to be freed */ void SCRadixReleaseRadixTree(SCRadixTree *tree) { if (tree == NULL) return; SCRadixReleaseRadixSubtree(tree->head, tree); tree->head = NULL; return; } /** * \brief Adds a key to the Radix tree. Used internally by the API. * * \param key_stream Data that has to added to the Radix tree * \param key_bitlen The bitlen of the the above stream. For example if the * stream is the string "abcd", the bitlen would be 32. If * the stream is an IPV6 address bitlen would be 128 * \param tree Pointer to the Radix tree * \param user Pointer to the user data that has to be associated with * this key * \param netmask The netmask (cidr) if we are adding an IP netblock; 255 * if we are not adding an IP netblock * * \retval node Pointer to the newly created node */ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree, void *user, uint8_t netmask) { SCRadixNode *node = NULL; SCRadixNode *new_node = NULL; SCRadixNode *parent = NULL; SCRadixNode *inter_node = NULL; SCRadixNode *bottom_node = NULL; SCRadixPrefix *prefix = NULL; uint8_t *stream = NULL; uint8_t bitlen = 0; int check_bit = 0; int differ_bit = 0; int i = 0; int j = 0; int temp = 0; if (tree == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Argument \"tree\" NULL"); return NULL; } /* chop the ip address against a netmask */ SCRadixChopIPAddressAgainstNetmask(key_stream, netmask, key_bitlen); if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, netmask)) == NULL) { SCLogError(SC_ERR_RADIX_TREE_GENERIC, "Error creating prefix"); return NULL; } /* the very first element in the radix tree */ if (tree->head == NULL) { node = SCRadixCreateNode(); if (node == NULL) return NULL; node->prefix = prefix; node->bit = prefix->bitlen; tree->head = node; if (netmask == 255 || (netmask == 32 && key_bitlen == 32) || (netmask == 128 && key_bitlen == 128)) return node; /* if we have reached here, we are actually having a proper netblock in * our hand(i.e. < 32 for ipv4 and < 128 for ipv6). Add the netmask for * this node. The reason we add netmasks other than 32 and 128, is * because we need those netmasks in case of searches for ips contained * in netblocks. If the netmask is 32 or 128, either ways we will be * having an exact match for that ip value. If it is not, we start * chopping the incoming search ip key using the netmask values added * into the tree and then verify for a match */ node->netmask_cnt++; if ( (node->netmasks = SCRealloc(node->netmasks, (node->netmask_cnt * sizeof(uint8_t)))) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Fatal error encountered in SCRadixAddKey. Mem not allocated"); return NULL; } node->netmasks[0] = netmask; return node; } node = tree->head; stream = prefix->stream; bitlen = prefix->bitlen; /* we walk down the tree only when we satisfy 2 conditions. The first one * being the incoming prefix is shorter than the differ bit of the current * node. In case we fail in this aspect, we walk down to the tree, till we * arrive at a node that ends in a prefix */ while (node->bit < bitlen || node->prefix == NULL) { /* if the bitlen isn't long enough to handle the bit test, we just walk * down along one of the paths, since either paths should end up with a * node that has a common prefix whose differ bit is greater than the * bitlen of the incoming prefix */ if (bitlen < node->bit) { if (node->right == NULL) break; node = node->right; } else { if (SC_RADIX_BITTEST(stream[node->bit >> 3], (0x80 >> (node->bit % 8))) ) { if (node->right == NULL) break; node = node->right; } else { if (node->left == NULL) break; node = node->left; } } } /* we need to keep a reference to the bottom-most node, that actually holds * the prefix */ bottom_node = node; /* get the first bit position where the ips differ */ check_bit = (node->bit < bitlen)? node->bit: bitlen; for (i = 0; (i * 8) < check_bit; i++) { if ((temp = (stream[i] ^ bottom_node->prefix->stream[i])) == 0) { differ_bit = (i + 1) * 8; continue; } /* find out the position where the first bit differs. This method is * faster, but at the cost of being larger. But with larger caches * these days we don't have to worry about cache misses */ temp = temp * 2; if (temp >= 256) j = 0; else if (temp >= 128) j = 1; else if (temp >= 64) j = 2; else if (temp >= 32) j = 3; else if (temp >= 16) j = 4; else if (temp >= 8) j = 5; else if (temp >= 4) j = 6; else if (temp >= 2) j = 7; differ_bit = i * 8 + j; break; } if (check_bit < differ_bit) differ_bit = check_bit; /* walk up the tree till we find the position, to fit our new node in */ parent = node->parent; while (parent && differ_bit <= parent->bit) { node = parent; parent = node->parent; } /* We already have the node in the tree with the same differing bit pstn */ if (differ_bit == bitlen && node->bit == bitlen) { if (node->prefix != NULL) { /* Check if we already have this netmask entry covered by this prefix */ if (SCRadixPrefixContainNetmask(node->prefix, netmask)) { /* Basically we already have this stream prefix, as well as the * netblock entry for this. A perfect duplicate. */ SCLogDebug("Duplicate entry for this ip address/netblock"); } else { /* Basically we already have this stream prefix, but we don't * have an entry for this particular netmask value for this * prefix. For example, we have an entry for 192.168.0.0 and * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */ SCRadixAddNetmaskUserDataToPrefix(node->prefix, netmask, user); /* if we are adding a netmask of 32(for ipv4) or 128(for ipv6) * it indicates we are adding an exact host ip into the radix * tree, in which case we don't need to add the netmask value * into the tree */ if (netmask == 255 || (netmask == 32 && bitlen == 32) || (netmask == 128 && bitlen == 128)) return node; /* looks like we have a netmask which is != 32 or 128, in which * case we walk up the tree to insert this netmask value in the * correct node */ parent = node->parent; while (parent != NULL && netmask < (parent->bit + 1)) { node = parent; parent = parent->parent; } node->netmask_cnt++; new_node = node; if ( (node->netmasks = SCRealloc(node->netmasks, (node->netmask_cnt * sizeof(uint8_t)))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixAddKey. Mem not allocated..."); return NULL; } if (node->netmask_cnt == 1) { node->netmasks[0] = netmask; return new_node; } node->netmasks[node->netmask_cnt - 1] = netmask; for (i = node->netmask_cnt - 2; i >= 0; i--) { if (netmask < node->netmasks[i]) { node->netmasks[i + 1] = netmask; break; } node->netmasks[i + 1] = node->netmasks[i]; node->netmasks[i] = netmask; } } } else { node->prefix = SCRadixCreatePrefix(prefix->stream, prefix->bitlen, user, 255); } return node; } /* create the leaf node for the new key */ new_node = SCRadixCreateNode(); new_node->prefix = prefix; new_node->bit = prefix->bitlen; /* indicates that we have got a key that has length that is already covered * by a prefix of some other key in the tree. We create a new intermediate * node with a single child and stick it in. We need the if only in the * case of variable length keys */ if (differ_bit == bitlen) { if (SC_RADIX_BITTEST(bottom_node->prefix->stream[differ_bit >> 3], (0x80 >> (differ_bit % 8))) ) { new_node->right = node; } else { new_node->left = node; } new_node->parent = node->parent; if (node->parent == NULL) tree->head = new_node; else if (node->parent->right == node) node->parent->right = new_node; else node->parent->left = new_node; node->parent = new_node; /* stick our new_node into the tree. Create a node that holds the * differing bit position and break the branch. Also handle the * tranfer of netmasks between node and inter_node(explained in more * detail below) */ } else { inter_node = SCRadixCreateNode(); inter_node->prefix = NULL; inter_node->bit = differ_bit; inter_node->parent = node->parent; if (node->netmasks != NULL) { for (i = 0; i < node->netmask_cnt; i++) { if (node->netmasks[i] < differ_bit + 1) break; } if ( (inter_node->netmasks = SCMalloc((node->netmask_cnt - i) * sizeof(uint8_t))) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Fatal error encountered in SCRadixAddKey. Mem not allocated..."); return NULL; } for (j = 0; j < (node->netmask_cnt - i); j++) inter_node->netmasks[j] = node->netmasks[i + j]; inter_node->netmask_cnt = (node->netmask_cnt - i); node->netmask_cnt = i; if (node->netmask_cnt == 0) { SCFree(node->netmasks); node->netmasks = NULL; } } if (SC_RADIX_BITTEST(stream[differ_bit >> 3], (0x80 >> (differ_bit % 8))) ) { inter_node->left = node; inter_node->right = new_node; } else { inter_node->left = new_node; inter_node->right = node; } new_node->parent = inter_node; if (node->parent == NULL) tree->head = inter_node; else if (node->parent->right == node) node->parent->right = inter_node; else node->parent->left = inter_node; node->parent = inter_node; } /* insert the netmask into the tree */ if (netmask != 255 && (netmask != 32 || (netmask == 32 && bitlen != 32)) && netmask != 128) { node = new_node; parent = new_node->parent; while (parent != NULL && netmask < (parent->bit + 1)) { node = parent; parent = parent->parent; } node->netmask_cnt++; if ( (node->netmasks = SCRealloc(node->netmasks, (node->netmask_cnt * sizeof(uint8_t)))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixAddKey. Exiting..."); exit(EXIT_FAILURE); } if (node->netmask_cnt == 1) { node->netmasks[0] = netmask; return new_node; } node->netmasks[node->netmask_cnt - 1] = netmask; for (i = node->netmask_cnt - 2; i >= 0; i--) { if (netmask < node->netmasks[i]) { node->netmasks[i + 1] = netmask; break; } node->netmasks[i + 1] = node->netmasks[i]; node->netmasks[i] = netmask; } } return new_node; } /** * \brief Adds a new generic key to the Radix tree * * \param key_stream Data that has to be added to the Radix tree * \param key_bitlen The bitlen of the the above stream. For example if the * stream is the string "abcd", the bitlen would be 32 * \param tree Pointer to the Radix tree * \param user Pointer to the user data that has to be associated with the * key * * \retval node Pointer to the newly created node */ SCRadixNode *SCRadixAddKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree, void *user) { SCRadixNode *node = SCRadixAddKey(key_stream, key_bitlen, tree, user, 255); return node; } /** * \brief Adds a new IPV4 address to the Radix tree * * \param key_stream Data that has to be added to the Radix tree. In this case * a pointer to an IPV4 address * \param tree Pointer to the Radix tree * \param user Pointer to the user data that has to be associated with the * key * * \retval node Pointer to the newly created node */ SCRadixNode *SCRadixAddKeyIPV4(uint8_t *key_stream, SCRadixTree *tree, void *user) { SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, 32); return node; } /** * \brief Adds a new IPV6 address to the Radix tree * * \param key_stream Data that has to be added to the Radix tree. In this case * the pointer to an IPV6 address * \param tree Pointer to the Radix tree * \param user Pointer to the user data that has to be associated with the * key * * \retval node Pointer to the newly created node */ SCRadixNode *SCRadixAddKeyIPV6(uint8_t *key_stream, SCRadixTree *tree, void *user) { SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, 128); return node; } /** * \brief Adds a new IPV4 netblock to the Radix tree * * \param key_stream Data that has to be added to the Radix tree. In this case * a pointer to an IPV4 netblock * \param tree Pointer to the Radix tree * \param user Pointer to the user data that has to be associated with the * key * \param netmask The netmask (cidr) if we are adding a netblock * * \retval node Pointer to the newly created node */ SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, void *user, uint8_t netmask) { SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, netmask); return node; } /** * \brief Adds a new IPV6 netblock to the Radix tree * * \param key_stream Data that has to be added to the Radix tree. In this case * a pointer to an IPV6 netblock * \param tree Pointer to the Radix tree * \param user Pointer to the user data that has to be associated with the * key * \param netmask The netmask (cidr) if we are adding a netblock * * \retval node Pointer to the newly created node */ SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, void *user, uint8_t netmask) { SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, netmask); return node; } /** * \brief Adds a new IPV4/netblock to the Radix tree from a string * * \param str IPV4 string with optional /cidr netmask * \param tree Pointer to the Radix tree * \param user Pointer to the user data that has to be associated with * the key * * \retval node Pointer to the newly created node */ SCRadixNode *SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *user) { uint32_t ip; uint8_t netmask = 32; char ip_str[32]; /* Max length for full ipv4/mask string with NUL */ char *mask_str = NULL; struct in_addr addr; /* Make a copy of the string so it can be modified */ strlcpy(ip_str, str, sizeof(ip_str) - 2); *(ip_str + (sizeof(ip_str) - 1)) = '\0'; /* Does it have a mask? */ if (NULL != (mask_str = strchr(ip_str, '/'))) { int cidr; *(mask_str++) = '\0'; /* Dotted type netmask not supported (yet) */ if (strchr(mask_str, '.') != NULL) { return NULL; } /* Get binary values for cidr mask */ cidr = atoi(mask_str); if ((cidr < 0) || (cidr > 32)) { return NULL; } netmask = (uint8_t)cidr; } /* Validate the IP */ if (inet_pton(AF_INET, ip_str, &addr) <= 0) { return NULL; } ip = addr.s_addr; return SCRadixAddKey((uint8_t *)&ip, 32, tree, user, netmask); } /** * \brief Adds a new IPV6/netblock to the Radix tree from a string * * \param str IPV6 string with optional /cidr netmask * \param tree Pointer to the Radix tree * \param user Pointer to the user data that has to be associated with * the key * * \retval node Pointer to the newly created node */ SCRadixNode *SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *user) { uint8_t netmask = 128; char ip_str[80]; /* Max length for full ipv6/mask string with NUL */ char *mask_str = NULL; struct in6_addr addr; /* Make a copy of the string so it can be modified */ strlcpy(ip_str, str, sizeof(ip_str) - 2); *(ip_str + sizeof(ip_str) - 1) = '\0'; /* Does it have a mask? */ if (NULL != (mask_str = strchr(ip_str, '/'))) { int cidr; *(mask_str++) = '\0'; /* Dotted type netmask not supported (yet) */ if (strchr(mask_str, '.') != NULL) { return NULL; } /* Get binary values for cidr mask */ cidr = atoi(mask_str); if ((cidr < 0) || (cidr > 32)) { return NULL; } netmask = (uint8_t)cidr; } /* Validate the IP */ if (inet_pton(AF_INET6, ip_str, &addr) <= 0) { return NULL; } return SCRadixAddKey(addr.s6_addr, 128, tree, user, netmask); } static void SCRadixTransferNetmasksBWNodes(SCRadixNode *dest, SCRadixNode *src) { int i = 0, j = 0; if (src == NULL || dest == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "src or dest NULL"); return; } /* no netmasks in the source node, to transfer to the destination node */ if (src->netmasks == NULL) return; if ( (dest->netmasks = SCRealloc(dest->netmasks, (src->netmask_cnt + dest->netmask_cnt) * sizeof(uint8_t))) == NULL) return; for (i = dest->netmask_cnt, j = 0; j < src->netmask_cnt; i++, j++) dest->netmasks[i] = src->netmasks[j]; return; } /** * \brief Removes a netblock entry from an ip node. The function first * deletes the netblock/user_data entry for the prefix and then * removes the netmask entry that has been made in the tree, by * walking up the tree and deleting the entry from the specific node. * * \param node The node from which the netblock entry has to be removed. * \param netmask The netmask entry (cidr) that has to be removed. */ static void SCRadixRemoveNetblockEntry(SCRadixNode *node, uint8_t netmask) { SCRadixNode *parent = NULL; int i = 0; if (node == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument. Node is NULL"); return; } SCRadixRemoveNetmaskUserDataFromPrefix(node->prefix, netmask); if (netmask == 32 || netmask == 128) return; parent = node->parent; while (parent != NULL && netmask < (parent->bit + 1)) { parent = parent->parent; } for (i = 0; i < node->netmask_cnt; i++) { if (node->netmasks[i] == netmask) break; } if (i == node->netmask_cnt) { SCLogDebug("Something's wrong with the tree. We are unable to find the " "netmask entry"); return; } for ( ; i < node->netmask_cnt - 1; i++) node->netmasks[i] = node->netmasks[i + 1]; node->netmask_cnt--; if (node->netmask_cnt == 0) { SCFree(node->netmasks); node->netmasks = NULL; return; } node->netmasks = SCRealloc(node->netmasks, node->netmask_cnt * sizeof(uint8_t)); if (node->netmasks == NULL) return; return; } /** * \brief Removes a key from the Radix tree * * \param key_stream Data that has to be removed from the Radix tree * \param key_bitlen The bitlen of the the above stream. For example if the * stream holds an IPV4 address(4 bytes), bitlen would be 32 * \param tree Pointer to the Radix tree from which the key has to be * removed */ static void SCRadixRemoveKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree, uint8_t netmask) { SCRadixNode *node = tree->head; SCRadixNode *parent = NULL; SCRadixNode *temp_dest = NULL; SCRadixPrefix *prefix = NULL; int mask = 0; int i = 0; if (node == NULL) return; if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, NULL, 255)) == NULL) return; while (node->bit < prefix->bitlen) { if (SC_RADIX_BITTEST(prefix->stream[node->bit >> 3], (0x80 >> (node->bit % 8))) ) { node = node->right; } else { node = node->left; } if (node == NULL) { SCRadixReleasePrefix(prefix, tree); return; } } if (node->bit != prefix->bitlen || node->prefix == NULL) { SCRadixReleasePrefix(prefix, tree); return; } i = prefix->bitlen / 8; if (SCMemcmp(node->prefix->stream, prefix->stream, i) == 0) { mask = -1 << (8 - prefix->bitlen % 8); if (prefix->bitlen % 8 == 0 || (node->prefix->stream[i] & mask) == (prefix->stream[i] & mask)) { if (!SCRadixPrefixContainNetmask(node->prefix, netmask)) { SCLogDebug("The ip key exists in the Radix Tree, but this(%d) " "netblock entry doesn't exist", netmask); SCRadixReleasePrefix(prefix, tree); return; } } else { SCLogDebug("You are trying to remove a key that doesn't exist in " "the Radix Tree"); SCRadixReleasePrefix(prefix, tree); return; } } else { SCLogDebug("You are trying to remove a key that doesn't exist in the " "Radix Tree"); SCRadixReleasePrefix(prefix, tree); return; } /* The ip node does exist, and the netblock entry does exist in this node, if * we have reached this point. If we have more than one netblock entry, it * indicates we have multiple entries for this key. So we delete that * particular netblock entry, and make our way out of this function */ if (SCRadixPrefixNetmaskCount(node->prefix) > 1) { SCRadixRemoveNetblockEntry(node, netmask); SCRadixReleasePrefix(prefix, tree); return; } /* we are deleting the root of the tree. This would be the only node left * in the tree */ if (tree->head == node) { SCFree(node); tree->head = NULL; SCRadixReleasePrefix(prefix, tree); return; } parent = node->parent; /* parent->parent is not the root of the tree */ if (parent->parent != NULL) { if (parent->parent->left == parent) { if (node->parent->left == node) { temp_dest = parent->right; parent->parent->left = parent->right; parent->right->parent = parent->parent; } else { temp_dest = parent->left; parent->parent->left = parent->left; parent->left->parent = parent->parent; } } else { if (node->parent->left == node) { temp_dest = parent->right; parent->parent->right = parent->right; parent->right->parent = parent->parent; } else { temp_dest = parent->left; parent->parent->right = parent->left; parent->left->parent = parent->parent; } } /* parent is the root of the tree */ } else { if (parent->left == node) { temp_dest = tree->head->right; tree->head->right->parent = NULL; tree->head = tree->head->right; } else { temp_dest = tree->head->left; tree->head->left->parent = NULL; tree->head = tree->head->left; } } /* We need to shift the netmask entries from the node that would be * deleted to its immediate descendant */ SCRadixTransferNetmasksBWNodes(temp_dest, parent); /* release the nodes */ SCRadixReleaseNode(parent, tree); SCRadixReleaseNode(node, tree); SCRadixReleasePrefix(prefix, tree); return; } /** * \brief Removes a key from the Radix tree * * \param key_stream Data that has to be removed from the Radix tree * \param key_bitlen The bitlen of the the above stream. * \param tree Pointer to the Radix tree from which the key has to be * removed */ void SCRadixRemoveKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree) { SCRadixRemoveKey(key_stream, key_bitlen, tree, 255); return; } /** * \brief Removes an IPV4 address netblock key from the Radix tree. * * \param key_stream Data that has to be removed from the Radix tree. In this * case an IPV4 address * \param tree Pointer to the Radix tree from which the key has to be * removed */ void SCRadixRemoveKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, uint8_t netmask) { SCRadixRemoveKey(key_stream, 32, tree, netmask); return; } /** * \brief Removes an IPV4 address key(not a netblock) from the Radix tree. * Instead of using this function, we can also used * SCRadixRemoveKeyIPV4Netblock(), by supplying a netmask value of 32. * * \param key_stream Data that has to be removed from the Radix tree. In this * case an IPV4 address * \param tree Pointer to the Radix tree from which the key has to be * removed */ void SCRadixRemoveKeyIPV4(uint8_t *key_stream, SCRadixTree *tree) { SCRadixRemoveKey(key_stream, 32, tree, 32); return; } /** * \brief Removes an IPV6 netblock address key from the Radix tree. * * \param key_stream Data that has to be removed from the Radix tree. In this * case an IPV6 address * \param tree Pointer to the Radix tree from which the key has to be * removed */ void SCRadixRemoveKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, uint8_t netmask) { SCRadixRemoveKey(key_stream, 128, tree, netmask); return; } /** * \brief Removes an IPV6 address key(not a netblock) from the Radix tree. * Instead of using this function, we can also used * SCRadixRemoveKeyIPV6Netblock(), by supplying a netmask value of 128. * * \param key_stream Data that has to be removed from the Radix tree. In this * case an IPV6 address * \param tree Pointer to the Radix tree from which the key has to be * removed */ void SCRadixRemoveKeyIPV6(uint8_t *key_stream, SCRadixTree *tree) { SCRadixRemoveKey(key_stream, 128, tree, 128); return; } /** * \brief Checks if an IP prefix falls under a netblock, in the path to the root * of the tree, from the node. Used internally by SCRadixFindKey() * * \param prefix Pointer to the prefix that contains the ip address * \param node Pointer to the node from where we have to climb the tree */ static inline SCRadixNode *SCRadixFindKeyIPNetblock(uint8_t *key_stream, uint8_t key_bitlen, SCRadixNode *node) { SCRadixNode *netmask_node = NULL; int mask = 0; int bytes = 0; int i = 0; int j = 0; while (node != NULL && node->netmasks == NULL) node = node->parent; if (node == NULL) return NULL; /* hold the node found containing a netmask. We will need it when we call * this function recursively */ netmask_node = node; for (j = 0; j < netmask_node->netmask_cnt; j++) { bytes = key_bitlen / 8; for (i = 0; i < bytes; i++) { mask = -1; if ( ((i + 1) * 8) > netmask_node->netmasks[j]) { if ( ((i + 1) * 8 - netmask_node->netmasks[j]) < 8) mask = -1 << ((i + 1) * 8 - netmask_node->netmasks[j]); else mask = 0; } key_stream[i] &= mask; } while (node->bit < key_bitlen) { if (SC_RADIX_BITTEST(key_stream[node->bit >> 3], (0x80 >> (node->bit % 8))) ) { node = node->right; } else { node = node->left; } if (node == NULL) return NULL; } if (node->bit != key_bitlen || node->prefix == NULL) return NULL; if (SCMemcmp(node->prefix->stream, key_stream, bytes) == 0) { mask = -1 << (8 - key_bitlen % 8); if (key_bitlen % 8 == 0 || (node->prefix->stream[bytes] & mask) == (key_stream[bytes] & mask)) { if (SCRadixPrefixContainNetmaskAndSetUserData(node->prefix, netmask_node->netmasks[j], 0)) return node; } } } return SCRadixFindKeyIPNetblock(key_stream, key_bitlen, netmask_node->parent); } /** * \brief Checks if an IP address key is present in the tree. The function * apart from handling any normal data, also handles ipv4/ipv6 netblocks * * \param key_stream Data that has to be found in the Radix tree * \param key_bitlen The bitlen of the above stream. * \param tree Pointer to the Radix tree * \param exact_match The key to be searched is an ip address */ static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree, int exact_match) { if (tree == NULL || tree->head == NULL) return NULL; SCRadixNode *node = tree->head; int mask = 0; int bytes = 0; uint8_t tmp_stream[255]; if (key_bitlen > 255) return NULL; memset(tmp_stream, 0, 255); memcpy(tmp_stream, key_stream, key_bitlen / 8); while (node->bit < key_bitlen) { if (SC_RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8))) ) { node = node->right; } else { node = node->left; } if (node == NULL) { return NULL; } } if (node->bit != key_bitlen || node->prefix == NULL) { return NULL; } bytes = key_bitlen / 8; if (SCMemcmp(node->prefix->stream, tmp_stream, bytes) == 0) { mask = -1 << (8 - key_bitlen % 8); if (key_bitlen % 8 == 0 || (node->prefix->stream[bytes] & mask) == (tmp_stream[bytes] & mask)) { if (SCRadixPrefixContainNetmaskAndSetUserData(node->prefix, key_bitlen, 1)) { return node; } } } /* if you are not an ip key, get out of here */ if (exact_match) { return NULL; } SCRadixNode *ret = SCRadixFindKeyIPNetblock(tmp_stream, key_bitlen, node); return ret; } /** * \brief Checks if a key is present in the tree * * \param key_stream Data that has to be found in the Radix tree * \param key_bitlen The bitlen of the the above stream. * \param tree Pointer to the Radix tree instance */ SCRadixNode *SCRadixFindKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree) { return SCRadixFindKey(key_stream, key_bitlen, tree, 1); } /** * \brief Checks if an IPV4 address is present in the tree * * \param key_stream Data that has to be found in the Radix tree. In this case * an IPV4 address * \param tree Pointer to the Radix tree instance */ SCRadixNode *SCRadixFindKeyIPV4ExactMatch(uint8_t *key_stream, SCRadixTree *tree) { return SCRadixFindKey(key_stream, 32, tree, 1); } /** * \brief Checks if an IPV4 address is present in the tree under a netblock * * \param key_stream Data that has to be found in the Radix tree. In this case * an IPV4 address * \param tree Pointer to the Radix tree instance */ SCRadixNode *SCRadixFindKeyIPV4BestMatch(uint8_t *key_stream, SCRadixTree *tree) { return SCRadixFindKey(key_stream, 32, tree, 0); } /** * \brief Checks if an IPV4 Netblock address is present in the tree * * \param key_stream Data that has to be found in the Radix tree. In this case * an IPV4 netblock address * \param tree Pointer to the Radix tree instance */ SCRadixNode *SCRadixFindKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, uint8_t netmask) { SCRadixNode *node = NULL; node = SCRadixFindKey(key_stream, 32, tree, 0); if (node == NULL) return node; if (SCRadixPrefixContainNetmaskAndSetUserData(node->prefix, netmask, 1)) return node; else return NULL; } /** * \brief Checks if an IPV6 Netblock address is present in the tree * * \param key_stream Data that has to be found in the Radix tree. In this case * an IPV6 netblock address * \param tree Pointer to the Radix tree instance */ SCRadixNode *SCRadixFindKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, uint8_t netmask) { SCRadixNode *node = NULL; node = SCRadixFindKey(key_stream, 128, tree, 0); if (node == NULL) return node; if (SCRadixPrefixContainNetmaskAndSetUserData(node->prefix, (uint16_t)netmask, 1)) return node; else return NULL; } /** * \brief Checks if an IPV6 address is present in the tree * * \param key_stream Data that has to be found in the Radix tree. In this case * an IPV6 address * \param tree Pointer to the Radix tree instance */ SCRadixNode *SCRadixFindKeyIPV6ExactMatch(uint8_t *key_stream, SCRadixTree *tree) { return SCRadixFindKey(key_stream, 128, tree, 1); } /** * \brief Checks if an IPV6 address is present in the tree under a netblock * * \param key_stream Data that has to be found in the Radix tree. In this case * an IPV6 address * \param tree Pointer to the Radix tree instance */ SCRadixNode *SCRadixFindKeyIPV6BestMatch(uint8_t *key_stream, SCRadixTree *tree) { return SCRadixFindKey(key_stream, 128, tree, 0); } /** * \brief Prints the node information from a Radix tree * * \param node Pointer to the Radix node whose information has to be printed * \param level Used for indentation purposes */ void SCRadixPrintNodeInfo(SCRadixNode *node, int level, void (*PrintData)(void*)) { int i = 0; if (node == NULL) return; for (i = 0; i < level; i++) printf(" "); printf("%d [", node->bit); if (node->netmasks == NULL) { printf("%d, ", -1); } else { for (i = 0; i < node->netmask_cnt; i++) printf("%s%d", (0 == i ? "" : ", "), node->netmasks[i]); } printf("] ("); if (node->prefix != NULL) { for (i = 0; i * 8 < node->prefix->bitlen; i++) printf("%s%d", (0 == i ? "" : "."), node->prefix->stream[i]); printf(")\n"); SCRadixUserData *ud = NULL; if (PrintData != NULL) { do { ud = node->prefix->user_data; printf(" [%d], ", ud->netmask); PrintData(ud->user); ud = ud->next; } while (ud != NULL); } else { //ud = node->prefix->user_data; //while (ud != NULL) { // printf(" [nm %d with data], ", ud->netmask); // ud = ud->next; //} printf("No print function provided"); } printf("\n"); } else { printf("NULL)\n"); } return; } /** * \brief Helper function used by SCRadixPrintTree. Prints the subtree with * node as the root of the subtree * * \param node Pointer to the node that is the root of the subtree to be printed * \param level Used for indentation purposes */ static void SCRadixPrintRadixSubtree(SCRadixNode *node, int level, void (*PrintData)(void*)) { if (node != NULL) { SCRadixPrintNodeInfo(node, level, PrintData); SCRadixPrintRadixSubtree(node->left, level + 1, PrintData); SCRadixPrintRadixSubtree(node->right, level + 1, PrintData); } return; } /** * \brief Prints the Radix Tree. While printing the radix tree we use the * following format * * Parent_0 * Left_Child_1 * Left_Child_2 * Right_Child_2 * Right_Child_1 * Left_Child_2 * Right_Child_2 and so on * * Each node printed out holds details on the next bit that differs * amongst its children, and if the node holds a prefix, the perfix is * printed as well. * * \param tree Pointer to the Radix tree that has to be printed */ void SCRadixPrintTree(SCRadixTree *tree) { printf("Printing the Radix Tree: \n"); SCRadixPrintRadixSubtree(tree->head, 0, tree->PrintData); return; } /*------------------------------------Unit_Tests------------------------------*/ #ifdef UNITTESTS int SCRadixTestInsertion01(void) { SCRadixTree *tree = NULL; SCRadixNode *node[2]; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); node[0] = SCRadixAddKeyGeneric((uint8_t *)"abaa", 32, tree, NULL); node[1] = SCRadixAddKeyGeneric((uint8_t *)"abab", 32, tree, NULL); result &= (tree->head->bit == 30); result &= (tree->head->right == node[0]); result &= (tree->head->left == node[1]); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestInsertion02(void) { SCRadixTree *tree = NULL; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); SCRadixAddKeyGeneric((uint8_t *)"aaaaaa", 48, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"aaaaab", 48, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"aaaaaba", 56, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"abab", 32, tree, NULL); SCRadixReleaseRadixTree(tree); /* If we don't have a segfault till here we have succeeded :) */ return result; } int SCRadixTestIPV4Insertion03(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); /* add a key that already exists in the tree */ SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); /* test for the existance of a key */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); /* test for the existance of a key */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); /* continue adding keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); /* test the existence of keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.3", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "127.234.2.62", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV4Removal04(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); /* remove the keys from the tree */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.1", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); result &= (tree->head == NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestCharacterInsertion05(void) { SCRadixTree *tree = NULL; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* Let us have our team here ;-) */ SCRadixAddKeyGeneric((uint8_t *)"Victor", 48, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Matt", 32, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Josh", 32, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Margaret", 64, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Pablo", 40, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Brian", 40, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Jasonish", 64, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Jasonmc", 56, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Nathan", 48, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Anoop", 40, tree, NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Victor", 48, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Matt", 32, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Josh", 32, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Margaret", 64, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Pablo", 40, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Brian", 40, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Jasonish", 64, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Jasonmc", 56, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Nathan", 48, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Anoop", 40, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"bamboo", 48, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"bool", 32, tree) == NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"meerkat", 56, tree) == NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Victor", 48, tree) == NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestCharacterRemoval06(void) { SCRadixTree *tree = NULL; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* Let us have our team here ;-) */ SCRadixAddKeyGeneric((uint8_t *)"Victor", 48, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Matt", 32, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Josh", 32, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Margaret", 64, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Pablo", 40, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Brian", 40, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Jasonish", 64, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Jasonmc", 56, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Nathan", 48, tree, NULL); SCRadixAddKeyGeneric((uint8_t *)"Anoop", 40, tree, NULL); SCRadixRemoveKeyGeneric((uint8_t *)"Nathan", 48, tree); SCRadixRemoveKeyGeneric((uint8_t *)"Brian", 40, tree); SCRadixRemoveKeyGeneric((uint8_t *)"Margaret", 64, tree); result &= (SCRadixFindKeyGeneric((uint8_t *)"Victor", 48, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Matt", 32, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Josh", 32, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Margaret", 64, tree) == NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Brian", 40, tree) == NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Nathan", 48, tree) == NULL); SCRadixRemoveKeyGeneric((uint8_t *)"Victor", 48, tree); SCRadixRemoveKeyGeneric((uint8_t *)"Josh", 32, tree); SCRadixRemoveKeyGeneric((uint8_t *)"Jasonmc", 56, tree); SCRadixRemoveKeyGeneric((uint8_t *)"Matt", 32, tree); result &= (SCRadixFindKeyGeneric((uint8_t *)"Pablo", 40, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Jasonish", 64, tree) != NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Anoop", 40, tree) != NULL); SCRadixRemoveKeyGeneric((uint8_t *)"Pablo", 40, tree); SCRadixRemoveKeyGeneric((uint8_t *)"Jasonish", 64, tree); SCRadixRemoveKeyGeneric((uint8_t *)"Anoop", 40, tree); result &= (SCRadixFindKeyGeneric((uint8_t *)"Pablo", 40, tree) == NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Jasonish", 64, tree) == NULL); result &= (SCRadixFindKeyGeneric((uint8_t *)"Anoop", 40, tree) == NULL); result &= (tree->head == NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV6Insertion07(void) { SCRadixTree *tree = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); /* Try to add the prefix that already exists in the tree */ SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); /* test the existence of keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV6Removal08(void) { SCRadixTree *tree = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); /* Try to add the prefix that already exists in the tree */ SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); /* test the existence of keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "8888:0BF1:5346:BDEA:6422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2006:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); /* test for existance */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:DDDD:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); /* remove keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); /* test for existance */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); /* remove keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); /* test for existance */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV4NetblockInsertion09(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.192.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); /* test for the existance of a key */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.170.1.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.145", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.64.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.191.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.224.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.174.224.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.175.224.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV4NetblockInsertion10(void) { SCRadixTree *tree = NULL; SCRadixNode *node[2]; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) return 0; node[0] = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; node[1] = SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); /* test for the existance of a key */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node[0]); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == node[1]); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node[1]); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node[0]); /* let us remove a netblock */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 24); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV4NetblockInsertion11(void) { SCRadixTree *tree = NULL; SCRadixNode *node = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) return 0; node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 0); /* test for the existance of a key */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL && SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "245.63.62.121", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL && SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL && SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node); /* remove node 0.0.0.0 */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 0); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV4NetblockInsertion12(void) { SCRadixTree *tree = NULL; SCRadixNode *node[2]; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) return 0; node[0] = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; node[1] = SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 32); /* test for the existance of a key */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node[0]); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == node[1]); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node[1]); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node[1]); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) == node[0]); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "225.175.21.224", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "225.175.21.229", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "225.175.21.230", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree) == NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV6NetblockInsertion13(void) { SCRadixTree *tree = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DB00:0000:0000:0000:0000", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 56); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); /* test the existence of keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1146:6241", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1356:1241", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DAAA:1245:2342:1146:6241", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); SCRadixReleaseRadixTree(tree); return result; } int SCRadixTestIPV6NetblockInsertion14(void) { SCRadixTree *tree = NULL; SCRadixNode *node = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); /* add the keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DB00:0000:0000:0000:0000", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 56); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", &servaddr.sin6_addr) <= 0) return 0; SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "::", &servaddr.sin6_addr) <= 0) return 0; node = SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 0); /* test the existence of keys */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) == NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2004:0BF1:5346:B116:2362:8713:9124:2315", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "2004:0B23:3252:BDEA:7422:8713:9124:2341", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) == node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL && SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree) != node); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", &servaddr.sin6_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) != NULL && SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree) != node); SCRadixReleaseRadixTree(tree); return result; } /** * \test Check that the best match search works for all the * possible netblocks of a fixed address */ int SCRadixTestIPV4NetBlocksAndBestSearch15(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t i = 0; uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.1", &servaddr.sin_addr) <= 0) { result = 0; goto end; } for (; i <= 32; i++) { user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = i; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, i); SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != i) { printf("User data == %"PRIu32"; i == %"PRIu32": ", *( (uint32_t*)node->prefix->user_data_result), i); result = 0; goto end; } } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check that the best match search works for all the * possible netblocks of a fixed address */ int SCRadixTestIPV4NetBlocksAndBestSearch16(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t i = 0; uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) { result = 0; goto end; } for (; i <= 32; i++) { user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = i; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, i); SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != i) { printf("User data == %"PRIu32"; i == %"PRIu32": ", *( (uint32_t*)node->prefix->user_data_result), i); result = 0; goto end; } } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check that the best match search works for all the * possible netblocks of a fixed address */ int SCRadixTestIPV4NetBlocksAndBestSearch17(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t i = 0; uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "10.0.0.1", &servaddr.sin_addr) <= 0) { result = 0; goto end; } for (; i <= 32; i++) { user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = i; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, i); SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != i) { printf("User data == %"PRIu32"; i == %"PRIu32": ", *( (uint32_t*)node->prefix->user_data_result), i); result = 0; goto end; } } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check that the best match search works for all the * possible netblocks of a fixed address */ int SCRadixTestIPV4NetBlocksAndBestSearch18(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t i = 0; uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "172.26.0.1", &servaddr.sin_addr) <= 0) { result = 0; goto end; } for (; i <= 32; i++) { user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = i; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, i); SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != i) { printf("User data == %"PRIu32"; i == %"PRIu32": ", *( (uint32_t*)node->prefix->user_data_result), i); result = 0; goto end; } } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check special combinations of netblocks and addresses * on best search checking the returned userdata */ int SCRadixTestIPV4NetBlocksAndBestSearch19(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) { result = 0; goto end; } user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = 100; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 0); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.1.15", &servaddr.sin_addr) <= 0) { result = 0; goto end; } SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 100) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "177.0.0.0", &servaddr.sin_addr) <= 0) { result = 0; goto end; } user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = 200; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 8); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "177.168.1.15", &servaddr.sin_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 200) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "178.168.1.15", &servaddr.sin_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 100) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "177.168.0.0", &servaddr.sin_addr) <= 0) { result = 0; goto end; } user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = 300; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 12); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "177.168.1.15", &servaddr.sin_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 300) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "177.167.1.15", &servaddr.sin_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 300) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "177.178.1.15", &servaddr.sin_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 200) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "197.178.1.15", &servaddr.sin_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 100) { result = 0; goto end; } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check that the best match search works for all the * possible netblocks of a fixed address */ int SCRadixTestIPV6NetBlocksAndBestSearch20(void) { SCRadixTree *tree = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t i = 0; uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ABAB:CDCD:ABAB:CDCD:1234:4321:1234:4321", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } for (; i <= 128; i++) { user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = i; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, user, i); SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != i) { printf("User data == %"PRIu32"; i == %"PRIu32": ", *( (uint32_t*)node->prefix->user_data_result), i); result = 0; goto end; } } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check that the best match search works for all the * possible netblocks of a fixed address */ int SCRadixTestIPV6NetBlocksAndBestSearch21(void) { SCRadixTree *tree = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t i = 0; uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ff00::1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } for (; i <= 128; i++) { user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = i; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, user, i); SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != i) { printf("User data == %"PRIu32"; i == %"PRIu32": ", *( (uint32_t*)node->prefix->user_data_result), i); result = 0; goto end; } } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check that the best match search works for all the * possible netblocks of a fixed address */ int SCRadixTestIPV6NetBlocksAndBestSearch22(void) { SCRadixTree *tree = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t i = 0; uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ff00::192:168:1:1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } for (; i <= 128; i++) { user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = i; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, user, i); SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != i) { printf("User data == %"PRIu32"; i == %"PRIu32": ", *( (uint32_t*)node->prefix->user_data_result), i); result = 0; goto end; } } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check that the best match search works for all the * possible netblocks of a fixed address */ int SCRadixTestIPV6NetBlocksAndBestSearch23(void) { SCRadixTree *tree = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t i = 0; uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "FF00:ABCD:BCDA::ABCD", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } for (; i <= 128; i++) { user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = i; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, user, i); SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != i) { printf("User data == %"PRIu32"; i == %"PRIu32": ", *( (uint32_t*)node->prefix->user_data_result), i); result = 0; goto end; } } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test Check special combinations of netblocks and addresses * on best search checking the returned userdata */ int SCRadixTestIPV6NetBlocksAndBestSearch24(void) { SCRadixTree *tree = NULL; struct sockaddr_in6 servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); uint32_t *user; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "::", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = 100; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, user, 0); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ABCD::1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 100) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ABCD::0", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = 200; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, user, 8); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ABCD::1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 200) { printf("User data == %"PRIu32"; i != 200 ", *( (uint32_t*)node->prefix->user_data_result)); result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "DCBA::1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 100) { printf("User data == %"PRIu32"; != 100 ", *( (uint32_t*)node->prefix->user_data_result)); result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ABCD:ABCD::0", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } user = SCMalloc(sizeof(uint32_t)); if (unlikely(user == NULL)) { result = 0; goto end; } *user = 300; SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, user, 12); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ABCD:ABCD::1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 300) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ABCD:AAAA::1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 300) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "ABAB::1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 200) { result = 0; goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET6, "CABD::1", &servaddr.sin6_addr) <= 0) { result = 0; goto end; } node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree); if (node == NULL) { printf("node == NULL: "); result = 0; goto end; } if (node->prefix->user_data_result == NULL) { printf("User data == NULL: "); result = 0; goto end; } if ( *( (uint32_t*)node->prefix->user_data_result) != 100) { result = 0; goto end; } end: SCRadixReleaseRadixTree(tree); return result; } /** * \test SCRadixTestIPV4NetblockInsertion15 insert a node searching on it. * Should always return true but the purposse of the test is to monitor * the memory usage to detect memleaks (there was one on searching) */ int SCRadixTestIPV4NetblockInsertion25(void) { SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; tree = SCRadixCreateRadixTree(free, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) return 0; SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); /* test for the existance of a key */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.128.53", &servaddr.sin_addr) <= 0) return 0; result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); SCRadixReleaseRadixTree(tree); return result; } /** * \test SCRadixTestIPV4NetblockInsertion26 insert a node searching on it. * Should always return true but the purposse of the test is to monitor * the memory usage to detect memleaks (there was one on searching) */ int SCRadixTestIPV4NetblockInsertion26(void) { SCRadixNode *tmp = NULL; SCRadixTree *tree = NULL; struct sockaddr_in servaddr; int result = 1; char *str = SCStrdup("Hello1"); tree = SCRadixCreateRadixTree(free, NULL); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) return 0; tmp = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 0); if (!tmp) { printf("Not inserted correctly 1 :"); result = 0; goto this_end; } str = SCStrdup("Hello1"); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "176.0.0.1", &servaddr.sin_addr) <= 0) return 0; tmp = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 5); if (!tmp) { printf("Not inserted correctly 2 :"); result = 0; goto this_end; } str = SCStrdup("Hello1"); bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) { SCFree(str); return 0; } tmp = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 7); if (!tmp) { printf("Not inserted correctly 3 :"); result = 0; goto this_end; } /* test for the existance of a key */ //result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); this_end: SCRadixReleaseRadixTree(tree); //SCFree(str); return result; } /** * \test SC_RADIX_NODE_USERDATA macro */ static int SCRadixTestUserdataMacro01(void) { int result = 0; SCRadixNode *node = SCMalloc(sizeof(SCRadixNode)); if (unlikely(node == NULL)) { goto end; } memset(node, 0x00, sizeof(*node)); void *ptr = SC_RADIX_NODE_USERDATA(node, void); if (ptr != NULL) { printf("ptr %p, expected NULL: ", ptr); goto end; } result = 1; end: if (node != NULL) SCFree(node); return result; } /** * \test SC_RADIX_NODE_USERDATA macro */ static int SCRadixTestUserdataMacro02(void) { SCRadixPrefix prefix; int result = 0; SCRadixNode *node = SCMalloc(sizeof(SCRadixNode)); if (unlikely(node == NULL)) { goto end; } memset(node, 0x00, sizeof(*node)); memset(&prefix, 0x00, sizeof(prefix)); node->prefix = &prefix; void *ptr = SC_RADIX_NODE_USERDATA(node, void); if (ptr != NULL) { printf("ptr %p, expected NULL: ", ptr); goto end; } result = 1; end: if (node != NULL) SCFree(node); return result; } /** * \test SC_RADIX_NODE_USERDATA macro */ static int SCRadixTestUserdataMacro03(void) { SCRadixPrefix prefix; int result = 0; void *somep = &result; SCRadixNode *node = SCMalloc(sizeof(SCRadixNode)); if (unlikely(node == NULL)) { goto end; } memset(node, 0x00, sizeof(*node)); memset(&prefix, 0x00, sizeof(prefix)); node->prefix = &prefix; prefix.user_data_result = somep; void *ptr = SC_RADIX_NODE_USERDATA(node, void); if (ptr != somep) { printf("ptr %p, expected %p: ", ptr, somep); goto end; } result = 1; end: if (node != NULL) SCFree(node); return result; } #endif void SCRadixRegisterTests(void) { #ifdef UNITTESTS //UtRegisterTest("SCRadixTestInsertion01", SCRadixTestInsertion01, 1); //UtRegisterTest("SCRadixTestInsertion02", SCRadixTestInsertion02, 1); UtRegisterTest("SCRadixTestIPV4Insertion03", SCRadixTestIPV4Insertion03, 1); UtRegisterTest("SCRadixTestIPV4Removal04", SCRadixTestIPV4Removal04, 1); //UtRegisterTest("SCRadixTestCharacterInsertion05", // SCRadixTestCharacterInsertion05, 1); //UtRegisterTest("SCRadixTestCharacterRemoval06", // SCRadixTestCharacterRemoval06, 1); UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07, 1); UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08, 1); UtRegisterTest("SCRadixTestIPV4NetblockInsertion09", SCRadixTestIPV4NetblockInsertion09, 1); UtRegisterTest("SCRadixTestIPV4NetblockInsertion10", SCRadixTestIPV4NetblockInsertion10, 1); UtRegisterTest("SCRadixTestIPV4NetblockInsertion11", SCRadixTestIPV4NetblockInsertion11, 1); UtRegisterTest("SCRadixTestIPV4NetblockInsertion12", SCRadixTestIPV4NetblockInsertion12, 1); UtRegisterTest("SCRadixTestIPV6NetblockInsertion13", SCRadixTestIPV6NetblockInsertion13, 1); UtRegisterTest("SCRadixTestIPV6NetblockInsertion14", SCRadixTestIPV6NetblockInsertion14, 1); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch15", SCRadixTestIPV4NetBlocksAndBestSearch15, 1); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch16", SCRadixTestIPV4NetBlocksAndBestSearch16, 1); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch17", SCRadixTestIPV4NetBlocksAndBestSearch17, 1); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch18", SCRadixTestIPV4NetBlocksAndBestSearch18, 1); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch19", SCRadixTestIPV4NetBlocksAndBestSearch19, 1); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch20", SCRadixTestIPV6NetBlocksAndBestSearch20, 1); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch21", SCRadixTestIPV6NetBlocksAndBestSearch21, 1); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch22", SCRadixTestIPV6NetBlocksAndBestSearch22, 1); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch23", SCRadixTestIPV6NetBlocksAndBestSearch23, 1); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch24", SCRadixTestIPV6NetBlocksAndBestSearch24, 1); UtRegisterTest("SCRadixTestIPV4NetblockInsertion25", SCRadixTestIPV4NetblockInsertion25, 1); UtRegisterTest("SCRadixTestIPV4NetblockInsertion26", SCRadixTestIPV4NetblockInsertion26, 1); UtRegisterTest("SCRadixTestUserdataMacro01", SCRadixTestUserdataMacro01, 1); UtRegisterTest("SCRadixTestUserdataMacro02", SCRadixTestUserdataMacro02, 1); UtRegisterTest("SCRadixTestUserdataMacro03", SCRadixTestUserdataMacro03, 1); #endif return; } suricata-1.4.7/src/conf.h0000644000000000000000000000544012253546156012126 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited - Jason Ish */ #ifndef __CONF_H__ #define __CONF_H__ #include "queue.h" /** * Structure of a configuration parameter. */ typedef struct ConfNode_ { char *name; char *val; int is_seq; int allow_override; struct ConfNode_ *parent; TAILQ_HEAD(, ConfNode_) head; TAILQ_ENTRY(ConfNode_) next; } ConfNode; /** * The default log directory. */ #ifdef OS_WIN32 #define DEFAULT_LOG_DIR "C:\\WINDOWS\\Temp" #else #define DEFAULT_LOG_DIR "/var/log/suricata" #endif /* OS_WIN32 */ void ConfInit(void); void ConfDeInit(void); ConfNode *ConfGetRootNode(void); int ConfGet(char *name, char **vptr); int ConfGetInt(char *name, intmax_t *val); int ConfGetBool(char *name, int *val); int ConfGetDouble(char *name, double *val); int ConfGetFloat(char *name, float *val); int ConfSet(char *name, char *val, int allow_override); void ConfDump(void); void ConfNodeDump(ConfNode *node, const char *prefix); ConfNode *ConfNodeNew(void); void ConfNodeFree(ConfNode *); ConfNode *ConfGetNode(char *key); void ConfCreateContextBackup(void); void ConfRestoreContextBackup(void); ConfNode *ConfNodeLookupChild(ConfNode *node, const char *key); const char *ConfNodeLookupChildValue(ConfNode *node, const char *key); void ConfNodeRemove(ConfNode *); void ConfRegisterTests(); int ConfNodeChildValueIsTrue(ConfNode *node, const char *key); int ConfValIsTrue(const char *val); int ConfValIsFalse(const char *val); ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *value); int ConfGetChildValue(ConfNode *base, char *name, char **vptr); int ConfGetChildValueInt(ConfNode *base, char *name, intmax_t *val); int ConfGetChildValueBool(ConfNode *base, char *name, int *val); int ConfGetChildValueWithDefault(ConfNode *base, ConfNode *dflt, char *name, char **vptr); int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, intmax_t *val); int ConfGetChildValueBoolWithDefault(ConfNode *base, ConfNode *dflt, char *name, int *val); char *ConfLoadCompleteIncludePath(char *); #endif /* ! __CONF_H__ */ suricata-1.4.7/src/detect-distance.c0000644000000000000000000003675612253546156014252 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * * Implements the distance keyword */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "app-layer.h" #include "detect-parse.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-pcre.h" #include "detect-byte-extract.h" #include "flow-var.h" #include "util-debug.h" #include "util-unittest.h" #include "detect-bytejump.h" #include "util-unittest-helper.h" static int DetectDistanceSetup(DetectEngineCtx *, Signature *, char *); void DetectDistanceRegisterTests(void); void DetectDistanceRegister (void) { sigmatch_table[DETECT_DISTANCE].name = "distance"; sigmatch_table[DETECT_DISTANCE].desc = "indicates a relation between this content keyword and the content preceding it"; sigmatch_table[DETECT_DISTANCE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Distance"; sigmatch_table[DETECT_DISTANCE].Match = NULL; sigmatch_table[DETECT_DISTANCE].Setup = DetectDistanceSetup; sigmatch_table[DETECT_DISTANCE].Free = NULL; sigmatch_table[DETECT_DISTANCE].RegisterTests = DetectDistanceRegisterTests; sigmatch_table[DETECT_DISTANCE].flags |= SIGMATCH_PAYLOAD; } static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, char *distancestr) { char *str = distancestr; char dubbed = 0; SigMatch *pm = NULL; /* strip "'s */ if (distancestr[0] == '\"' && distancestr[strlen(distancestr) - 1] == '\"') { str = SCStrdup(distancestr + 1); if (unlikely(str == NULL)) goto error; str[strlen(distancestr) - 2] = '\0'; dubbed = 1; } /* if we still haven't found that the sig is related to DCERPC, * it's a direct entry into Signature->sm_lists[DETECT_SM_LIST_PMATCH] */ if (s->alproto == ALPROTO_DCERPC) { SigMatch *dcem = NULL; SigMatch *dm = NULL; SigMatch *pm1 = NULL; SigMatch *pm1_ots = NULL; SigMatch *pm2_ots = NULL; dcem = SigMatchGetLastSMFromLists(s, 6, DETECT_DCE_IFACE, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_DCE_OPNUM, s->sm_lists_tail[DETECT_SM_LIST_AMATCH], DETECT_DCE_STUB_DATA, s->sm_lists_tail[DETECT_SM_LIST_AMATCH]); pm1_ots = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm1_ots != NULL && pm1_ots->prev != NULL) { pm2_ots = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, pm1_ots->prev, DETECT_PCRE, pm1_ots->prev, DETECT_BYTEJUMP, pm1_ots->prev); } dm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm1 = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (dm == NULL && pm1 == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid signature. within " "needs a preceding content keyword"); goto error; } if (dm == NULL) { if (pm2_ots == NULL) { if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ pm = pm1; } } else if (pm2_ots->idx > dcem->idx) { /* within is against pm1, pm = pm1; */ pm = pm1; } else if (pm1->idx > dcem->idx) { /* transfer pm1 to dmatch list and within is against this */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1 and we continue this way */ pm = pm1; } } else { if (pm1 == NULL) { /* within is against dm and continue this way */ pm = dm; } else if (dm->idx > pm1->idx) { /* within is against dm */ pm = dm; } else if (pm2_ots == NULL || pm2_ots->idx < dcem->idx) { /* trasnfer pm1 to dmatch list and pm = pm1 */ SigMatchTransferSigMatchAcrossLists(pm1, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_DMATCH], &s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); pm = pm1; } else { /* within is against pm1, pm = pm1 */ pm = pm1; } } } else { pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "within needs " "preceding content, uricontent option, http_client_body, " "http_server_body, http_header, http_raw_header, http_method, " "http_cookie, http_raw_uri, http_stat_msg, http_stat_code, " "http_user_agent, http_host or http_raw_host option"); if (dubbed) SCFree(str); return -1; } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (pm->type) { case DETECT_CONTENT: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two " "preceding content or uricontent options"); goto error; } if (cd->flags & DETECT_CONTENT_NEGATED) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a fast_pattern"); goto error; } } else { if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "keyword set along with a fast_pattern:only;"); goto error; } } if ((cd->flags & DETECT_CONTENT_DEPTH) || (cd->flags & DETECT_CONTENT_OFFSET)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative keyword " "with a non-relative keyword for the same content." ); goto error; } if (cd->flags & DETECT_CONTENT_DISTANCE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple distances with the same content. "); goto error; } if (str[0] != '-' && isalpha((unsigned char)str[0])) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var " "seen in distance - %s\n", str); goto error; } cd->distance = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_DISTANCE_BE; } else { cd->distance = strtol(str, NULL, 10); } cd->flags |= DETECT_CONTENT_DISTANCE; pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, pm->prev, DETECT_PCRE, pm->prev, DETECT_BYTEJUMP, pm->prev); if (pm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("content relative without a previous content based " "keyword. Holds good only in the case of DCERPC " "alproto like now."); } else { //SCLogError(SC_ERR_INVALID_SIGNATURE, "No related " //"previous-previous content or pcre keyword"); //goto error; ; } } else { switch (pm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown previous-" "previous keyword!"); goto error; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "previous keyword " "has a fast_pattern:only; set. Can't have " "relative keywords around a fast_pattern " "only content"); goto error; } break; case DETECT_PCRE: pe = (DetectPcreData *) pm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown previous-" "previous keyword!"); goto error; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: SCLogDebug("no setting relative_next for bytejump. We " "have no use for it"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown previous-" "previous keyword!"); break; } } break; default: SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "distance needs two " "preceding content or uricontent options"); goto error; } if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; } #ifdef UNITTESTS static int DetectDistanceTest01(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("no de_ctx: "); goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"|AA BB|\"; content:\"|CC DD EE FF 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE|\"; distance: 4; within: 19; sid:1; rev:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } SigMatch *sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm == NULL) { printf("sm NULL: "); goto end; } sm = sm->next; if (sm == NULL) { printf("sm2 NULL: "); goto end; } DetectContentData *co = (DetectContentData *)sm->ctx; if (co == NULL) { printf("co == NULL: "); goto end; } if (co->distance != 4) { printf("distance %"PRIi32", expected 4: ", co->distance); goto end; } /* within needs to be 23: distance + content_len as Snort auto fixes this */ if (co->within != 19) { printf("within %"PRIi32", expected 23: ", co->within); goto end; } result = 1; end: DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectDistanceTestPacket01 is a test to check matches of * distance works, if the previous keyword is byte_jump and content * (bug 163) */ int DetectDistanceTestPacket01 (void) { int result = 0; uint8_t buf[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint16_t buflen = sizeof(buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"suricata test\"; " "byte_jump:1,2; content:\"|00|\"; " "within:1; distance:2; sid:98711212; rev:1;)"; p->flowflags = FLOW_PKT_ESTABLISHED | FLOW_PKT_TOCLIENT; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } #endif /* UNITTESTS */ void DetectDistanceRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDistanceTest01 -- distance / within mix", DetectDistanceTest01, 1); UtRegisterTest("DetectDistanceTestPacket01", DetectDistanceTestPacket01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-distance.h0000644000000000000000000000164712253546156014246 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_DISTANCE_H__ #define __DETECT_DISTANCE_H__ /* prototypes */ void DetectDistanceRegister (void); #endif /* __DETECT_DISTANCE_H__ */ suricata-1.4.7/src/detect-rpc.c0000644000000000000000000004325012253546156013227 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * * Implements RPC keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-rpc.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-siggroup.h" #include "detect-engine-address.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "util-byte.h" /** * \brief Regex for parsing our rpc options */ #define PARSE_REGEX "^\\s*([0-9]{0,10})\\s*(?:,\\s*([0-9]{0,10}|[*])\\s*(?:,\\s*([0-9]{0,10}|[*]))?)?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectRpcMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectRpcSetup (DetectEngineCtx *, Signature *, char *); void DetectRpcRegisterTests(void); void DetectRpcFree(void *); /** * \brief Registration function for rpc keyword */ void DetectRpcRegister (void) { sigmatch_table[DETECT_RPC].name = "rpc"; sigmatch_table[DETECT_RPC].desc = "match RPC procedure numbers and RPC version"; sigmatch_table[DETECT_RPC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#rpc"; sigmatch_table[DETECT_RPC].Match = DetectRpcMatch; sigmatch_table[DETECT_RPC].Setup = DetectRpcSetup; sigmatch_table[DETECT_RPC].Free = DetectRpcFree; sigmatch_table[DETECT_RPC].RegisterTests = DetectRpcRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /* * returns 0: no match * 1: match * -1: error */ /** * \brief This function is used to match rpc request set on a packet with those passed via rpc * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectRpcData * * \retval 0 no match * \retval 1 match */ int DetectRpcMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { /* PrintRawDataFp(stdout, p->payload, p->payload_len); */ DetectRpcData *rd = (DetectRpcData *)m->ctx; char *rpcmsg = (char *)p->payload; if (PKT_IS_TCP(p)) { /* if Rpc msg too small */ if (p->payload_len < 28) { SCLogDebug("TCP packet to small for the rpc msg (%u)", p->payload_len); return 0; } rpcmsg += 4; } else if (PKT_IS_UDP(p)) { /* if Rpc msg too small */ if (p->payload_len < 24) { SCLogDebug("UDP packet to small for the rpc msg (%u)", p->payload_len); return 0; } } else { SCLogDebug("No valid proto for the rpc message"); return 0; } /* Point through the rpc msg structure. Use ntohl() to compare values */ RpcMsg *msg = (RpcMsg *)rpcmsg; /* If its not a call, no match */ if (ntohl(msg->type) != 0) { SCLogDebug("RPC message type is not a call"); return 0; } if (ntohl(msg->prog) != rd->program) return 0; if ((rd->flags & DETECT_RPC_CHECK_VERSION) && ntohl(msg->vers) != rd->program_version) return 0; if ((rd->flags & DETECT_RPC_CHECK_PROCEDURE) && ntohl(msg->proc) != rd->procedure) return 0; SCLogDebug("prog:%u pver:%u proc:%u matched", ntohl(msg->prog), ntohl(msg->vers), ntohl(msg->proc)); return 1; } /** * \brief This function is used to parse rpc options passed via rpc keyword * * \param rpcstr Pointer to the user provided rpc options * * \retval rd pointer to DetectRpcData on success * \retval NULL on failure */ DetectRpcData *DetectRpcParse (char *rpcstr) { DetectRpcData *rd = NULL; char *args[3] = {NULL,NULL,NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, rpcstr, strlen(rpcstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 ", string %s", ret, rpcstr); goto error; } if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)rpcstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[0] = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)rpcstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[1] = (char *)str_ptr; } if (ret > 3) { res = pcre_get_substring((char *)rpcstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[2] = (char *)str_ptr; } } rd = SCMalloc(sizeof(DetectRpcData)); if (unlikely(rd == NULL)) goto error; rd->flags = 0; rd->program = 0; rd->program_version = 0; rd->procedure = 0; int i; for (i = 0; i < (ret -1); i++) { if (args[i]) { switch (i) { case 0: if (ByteExtractStringUint32(&rd->program, 10, strlen(args[i]), args[i]) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size specified for the rpc program:\"%s\"", args[i]); goto error; } rd->flags |= DETECT_RPC_CHECK_PROGRAM; break; case 1: if (args[i][0] != '*') { if (ByteExtractStringUint32(&rd->program_version, 10, strlen(args[i]), args[i]) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size specified for the rpc version:\"%s\"", args[i]); goto error; } rd->flags |= DETECT_RPC_CHECK_VERSION; } break; case 2: if (args[i][0] != '*') { if (ByteExtractStringUint32(&rd->procedure, 10, strlen(args[i]), args[i]) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size specified for the rpc procedure:\"%s\"", args[i]); goto error; } rd->flags |= DETECT_RPC_CHECK_PROCEDURE; } break; } } else { SCLogError(SC_ERR_INVALID_VALUE, "invalid rpc option %s",args[i]); goto error; } } for (i = 0; i < (ret -1); i++){ if (args[i] != NULL) SCFree(args[i]); } return rd; error: for (i = 0; i < (ret -1) && i < 3; i++){ if (args[i] != NULL) SCFree(args[i]); } if (rd != NULL) DetectRpcFree(rd); return NULL; } /** * \brief this function is used to add the parsed rpcdata into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param m pointer to the Current SigMatch * \param rpcstr pointer to the user provided rpc options * * \retval 0 on Success * \retval -1 on Failure */ int DetectRpcSetup (DetectEngineCtx *de_ctx, Signature *s, char *rpcstr) { DetectRpcData *rd = NULL; SigMatch *sm = NULL; rd = DetectRpcParse(rpcstr); if (rd == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_RPC; sm->ctx = (void *)rd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (rd != NULL) DetectRpcFree(rd); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectRpcData * * \param rd pointer to DetectRpcData */ void DetectRpcFree(void *ptr) { SCEnter(); if (ptr == NULL) { SCReturn; } DetectRpcData *rd = (DetectRpcData *)ptr; SCFree(rd); SCReturn; } #ifdef UNITTESTS /** * \test DetectRpcTestParse01 is a test to make sure that we return "something" * when given valid rpc opt */ int DetectRpcTestParse01 (void) { int result = 0; DetectRpcData *rd = NULL; rd = DetectRpcParse("123,444,555"); if (rd != NULL) { DetectRpcFree(rd); result = 1; } return result; } /** * \test DetectRpcTestParse02 is a test for setting the established rpc opt */ int DetectRpcTestParse02 (void) { int result = 0; DetectRpcData *rd = NULL; rd = DetectRpcParse("111,222,333"); if (rd != NULL) { if (rd->flags & DETECT_RPC_CHECK_PROGRAM && rd->flags & DETECT_RPC_CHECK_VERSION && rd->flags & DETECT_RPC_CHECK_PROCEDURE && rd->program == 111 && rd->program_version == 222 && rd->procedure == 333) { result = 1; } else { SCLogDebug("Error: Flags: %d; program: %u, version: %u, procedure: %u", rd->flags, rd->program, rd->program_version, rd->procedure); } DetectRpcFree(rd); } return result; } /** * \test DetectRpcTestParse03 is a test for checking the wildcards * and not specified fields */ int DetectRpcTestParse03 (void) { int result = 1; DetectRpcData *rd = NULL; rd = DetectRpcParse("111,*,333"); if (rd == NULL) return 0; if ( !(rd->flags & DETECT_RPC_CHECK_PROGRAM && !(rd->flags & DETECT_RPC_CHECK_VERSION) && rd->flags & DETECT_RPC_CHECK_PROCEDURE && rd->program == 111 && rd->program_version == 0 && rd->procedure == 333)) result = 0; SCLogDebug("rd1 Flags: %d; program: %u, version: %u, procedure: %u", rd->flags, rd->program, rd->program_version, rd->procedure); DetectRpcFree(rd); rd = DetectRpcParse("111,222,*"); if (rd == NULL) return 0; if ( !(rd->flags & DETECT_RPC_CHECK_PROGRAM && rd->flags & DETECT_RPC_CHECK_VERSION && !(rd->flags & DETECT_RPC_CHECK_PROCEDURE) && rd->program == 111 && rd->program_version == 222 && rd->procedure == 0)) result = 0; SCLogDebug("rd2 Flags: %d; program: %u, version: %u, procedure: %u", rd->flags, rd->program, rd->program_version, rd->procedure); DetectRpcFree(rd); rd = DetectRpcParse("111,*,*"); if (rd == NULL) return 0; if ( !(rd->flags & DETECT_RPC_CHECK_PROGRAM && !(rd->flags & DETECT_RPC_CHECK_VERSION) && !(rd->flags & DETECT_RPC_CHECK_PROCEDURE) && rd->program == 111 && rd->program_version == 0 && rd->procedure == 0)) result = 0; SCLogDebug("rd2 Flags: %d; program: %u, version: %u, procedure: %u", rd->flags, rd->program, rd->program_version, rd->procedure); DetectRpcFree(rd); rd = DetectRpcParse("111,222"); if (rd == NULL) return 0; if ( !(rd->flags & DETECT_RPC_CHECK_PROGRAM && rd->flags & DETECT_RPC_CHECK_VERSION && !(rd->flags & DETECT_RPC_CHECK_PROCEDURE) && rd->program == 111 && rd->program_version == 222 && rd->procedure == 0)) result = 0; SCLogDebug("rd2 Flags: %d; program: %u, version: %u, procedure: %u", rd->flags, rd->program, rd->program_version, rd->procedure); DetectRpcFree(rd); rd = DetectRpcParse("111"); if (rd == NULL) return 0; if ( !(rd->flags & DETECT_RPC_CHECK_PROGRAM && !(rd->flags & DETECT_RPC_CHECK_VERSION) && !(rd->flags & DETECT_RPC_CHECK_PROCEDURE) && rd->program == 111 && rd->program_version == 0 && rd->procedure == 0)) result = 0; SCLogDebug("rd2 Flags: %d; program: %u, version: %u, procedure: %u", rd->flags, rd->program, rd->program_version, rd->procedure); DetectRpcFree(rd); return result; } /** * \test DetectRpcTestParse04 is a test for check the discarding of empty options */ int DetectRpcTestParse04 (void) { int result = 0; DetectRpcData *rd = NULL; rd = DetectRpcParse(""); if (rd == NULL) { result = 1; } else { SCLogDebug("Error: Flags: %d; program: %u, version: %u, procedure: %u", rd->flags, rd->program, rd->program_version, rd->procedure); DetectRpcFree(rd); } return result; } /** * \test DetectRpcTestParse05 is a test for check invalid values */ int DetectRpcTestParse05 (void) { int result = 0; DetectRpcData *rd = NULL; rd = DetectRpcParse("111,aaa,*"); if (rd == NULL) { result = 1; } else { SCLogDebug("Error: Flags: %d; program: %u, version: %u, procedure: %u", rd->flags, rd->program, rd->program_version, rd->procedure); DetectRpcFree(rd); } return result; } /** * \test DetectRpcTestParse05 is a test to check the match function */ static int DetectRpcTestSig01(void) { /* RPC Call */ uint8_t buf[] = { /* XID */ 0x64,0xb2,0xb3,0x75, /* Message type: Call (0) */ 0x00,0x00,0x00,0x00, /* RPC Version (2) */ 0x00,0x00,0x00,0x02, /* Program portmap (100000) */ 0x00,0x01,0x86,0xa0, /* Program version (2) */ 0x00,0x00,0x00,0x02, /* Program procedure (3) = GETPORT */ 0x00,0x00,0x00,0x03, /* AUTH_NULL */ 0x00,0x00,0x00,0x00, /* Length 0 */ 0x00,0x00,0x00,0x00, /* VERIFIER NULL */ 0x00,0x00,0x00,0x00, /* Length 0 */ 0x00,0x00,0x00,0x00, /* Program portmap */ 0x00,0x01,0x86,0xa2, /* Version 2 */ 0x00,0x00,0x00,0x02, /* Proto UDP */ 0x00,0x00,0x00,0x11, /* Port 0 */ 0x00,0x00,0x00,0x00 }; uint16_t buflen = sizeof(buf); Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_UDP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert udp any any -> any any (msg:\"RPC Get Port Call\"; rpc:100000, 2, 3; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert udp any any -> any any (msg:\"RPC Get Port Call\"; rpc:100000, 2, *; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert udp any any -> any any (msg:\"RPC Get Port Call\"; rpc:100000, *, 3; sid:3;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert udp any any -> any any (msg:\"RPC Get Port Call\"; rpc:100000, *, *; sid:4;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert udp any any -> any any (msg:\"RPC Get XXX Call.. no match\"; rpc:123456, *, 3; sid:5;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { printf("sid 1 didnt alert, but it should have: "); goto cleanup; } else if (PacketAlertCheck(p, 2) == 0) { printf("sid 2 didnt alert, but it should have: "); goto cleanup; } else if (PacketAlertCheck(p, 3) == 0) { printf("sid 3 didnt alert, but it should have: "); goto cleanup; } else if (PacketAlertCheck(p, 4) == 0) { printf("sid 4 didnt alert, but it should have: "); goto cleanup; } else if (PacketAlertCheck(p, 5) > 0) { printf("sid 5 did alert, but should not: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); UTHFreePackets(&p, 1); end: return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectRpc */ void DetectRpcRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectRpcTestParse01", DetectRpcTestParse01, 1); UtRegisterTest("DetectRpcTestParse02", DetectRpcTestParse02, 1); UtRegisterTest("DetectRpcTestParse03", DetectRpcTestParse03, 1); UtRegisterTest("DetectRpcTestParse04", DetectRpcTestParse04, 1); UtRegisterTest("DetectRpcTestParse05", DetectRpcTestParse05, 1); UtRegisterTest("DetectRpcTestSig01", DetectRpcTestSig01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-runmodes.h0000644000000000000000000000626212253546156014013 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Eric Leblond */ #ifndef __UTIL_RUNMODES_H__ #define __UTIL_RUNMODES_H__ typedef void *(*ConfigIfaceParserFunc) (const char *); typedef void *(*ConfigIPSParserFunc) (int); typedef int (*ConfigIfaceThreadsCountFunc) (void *); int RunModeSetLiveCaptureAuto(DetectEngineCtx *de_ctx, ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev); int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev); int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev); int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, char *recv_mod_name, char *decode_mod_name, char *thread_name, const char *live_dev); int RunModeSetIPSAuto(DetectEngineCtx *de_ctx, ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name); int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name); int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, ConfigIPSParserFunc ConfigParser, char *recv_mod_name, char *verdict_mod_name, char *decode_mod_name); #endif /* __UTIL_RUNMODES_H__ */ suricata-1.4.7/src/decode-raw.c0000644000000000000000000001400712253546156013205 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author William Metcalf * * Decode RAW */ #include "suricata-common.h" #include "decode.h" #include "decode-raw.h" #include "decode-events.h" #include "util-unittest.h" #include "util-debug.h" void DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_raw, tv->sc_perf_pca); /* If it is ipv4 or ipv6 it should at least be the size of ipv4 */ if (len < IPV4_HEADER_LEN) { ENGINE_SET_EVENT(p,IPV4_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 4) { SCLogDebug("IPV4 Packet"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if (IP_GET_RAW_VER(pkt) == 6) { SCLogDebug("IPV6 Packet"); DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else { SCLogDebug("Unknown ip version %" PRIu8 "", IP_GET_RAW_VER(pkt)); ENGINE_SET_EVENT(p,IPRAW_INVALID_IPV); } return; } #ifdef UNITTESTS #include "flow.h" #include "flow-util.h" /** DecodeRawtest01 * \brief Valid Raw packet * \retval 0 Expected test value */ static int DecodeRawTest01 (void) { /* IPV6/TCP/no eth header */ uint8_t raw_ip[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x28, 0x06, 0x40, 0x20, 0x01, 0x06, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x99, 0xcc, 0x70, 0x20, 0x01, 0x06, 0x18, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x8c, 0x9b, 0x00, 0x50, 0x6a, 0xe7, 0x07, 0x36, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0x30, 0x29, 0x9c, 0x00, 0x00, 0x02, 0x04, 0x05, 0x8c, 0x04, 0x02, 0x08, 0x0a, 0x00, 0xdd, 0x1a, 0x39, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); return 1; } FlowInitConfig(FLOW_QUIET); DecodeRaw(&tv, &dtv, p, raw_ip, GET_PKT_LEN(p), NULL); if (p->ip6h == NULL) { printf("expected a valid ipv6 header but it was NULL: "); FlowShutdown(); SCFree(p); return 1; } FlowShutdown(); SCFree(p); return 0; } /** DecodeRawtest02 * \brief Valid Raw packet * \retval 0 Expected test value */ static int DecodeRawTest02 (void) { /* IPV4/TCP/no eth header */ uint8_t raw_ip[] = { 0x45, 0x00, 0x00, 0x30, 0x00, 0xad, 0x40, 0x00, 0x7f, 0x06, 0xac, 0xc5, 0xc0, 0xa8, 0x67, 0x02, 0xc0, 0xa8, 0x66, 0x02, 0x0b, 0xc7, 0x00, 0x50, 0x1d, 0xb3, 0x12, 0x37, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, 0x40, 0x00, 0xb8, 0xc8, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); return 1; } FlowInitConfig(FLOW_QUIET); DecodeRaw(&tv, &dtv, p, raw_ip, GET_PKT_LEN(p), NULL); FlowShutdown(); if (p->ip4h == NULL) { printf("expected a valid ipv4 header but it was NULL: "); SCFree(p); return 1; } SCFree(p); return 0; } /** DecodeRawtest03 * \brief Valid Raw packet * \retval 0 Expected test value */ static int DecodeRawTest03 (void) { /* IPV13 */ uint8_t raw_ip[] = { 0xdf, 0x00, 0x00, 0x3d, 0x49, 0x42, 0x40, 0x00, 0x40, 0x06, 0xcf, 0x8a, 0x0a, 0x1f, 0x03, 0xaf, 0x0a, 0x1f, 0x0a, 0x02, 0xa5, 0xe7, 0xde, 0xad, 0x00, 0x0c, 0xe2, 0x0e, 0x8b, 0xfe, 0x0c, 0xe7, 0x80, 0x18, 0x00, 0xb7, 0xaf, 0xeb, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xab, 0x4f, 0x34, 0x40, 0x67, 0x31, 0x3b, 0x63, 0x61, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x3b }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); return 1; } FlowInitConfig(FLOW_QUIET); DecodeRaw(&tv, &dtv, p, raw_ip, GET_PKT_LEN(p), NULL); if (ENGINE_ISSET_EVENT(p,IPRAW_INVALID_IPV)) { FlowShutdown(); SCFree(p); return 0; } else { printf("expected IPRAW_INVALID_IPV to be set but it wasn't: "); } FlowShutdown(); SCFree(p); return 1; } #endif /* UNITTESTS */ /** * \brief Registers Raw unit tests * \todo More Raw tests */ void DecodeRawRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeRawTest01", DecodeRawTest01, 0); UtRegisterTest("DecodeRawTest02", DecodeRawTest02, 0); UtRegisterTest("DecodeRawTest03", DecodeRawTest03, 0); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/detect-engine-uri.c0000644000000000000000000031547712253546156014522 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien * \author Pablo Rincon Crespo * * Based on detect-engine-uri.c */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" /** \brief Do the content inspection & validation for a signature * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param sm SigMatch to inspect * \param f Flow * \param flags app layer flags * \param state App layer state * * \retval 0 no match * \retval 1 match */ int DetectEngineInspectPacketUris(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL || tx->request_uri_normalized == NULL) return 0; det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; //PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), // bstr_len(tx->request_uri_normalized)); /* Inspect all the uricontents fetched on each * transaction at the app layer */ int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_UMATCH], f, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_URI, NULL); if (r == 1) { return 1; } return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** \test Test a simple uricontent option */ static int UriTestSig01(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test uricontent option\"; " "uricontent:\"one\"; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } if (!PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the pcre /U option */ static int UriTestSig02(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /on HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test pcre /U option\"; " "pcre:/one/U; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted with payload2, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the pcre /U option */ static int UriTestSig03(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test pcre /U option\"; " "pcre:/blah/U; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the urilen option */ static int UriTestSig04(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test urilen option\"; " "urilen:>20; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the urilen option */ static int UriTestSig05(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test urilen option\"; " "urilen:>4; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the pcre /U option */ static int UriTestSig06(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test pcre /U option\"; " "pcre:/(oneself)+/U; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert on payload2, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the pcre /U option in combination with urilen */ static int UriTestSig07(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test pcre /U option with urilen \"; " "pcre:/(one){2,}(self)?/U; urilen:3<>20; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert, but it should: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the pcre /U option in combination with urilen */ static int UriTestSig08(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test pcre /U option with urilen\"; " "pcre:/(blabla){2,}(self)?/U; urilen:3<>20; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the pcre /U option in combination with urilen */ static int UriTestSig09(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test pcre /U option with urilen \"; " "pcre:/(one){2,}(self)?/U; urilen:<2; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test the uricontent option in combination with urilen */ static int UriTestSig10(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test uricontent with urilen option\"; " "uricontent:\"one\"; urilen:<2; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test content, uricontent, urilen, pcre /U options */ static int UriTestSig11(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test content, uricontent, pcre /U and urilen options\"; " "content:\"one\"; uricontent:\"one\"; pcre:/(one){2,}(self)?/U;" "urilen:<2; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test uricontent, urilen, pcre /U options */ static int UriTestSig12(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test pcre /U, uricontent and urilen option\"; " "uricontent:\"one\"; " "pcre:/(one)+self/U; urilen:>2; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test uricontent, urilen */ static int UriTestSig13(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test urilen option\"; " "urilen:>2; uricontent:\"one\"; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with pkt, but it should: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test uricontent, pcre /U */ static int UriTestSig14(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test uricontent option\"; " "uricontent:\"one\"; pcre:/one(self)?/U;sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with pkt, but it should: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test pcre /U with anchored regex (bug 155) */ static int UriTestSig15(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Test uricontent option\"; " "uricontent:\"one\"; pcre:/^\\/one(self)?$/U;sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with pkt, but it should: "); goto end; } DetectEngineStateReset(f.de_state); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test Test pcre /U with anchored regex (bug 155) */ static int UriTestSig16(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" "User-Agent: Mozilla/1.0/\r\n" "Host: 1.2.3.4\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; rev:9;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 2009024)) { printf("sig 1 didnt alert with pkt, but it should: "); goto end; } p->alerts.cnt = 0; DetectEngineStateReset(f.de_state); p->payload = http_buf2; p->payload_len = http_buf2_len; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 2009024)) { printf("sig 1 alerted, but it should not (host should not match): "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents */ static int UriTestSig17(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_big_big_string_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:\"this\"; uricontent:\"is\"; within:6; " "uricontent:\"big\"; within:8; " "uricontent:\"string\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents */ static int UriTestSig18(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_is_big_big_big_string_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:\"this\"; uricontent:\"is\"; within:9; " "uricontent:\"big\"; within:12; " "uricontent:\"string\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents */ static int UriTestSig19(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_this_now_is_is_____big_string_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:\"now\"; uricontent:\"this\"; " "uricontent:\"is\"; within:12; " "uricontent:\"big\"; within:8; " "uricontent:\"string\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents with offset */ static int UriTestSig20(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /_________thus_thus_is_a_big HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:\"thus\"; offset:8; " "uricontent:\"is\"; within:6; " "uricontent:\"big\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents with a negated content. */ static int UriTestSig21(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:\"fix\"; uricontent:\"this\"; within:6; " "uricontent:!\"and\"; distance:0; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test relative pcre. */ static int UriTestSig22(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_is_a_super_duper_" "nova_in_super_nova_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "pcre:/super/U; uricontent:\"nova\"; within:7; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents with a negated content. */ static int UriTestSig23(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:!\"fix_this_now\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents with a negated content. */ static int UriTestSig24(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:\"we_need_to\"; uricontent:!\"fix_this_now\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test normalized uricontents. */ static int UriTestSig25(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "pcre:/normalized/U; uricontent:\"normalized uri\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents with a negated content. */ static int UriTestSig26(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:\"fix_this\"; isdataat:4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents with a negated content. */ static int UriTestSig27(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "uricontent:\"fix_this\"; isdataat:!10,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig28(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " "uricontent:\"this\"; " "byte_extract:1,2,one,string,dec,relative; " "uricontent:\"ring\"; distance:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig29(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " "uricontent:\"this\"; " "byte_extract:1,2,one,string,dec,relative; " "uricontent:\"ring\"; distance:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig30(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " "uricontent:\"this\"; " "byte_extract:1,2,one,string,dec,relative; " "uricontent:\"_b5ig\"; offset:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig31(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " "uricontent:\"this\"; " "byte_extract:1,2,one,string,dec,relative; " "uricontent:\"his\"; depth:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig32(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " "uricontent:\"this\"; " "byte_extract:1,2,one,string,dec,relative; " "uricontent:\"g_st\"; within:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig33(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "urilen:15; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig34(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "urilen:15, norm; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig35(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "urilen:16; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it shouldn't have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig36(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "urilen:16, norm; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it shouldn't have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig37(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "urilen:17, raw; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int UriTestSig38(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative uricontents\"; " "urilen:18, raw; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it shouldn't have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } #endif /* UNITTESTS */ void UriRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("UriTestSig01", UriTestSig01, 1); UtRegisterTest("UriTestSig02", UriTestSig02, 1); UtRegisterTest("UriTestSig03", UriTestSig03, 1); UtRegisterTest("UriTestSig04", UriTestSig04, 1); UtRegisterTest("UriTestSig05", UriTestSig05, 1); UtRegisterTest("UriTestSig06", UriTestSig06, 1); UtRegisterTest("UriTestSig07", UriTestSig07, 1); UtRegisterTest("UriTestSig08", UriTestSig08, 1); UtRegisterTest("UriTestSig09", UriTestSig09, 1); UtRegisterTest("UriTestSig10", UriTestSig10, 1); UtRegisterTest("UriTestSig11", UriTestSig11, 1); UtRegisterTest("UriTestSig12", UriTestSig12, 1); UtRegisterTest("UriTestSig13", UriTestSig13, 1); UtRegisterTest("UriTestSig14", UriTestSig14, 1); UtRegisterTest("UriTestSig15", UriTestSig15, 1); UtRegisterTest("UriTestSig16", UriTestSig16, 1); UtRegisterTest("UriTestSig17", UriTestSig17, 1); UtRegisterTest("UriTestSig18", UriTestSig18, 1); UtRegisterTest("UriTestSig19", UriTestSig19, 1); UtRegisterTest("UriTestSig20", UriTestSig20, 1); UtRegisterTest("UriTestSig21", UriTestSig21, 1); UtRegisterTest("UriTestSig22", UriTestSig22, 1); UtRegisterTest("UriTestSig23", UriTestSig23, 1); UtRegisterTest("UriTestSig24", UriTestSig24, 1); UtRegisterTest("UriTestSig25", UriTestSig25, 1); UtRegisterTest("UriTestSig26", UriTestSig26, 1); UtRegisterTest("UriTestSig27", UriTestSig27, 1); UtRegisterTest("UriTestSig28", UriTestSig28, 1); UtRegisterTest("UriTestSig29", UriTestSig29, 1); UtRegisterTest("UriTestSig30", UriTestSig30, 1); UtRegisterTest("UriTestSig31", UriTestSig31, 1); UtRegisterTest("UriTestSig32", UriTestSig32, 1); UtRegisterTest("UriTestSig33", UriTestSig33, 1); UtRegisterTest("UriTestSig34", UriTestSig34, 1); UtRegisterTest("UriTestSig35", UriTestSig35, 1); UtRegisterTest("UriTestSig36", UriTestSig36, 1); UtRegisterTest("UriTestSig37", UriTestSig37, 1); UtRegisterTest("UriTestSig38", UriTestSig38, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/util-affinity.c0000644000000000000000000002337012253546156013762 00000000000000/* Copyright (C) 2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Eric Leblond * * CPU affinity related code and helper. */ #include "suricata-common.h" #define _THREAD_AFFINITY #include "util-affinity.h" #include "util-cpu.h" #include "conf.h" #include "threads.h" #include "queue.h" #include "runmodes.h" ThreadsAffinityType thread_affinity[MAX_CPU_SET] = { { .name = "receive-cpu-set", .mode_flag = EXCLUSIVE_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, }, { .name = "decode-cpu-set", .mode_flag = BALANCED_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, }, { .name = "stream-cpu-set", .mode_flag = BALANCED_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, }, { .name = "detect-cpu-set", .mode_flag = EXCLUSIVE_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, }, { .name = "verdict-cpu-set", .mode_flag = BALANCED_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, }, { .name = "reject-cpu-set", .mode_flag = BALANCED_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, }, { .name = "output-cpu-set", .mode_flag = BALANCED_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, }, { .name = "management-cpu-set", .mode_flag = BALANCED_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, }, }; int thread_affinity_init_done = 0; /** * \brief find affinity by its name * \retval a pointer to the affinity or NULL if not found */ ThreadsAffinityType * GetAffinityTypeFromName(const char *name) { int i; for (i = 0; i < MAX_CPU_SET; i++) { if (!strcmp(thread_affinity[i].name, name)) { return &thread_affinity[i]; } } return NULL; } #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ static void AffinitySetupInit() { int i, j; int ncpu = UtilCpuGetNumProcessorsConfigured(); SCLogDebug("Initialize affinity setup\n"); /* be conservative relatively to OS: use all cpus by default */ for (i = 0; i < MAX_CPU_SET; i++) { cpu_set_t *cs = &thread_affinity[i].cpu_set; CPU_ZERO(cs); for (j = 0; j < ncpu; j++) { CPU_SET(j, cs); } SCMutexInit(&thread_affinity[i].taf_mutex, NULL); } return; } static void build_cpuset(char *name, ConfNode *node, cpu_set_t *cpu) { ConfNode *lnode; TAILQ_FOREACH(lnode, &node->head, next) { int i; long int a,b; int stop = 0; int max = UtilCpuGetNumProcessorsOnline() - 1; if (!strcmp(lnode->val, "all")) { a = 0; b = max; stop = 1; } else if (index(lnode->val, '-') != NULL) { char *sep = index(lnode->val, '-'); char *end; a = strtoul(lnode->val, &end, 10); if (end != sep) { SCLogError(SC_ERR_INVALID_ARGUMENT, "%s: invalid cpu range (start invalid): \"%s\"", name, lnode->val); exit(EXIT_FAILURE); } b = strtol(sep + 1, &end, 10); if (end != sep + strlen(sep)) { SCLogError(SC_ERR_INVALID_ARGUMENT, "%s: invalid cpu range (end invalid): \"%s\"", name, lnode->val); exit(EXIT_FAILURE); } if (a > b) { SCLogError(SC_ERR_INVALID_ARGUMENT, "%s: invalid cpu range (bad order): \"%s\"", name, lnode->val); exit(EXIT_FAILURE); } if (b > max) { SCLogError(SC_ERR_INVALID_ARGUMENT, "%s: upper bound (%ld) of cpu set is too high, only %d cpu(s)", name, b, max + 1); } } else { char *end; a = strtoul(lnode->val, &end, 10); if (end != lnode->val + strlen(lnode->val)) { SCLogError(SC_ERR_INVALID_ARGUMENT, "%s: invalid cpu range (not an integer): \"%s\"", name, lnode->val); exit(EXIT_FAILURE); } b = a; } for (i = a; i<= b; i++) { CPU_SET(i, cpu); } if (stop) break; } } #endif /* OS_WIN32 and __OpenBSD__ */ /** * \brief Extract cpu affinity configuration from current config file */ void AffinitySetupLoadFromConfig() { #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ ConfNode *root = ConfGetNode("threading.cpu-affinity"); ConfNode *affinity; if (thread_affinity_init_done == 0) { AffinitySetupInit(); thread_affinity_init_done = 1; } SCLogDebug("Load affinity from config\n"); if (root == NULL) { SCLogInfo("can't get cpu-affinity node"); return; } TAILQ_FOREACH(affinity, &root->head, next) { ThreadsAffinityType *taf = GetAffinityTypeFromName(affinity->val); ConfNode *node = NULL; ConfNode *nprio = NULL; if (taf == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu-affinity type"); exit(EXIT_FAILURE); } else { SCLogInfo("Found affinity definition for \"%s\"", affinity->val); } CPU_ZERO(&taf->cpu_set); node = ConfNodeLookupChild(affinity->head.tqh_first, "cpu"); if (node == NULL) { SCLogInfo("unable to find 'cpu'"); } else { build_cpuset(affinity->val, node, &taf->cpu_set); } CPU_ZERO(&taf->lowprio_cpu); CPU_ZERO(&taf->medprio_cpu); CPU_ZERO(&taf->hiprio_cpu); nprio = ConfNodeLookupChild(affinity->head.tqh_first, "prio"); if (nprio != NULL) { node = ConfNodeLookupChild(nprio, "low"); if (node == NULL) { SCLogDebug("unable to find 'low' prio using default value"); } else { build_cpuset(affinity->val, node, &taf->lowprio_cpu); } node = ConfNodeLookupChild(nprio, "medium"); if (node == NULL) { SCLogDebug("unable to find 'medium' prio using default value"); } else { build_cpuset(affinity->val, node, &taf->medprio_cpu); } node = ConfNodeLookupChild(nprio, "high"); if (node == NULL) { SCLogDebug("unable to find 'high' prio using default value"); } else { build_cpuset(affinity->val, node, &taf->hiprio_cpu); } node = ConfNodeLookupChild(nprio, "default"); if (node != NULL) { if (!strcmp(node->val, "low")) { taf->prio = PRIO_LOW; } else if (!strcmp(node->val, "medium")) { taf->prio = PRIO_MEDIUM; } else if (!strcmp(node->val, "high")) { taf->prio = PRIO_HIGH; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu_affinity prio"); exit(EXIT_FAILURE); } SCLogInfo("Using default prio '%s'", node->val); } } node = ConfNodeLookupChild(affinity->head.tqh_first, "mode"); if (node != NULL) { if (!strcmp(node->val, "exclusive")) { taf->mode_flag = EXCLUSIVE_AFFINITY; } else if (!strcmp(node->val, "balanced")) { taf->mode_flag = BALANCED_AFFINITY; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu_affinity node"); exit(EXIT_FAILURE); } } node = ConfNodeLookupChild(affinity->head.tqh_first, "threads"); if (node != NULL) { taf->nb_threads = atoi(node->val); if (! taf->nb_threads) { SCLogError(SC_ERR_INVALID_ARGUMENT, "bad value for threads count"); exit(EXIT_FAILURE); } } } #endif /* OS_WIN32 and __OpenBSD__ */ } /** * \brief Return next cpu to use for a given thread family * \retval the cpu to used given by its id */ int AffinityGetNextCPU(ThreadsAffinityType *taf) { int ncpu = 0; #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ int iter = 0; SCMutexLock(&taf->taf_mutex); ncpu = taf->lcpu; while (!CPU_ISSET(ncpu, &taf->cpu_set) && iter < 2) { ncpu++; if (ncpu >= UtilCpuGetNumProcessorsOnline()) { ncpu = 0; iter++; } } if (iter == 2) { SCLogError(SC_ERR_INVALID_ARGUMENT, "cpu_set does not contains available cpus, cpu afinity conf is invalid"); } taf->lcpu = ncpu + 1; if (taf->lcpu >= UtilCpuGetNumProcessorsOnline()) taf->lcpu = 0; SCMutexUnlock(&taf->taf_mutex); SCLogInfo("Setting affinity on CPU %d", ncpu); #endif /* OS_WIN32 and __OpenBSD__ */ return ncpu; } suricata-1.4.7/src/util-profiling-rules.c0000644000000000000000000004227512253546156015277 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited. * \author Victor Julien * * An API for rule profiling operations. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "conf.h" #include "tm-threads.h" #include "util-unittest.h" #include "util-byte.h" #include "util-profiling.h" #include "util-profiling-locks.h" #ifdef PROFILING #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif /** * Extra data for rule profiling. */ typedef struct SCProfileData_ { uint32_t sid; uint32_t gid; uint32_t rev; uint64_t checks; uint64_t matches; uint64_t max; uint64_t ticks_match; uint64_t ticks_no_match; } SCProfileData; typedef struct SCProfileDetectCtx_ { uint32_t size; uint32_t id; SCProfileData *data; pthread_mutex_t data_m; } SCProfileDetectCtx; /** * Used for generating the summary data to print. */ typedef struct SCProfileSummary_ { uint32_t sid; uint32_t gid; uint32_t rev; uint64_t ticks; double avgticks; double avgticks_match; double avgticks_no_match; uint64_t checks; uint64_t matches; uint64_t max; uint64_t ticks_match; uint64_t ticks_no_match; } SCProfileSummary; extern int profiling_output_to_file; int profiling_rules_enabled = 0; static char *profiling_file_name = ""; static const char *profiling_file_mode = "a"; /** * Sort orders for dumping profiled rules. */ enum { SC_PROFILING_RULES_SORT_BY_TICKS = 0, SC_PROFILING_RULES_SORT_BY_AVG_TICKS, SC_PROFILING_RULES_SORT_BY_CHECKS, SC_PROFILING_RULES_SORT_BY_MATCHES, SC_PROFILING_RULES_SORT_BY_MAX_TICKS, SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, }; static int profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_TICKS; /** * Maximum number of rules to dump. */ static uint32_t profiling_rules_limit = UINT32_MAX; void SCProfilingRulesGlobalInit(void) { ConfNode *conf; const char *val; conf = ConfGetNode("profiling.rules"); if (conf != NULL) { if (ConfNodeChildValueIsTrue(conf, "enabled")) { profiling_rules_enabled = 1; val = ConfNodeLookupChildValue(conf, "sort"); if (val != NULL) { if (strcmp(val, "ticks") == 0) { profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_TICKS; } else if (strcmp(val, "avgticks") == 0) { profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_AVG_TICKS; } else if (strcmp(val, "avgticks_match") == 0) { profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH; } else if (strcmp(val, "avgticks_no_match") == 0) { profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH; } else if (strcmp(val, "checks") == 0) { profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_CHECKS; } else if (strcmp(val, "matches") == 0) { profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_MATCHES; } else if (strcmp(val, "maxticks") == 0) { profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_MAX_TICKS; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid profiling sort order: %s", val); exit(EXIT_FAILURE); } } val = ConfNodeLookupChildValue(conf, "limit"); if (val != NULL) { if (ByteExtractStringUint32(&profiling_rules_limit, 10, (uint16_t)strlen(val), val) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid limit: %s", val); exit(EXIT_FAILURE); } } const char *filename = ConfNodeLookupChildValue(conf, "filename"); if (filename != NULL) { char *log_dir; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; profiling_file_name = SCMalloc(PATH_MAX); if (unlikely(profiling_file_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); exit(EXIT_FAILURE); } snprintf(profiling_file_name, PATH_MAX, "%s/%s", log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { profiling_file_mode = "a"; } else { profiling_file_mode = "w"; } profiling_output_to_file = 1; } } } } /** * \brief Qsort comparison function to sort by ticks. */ static int SCProfileSummarySortByTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; return s1->ticks - s0->ticks; } /** * \brief Qsort comparison function to sort by average ticks per match. */ static int SCProfileSummarySortByAvgTicksMatch(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; return s1->avgticks_match - s0->avgticks_match; } /** * \brief Qsort comparison function to sort by average ticks per non match. */ static int SCProfileSummarySortByAvgTicksNoMatch(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; return s1->avgticks_no_match - s0->avgticks_no_match; } /** * \brief Qsort comparison function to sort by average ticks. */ static int SCProfileSummarySortByAvgTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; return s1->avgticks - s0->avgticks; } /** * \brief Qsort comparison function to sort by checks. */ static int SCProfileSummarySortByChecks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; return s1->checks - s0->checks; } /** * \brief Qsort comparison function to sort by matches. */ static int SCProfileSummarySortByMatches(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; return s1->matches - s0->matches; } /** * \brief Qsort comparison function to sort by max ticks. */ static int SCProfileSummarySortByMaxTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; return s1->max - s0->max; } void SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) { uint32_t i; FILE *fp; if (rules_ctx == NULL) return; struct timeval tval; struct tm *tms; if (profiling_output_to_file == 1) { fp = fopen(profiling_file_name, profiling_file_mode); if (fp == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", profiling_file_name, strerror(errno)); return; } } else { fp = stdout; } int summary_size = sizeof(SCProfileSummary) * rules_ctx->size; SCProfileSummary *summary = SCMalloc(summary_size); if (unlikely(summary == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for profiling summary"); return; } uint32_t count = rules_ctx->size; uint64_t total_ticks = 0; SCLogInfo("Dumping profiling data for %u rules.", count); memset(summary, 0, summary_size); for (i = 0; i < count; i++) { summary[i].sid = rules_ctx->data[i].sid; summary[i].rev = rules_ctx->data[i].rev; summary[i].gid = rules_ctx->data[i].gid; summary[i].ticks = rules_ctx->data[i].ticks_match + rules_ctx->data[i].ticks_no_match; summary[i].checks = rules_ctx->data[i].checks; if (summary[i].ticks > 0) { summary[i].avgticks = (long double)summary[i].ticks / (long double)summary[i].checks; } summary[i].matches = rules_ctx->data[i].matches; summary[i].max = rules_ctx->data[i].max; summary[i].ticks_match = rules_ctx->data[i].ticks_match; summary[i].ticks_no_match = rules_ctx->data[i].ticks_no_match; if (summary[i].ticks_match > 0) { summary[i].avgticks_match = (long double)summary[i].ticks_match / (long double)summary[i].matches; } if (summary[i].ticks_no_match > 0) { summary[i].avgticks_no_match = (long double)summary[i].ticks_no_match / ((long double)summary[i].checks - (long double)summary[i].matches); } total_ticks += summary[i].ticks; } switch (profiling_rules_sort_order) { case SC_PROFILING_RULES_SORT_BY_TICKS: qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByTicks); break; case SC_PROFILING_RULES_SORT_BY_AVG_TICKS: qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByAvgTicks); break; case SC_PROFILING_RULES_SORT_BY_CHECKS: qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByChecks); break; case SC_PROFILING_RULES_SORT_BY_MATCHES: qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByMatches); break; case SC_PROFILING_RULES_SORT_BY_MAX_TICKS: qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByMaxTicks); break; case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH: qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByAvgTicksMatch); break; case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH: qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByAvgTicksNoMatch); break; } gettimeofday(&tval, NULL); struct tm local_tm; tms = (struct tm *)SCLocalTime(tval.tv_sec, &local_tm); fprintf(fp, " ----------------------------------------------" "----------------------------\n"); fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour,tms->tm_min, tms->tm_sec); fprintf(fp, " ----------------------------------------------" "----------------------------\n"); fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match"); fprintf(fp, " -------- " "------------ " "-------- " "-------- " "------------ " "------ " "-------- " "-------- " "----------- " "----------- " "----------- " "-------------- " "\n"); for (i = 0; i < MIN(count, profiling_rules_limit); i++) { /* Stop dumping when we hit our first rule with 0 checks. Due * to sorting this will be the beginning of all the rules with * 0 checks. */ if (summary[i].checks == 0) break; double percent = (long double)summary[i].ticks / (long double)total_ticks * 100; fprintf(fp, " %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n", i + 1, summary[i].sid, summary[i].gid, summary[i].rev, summary[i].ticks, percent, summary[i].checks, summary[i].matches, summary[i].max, summary[i].avgticks, summary[i].avgticks_match, summary[i].avgticks_no_match); } fprintf(fp,"\n"); if (fp != stdout) fclose(fp); SCFree(summary); SCLogInfo("Done dumping profiling data."); } /** * \brief Register a rule profiling counter. * * \retval Returns the ID of the counter on success, 0 on failure. */ static uint16_t SCProfilingRegisterRuleCounter(SCProfileDetectCtx *ctx) { ctx->size++; return ctx->id++; } /** * \brief Update a rule counter. * * \param id The ID of this counter. * \param ticks Number of CPU ticks for this rule. * \param match Did the rule match? */ void SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *det_ctx, uint16_t id, uint64_t ticks, int match) { if (det_ctx != NULL && det_ctx->rule_perf_data != NULL && det_ctx->rule_perf_data_size > id) { SCProfileData *p = &det_ctx->rule_perf_data[id]; p->checks++; p->matches += match; if (ticks > p->max) p->max = ticks; if (match == 1) p->ticks_match += ticks; else p->ticks_no_match += ticks; } } SCProfileDetectCtx *SCProfilingRuleInitCtx(void) { SCProfileDetectCtx *ctx = SCMalloc(sizeof(SCProfileDetectCtx)); if (ctx != NULL) { memset(ctx, 0x00, sizeof(SCProfileDetectCtx)); if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { SCLogError(SC_ERR_MUTEX, "Failed to initialize hash table mutex."); exit(EXIT_FAILURE); } } return ctx; } void SCProfilingRuleDestroyCtx(SCProfileDetectCtx *ctx) { if (ctx != NULL) { SCProfilingRuleDump(ctx); if (ctx->data != NULL) SCFree(ctx->data); pthread_mutex_destroy(&ctx->data_m); SCFree(ctx); } } void SCProfilingRuleThreadSetup(SCProfileDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) { if (ctx == NULL) return; SCProfileData *a = SCMalloc(sizeof(SCProfileData) * ctx->size); if (a != NULL) { memset(a, 0x00, sizeof(SCProfileData) * ctx->size); det_ctx->rule_perf_data = a; det_ctx->rule_perf_data_size = ctx->size; } } static void SCProfilingRuleThreadMerge(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { if (de_ctx == NULL || de_ctx->profile_ctx == NULL || de_ctx->profile_ctx->data == NULL || det_ctx == NULL || det_ctx->rule_perf_data == NULL) return; int i; for (i = 0; i < det_ctx->rule_perf_data_size; i++) { de_ctx->profile_ctx->data[i].checks += det_ctx->rule_perf_data[i].checks; de_ctx->profile_ctx->data[i].matches += det_ctx->rule_perf_data[i].matches; de_ctx->profile_ctx->data[i].ticks_match += det_ctx->rule_perf_data[i].ticks_match; de_ctx->profile_ctx->data[i].ticks_no_match += det_ctx->rule_perf_data[i].ticks_no_match; if (det_ctx->rule_perf_data[i].max > de_ctx->profile_ctx->data[i].max) de_ctx->profile_ctx->data[i].max = det_ctx->rule_perf_data[i].max; } } void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *det_ctx) { if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->rule_perf_data == NULL) return; pthread_mutex_lock(&det_ctx->de_ctx->profile_ctx->data_m); SCProfilingRuleThreadMerge(det_ctx->de_ctx, det_ctx); pthread_mutex_unlock(&det_ctx->de_ctx->profile_ctx->data_m); } /** * \brief Register the rule profiling counters. * * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. */ void SCProfilingRuleInitCounters(DetectEngineCtx *de_ctx) { de_ctx->profile_ctx = SCProfilingRuleInitCtx(); BUG_ON(de_ctx->profile_ctx == NULL); Signature *sig = de_ctx->sig_list; uint32_t count = 0; while (sig != NULL) { sig->profiling_id = SCProfilingRegisterRuleCounter(de_ctx->profile_ctx); sig = sig->next; count++; } if (count > 0) { de_ctx->profile_ctx->data = SCMalloc(sizeof(SCProfileData) * de_ctx->profile_ctx->size); BUG_ON(de_ctx->profile_ctx->data == NULL); memset(de_ctx->profile_ctx->data, 0x00, sizeof(SCProfileData) * de_ctx->profile_ctx->size); sig = de_ctx->sig_list; while (sig != NULL) { de_ctx->profile_ctx->data[sig->profiling_id].sid = sig->id; de_ctx->profile_ctx->data[sig->profiling_id].gid = sig->gid; de_ctx->profile_ctx->data[sig->profiling_id].rev = sig->rev; sig = sig->next; } } SCLogInfo("Registered %"PRIu32" rule profiling counters.", count); } #endif /* PROFILING */ suricata-1.4.7/src/runmode-pcap.c0000644000000000000000000002761012253546156013571 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-pcap.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "util-device.h" #include "util-runmodes.h" #include "util-atomic.h" #include "util-misc.h" static const char *default_mode = NULL; const char *RunModeIdsGetDefaultMode(void) { return default_mode; } int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx); void RunModeIdsPcapRegister(void) { RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "single", "Single threaded pcap live mode", RunModeIdsPcapSingle); RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "auto", "Multi threaded pcap live mode", RunModeIdsPcapAuto); default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "autofp", "Multi threaded pcap live mode. Packets from " "each flow are assigned to a single detect thread, " "unlike \"pcap_live_auto\" where packets from " "the same flow can be processed by any detect " "thread", RunModeIdsPcapAutoFp); RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "workers", "Workers pcap live mode, each thread does all" " tasks from acquisition to logging", RunModeIdsPcapWorkers); return; } void PcapDerefConfig(void *conf) { PcapIfaceConfig *pfp = (PcapIfaceConfig *)conf; /* Pcap config is used only once but cost of this low. */ if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { SCFree(pfp); } } void *ParsePcapConfig(const char *iface) { char *threadsstr = NULL; ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *pcap_node; PcapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpbpf; char *tmpctype; intmax_t value; int promisc = 0; intmax_t snaplen = 0; if (unlikely(aconf == NULL)) { return NULL; } if (iface == NULL) { SCFree(aconf); return NULL; } memset(aconf, 0x00, sizeof(*aconf)); strlcpy(aconf->iface, iface, sizeof(aconf->iface)); aconf->buffer_size = 0; /* If set command line option has precedence over config */ if ((ConfGetInt("pcap.buffer-size", &value)) == 1) { SCLogInfo("Pcap will use %d buffer size", (int)value); aconf->buffer_size = value; } aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; aconf->bpf_filter = NULL; if ((ConfGet("bpf-filter", &tmpbpf)) == 1) { aconf->bpf_filter = tmpbpf; } SC_ATOMIC_INIT(aconf->ref); aconf->DerefFunc = PcapDerefConfig; aconf->threads = 1; /* Find initial node */ pcap_node = ConfGetNode("pcap"); if (pcap_node == NULL) { SCLogInfo("Unable to find pcap config using default value"); return aconf; } if_root = ConfNodeLookupKeyValue(pcap_node, "interface", iface); if_default = ConfNodeLookupKeyValue(pcap_node, "interface", "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find pcap config for " "interface %s, using default value", iface); return aconf; } /* If there is no setting for current interface use default one as main iface */ if (if_root == NULL) { if_root = if_default; if_default = NULL; } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { aconf->threads = 1; } else { if (threadsstr != NULL) { aconf->threads = (uint8_t)atoi(threadsstr); } } if (aconf->threads == 0) { aconf->threads = 1; } (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); if (aconf->buffer_size == 0) { char *s_limit = NULL; int ret; ret = ConfGetChildValueWithDefault(if_root, if_default, "buffer-size", &s_limit); if (ret == 1 && s_limit) { uint64_t bsize = 0; if (ParseSizeStringU64(s_limit, &bsize) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to parse pcap buffer size: %s", s_limit); } else { /* the string 2gb returns 2147483648 which is 1 to high * for a int. */ if (bsize == (uint64_t)((uint64_t)INT_MAX + (uint64_t)1)) bsize = (uint64_t)INT_MAX; if (bsize > INT_MAX) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to set pcap buffer size: 2gb max. %"PRIu64" > %d", bsize, INT_MAX); } else { aconf->buffer_size = (int)bsize; } } } } if (aconf->bpf_filter == NULL) { /* set bpf filter if we have one */ if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &tmpbpf) != 1) { SCLogDebug("could not get bpf or none specified"); } else { aconf->bpf_filter = tmpbpf; } } else { SCLogInfo("BPF filter set from command line or via old 'bpf-filter' option."); } if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (strcmp(tmpctype, "yes") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (strcmp(tmpctype, "no") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); } } aconf->promisc = LIBPCAP_PROMISC; if (ConfGetChildValueBoolWithDefault(if_root, if_default, "promisc", &promisc) != 1) { SCLogDebug("could not get promisc or none specified"); } else { aconf->promisc = promisc; } aconf->snaplen = 0; if (ConfGetChildValueIntWithDefault(if_root, if_default, "snaplen", &snaplen) != 1) { SCLogDebug("could not get snaplen or none specified"); } else { aconf->snaplen = snaplen; } return aconf; } int PcapConfigGeThreadsCount(void *conf) { PcapIfaceConfig *pfp = (PcapIfaceConfig *)conf; return pfp->threads; } /** * \brief Single thread version of the Pcap live processing. */ int RunModeIdsPcapSingle(DetectEngineCtx *de_ctx) { int ret; char *live_dev = NULL; SCEnter(); RunModeInitialize(); TimeModeSetLive(); (void)ConfGet("pcap.single-pcap-dev", &live_dev); ret = RunModeSetLiveCaptureSingle(de_ctx, ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", "PcapLive", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsPcapSingle initialised"); SCReturnInt(0); } /** * \brief RunModeIdsPcapAuto set up the following thread packet handlers: * - Receive thread (from iface pcap) * - Decode thread * - Stream thread * - Detect: If we have only 1 cpu, it will setup one Detect thread * If we have more than one, it will setup num_cpus - 1 * starting from the second cpu available. * - Respond/Reject thread * - Outputs thread * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * * \param de_ctx Pointer to the Detection Engine. * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ int RunModeIdsPcapAuto(DetectEngineCtx *de_ctx) { /* tname = Detect + cpuid, this is 11bytes length as max */ char *live_dev = NULL; int ret; SCEnter(); RunModeInitialize(); TimeModeSetLive(); (void) ConfGet("pcap.single-pcap-dev", &live_dev); ret = RunModeSetLiveCaptureAuto(de_ctx, ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", "RecvPcap", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsPcapAuto initialised"); SCReturnInt(0); } /** * \brief RunModIdsPcapAutoFp set up the following thread packet handlers: * - Receive thread (from pcap device) * - Decode thread * - Stream thread * - Detect: If we have only 1 cpu, it will setup one Detect thread * If we have more than one, it will setup num_cpus - 1 * starting from the second cpu available. * - Outputs thread * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * * \param de_ctx Pointer to the Detection Engine * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx) { int ret; char *live_dev = NULL; SCEnter(); RunModeInitialize(); TimeModeSetLive(); (void) ConfGet("pcap.single-pcap-dev", &live_dev); ret = RunModeSetLiveCaptureAutoFp(de_ctx, ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", "RxPcap", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsPcapAutoFp initialised"); SCReturnInt(0); } /** * \brief Workers version of the PCAP LIVE processing. * * Start N threads with each thread doing all the work. * */ int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx) { int ret; char *live_dev = NULL; SCEnter(); RunModeInitialize(); TimeModeSetLive(); (void) ConfGet("pcap.single-pcap-dev", &live_dev); ret = RunModeSetLiveCaptureWorkers(de_ctx, ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", "RxPcap", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsPcapWorkers initialised"); SCReturnInt(0); } suricata-1.4.7/src/app-layer-htp-file.c0000644000000000000000000013724212253546156014602 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * This file provides HTTP protocol file handling support for the engine * using HTP library. */ #include "suricata.h" #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "util-radix-tree.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-htp.h" #include "util-spm.h" #include "util-debug.h" #include "app-layer-htp.h" #include "util-time.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "flow-util.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "detect-parse.h" #include "conf.h" #include "util-memcmp.h" /** * \brief Open the file with "filename" and pass the first chunk * of data if any. * * \param s http state * \param filename name of the file * \param filename_len length of the name * \param data data chunk (if any) * \param data_len length of the data portion * \param direction flow direction * * \retval 0 ok * \retval -1 error * \retval -2 not handling files on this flow */ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, uint8_t *data, uint32_t data_len, uint16_t txid, uint8_t direction) { int retval = 0; uint8_t flags = 0; FileContainer *files = NULL; FileContainer *files_opposite = NULL; SCLogDebug("data %p data_len %"PRIu32, data, data_len); if (s == NULL) { SCReturnInt(-1); } if (direction & STREAM_TOCLIENT) { if (s->files_tc == NULL) { s->files_tc = FileContainerAlloc(); if (s->files_tc == NULL) { retval = -1; goto end; } } files = s->files_tc; files_opposite = s->files_ts; if ((s->flags & HTP_FLAG_STORE_FILES_TS) || ((s->flags & HTP_FLAG_STORE_FILES_TX_TS) && txid == s->store_tx_id)) { flags |= FILE_STORE; } if (s->f->flags & FLOW_FILE_NO_MAGIC_TC) { SCLogDebug("no magic for this flow in toclient direction, so none for this file"); flags |= FILE_NOMAGIC; } if (s->f->flags & FLOW_FILE_NO_MD5_TC) { SCLogDebug("no md5 for this flow in toclient direction, so none for this file"); flags |= FILE_NOMD5; } if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) { flags |= FILE_NOSTORE; } } else { if (s->files_ts == NULL) { s->files_ts = FileContainerAlloc(); if (s->files_ts == NULL) { retval = -1; goto end; } } files = s->files_ts; files_opposite = s->files_tc; if ((s->flags & HTP_FLAG_STORE_FILES_TC) || ((s->flags & HTP_FLAG_STORE_FILES_TX_TC) && txid == s->store_tx_id)) { flags |= FILE_STORE; } if (s->f->flags & FLOW_FILE_NO_MAGIC_TS) { SCLogDebug("no magic for this flow in toserver direction, so none for this file"); flags |= FILE_NOMAGIC; } if (s->f->flags & FLOW_FILE_NO_MD5_TS) { SCLogDebug("no md5 for this flow in toserver direction, so none for this file"); flags |= FILE_NOMD5; } if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) { flags |= FILE_NOSTORE; } } /* if the previous file is in the same txid, we reset the file part of the * stateful detection engine. We cannot do that here directly, because of * locking order. Flow is locked at this point and we can't lock flow * before de_state */ if (files != NULL && files->tail != NULL && files->tail->txid == txid) { SCLogDebug("new file in same tx, flagging http state for de_state reset"); if (direction & STREAM_TOCLIENT) { s->flags |= HTP_FLAG_NEW_FILE_TX_TC; } else { s->flags |= HTP_FLAG_NEW_FILE_TX_TS; } } if (files_opposite != NULL && files_opposite->tail != NULL && files_opposite->tail->txid == txid) { SCLogDebug("new file in same tx, flagging http state for de_state reset"); if (direction & STREAM_TOCLIENT) { SCLogDebug("flagging TC"); s->flags |= HTP_FLAG_NEW_FILE_TX_TC; } else { SCLogDebug("flagging TS"); s->flags |= HTP_FLAG_NEW_FILE_TX_TS; } } if (FileOpenFile(files, filename, filename_len, data, data_len, flags) == NULL) { retval = -1; } FileSetTx(files->tail, txid); FilePrune(files); end: SCReturnInt(retval); } /** * \brief Store a chunk of data in the flow * * \param s http state * \param data data chunk (if any) * \param data_len length of the data portion * \param direction flow direction * * \retval 0 ok * \retval -1 error * \retval -2 file doesn't need storing */ int HTPFileStoreChunk(HtpState *s, uint8_t *data, uint32_t data_len, uint8_t direction) { SCEnter(); int retval = 0; int result = 0; FileContainer *files = NULL; if (s == NULL) { SCReturnInt(-1); } if (direction & STREAM_TOCLIENT) { files = s->files_tc; } else { files = s->files_ts; } if (files == NULL) { SCLogDebug("no files in state"); retval = -1; goto end; } result = FileAppendData(files, data, data_len); if (result == -1) { SCLogDebug("appending data failed"); retval = -1; } else if (result == -2) { retval = -2; } FilePrune(files); end: SCReturnInt(retval); } /** * \brief Close the file in the flow * * \param s http state * \param data data chunk if any * \param data_len length of the data portion * \param flags flags to indicate events * \param direction flow direction * * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating * that the file isn't complete but we're stopping storing it. * * \retval 0 ok * \retval -1 error * \retval -2 not storing files on this flow/tx */ int HTPFileClose(HtpState *s, uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction) { SCEnter(); int retval = 0; int result = 0; FileContainer *files = NULL; if (s == NULL) { SCReturnInt(-1); } if (direction & STREAM_TOCLIENT) { files = s->files_tc; } else { files = s->files_ts; } if (files == NULL) { retval = -1; goto end; } result = FileCloseFile(files, data, data_len, flags); if (result == -1) { retval = -1; } else if (result == -2) { retval = -2; } FilePrune(files); end: SCReturnInt(retval); } #ifdef UNITTESTS static int HTPFileParserTest01(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); if (tx == NULL) { goto end; } if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) { printf("expected method POST, got %s \n", bstr_tocstr(tx->request_method)); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } static int HTPFileParserTest02(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 337\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"email\"\r\n" "\r\n" "someaddress@somedomain.lan\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); if (tx == NULL) { goto end; } if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) { printf("expected method POST, got %s \n", bstr_tocstr(tx->request_method)); goto end; } if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL || http_state->files_ts->tail->state != FILE_STATE_CLOSED) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } static int HTPFileParserTest03(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 337\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"email\"\r\n" "\r\n" "someaddress@somedomain.lan\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "file"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "content\r\n"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint8_t httpbuf6[] = "-----------------------------277531038314945--"; uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); if (tx == NULL) { goto end; } if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) { printf("expected method POST, got %s \n", bstr_tocstr(tx->request_method)); goto end; } if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL || http_state->files_ts->tail->state != FILE_STATE_CLOSED) { goto end; } if (http_state->files_ts->head->chunks_head->len != 11) { printf("filedata len not 11 but %u: ", http_state->files_ts->head->chunks_head->len); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } static int HTPFileParserTest04(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 373\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"email\"\r\n" "\r\n" "someaddress@somedomain.lan\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "content\r\n"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint8_t httpbuf6[] = "-----------------------------277531038314945--"; uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); if (tx == NULL) { goto end; } if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) { printf("expected method POST, got %s: ", bstr_tocstr(tx->request_method)); goto end; } if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL || http_state->files_ts->tail->state != FILE_STATE_CLOSED) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } static int HTPFileParserTest05(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 544\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" "-----------------------------277531038314945\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "FILECONTENT\r\n" "-----------------------------277531038314945--"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); if (tx == NULL) { goto end; } if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) { printf("expected method POST, got %s \n", bstr_tocstr(tx->request_method)); goto end; } if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL || http_state->files_ts->tail->state != FILE_STATE_CLOSED) { goto end; } if (http_state->files_ts->head == http_state->files_ts->tail) goto end; if (http_state->files_ts->head->next != http_state->files_ts->tail) goto end; if (http_state->files_ts->head->chunks_head->len != 11) { printf("expected 11 but file is %u bytes instead: ", http_state->files_ts->head->chunks_head->len); PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, http_state->files_ts->head->chunks_head->len); goto end; } if (memcmp("filecontent", http_state->files_ts->head->chunks_head->data, http_state->files_ts->head->chunks_head->len) != 0) { goto end; } if (http_state->files_ts->tail->chunks_head->len != 11) { printf("expected 11 but file is %u bytes instead: ", http_state->files_ts->tail->chunks_head->len); PrintRawDataFp(stdout, http_state->files_ts->tail->chunks_head->data, http_state->files_ts->tail->chunks_head->len); goto end; } if (memcmp("FILECONTENT", http_state->files_ts->tail->chunks_head->data, http_state->files_ts->tail->chunks_head->len) != 0) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } /** \test first multipart part contains file but doesn't end in first chunk */ static int HTPFileParserTest06(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 544\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" "-----------------------------27753103831494"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "FILECONTENT\r\n" "-----------------------------277531038314945--"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); if (tx == NULL) { goto end; } if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) { printf("expected method POST, got %s \n", bstr_tocstr(tx->request_method)); goto end; } if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL || http_state->files_ts->tail->state != FILE_STATE_CLOSED) { goto end; } if (http_state->files_ts->head == http_state->files_ts->tail) goto end; if (http_state->files_ts->head->next != http_state->files_ts->tail) goto end; if (http_state->files_ts->head->chunks_head->len != 11) { printf("expected 11 but file is %u bytes instead: ", http_state->files_ts->head->chunks_head->len); PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, http_state->files_ts->head->chunks_head->len); goto end; } if (memcmp("filecontent", http_state->files_ts->head->chunks_head->data, http_state->files_ts->head->chunks_head->len) != 0) { goto end; } if (http_state->files_ts->tail->chunks_head->len != 11) { printf("expected 11 but file is %u bytes instead: ", http_state->files_ts->tail->chunks_head->len); PrintRawDataFp(stdout, http_state->files_ts->tail->chunks_head->data, http_state->files_ts->tail->chunks_head->len); goto end; } if (memcmp("FILECONTENT", http_state->files_ts->tail->chunks_head->data, http_state->files_ts->tail->chunks_head->len) != 0) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } /** \test POST, but not multipart */ static int HTPFileParserTest07(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Length: 11\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "FILECONTENT"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); if (tx == NULL) { goto end; } if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) { printf("expected method POST, got %s \n", bstr_tocstr(tx->request_method)); goto end; } if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL || http_state->files_ts->tail->state != FILE_STATE_CLOSED) { printf("state != FILE_STATE_CLOSED"); goto end; } if (http_state->files_ts->head->chunks_head->len != 11) { printf("expected 11 but file is %u bytes instead: ", http_state->files_ts->head->chunks_head->len); PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, http_state->files_ts->head->chunks_head->len); goto end; } if (memcmp("FILECONTENT", http_state->files_ts->head->chunks_head->data, http_state->files_ts->head->chunks_head->len) != 0) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } static int HTPFileParserTest08(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "filecontent\r\n\r\n" "-----------------------------277531038314945--"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } AppLayerDecoderEvents *decoder_events = AppLayerGetDecoderEventsForFlow(f); if (decoder_events == NULL) { printf("no app events: "); goto end; } if (decoder_events->cnt != 2) { printf("expected 2 events: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } /** \test invalid header: Somereallylongheaderstr: has no value */ static int HTPFileParserTest09(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 337\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"email\"\r\n" "\r\n" "someaddress@somedomain.lan\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Somereallylongheaderstr:\r\n" "\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } AppLayerDecoderEvents *decoder_events = AppLayerGetDecoderEventsForFlow(f); if (decoder_events == NULL) { printf("no app events: "); goto end; } if (decoder_events->cnt != 1) { printf("expected 1 event: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } /** \test empty entries */ static int HTPFileParserTest10(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" "Content-Length: 337\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" "\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" "Somereallylongheaderstr: with a good value\r\n" "\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "filecontent\r\n" "-----------------------------277531038314945--"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } AppLayerDecoderEvents *decoder_events = AppLayerGetDecoderEventsForFlow(f); if (decoder_events != NULL) { printf("app events: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } /** \test filedata cut in two pieces */ static int HTPFileParserTest11(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Length: 1102\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n" "\r\n" "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n" "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n" "\r\n" "10\r\n" "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Disposition: form-data; name=\"js_enabled\"\r\n" "\r\n" "1" "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Disposition: form-data; name=\"signature\"\r\n" "\r\n" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Disposition: form-data; name=\"upload_files\"\r\n" "\r\n" "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Disposition: form-data; name=\"terms\"\r\n" "\r\n" "1" "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Disposition: form-data; name=\"file[]\"\r\n" "\r\n" "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Disposition: form-data; name=\"description[]\"\r\n" "\r\n" "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n" "Content-Type: application/msword\r\n" "\r\n" "FILE"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "CONTENT\r\n" "------WebKitFormBoundaryBRDbP74mBhBxsIdo--"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); goto end; } AppLayerDecoderEvents *decoder_events = AppLayerGetDecoderEventsForFlow(f); if (decoder_events != NULL) { printf("app events: "); goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); if (tx == NULL) { goto end; } if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) { printf("expected method POST, got %s \n", bstr_tocstr(tx->request_method)); goto end; } if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL || http_state->files_ts->tail->state != FILE_STATE_CLOSED) { printf("state != FILE_STATE_CLOSED: "); goto end; } if (http_state->files_ts->head->chunks_head->len != 11) { printf("expected 11 but file is %u bytes instead: ", http_state->files_ts->head->chunks_head->len); PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, http_state->files_ts->head->chunks_head->len); goto end; } if (memcmp("FILECONTENT", http_state->files_ts->head->chunks_head->data, http_state->files_ts->head->chunks_head->len) != 0) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } #endif /* UNITTESTS */ void HTPFileParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01, 1); UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02, 1); UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03, 1); UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04, 1); UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05, 1); UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06, 1); UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07, 1); UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08, 1); UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09, 1); UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10, 1); UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-sameip.c0000644000000000000000000001373612253546156013727 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus * * Implements the sameip keyword. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-sameip.h" #include "util-unittest.h" #include "util-unittest-helper.h" static int DetectSameipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectSameipSetup(DetectEngineCtx *, Signature *, char *); static void DetectSameipRegisterTests(void); /** * \brief Registration function for sameip: keyword * \todo add support for no_stream and stream_only */ void DetectSameipRegister(void) { sigmatch_table[DETECT_SAMEIP].name = "sameip"; sigmatch_table[DETECT_SAMEIP].desc = "check if the IP address of the source is the same as the IP address of the destination"; sigmatch_table[DETECT_SAMEIP].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#sameip"; sigmatch_table[DETECT_SAMEIP].Match = DetectSameipMatch; sigmatch_table[DETECT_SAMEIP].Setup = DetectSameipSetup; sigmatch_table[DETECT_SAMEIP].Free = NULL; sigmatch_table[DETECT_SAMEIP].RegisterTests = DetectSameipRegisterTests; } /** * \internal * \brief This function is used to match packets with same src/dst IPs * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectSameipData * * \retval 0 no match * \retval 1 match */ static int DetectSameipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { return CMP_ADDR(&p->src, &p->dst) ? 1 : 0; } /** * \internal * \brief this function is used to add the sameip option into the signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param optstr pointer to the user provided options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectSameipSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { SigMatch *sm = NULL; /* Get this into a SigMatch and put it in the Signature. */ sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_SAMEIP; sm->ctx = NULL; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (sm != NULL) SCFree(sm); return -1; } #ifdef UNITTESTS /* NOTE: No parameters, so no parse tests */ /** * \internal * \brief This test tests sameip success and failure. */ static int DetectSameipSigTest01Real(int mpm_type) { uint8_t *buf = (uint8_t *) "GET / HTTP/1.0\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); /* First packet has same IPs */ p1 = UTHBuildPacketSrcDst(buf, buflen, IPPROTO_TCP, "1.2.3.4", "1.2.3.4"); /* Second packet does not have same IPs */ p2 = UTHBuildPacketSrcDst(buf, buflen, IPPROTO_TCP, "1.2.3.4", "4.3.2.1"); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing sameip\"; sameip; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1) == 0) { printf("sid 2 did not alert, but should have: "); goto cleanup; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1) != 0) { printf("sid 2 alerted, but should not have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: return result; } /** * \test DetectSameipSigTest01B2g tests sameip under B2g MPM */ static int DetectSameipSigTest01B2g(void) { return DetectSameipSigTest01Real(MPM_B2G); } /** * \test DetectSameipSigTest01B2g tests sameip under B3g MPM */ static int DetectSameipSigTest01B3g(void) { return DetectSameipSigTest01Real(MPM_B3G); } /** * \test DetectSameipSigTest01B2g tests sameip under WuManber MPM */ static int DetectSameipSigTest01Wm(void) { return DetectSameipSigTest01Real(MPM_WUMANBER); } #endif /* UNITTESTS */ /** * \internal * \brief This function registers unit tests for DetectSameip */ static void DetectSameipRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectSameipSigTest01B2g", DetectSameipSigTest01B2g, 1); UtRegisterTest("DetectSameipSigTest01B3g", DetectSameipSigTest01B3g, 1); UtRegisterTest("DetectSameipSigTest01Wm", DetectSameipSigTest01Wm, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-engine-hhd.h0000644000000000000000000000271412253546156014456 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HHD_H__ #define __DETECT_ENGINE_HHD_H__ #include "app-layer-htp.h" int DetectEngineInspectHttpHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id); int DetectEngineRunHttpHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags); void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); void DetectEngineHttpHeaderRegisterTests(void); #endif /* __DETECT_ENGINE_HHD_H__ */ suricata-1.4.7/src/detect-within.h0000644000000000000000000000163712253546156013755 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_WITHIN_H__ #define __DETECT_WITHIN_H__ /* prototypes */ void DetectWithinRegister (void); #endif /* __DETECT_WITHIN_H__ */ suricata-1.4.7/src/defrag-timeout.c0000644000000000000000000000754012253546156014113 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #include "suricata-common.h" #include "defrag.h" #include "defrag-hash.h" uint32_t DefragTrackerGetSpareCount(void) { return DefragTrackerSpareQueueGetSize(); } uint32_t DefragTrackerGetActiveCount(void) { return SC_ATOMIC_GET(defragtracker_counter); } /** \internal * \brief See if we can really discard this tracker. Check use_cnt reference. * * \param dt tracker * \param ts timestamp * * \retval 0 not timed out just yet * \retval 1 fully timed out, lets kill it */ static int DefragTrackerTimedOut(DefragTracker *dt, struct timeval *ts) { /** never prune a trackers that is used by a packet * we are currently processing in one of the threads */ if (SC_ATOMIC_GET(dt->use_cnt) > 0) { return 0; } /* retain if remove is not set and not timed out */ if (!dt->remove && dt->timeout > (uint32_t)ts->tv_sec) return 0; return 1; } /** * \internal * * \brief check all trackers in a hash row for timing out * * \param hb tracker hash row *LOCKED* * \param dt last tracker in the hash row * \param ts timestamp * * \retval cnt timed out tracker */ static uint32_t DefragTrackerHashRowTimeout(DefragTrackerHashRow *hb, DefragTracker *dt, struct timeval *ts) { uint32_t cnt = 0; do { if (SCMutexTrylock(&dt->lock) != 0) { dt = dt->hprev; continue; } DefragTracker *next_dt = dt->hprev; /* check if the tracker is fully timed out and * ready to be discarded. */ if (DefragTrackerTimedOut(dt, ts) == 1) { /* remove from the hash */ if (dt->hprev != NULL) dt->hprev->hnext = dt->hnext; if (dt->hnext != NULL) dt->hnext->hprev = dt->hprev; if (hb->head == dt) hb->head = dt->hnext; if (hb->tail == dt) hb->tail = dt->hprev; dt->hnext = NULL; dt->hprev = NULL; DefragTrackerClearMemory(dt); /* no one is referring to this tracker, use_cnt 0, removed from hash * so we can unlock it and move it back to the spare queue. */ SCMutexUnlock(&dt->lock); /* move to spare list */ DefragTrackerMoveToSpare(dt); cnt++; } else { SCMutexUnlock(&dt->lock); } dt = next_dt; } while (dt != NULL); return cnt; } /** * \brief time out tracker from the hash * * \param ts timestamp * * \retval cnt number of timed out tracker */ uint32_t DefragTimeoutHash(struct timeval *ts) { uint32_t idx = 0; uint32_t cnt = 0; for (idx = 0; idx < defrag_config.hash_size; idx++) { DefragTrackerHashRow *hb = &defragtracker_hash[idx]; if (DRLOCK_TRYLOCK(hb) != 0) continue; /* defrag hash bucket is now locked */ if (hb->tail == NULL) { DRLOCK_UNLOCK(hb); continue; } /* we have a tracker, or more than one */ cnt += DefragTrackerHashRowTimeout(hb, hb->tail, ts); DRLOCK_UNLOCK(hb); } return cnt; } suricata-1.4.7/src/detect-engine-hscd.c0000644000000000000000000015333312253546156014633 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-hscd.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" /** * \brief Run the mpm against http stat code. * * \retval cnt Number of matches reported by the mpm algo. */ int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { SCEnter(); uint32_t cnt = 0; if (htp_state == NULL) { SCLogDebug("no HTTP state"); SCReturnInt(0); } /* locking the flow, we will inspect the htp state */ FLOWLOCK_RDLOCK(f); if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } int idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } htp_tx_t *tx = NULL; int size = (int)list_size(htp_state->connp->conn->transactions); for ( ; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->response_status == NULL) continue; cnt += HttpStatCodePatternSearch(det_ctx, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status), flags); } end: FLOWLOCK_UNLOCK(f); SCReturnInt(cnt); } /** * \brief Do the http_stat_code content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpStatCode(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL || tx->response_status == NULL) return 0; det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HSCDMATCH], f, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSCD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS static int DetectEngineHttpStatCodeTest01(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 message\r\n" "Content-Type: text/html\r\n" "Content-Length: 7\r\n" "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"200\"; http_stat_code; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest02(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 2000123 xxxxABC\r\n" "Content-Type: text/html\r\n" "Content-Length: 7\r\n" "\r\n" "xxxxABC"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"123\"; http_stat_code; offset:4; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpStatCodeTest03(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; int result = 0; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 123"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "456789\r\n" "Content-Type: text/html\r\n" "Content-Length: 17\r\n" "\r\n" "12345678901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"789\"; http_stat_code; offset:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest04(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:!\"200\"; http_stat_code; offset:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest05(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"200\"; http_stat_code; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest06(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:!\"123\"; http_stat_code; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:!\"123\"; http_stat_code; offset:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:!\"200\"; http_stat_code; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"200\"; http_stat_code; depth:3; " "content:\"123\"; http_stat_code; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"200\"; http_stat_code; depth:3; " "content:!\"124\"; http_stat_code; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest11(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"200\"; http_stat_code; depth:3; " "content:\"124\"; http_stat_code; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 did match but should not have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest12(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"20\"; http_stat_code; depth:2; " "content:\"23\"; http_stat_code; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest13(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "content:\"20\"; http_stat_code; depth:3; " "content:!\"25\"; http_stat_code; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest14(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "pcre:/20/S; " "content:\"23\"; http_stat_code; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatCodeTest15(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat code test\"; " "pcre:/200/S; " "content:!\"124\"; http_stat_code; distance:0; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpStatCodeRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpStatCodeTest01", DetectEngineHttpStatCodeTest01, 1); UtRegisterTest("DetectEngineHttpStatCodeTest02", DetectEngineHttpStatCodeTest02, 1); UtRegisterTest("DetectEngineHttpStatCodeTest03", DetectEngineHttpStatCodeTest03, 1); UtRegisterTest("DetectEngineHttpStatCodeTest04", DetectEngineHttpStatCodeTest04, 1); UtRegisterTest("DetectEngineHttpStatCodeTest05", DetectEngineHttpStatCodeTest05, 1); UtRegisterTest("DetectEngineHttpStatCodeTest06", DetectEngineHttpStatCodeTest06, 1); UtRegisterTest("DetectEngineHttpStatCodeTest07", DetectEngineHttpStatCodeTest07, 1); UtRegisterTest("DetectEngineHttpStatCodeTest08", DetectEngineHttpStatCodeTest08, 1); UtRegisterTest("DetectEngineHttpStatCodeTest09", DetectEngineHttpStatCodeTest09, 1); UtRegisterTest("DetectEngineHttpStatCodeTest10", DetectEngineHttpStatCodeTest10, 1); UtRegisterTest("DetectEngineHttpStatCodeTest11", DetectEngineHttpStatCodeTest11, 1); UtRegisterTest("DetectEngineHttpStatCodeTest12", DetectEngineHttpStatCodeTest12, 1); UtRegisterTest("DetectEngineHttpStatCodeTest13", DetectEngineHttpStatCodeTest13, 1); UtRegisterTest("DetectEngineHttpStatCodeTest14", DetectEngineHttpStatCodeTest14, 1); UtRegisterTest("DetectEngineHttpStatCodeTest15", DetectEngineHttpStatCodeTest15, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/util-proto-name.c0000644000000000000000000000637612253546156014241 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * File to provide the protocol names based on protocol numbers defined in the * specified protocol file. */ #include "suricata-common.h" #include "util-proto-name.h" /** * \brief Function to load the protocol names from the specified protocol * file. */ void SCProtoNameInit() { /* Load the known protocols name from the /etc/protocols file */ FILE *fp = fopen(PROTO_FILE,"r"); if (fp != NULL) { char line[200]; #if !defined(__WIN32) && !defined(_WIN32) char *ptr = NULL; #endif /* __WIN32 */ while(fgets(line, sizeof(line), fp) != NULL) { if (line[0] == '#') continue; #if defined(__WIN32) || defined(_WIN32) char *name = strtok(line," \t"); #else char *name = strtok_r(line," \t", &ptr); #endif /* __WIN32 */ if (name == NULL) continue; #if defined(__WIN32) || defined(_WIN32) char *proto_ch = strtok(NULL," \t"); #else char *proto_ch = strtok_r(NULL," \t", &ptr); #endif /* __WIN32 */ if (proto_ch == NULL) continue; int proto = atoi(proto_ch); if (proto >= 255) continue; #if defined(__WIN32) || defined(_WIN32) char *cname = strtok(NULL, " \t"); #else char *cname = strtok_r(NULL, " \t", &ptr); #endif /* __WIN32 */ if (cname != NULL) { known_proto[proto] = SCStrdup(cname); } else { known_proto[proto] = SCStrdup(name); } int proto_len = strlen(known_proto[proto]); if (proto_len > 0 && known_proto[proto][proto_len - 1] == '\n') known_proto[proto][proto_len - 1] = '\0'; } fclose(fp); } } /** * \brief Function to check if the received protocol number is valid and do * we have corresponding name entry for this number or not. * * \param proto Protocol number to be validated * \retval ret On success returns TRUE otherwise FALSE */ uint8_t SCProtoNameValid(uint16_t proto) { uint8_t ret = FALSE; if (proto <= 255 && known_proto[proto] != NULL) { ret = TRUE; } return ret; } /** * \brief Function to clears the memory used in storing the protocol names. */ void SCProtoNameDeInit() { /* clears the memory of loaded protocol names */ for (uint8_t cnt=0;cnt < 255;cnt++) { if(known_proto[cnt] != NULL) SCFree(known_proto[cnt]); } } suricata-1.4.7/src/detect-engine-hscd.h0000644000000000000000000000243412253546156014633 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HSCD_H__ #define __DETECT_ENGINE_HSCD_H__ #include "app-layer-htp.h" int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *, Flow *f, HtpState *, uint8_t); int DetectEngineInspectHttpStatCode(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); void DetectEngineHttpStatCodeRegisterTests(void); #endif /* __DETECT_ENGINE_HSCD_H__ */ suricata-1.4.7/src/threads.c0000644000000000000000000000744512253546156012635 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon Crespo * * This file now only contains unit tests see macros in threads.h */ #include "suricata-common.h" #include "util-unittest.h" #include "debug.h" #include "util-debug.h" #include "threads.h" #ifdef UNITTESTS /* UNIT TESTS */ /** * \brief Test Mutex macros */ int ThreadMacrosTest01Mutex(void) { SCMutex mut; int r = 0; r |= SCMutexInit(&mut, NULL); r |= SCMutexLock(&mut); r |= (SCMutexTrylock(&mut) == EBUSY)? 0 : 1; r |= SCMutexUnlock(&mut); r |= SCMutexDestroy(&mut); return (r == 0)? 1 : 0; } /** * \brief Test Spinlock Macros * * Valgrind's DRD tool (valgrind-3.5.0-Debian) reports: * * ==31156== Recursive locking not allowed: mutex 0x7fefff97c, recursion count 1, owner 1. * ==31156== at 0x4C2C77E: pthread_spin_trylock (drd_pthread_intercepts.c:829) * ==31156== by 0x40EB3E: ThreadMacrosTest02Spinlocks (threads.c:40) * ==31156== by 0x532E8A: UtRunTests (util-unittest.c:182) * ==31156== by 0x4065C3: main (suricata.c:789) * * To me this is a false positve, as the whole point of "trylock" is to see * if a spinlock is actually locked. * */ int ThreadMacrosTest02Spinlocks(void) { SCSpinlock mut; int r = 0; r |= SCSpinInit(&mut, 0); r |= SCSpinLock(&mut); #ifndef __OpenBSD__ r |= (SCSpinTrylock(&mut) == EBUSY)? 0 : 1; #else r |= (SCSpinTrylock(&mut) == EDEADLK)? 0 : 1; #endif r |= SCSpinUnlock(&mut); r |= SCSpinDestroy(&mut); return (r == 0)? 1 : 0; } /** * \brief Test RWLock macros */ int ThreadMacrosTest03RWLocks(void) { SCRWLock rwl_write; int r = 0; r |= SCRWLockInit(&rwl_write, NULL); r |= SCRWLockWRLock(&rwl_write); r |= (SCRWLockTryWRLock(&rwl_write) == EBUSY)? 0 : 1; r |= SCRWLockUnlock(&rwl_write); r |= SCRWLockDestroy(&rwl_write); return (r == 0)? 1 : 0; } /** * \brief Test RWLock macros */ int ThreadMacrosTest04RWLocks(void) { SCRWLock rwl_read; int r = 0; r |= SCRWLockInit(&rwl_read, NULL); r |= SCRWLockRDLock(&rwl_read); r |= (SCRWLockTryWRLock(&rwl_read) == EBUSY)? 0 : 1; r |= SCRWLockUnlock(&rwl_read); r |= SCRWLockDestroy(&rwl_read); return (r == 0)? 1 : 0; } /** * \brief Test RWLock macros */ int ThreadMacrosTest05RWLocks(void) { SCRWLock rwl_read; int r = 0; r |= SCRWLockInit(&rwl_read, NULL); r |= SCRWLockWRLock(&rwl_read); r |= (SCRWLockTryRDLock(&rwl_read) == EBUSY)? 0 : 1; r |= SCRWLockUnlock(&rwl_read); r |= SCRWLockDestroy(&rwl_read); return (r == 0)? 1 : 0; } #endif /* UNIT TESTS */ /** * \brief this function registers unit tests for DetectId */ void ThreadMacrosRegisterTests(void) { #ifdef UNITTESTS /* UNIT TESTS */ UtRegisterTest("ThreadMacrosTest01Mutex", ThreadMacrosTest01Mutex, 1); UtRegisterTest("ThreadMacrosTest02Spinlocks", ThreadMacrosTest02Spinlocks, 1); UtRegisterTest("ThreadMacrosTest03RWLocks", ThreadMacrosTest03RWLocks, 1); UtRegisterTest("ThreadMacrosTest04RWLocks", ThreadMacrosTest04RWLocks, 1); #endif /* UNIT TESTS */ } suricata-1.4.7/src/source-af-packet.c0000644000000000000000000014534112253546156014332 00000000000000/* Copyright (C) 2011,2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \defgroup afppacket AF_PACKET running mode * * @{ */ /** * \file * * \author Eric Leblond * * AF_PACKET socket acquisition support * * \todo watch other interface event to detect suppression of the monitored * interface */ #include "suricata-common.h" #include "config.h" #include "suricata.h" #include "decode.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tm-modules.h" #include "tm-threads.h" #include "tm-threads-common.h" #include "conf.h" #include "util-debug.h" #include "util-device.h" #include "util-error.h" #include "util-privs.h" #include "util-optimize.h" #include "util-checksum.h" #include "util-ioctl.h" #include "tmqh-packetpool.h" #include "source-af-packet.h" #include "runmodes.h" #ifdef HAVE_AF_PACKET #if HAVE_SYS_IOCTL_H #include #endif #if HAVE_LINUX_IF_ETHER_H #include #endif #if HAVE_LINUX_IF_PACKET_H #include #endif #if HAVE_LINUX_IF_ARP_H #include #endif #if HAVE_LINUX_FILTER_H #include #endif #if HAVE_SYS_MMAN_H #include #endif #endif /* HAVE_AF_PACKET */ extern uint8_t suricata_ctl_flags; extern int max_pending_packets; #ifndef HAVE_AF_PACKET TmEcode NoAFPSupportExit(ThreadVars *, void *, void **); void TmModuleReceiveAFPRegister (void) { tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; tmm_modules[TMM_RECEIVEAFP].ThreadInit = NoAFPSupportExit; tmm_modules[TMM_RECEIVEAFP].Func = NULL; tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; tmm_modules[TMM_RECEIVEAFP].cap_flags = 0; tmm_modules[TMM_RECEIVEAFP].flags = TM_FLAG_RECEIVE_TM; } /** * \brief Registration Function for DecodeAFP. * \todo Unit tests are needed for this module. */ void TmModuleDecodeAFPRegister (void) { tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; tmm_modules[TMM_DECODEAFP].ThreadInit = NoAFPSupportExit; tmm_modules[TMM_DECODEAFP].Func = NULL; tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEAFP].ThreadDeinit = NULL; tmm_modules[TMM_DECODEAFP].RegisterTests = NULL; tmm_modules[TMM_DECODEAFP].cap_flags = 0; tmm_modules[TMM_DECODEAFP].flags = TM_FLAG_DECODE_TM; } /** * \brief this function prints an error message and exits. */ TmEcode NoAFPSupportExit(ThreadVars *tv, void *initdata, void **data) { SCLogError(SC_ERR_NO_AF_PACKET,"Error creating thread %s: you do not have " "support for AF_PACKET enabled, on Linux host please recompile " "with --enable-af-packet", tv->name); exit(EXIT_FAILURE); } #else /* We have AF_PACKET support */ #define AFP_IFACE_NAME_LENGTH 48 #define AFP_STATE_DOWN 0 #define AFP_STATE_UP 1 #define AFP_RECONNECT_TIMEOUT 500000 #define AFP_DOWN_COUNTER_INTERVAL 40 #define POLL_TIMEOUT 100 #ifndef TP_STATUS_USER_BUSY /* for new use latest bit available in tp_status */ #define TP_STATUS_USER_BUSY (1 << 31) #endif /** protect pfring_set_bpf_filter, as it is not thread safe */ static SCMutex afpacket_bpf_set_filter_lock = PTHREAD_MUTEX_INITIALIZER; enum { AFP_READ_OK, AFP_READ_FAILURE, AFP_FAILURE, AFP_KERNEL_DROP, }; union thdr { struct tpacket2_hdr *h2; void *raw; }; /** * \brief Structure to hold thread specific variables. */ typedef struct AFPThreadVars_ { /* thread specific socket */ int socket; /* handle state */ unsigned char afp_state; /* data link type for the thread */ int datalink; int cooked; /* counters */ uint32_t pkts; uint64_t bytes; uint32_t errs; ThreadVars *tv; TmSlot *slot; uint8_t *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ char iface[AFP_IFACE_NAME_LENGTH]; LiveDevice *livedev; int down_count; /* Filter */ char *bpf_filter; /* socket buffer size */ int buffer_size; int promisc; ChecksumValidationMode checksum_mode; /* IPS stuff */ char out_iface[AFP_IFACE_NAME_LENGTH]; AFPPeer *mpeer; int flags; uint16_t capture_kernel_packets; uint16_t capture_kernel_drops; int cluster_id; int cluster_type; int threads; int copy_mode; struct tpacket_req req; unsigned int tp_hdrlen; unsigned int ring_buflen; char *ring_buf; char *frame_buf; unsigned int frame_offset; int ring_size; } AFPThreadVars; TmEcode ReceiveAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode ReceiveAFPThreadInit(ThreadVars *, void *, void **); void ReceiveAFPThreadExitStats(ThreadVars *, void *); TmEcode ReceiveAFPThreadDeinit(ThreadVars *, void *); TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot); TmEcode DecodeAFPThreadInit(ThreadVars *, void *, void **); TmEcode DecodeAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AFPSetBPFFilter(AFPThreadVars *ptv); static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose); static int AFPGetDevFlags(int fd, const char *ifname); static int AFPDerefSocket(AFPPeer* peer); static int AFPRefSocket(AFPPeer* peer); /** * \brief Registration Function for RecieveAFP. * \todo Unit tests are needed for this module. */ void TmModuleReceiveAFPRegister (void) { tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; tmm_modules[TMM_RECEIVEAFP].ThreadInit = ReceiveAFPThreadInit; tmm_modules[TMM_RECEIVEAFP].Func = NULL; tmm_modules[TMM_RECEIVEAFP].PktAcqLoop = ReceiveAFPLoop; tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = ReceiveAFPThreadExitStats; tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; tmm_modules[TMM_RECEIVEAFP].cap_flags = SC_CAP_NET_RAW; tmm_modules[TMM_RECEIVEAFP].flags = TM_FLAG_RECEIVE_TM; } /** * \defgroup afppeers AFP peers list * * AF_PACKET has an IPS mode were interface are peered: packet from * on interface are sent the peered interface and the other way. The ::AFPPeer * list is maitaining the list of peers. Each ::AFPPeer is storing the needed * information to be able to send packet on the interface. * A element of the list must not be destroyed during the run of Suricata as it * is used by ::Packet and other threads. * * @{ */ typedef struct AFPPeersList_ { TAILQ_HEAD(, AFPPeer_) peers; /**< Head of list of fragments. */ int cnt; int peered; int turn; /**< Next value for initialisation order */ SC_ATOMIC_DECLARE(int, reached); /**< Counter used to synchronize start */ } AFPPeersList; /** * \brief Update the peer. * * Update the AFPPeer of a thread ie set new state, socket number * or iface index. * */ void AFPPeerUpdate(AFPThreadVars *ptv) { if (ptv->mpeer == NULL) { return; } (void)SC_ATOMIC_SET(ptv->mpeer->if_idx, AFPGetIfnumByDev(ptv->socket, ptv->iface, 0)); (void)SC_ATOMIC_SET(ptv->mpeer->socket, ptv->socket); (void)SC_ATOMIC_SET(ptv->mpeer->state, ptv->afp_state); } /** * \brief Clean and free ressource used by an ::AFPPeer */ void AFPPeerClean(AFPPeer *peer) { if (peer->flags & AFP_SOCK_PROTECT) SCMutexDestroy(&peer->sock_protect); SC_ATOMIC_DESTROY(peer->socket); SC_ATOMIC_DESTROY(peer->if_idx); SC_ATOMIC_DESTROY(peer->state); SCFree(peer); } AFPPeersList peerslist; /** * \brief Init the global list of ::AFPPeer */ TmEcode AFPPeersListInit() { SCEnter(); TAILQ_INIT(&peerslist.peers); peerslist.peered = 0; peerslist.cnt = 0; peerslist.turn = 0; SC_ATOMIC_INIT(peerslist.reached); (void) SC_ATOMIC_SET(peerslist.reached, 0); SCReturnInt(TM_ECODE_OK); } /** * \brief Check that all ::AFPPeer got a peer * * \retval TM_ECODE_FAILED if some threads are not peered or TM_ECODE_OK else. */ TmEcode AFPPeersListCheck() { #define AFP_PEERS_MAX_TRY 4 #define AFP_PEERS_WAIT 20000 int try = 0; SCEnter(); while (try < AFP_PEERS_MAX_TRY) { if (peerslist.cnt != peerslist.peered) { usleep(AFP_PEERS_WAIT); } else { SCReturnInt(TM_ECODE_OK); } try++; } SCLogError(SC_ERR_AFP_CREATE, "Threads number not equals"); SCReturnInt(TM_ECODE_FAILED); } /** * \brief Declare a new AFP thread to AFP peers list. */ TmEcode AFPPeersListAdd(AFPThreadVars *ptv) { SCEnter(); AFPPeer *peer = SCMalloc(sizeof(AFPPeer)); AFPPeer *pitem; int mtu, out_mtu; if (unlikely(peer == NULL)) { SCReturnInt(TM_ECODE_FAILED); } memset(peer, 0, sizeof(AFPPeer)); SC_ATOMIC_INIT(peer->socket); SC_ATOMIC_INIT(peer->sock_usage); SC_ATOMIC_INIT(peer->if_idx); SC_ATOMIC_INIT(peer->state); peer->flags = ptv->flags; peer->turn = peerslist.turn++; if (peer->flags & AFP_SOCK_PROTECT) { SCMutexInit(&peer->sock_protect, NULL); } (void)SC_ATOMIC_SET(peer->sock_usage, 0); (void)SC_ATOMIC_SET(peer->state, AFP_STATE_DOWN); strlcpy(peer->iface, ptv->iface, AFP_IFACE_NAME_LENGTH); ptv->mpeer = peer; /* add element to iface list */ TAILQ_INSERT_TAIL(&peerslist.peers, peer, next); if (ptv->copy_mode != AFP_COPY_MODE_NONE) { peerslist.cnt++; /* Iter to find a peer */ TAILQ_FOREACH(pitem, &peerslist.peers, next) { if (pitem->peer) continue; if (strcmp(pitem->iface, ptv->out_iface)) continue; peer->peer = pitem; pitem->peer = peer; mtu = GetIfaceMTU(ptv->iface); out_mtu = GetIfaceMTU(ptv->out_iface); if (mtu != out_mtu) { SCLogError(SC_ERR_AFP_CREATE, "MTU on %s (%d) and %s (%d) are not equal, " "transmission of packets bigger than %d will fail.", ptv->iface, mtu, ptv->out_iface, out_mtu, (out_mtu > mtu) ? mtu : out_mtu); } peerslist.peered += 2; break; } } AFPPeerUpdate(ptv); SCReturnInt(TM_ECODE_OK); } int AFPPeersListWaitTurn(AFPPeer *peer) { /* If turn is zero, we already have started threads once */ if (peerslist.turn == 0) return 0; if (peer->turn == SC_ATOMIC_GET(peerslist.reached)) return 0; return 1; } void AFPPeersListReachedInc() { if (peerslist.turn == 0) return; if (SC_ATOMIC_ADD(peerslist.reached, 1) == peerslist.turn) { SCLogInfo("All AFP capture threads are running."); (void)SC_ATOMIC_SET(peerslist.reached, 0); /* Set turn to 0 to skip syncrhonization when ReceiveAFPLoop is * restarted. */ peerslist.turn = 0; } } /** * \brief Clean the global peers list. */ void AFPPeersListClean() { AFPPeer *pitem; while ((pitem = TAILQ_FIRST(&peerslist.peers))) { TAILQ_REMOVE(&peerslist.peers, pitem, next); AFPPeerClean(pitem); } } /** * @} */ /** * \brief Registration Function for DecodeAFP. * \todo Unit tests are needed for this module. */ void TmModuleDecodeAFPRegister (void) { tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; tmm_modules[TMM_DECODEAFP].ThreadInit = DecodeAFPThreadInit; tmm_modules[TMM_DECODEAFP].Func = DecodeAFP; tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEAFP].ThreadDeinit = NULL; tmm_modules[TMM_DECODEAFP].RegisterTests = NULL; tmm_modules[TMM_DECODEAFP].cap_flags = 0; tmm_modules[TMM_DECODEAFP].flags = TM_FLAG_DECODE_TM; } static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose); static inline void AFPDumpCounters(AFPThreadVars *ptv) { #ifdef PACKET_STATISTICS struct tpacket_stats kstats; socklen_t len = sizeof (struct tpacket_stats); if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, &kstats, &len) > -1) { SCLogDebug("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", ptv->tv->name, kstats.tp_packets, kstats.tp_drops); SCPerfCounterAddUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, kstats.tp_packets); SCPerfCounterAddUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->drop, kstats.tp_drops); } #endif } /** * \brief AF packet read function. * * This function fills * From here the packets are picked up by the DecodeAFP thread. * * \param user pointer to AFPThreadVars * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success */ int AFPRead(AFPThreadVars *ptv) { Packet *p = NULL; /* XXX should try to use read that get directly to packet */ int offset = 0; int caplen; struct sockaddr_ll from; struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr cmsg; char buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))]; } cmsg_buf; unsigned char aux_checksum = 0; msg.msg_name = &from; msg.msg_namelen = sizeof(from); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsg_buf; msg.msg_controllen = sizeof(cmsg_buf); msg.msg_flags = 0; if (ptv->cooked) offset = SLL_HEADER_LEN; else offset = 0; iov.iov_len = ptv->datalen - offset; iov.iov_base = ptv->data + offset; caplen = recvmsg(ptv->socket, &msg, MSG_TRUNC); if (caplen < 0) { SCLogWarning(SC_ERR_AFP_READ, "recvmsg failed with error code %" PRId32, errno); SCReturnInt(AFP_READ_FAILURE); } p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCReturnInt(AFP_FAILURE); } PKT_SET_SRC(p, PKT_SRC_WIRE); /* get timestamp of packet via ioctl */ if (ioctl(ptv->socket, SIOCGSTAMP, &p->ts) == -1) { SCLogWarning(SC_ERR_AFP_READ, "recvmsg failed with error code %" PRId32, errno); TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(AFP_READ_FAILURE); } ptv->pkts++; ptv->bytes += caplen + offset; (void) SC_ATOMIC_ADD(ptv->livedev->pkts, 1); p->livedev = ptv->livedev; /* add forged header */ if (ptv->cooked) { SllHdr * hdrp = (SllHdr *)ptv->data; /* XXX this is minimalist, but this seems enough */ hdrp->sll_protocol = from.sll_protocol; } p->datalink = ptv->datalink; SET_PKT_LEN(p, caplen + offset); if (PacketCopyData(p, ptv->data, GET_PKT_LEN(p)) == -1) { TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(AFP_FAILURE); } SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", GET_PKT_LEN(p), p, GET_PKT_DATA(p)); /* We only check for checksum disable */ if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { if (ptv->livedev->ignore_checksum) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (ChecksumAutoModeCheck(ptv->pkts, SC_ATOMIC_GET(ptv->livedev->pkts), SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { ptv->livedev->ignore_checksum = 1; p->flags |= PKT_IGNORE_CHECKSUM; } } else { aux_checksum = 1; } /* List is NULL if we don't have activated auxiliary data */ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { struct tpacket_auxdata *aux; if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) || cmsg->cmsg_level != SOL_PACKET || cmsg->cmsg_type != PACKET_AUXDATA) continue; aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg); if (aux_checksum && (aux->tp_status & TP_STATUS_CSUMNOTREADY)) { p->flags |= PKT_IGNORE_CHECKSUM; } break; } if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(AFP_FAILURE); } SCReturnInt(AFP_READ_OK); } TmEcode AFPWritePacket(Packet *p) { struct sockaddr_ll socket_address; int socket; if (p->afp_v.copy_mode == AFP_COPY_MODE_IPS) { if (PACKET_TEST_ACTION(p, ACTION_DROP)) { return TM_ECODE_OK; } } if (SC_ATOMIC_GET(p->afp_v.peer->state) == AFP_STATE_DOWN) return TM_ECODE_OK; if (p->ethh == NULL) { SCLogWarning(SC_ERR_INVALID_VALUE, "Should have an Ethernet header"); return TM_ECODE_FAILED; } /* Index of the network device */ socket_address.sll_ifindex = SC_ATOMIC_GET(p->afp_v.peer->if_idx); /* Address length*/ socket_address.sll_halen = ETH_ALEN; /* Destination MAC */ memcpy(socket_address.sll_addr, p->ethh, 6); /* Send packet, locking the socket if necessary */ if (p->afp_v.peer->flags & AFP_SOCK_PROTECT) SCMutexLock(&p->afp_v.peer->sock_protect); socket = SC_ATOMIC_GET(p->afp_v.peer->socket); if (sendto(socket, GET_PKT_DATA(p), GET_PKT_LEN(p), 0, (struct sockaddr*) &socket_address, sizeof(struct sockaddr_ll)) < 0) { SCLogWarning(SC_ERR_SOCKET, "Sending packet failed on socket %d: %s", socket, strerror(errno)); if (p->afp_v.peer->flags & AFP_SOCK_PROTECT) SCMutexUnlock(&p->afp_v.peer->sock_protect); return TM_ECODE_FAILED; } if (p->afp_v.peer->flags & AFP_SOCK_PROTECT) SCMutexUnlock(&p->afp_v.peer->sock_protect); return TM_ECODE_OK; } TmEcode AFPReleaseDataFromRing(ThreadVars *t, Packet *p) { int ret = TM_ECODE_OK; /* Need to be in copy mode and need to detect early release where Ethernet header could not be set (and pseudo packet) */ if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { ret = AFPWritePacket(p); } if (AFPDerefSocket(p->afp_v.mpeer) == 0) goto cleanup; if (p->afp_v.relptr) { union thdr h; h.raw = p->afp_v.relptr; h.h2->tp_status = TP_STATUS_KERNEL; } cleanup: AFPV_CLEANUP(&p->afp_v); return ret; } /** * \brief AF packet read function for ring * * This function fills * From here the packets are picked up by the DecodeAFP thread. * * \param user pointer to AFPThreadVars * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success */ int AFPReadFromRing(AFPThreadVars *ptv) { Packet *p = NULL; union thdr h; struct sockaddr_ll *from; uint8_t emergency_flush = 0; int read_pkts = 0; int loop_start = -1; /* Loop till we have packets available */ while (1) { if (unlikely(suricata_ctl_flags != 0)) { break; } /* Read packet from ring */ h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); if (h.raw == NULL) { SCReturnInt(AFP_FAILURE); } if (h.h2->tp_status == TP_STATUS_KERNEL) { if (read_pkts == 0) { if (loop_start == -1) { loop_start = ptv->frame_offset; } else if (unlikely(loop_start == (int)ptv->frame_offset)) { SCReturnInt(AFP_READ_OK); } if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { ptv->frame_offset = 0; } continue; } if ((emergency_flush) && (ptv->flags & AFP_EMERGENCY_MODE)) { SCReturnInt(AFP_KERNEL_DROP); } else { SCReturnInt(AFP_READ_OK); } } read_pkts++; loop_start = -1; /* Our packet is still used by suricata, we exit read loop to * gain some time */ if (h.h2->tp_status & TP_STATUS_USER_BUSY) { SCReturnInt(AFP_READ_OK); } if ((ptv->flags & AFP_EMERGENCY_MODE) && (emergency_flush == 1)) { h.h2->tp_status = TP_STATUS_KERNEL; goto next_frame; } p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCReturnInt(AFP_FAILURE); } PKT_SET_SRC(p, PKT_SRC_WIRE); /* Suricata will treat packet so telling it is busy, this * status will be reset to 0 (ie TP_STATUS_KERNEL) in the release * function. */ h.h2->tp_status |= TP_STATUS_USER_BUSY; from = (void *)h.raw + TPACKET_ALIGN(ptv->tp_hdrlen); ptv->pkts++; ptv->bytes += h.h2->tp_len; (void) SC_ATOMIC_ADD(ptv->livedev->pkts, 1); p->livedev = ptv->livedev; /* add forged header */ if (ptv->cooked) { SllHdr * hdrp = (SllHdr *)ptv->data; /* XXX this is minimalist, but this seems enough */ hdrp->sll_protocol = from->sll_protocol; } p->datalink = ptv->datalink; if (h.h2->tp_len > h.h2->tp_snaplen) { SCLogDebug("Packet length (%d) > snaplen (%d), truncating", h.h2->tp_len, h.h2->tp_snaplen); } if (ptv->flags & AFP_ZERO_COPY) { if (PacketSetData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) { TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(AFP_FAILURE); } else { p->afp_v.relptr = h.raw; p->ReleaseData = AFPReleaseDataFromRing; p->afp_v.mpeer = ptv->mpeer; AFPRefSocket(ptv->mpeer); p->afp_v.copy_mode = ptv->copy_mode; if (p->afp_v.copy_mode != AFP_COPY_MODE_NONE) { p->afp_v.peer = ptv->mpeer->peer; } else { p->afp_v.peer = NULL; } } } else { if (PacketCopyData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) { TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(AFP_FAILURE); } } /* Timestamp */ p->ts.tv_sec = h.h2->tp_sec; p->ts.tv_usec = h.h2->tp_nsec/1000; SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", GET_PKT_LEN(p), p, GET_PKT_DATA(p)); /* We only check for checksum disable */ if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { if (ptv->livedev->ignore_checksum) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (ChecksumAutoModeCheck(ptv->pkts, SC_ATOMIC_GET(ptv->livedev->pkts), SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { ptv->livedev->ignore_checksum = 1; p->flags |= PKT_IGNORE_CHECKSUM; } } else { if (h.h2->tp_status & TP_STATUS_CSUMNOTREADY) { p->flags |= PKT_IGNORE_CHECKSUM; } } if (h.h2->tp_status & TP_STATUS_LOSING) { emergency_flush = 1; AFPDumpCounters(ptv); } /* release frame if not in zero copy mode */ if (!(ptv->flags & AFP_ZERO_COPY)) { h.h2->tp_status = TP_STATUS_KERNEL; } if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { h.h2->tp_status = TP_STATUS_KERNEL; if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { ptv->frame_offset = 0; } TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(AFP_FAILURE); } next_frame: if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { ptv->frame_offset = 0; /* Get out of loop to be sure we will reach maintenance tasks */ SCReturnInt(AFP_READ_OK); } } SCReturnInt(AFP_READ_OK); } /** * \brief Reference socket * * \retval O in case of failure, 1 in case of success */ static int AFPRefSocket(AFPPeer* peer) { if (unlikely(peer == NULL)) return 0; (void)SC_ATOMIC_ADD(peer->sock_usage, 1); return 1; } /** * \brief Dereference socket * * \retval 1 if socket is still alive, 0 if not */ static int AFPDerefSocket(AFPPeer* peer) { if (SC_ATOMIC_SUB(peer->sock_usage, 1) == 0) { if (SC_ATOMIC_GET(peer->state) == AFP_STATE_DOWN) { SCLogInfo("Cleaning socket connected to '%s'", peer->iface); close(SC_ATOMIC_GET(peer->socket)); return 0; } } return 1; } void AFPSwitchState(AFPThreadVars *ptv, int state) { ptv->afp_state = state; ptv->down_count = 0; AFPPeerUpdate(ptv); /* Do cleaning if switching to down state */ if (state == AFP_STATE_DOWN) { if (ptv->frame_buf) { /* only used in reading phase, we can free it */ SCFree(ptv->frame_buf); ptv->frame_buf = NULL; } if (ptv->socket != -1) { /* we need to wait for all packets to return data */ if (SC_ATOMIC_SUB(ptv->mpeer->sock_usage, 1) == 0) { SCLogInfo("Cleaning socket connected to '%s'", ptv->iface); close(ptv->socket); ptv->socket = -1; } } } if (state == AFP_STATE_UP) { (void)SC_ATOMIC_SET(ptv->mpeer->sock_usage, 1); } } /** * \brief Try to reopen socket * * \retval 0 in case of success, negative if error occurs or a condition * is not met. */ static int AFPTryReopen(AFPThreadVars *ptv) { int afp_activate_r; ptv->down_count++; /* Don't reconnect till we have packet that did not release data */ if (SC_ATOMIC_GET(ptv->mpeer->sock_usage) != 0) { return -1; } afp_activate_r = AFPCreateSocket(ptv, ptv->iface, 0); if (afp_activate_r != 0) { if (ptv->down_count % AFP_DOWN_COUNTER_INTERVAL == 0) { SCLogWarning(SC_ERR_AFP_CREATE, "Can not open iface '%s'", ptv->iface); } return afp_activate_r; } SCLogInfo("Interface '%s' is back", ptv->iface); return 0; } /** * \brief Main AF_PACKET reading Loop function */ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); uint16_t packet_q_len = 0; AFPThreadVars *ptv = (AFPThreadVars *)data; struct pollfd fds; int r; TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; struct timeval current_time; ptv->slot = s->slot_next; if (ptv->afp_state == AFP_STATE_DOWN) { /* Wait for our turn, threads before us must have opened the socket */ while (AFPPeersListWaitTurn(ptv->mpeer)) { usleep(1000); } r = AFPCreateSocket(ptv, ptv->iface, 1); if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket"); } AFPPeersListReachedInc(); } if (ptv->afp_state == AFP_STATE_UP) { SCLogInfo("Thread %s using socket %d", tv->name, ptv->socket); } fds.fd = ptv->socket; fds.events = POLLIN; while (1) { /* Start by checking the state of our interface */ if (unlikely(ptv->afp_state == AFP_STATE_DOWN)) { int dbreak = 0; do { usleep(AFP_RECONNECT_TIMEOUT); if (suricata_ctl_flags != 0) { dbreak = 1; break; } r = AFPTryReopen(ptv); fds.fd = ptv->socket; } while (r < 0); if (dbreak == 1) break; } /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); r = poll(&fds, 1, POLL_TIMEOUT); if (suricata_ctl_flags != 0) { break; } if (r > 0 && (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { if (fds.revents & (POLLHUP | POLLRDHUP)) { AFPSwitchState(ptv, AFP_STATE_DOWN); continue; } else if (fds.revents & POLLERR) { char c; /* Do a recv to get errno */ if (recv(ptv->socket, &c, sizeof c, MSG_PEEK) != -1) continue; /* what, no error? */ SCLogError(SC_ERR_AFP_READ, "Error reading data from iface '%s': (%d" PRIu32 ") %s", ptv->iface, errno, strerror(errno)); AFPSwitchState(ptv, AFP_STATE_DOWN); continue; } else if (fds.revents & POLLNVAL) { SCLogError(SC_ERR_AFP_READ, "Invalid polling request"); AFPSwitchState(ptv, AFP_STATE_DOWN); continue; } } else if (r > 0) { if (ptv->flags & AFP_RING_MODE) { r = AFPReadFromRing(ptv); } else { /* AFPRead will call TmThreadsSlotProcessPkt on read packets */ r = AFPRead(ptv); } switch (r) { case AFP_READ_FAILURE: /* AFPRead in error: best to reset the socket */ SCLogError(SC_ERR_AFP_READ, "AFPRead error reading data from iface '%s': (%d" PRIu32 ") %s", ptv->iface, errno, strerror(errno)); AFPSwitchState(ptv, AFP_STATE_DOWN); continue; case AFP_FAILURE: AFPSwitchState(ptv, AFP_STATE_DOWN); SCReturnInt(TM_ECODE_FAILED); break; case AFP_READ_OK: /* Trigger one dump of stats every second */ TimeGet(¤t_time); if (current_time.tv_sec != last_dump) { AFPDumpCounters(ptv); last_dump = current_time.tv_sec; } break; case AFP_KERNEL_DROP: AFPDumpCounters(ptv); break; } } else if ((r < 0) && (errno != EINTR)) { SCLogError(SC_ERR_AFP_READ, "Error reading data from iface '%s': (%d" PRIu32 ") %s", ptv->iface, errno, strerror(errno)); AFPSwitchState(ptv, AFP_STATE_DOWN); continue; } SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); } static int AFPGetDevFlags(int fd, const char *ifname) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { SCLogError(SC_ERR_AFP_CREATE, "Unable to find type for iface \"%s\": %s", ifname, strerror(errno)); return -1; } return ifr.ifr_flags; } static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { if (verbose) SCLogError(SC_ERR_AFP_CREATE, "Unable to find iface %s: %s", ifname, strerror(errno)); return -1; } return ifr.ifr_ifindex; } static int AFPGetDevLinktype(int fd, const char *ifname) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { SCLogError(SC_ERR_AFP_CREATE, "Unable to find type for iface \"%s\": %s", ifname, strerror(errno)); return -1; } switch (ifr.ifr_hwaddr.sa_family) { case ARPHRD_LOOPBACK: return LINKTYPE_ETHERNET; case ARPHRD_PPP: return LINKTYPE_RAW; default: return ifr.ifr_hwaddr.sa_family; } } static int AFPComputeRingParams(AFPThreadVars *ptv, int order) { /* Compute structure: Target is to store all pending packets with a size equal to MTU + auxdata And we keep a decent number of block To do so: Compute frame_size (aligned to be able to fit in block Check which block size we need. Blocksize is a 2^n * pagesize We then need to get order, big enough to have frame_size < block size Find number of frame per block (divide) Fill in packet_req Compute frame size: described in packet_mmap.txt dependant on snaplen (need to use a variable ?) snaplen: MTU ? tp_hdrlen determine_version in daq_afpacket in V1: sizeof(struct tpacket_hdr); in V2: val in getsockopt(instance->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); */ int tp_hdrlen = sizeof(struct tpacket_hdr); int snaplen = default_packet_size; ptv->req.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); ptv->req.tp_block_size = getpagesize() << order; int frames_per_block = ptv->req.tp_block_size / ptv->req.tp_frame_size; if (frames_per_block == 0) { SCLogInfo("frame size to big"); return -1; } ptv->req.tp_frame_nr = ptv->ring_size; ptv->req.tp_block_nr = ptv->req.tp_frame_nr / frames_per_block + 1; /* exact division */ ptv->req.tp_frame_nr = ptv->req.tp_block_nr * frames_per_block; SCLogInfo("AF_PACKET RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d", ptv->req.tp_block_size, ptv->req.tp_block_nr, ptv->req.tp_frame_size, ptv->req.tp_frame_nr); return 1; } static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) { int r; struct packet_mreq sock_params; struct sockaddr_ll bind_address; int order; unsigned int i; int if_idx; /* open socket */ ptv->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (ptv->socket == -1) { SCLogError(SC_ERR_AFP_CREATE, "Couldn't create a AF_PACKET socket, error %s", strerror(errno)); goto error; } if_idx = AFPGetIfnumByDev(ptv->socket, devname, verbose); /* bind socket */ memset(&bind_address, 0, sizeof(bind_address)); bind_address.sll_family = AF_PACKET; bind_address.sll_protocol = htons(ETH_P_ALL); bind_address.sll_ifindex = if_idx; if (bind_address.sll_ifindex == -1) { if (verbose) SCLogError(SC_ERR_AFP_CREATE, "Couldn't find iface %s", devname); goto socket_err; } if (ptv->promisc != 0) { /* Force promiscuous mode */ memset(&sock_params, 0, sizeof(sock_params)); sock_params.mr_type = PACKET_MR_PROMISC; sock_params.mr_ifindex = bind_address.sll_ifindex; r = setsockopt(ptv->socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP,(void *)&sock_params, sizeof(sock_params)); if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, "Couldn't switch iface %s to promiscuous, error %s", devname, strerror(errno)); goto frame_err; } } if (ptv->checksum_mode == CHECKSUM_VALIDATION_KERNEL) { int val = 1; if (setsockopt(ptv->socket, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1 && errno != ENOPROTOOPT) { SCLogWarning(SC_ERR_NO_AF_PACKET, "'kernel' checksum mode not supported, failling back to full mode."); ptv->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } } /* set socket recv buffer size */ if (ptv->buffer_size != 0) { /* * Set the socket buffer size to the specified value. */ SCLogInfo("Setting AF_PACKET socket buffer to %d", ptv->buffer_size); if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF, &ptv->buffer_size, sizeof(ptv->buffer_size)) == -1) { SCLogError(SC_ERR_AFP_CREATE, "Couldn't set buffer size to %d on iface %s, error %s", ptv->buffer_size, devname, strerror(errno)); goto frame_err; } } r = bind(ptv->socket, (struct sockaddr *)&bind_address, sizeof(bind_address)); if (r < 0) { if (verbose) { if (errno == ENETDOWN) { SCLogError(SC_ERR_AFP_CREATE, "Couldn't bind AF_PACKET socket, iface %s is down", devname); } else { SCLogError(SC_ERR_AFP_CREATE, "Couldn't bind AF_PACKET socket to iface %s, error %s", devname, strerror(errno)); } } goto frame_err; } int if_flags = AFPGetDevFlags(ptv->socket, ptv->iface); if (if_flags == -1) { if (verbose) { SCLogError(SC_ERR_AFP_READ, "Can not acces to interface '%s'", ptv->iface); } goto frame_err; } if ((if_flags & IFF_UP) == 0) { if (verbose) { SCLogError(SC_ERR_AFP_READ, "Interface '%s' is down", ptv->iface); } goto frame_err; } if (ptv->flags & AFP_RING_MODE) { int val = TPACKET_V2; unsigned int len = sizeof(val); if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { if (errno == ENOPROTOOPT) { SCLogError(SC_ERR_AFP_CREATE, "Too old kernel giving up (need 2.6.27 at least)"); } SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); goto socket_err; } ptv->tp_hdrlen = val; val = TPACKET_V2; if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) { SCLogError(SC_ERR_AFP_CREATE, "Can't activate TPACKET_V2 on packet socket: %s", strerror(errno)); goto socket_err; } /* Allocate RX ring */ #define DEFAULT_ORDER 3 for (order = DEFAULT_ORDER; order >= 0; order--) { if (AFPComputeRingParams(ptv, order) != 1) { SCLogInfo("Ring parameter are incorrect. Please correct the devel"); } r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *) &ptv->req, sizeof(ptv->req)); if (r < 0) { if (errno == ENOMEM) { SCLogInfo("Memory issue with ring parameters. Retrying."); continue; } SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate RX Ring for iface %s: (%d) %s", devname, errno, strerror(errno)); goto socket_err; } else { break; } } if (order < 0) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate RX Ring for iface %s (order 0 failed)", devname); goto socket_err; } /* Allocate the Ring */ ptv->ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; ptv->ring_buf = mmap(0, ptv->ring_buflen, PROT_READ|PROT_WRITE, MAP_SHARED, ptv->socket, 0); if (ptv->ring_buf == MAP_FAILED) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); goto socket_err; } /* allocate a ring for each frame header pointer*/ ptv->frame_buf = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); if (ptv->frame_buf == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); goto mmap_err; } memset(ptv->frame_buf, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); /* fill the header ring with proper frame ptr*/ ptv->frame_offset = 0; for (i = 0; i < ptv->req.tp_block_nr; ++i) { void *base = &ptv->ring_buf[i * ptv->req.tp_block_size]; unsigned int j; for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { (((union thdr **)ptv->frame_buf)[ptv->frame_offset]) = base; base += ptv->req.tp_frame_size; } } ptv->frame_offset = 0; } SCLogInfo("Using interface '%s' via socket %d", (char *)devname, ptv->socket); #ifdef HAVE_PACKET_FANOUT /* add binded socket to fanout group */ if (ptv->threads > 1) { uint32_t option = 0; uint16_t mode = ptv->cluster_type; uint16_t id = ptv->cluster_id; option = (mode << 16) | (id & 0xffff); r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, "Coudn't set fanout mode, error %s", strerror(errno)); goto frame_err; } } #endif ptv->datalink = AFPGetDevLinktype(ptv->socket, ptv->iface); switch (ptv->datalink) { case ARPHRD_PPP: case ARPHRD_ATM: ptv->cooked = 1; } TmEcode rc; rc = AFPSetBPFFilter(ptv); if (rc == TM_ECODE_FAILED) { SCLogError(SC_ERR_AFP_CREATE, "Set AF_PACKET bpf filter \"%s\" failed.", ptv->bpf_filter); goto frame_err; } /* Init is ok */ AFPSwitchState(ptv, AFP_STATE_UP); return 0; frame_err: if (ptv->frame_buf) SCFree(ptv->frame_buf); mmap_err: /* Packet mmap does the cleaning when socket is closed */ socket_err: close(ptv->socket); ptv->socket = -1; error: return -1; } TmEcode AFPSetBPFFilter(AFPThreadVars *ptv) { struct bpf_program filter; struct sock_fprog fcode; int rc; if (!ptv->bpf_filter) return TM_ECODE_OK; SCMutexLock(&afpacket_bpf_set_filter_lock); SCLogInfo("Using BPF '%s' on iface '%s'", ptv->bpf_filter, ptv->iface); if (pcap_compile_nopcap(default_packet_size, /* snaplen_arg */ ptv->datalink, /* linktype_arg */ &filter, /* program */ ptv->bpf_filter, /* const char *buf */ 0, /* optimize */ 0 /* mask */ ) == -1) { SCLogError(SC_ERR_AFP_CREATE, "Filter compilation failed."); SCMutexUnlock(&afpacket_bpf_set_filter_lock); return TM_ECODE_FAILED; } SCMutexUnlock(&afpacket_bpf_set_filter_lock); if (filter.bf_insns == NULL) { SCLogError(SC_ERR_AFP_CREATE, "Filter badly setup."); return TM_ECODE_FAILED; } fcode.len = filter.bf_len; fcode.filter = (struct sock_filter*)filter.bf_insns; rc = setsockopt(ptv->socket, SOL_SOCKET, SO_ATTACH_FILTER, &fcode, sizeof(fcode)); if(rc == -1) { SCLogError(SC_ERR_AFP_CREATE, "Failed to attach filter: %s", strerror(errno)); return TM_ECODE_FAILED; } SCMutexUnlock(&afpacket_bpf_set_filter_lock); return TM_ECODE_OK; } /** * \brief Init function for ReceiveAFP. * * \param tv pointer to ThreadVars * \param initdata pointer to the interface passed from the user * \param data pointer gets populated with AFPThreadVars * * \todo Create a general AFP setup function. */ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); AFPIfaceConfig *afpconfig = initdata; if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL"); SCReturnInt(TM_ECODE_FAILED); } AFPThreadVars *ptv = SCMalloc(sizeof(AFPThreadVars)); if (unlikely(ptv == NULL)) { afpconfig->DerefFunc(afpconfig); SCReturnInt(TM_ECODE_FAILED); } memset(ptv, 0, sizeof(AFPThreadVars)); ptv->tv = tv; ptv->cooked = 0; strlcpy(ptv->iface, afpconfig->iface, AFP_IFACE_NAME_LENGTH); ptv->iface[AFP_IFACE_NAME_LENGTH - 1]= '\0'; ptv->livedev = LiveGetDevice(ptv->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } ptv->buffer_size = afpconfig->buffer_size; ptv->ring_size = afpconfig->ring_size; ptv->promisc = afpconfig->promisc; ptv->checksum_mode = afpconfig->checksum_mode; ptv->bpf_filter = NULL; ptv->threads = 1; #ifdef HAVE_PACKET_FANOUT ptv->cluster_type = PACKET_FANOUT_LB; ptv->cluster_id = 1; /* We only set cluster info if the number of reader threads is greater than 1 */ if (afpconfig->threads > 1) { ptv->cluster_id = afpconfig->cluster_id; ptv->cluster_type = afpconfig->cluster_type; ptv->threads = afpconfig->threads; } #endif ptv->flags = afpconfig->flags; if (afpconfig->bpf_filter) { ptv->bpf_filter = afpconfig->bpf_filter; } #ifdef PACKET_STATISTICS ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", ptv->tv, SC_PERF_TYPE_UINT64, "NULL"); ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", ptv->tv, SC_PERF_TYPE_UINT64, "NULL"); #endif char *active_runmode = RunmodeGetActive(); if (active_runmode && !strcmp("workers", active_runmode)) { ptv->flags |= AFP_ZERO_COPY; SCLogInfo("Enabling zero copy mode"); } else { /* If we are using copy mode we need a lock */ ptv->flags |= AFP_SOCK_PROTECT; } /* If we are in RING mode, then we can use ZERO copy * by using the data release mechanism */ if (ptv->flags & AFP_RING_MODE) { ptv->flags |= AFP_ZERO_COPY; SCLogInfo("Enabling zero copy mode by using data release call"); } ptv->copy_mode = afpconfig->copy_mode; if (ptv->copy_mode != AFP_COPY_MODE_NONE) { strlcpy(ptv->out_iface, afpconfig->out_iface, AFP_IFACE_NAME_LENGTH); ptv->out_iface[AFP_IFACE_NAME_LENGTH - 1]= '\0'; /* Warn about BPF filter consequence */ if (ptv->bpf_filter) { SCLogWarning(SC_WARN_UNCOMMON, "Enabling a BPF filter in IPS mode result" " in dropping all non matching packets."); } } if (AFPPeersListAdd(ptv) == TM_ECODE_FAILED) { SCFree(ptv); afpconfig->DerefFunc(afpconfig); SCReturnInt(TM_ECODE_FAILED); } #define T_DATA_SIZE 70000 ptv->data = SCMalloc(T_DATA_SIZE); if (ptv->data == NULL) { afpconfig->DerefFunc(afpconfig); SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } ptv->datalen = T_DATA_SIZE; #undef T_DATA_SIZE *data = (void *)ptv; afpconfig->DerefFunc(afpconfig); SCReturnInt(TM_ECODE_OK); } /** * \brief This function prints stats to the screen at exit. * \param tv pointer to ThreadVars * \param data pointer that gets cast into AFPThreadVars for ptv */ void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) { SCEnter(); AFPThreadVars *ptv = (AFPThreadVars *)data; #ifdef PACKET_STATISTICS AFPDumpCounters(ptv); SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->sc_perf_pca), (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->sc_perf_pca)); #endif SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } /** * \brief DeInit function closes af packet socket at exit. * \param tv pointer to ThreadVars * \param data pointer that gets cast into AFPThreadVars for ptv */ TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data) { AFPThreadVars *ptv = (AFPThreadVars *)data; AFPSwitchState(ptv, AFP_STATE_DOWN); if (ptv->data != NULL) { SCFree(ptv->data); ptv->data = NULL; } ptv->datalen = 0; ptv->bpf_filter = NULL; SCReturnInt(TM_ECODE_OK); } /** * \brief This function passes off to link type decoders. * * DecodeAFP reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param t pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into AFPThreadVars for ptv * \param pq pointer to the current PacketQueue */ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { case LINKTYPE_LINUX_SLL: DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p,GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; case LINKTYPE_PPP: DecodePPP(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; case LINKTYPE_RAW: DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodeAFP", p->datalink); break; } SCReturnInt(TM_ECODE_OK); } TmEcode DecodeAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if (dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; SCReturnInt(TM_ECODE_OK); } #endif /* HAVE_AF_PACKET */ /* eof */ /** * @} */ suricata-1.4.7/src/detect-tls-version.c0000644000000000000000000004632312253546156014734 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the tls.version keyword */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-ssl.h" #include "detect-tls-version.h" #include "stream-tcp.h" /** * \brief Regex for parsing "id" option, matching number or "number" */ #define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9\\.]+\")\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectTlsVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectTlsVersionRegisterTests(void); void DetectTlsVersionFree(void *); /** * \brief Registration function for keyword: tls.version */ void DetectTlsVersionRegister (void) { sigmatch_table[DETECT_AL_TLS_VERSION].name = "tls.version"; sigmatch_table[DETECT_AL_TLS_VERSION].desc = "match on TLS/SSL version"; sigmatch_table[DETECT_AL_TLS_VERSION].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsversion"; sigmatch_table[DETECT_AL_TLS_VERSION].Match = NULL; sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerMatch = DetectTlsVersionMatch; sigmatch_table[DETECT_AL_TLS_VERSION].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_VERSION].Setup = DetectTlsVersionSetup; sigmatch_table[DETECT_AL_TLS_VERSION].Free = DetectTlsVersionFree; sigmatch_table[DETECT_AL_TLS_VERSION].RegisterTests = DetectTlsVersionRegisterTests; const char *eb; int eo; int opts = 0; SCLogDebug("registering tls.version rule option"); parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief match the specified version on a tls session * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectTlsVersionData * * \retval 0 no match * \retval 1 match */ int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); DetectTlsVersionData *tls_data = (DetectTlsVersionData *)m->ctx; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); SCReturnInt(0); } int ret = 0; FLOWLOCK_RDLOCK(f); SCLogDebug("looking for tls_data->ver 0x%02X (flags 0x%02X)", tls_data->ver, flags); if (flags & STREAM_TOCLIENT) { SCLogDebug("server (toclient) version is 0x%02X", ssl_state->server_connp.version); if (tls_data->ver == ssl_state->server_connp.version) ret = 1; } else if (flags & STREAM_TOSERVER) { SCLogDebug("client (toserver) version is 0x%02X", ssl_state->client_connp.version); if (tls_data->ver == ssl_state->client_connp.version) ret = 1; } FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" * * \param idstr Pointer to the user provided id option * * \retval id_d pointer to DetectTlsVersionData on success * \retval NULL on failure */ DetectTlsVersionData *DetectTlsVersionParse (char *str) { uint16_t temp; DetectTlsVersionData *tls = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 3) { SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.version option"); goto error; } if (ret > 1) { const char *str_ptr; char *orig; char *tmp_str; res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct id option */ tls = SCMalloc(sizeof(DetectTlsVersionData)); if (unlikely(tls == NULL)) goto error; orig = SCStrdup((char*)str_ptr); if (unlikely(orig == NULL)) { goto error; } tmp_str=orig; /* Let's see if we need to scape "'s */ if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } if (strcmp("1.0", tmp_str) == 0) { temp = TLS_VERSION_10; } else if (strcmp("1.1", tmp_str) == 0) { temp = TLS_VERSION_11; } else if (strcmp("1.2", tmp_str) == 0) { temp = TLS_VERSION_12; } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid value"); goto error; } tls->ver = temp; SCFree(orig); SCLogDebug("will look for tls %"PRIu8"", tls->ver); } return tls; error: if (tls != NULL) DetectTlsVersionFree(tls); return NULL; } /** * \brief this function is used to add the parsed "id" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "id" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectTlsVersionData *tls = NULL; SigMatch *sm = NULL; tls = DetectTlsVersionParse(str); if (tls == 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_AL_TLS_VERSION; sm->ctx = (void *)tls; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_TLS; return 0; error: if (tls != NULL) DetectTlsVersionFree(tls); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectTlsVersionData * * \param id_d pointer to DetectTlsVersionData */ void DetectTlsVersionFree(void *ptr) { DetectTlsVersionData *id_d = (DetectTlsVersionData *)ptr; SCFree(id_d); } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectTlsVersionTestParse01 is a test to make sure that we parse the "id" * option correctly when given valid id option */ int DetectTlsVersionTestParse01 (void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse("1.0"); if (tls != NULL && tls->ver == TLS_VERSION_10) { DetectTlsVersionFree(tls); return 1; } return 0; } /** * \test DetectTlsVersionTestParse02 is a test to make sure that we parse the "id" * option correctly when given an invalid id option * it should return id_d = NULL */ int DetectTlsVersionTestParse02 (void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse("2.5"); if (tls == NULL) { DetectTlsVersionFree(tls); return 1; } return 0; } #include "stream-tcp-reassemble.h" /** \test Send a get request in three chunks + more data. */ static int DetectTlsVersionTestDetect01(void) { int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); uint8_t tlsbuf2[] = { 0x03 }; uint32_t tlslen2 = sizeof(tlsbuf2); uint8_t tlsbuf3[] = { 0x01 }; uint32_t tlslen3 = sizeof(tlsbuf3); uint8_t tlsbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x01 }; uint32_t tlslen4 = sizeof(tlsbuf4); TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_TLS; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; tls.version:1.0; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); goto end; } SCLogDebug("ssl_state is at %p, ssl_state->server_version 0x%02X " "ssl_state->client_version 0x%02X", ssl_state, ssl_state->server_connp.version, ssl_state->client_connp.version); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectTlsVersionTestDetect02(void) { int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); uint8_t tlsbuf2[] = { 0x03 }; uint32_t tlslen2 = sizeof(tlsbuf2); uint8_t tlsbuf3[] = { 0x01 }; uint32_t tlslen3 = sizeof(tlsbuf3); uint8_t tlsbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x02 }; uint32_t tlslen4 = sizeof(tlsbuf4); TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_TLS; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; tls.version:1.0; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("signature 1 didn't match while it should have: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectTlsVersionTestDetect03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); uint8_t tlsbuf2[] = { 0x03 }; uint32_t tlslen2 = sizeof(tlsbuf2); uint8_t tlsbuf3[] = { 0x01 }; uint32_t tlslen3 = sizeof(tlsbuf3); uint8_t tlsbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x02 }; uint32_t tlslen4 = sizeof(tlsbuf4); TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->tcph->th_seq = htonl(1000); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_TLS; f.proto = p->proto; StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); if (stream_msg == NULL) { printf("no stream_msg: "); goto end; } memcpy(stream_msg->data.data, tlsbuf4, tlslen4); stream_msg->data.data_len = tlslen4; ssn.toserver_smsg_head = stream_msg; ssn.toserver_smsg_tail = stream_msg; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"TLS\"; tls.version:1.0; content:\"|01 00 00 AD|\"; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("signature 1 didn't match while it should have: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectTlsVersion */ void DetectTlsVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectTlsVersionTestParse01", DetectTlsVersionTestParse01, 1); UtRegisterTest("DetectTlsVersionTestParse02", DetectTlsVersionTestParse02, 1); UtRegisterTest("DetectTlsVersionTestDetect01", DetectTlsVersionTestDetect01, 1); UtRegisterTest("DetectTlsVersionTestDetect02", DetectTlsVersionTestDetect02, 1); UtRegisterTest("DetectTlsVersionTestDetect03", DetectTlsVersionTestDetect03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-cidr.c0000644000000000000000000000232612253546156013070 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * CIDR utility functions */ #include "suricata-common.h" static uint32_t cidrs[33]; void CIDRInit(void) { int i = 0; /* skip 0 as it will result in 0xffffffff */ cidrs[0] = 0; for (i = 1; i < 33; i++) { cidrs[i] = htonl(0xFFFFFFFF << (32 - i)); //printf("CIDRInit: cidrs[%02d] = 0x%08X\n", i, cidrs[i]); } } uint32_t CIDRGet(int cidr) { if (cidr < 0 || cidr > 32) return 0; return cidrs[cidr]; } suricata-1.4.7/src/detect-engine-tag.c0000644000000000000000000004353512253546156014467 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file detect-engine-tag.c * * \author Victor Julien * \author Pablo Rincon Crespo * * Implements a global context to store data related to hosts flagged * tag keyword */ #include "suricata-common.h" #include "util-hash.h" #include "util-atomic.h" #include "util-time.h" #include "util-hashlist.h" #include "detect-engine-tag.h" #include "detect-tag.h" #include "host.h" SC_ATOMIC_DECLARE(unsigned int, num_tags); /**< Atomic counter, to know if we have tagged hosts/sessions, to avoid locking */ void TagInitCtx(void) { SC_ATOMIC_INIT(num_tags); } /** * \brief Destroy tag context hash tables * * \param tag_ctx Tag Context * */ void TagDestroyCtx(void) { #ifdef DEBUG BUG_ON(SC_ATOMIC_GET(num_tags) != 0); #endif SC_ATOMIC_DESTROY(num_tags); } /** \brief Reset the tagging engine context */ void TagRestartCtx() { TagDestroyCtx(); TagInitCtx(); } static DetectTagDataEntry *DetectTagDataCopy(DetectTagDataEntry *dtd) { DetectTagDataEntry *tde = SCMalloc(sizeof(DetectTagDataEntry)); if (unlikely(tde == NULL)) { return NULL; } memset(tde, 0, sizeof(DetectTagDataEntry)); tde->sid = dtd->sid; tde->gid = dtd->gid; tde->flags = dtd->flags; tde->metric = dtd->metric; tde->count = dtd->count; tde->first_ts = dtd->first_ts; tde->last_ts = dtd->last_ts; return tde; } /** * \brief This function is used to add a tag to a session (type session) * or update it if it's already installed. The number of times to * allow an update is limited by DETECT_TAG_MATCH_LIMIT. This way * repetitive matches to the same rule are limited of setting tags, * to avoid DOS attacks * * \param p pointer to the current packet * \param tde pointer to the new DetectTagDataEntry * * \retval 0 if the tde was added succesfuly * \retval 1 if an entry of this sid/gid already exist and was updated */ int TagFlowAdd(Packet *p, DetectTagDataEntry *tde) { uint8_t updated = 0; uint16_t num_tags = 0; DetectTagDataEntry *iter = NULL; if (p->flow == NULL) return 1; FLOWLOCK_WRLOCK(p->flow); if (p->flow->tag_list != NULL) { iter = p->flow->tag_list; /* First iterate installed entries searching a duplicated sid/gid */ for (; iter != NULL; iter = iter->next) { num_tags++; if (iter->sid == tde->sid && iter->gid == tde->gid) { iter->cnt_match++; /* If so, update data, unless the maximum MATCH limit is * reached. This prevents possible DOS attacks */ if (iter->cnt_match < DETECT_TAG_MATCH_LIMIT) { /* Reset time and counters */ iter->first_ts = iter->last_ts = tde->first_ts; iter->packets = 0; iter->bytes = 0; } updated = 1; break; } } } /* If there was no entry of this rule, prepend the new tde */ if (updated == 0 && num_tags < DETECT_TAG_MAX_TAGS) { DetectTagDataEntry *new_tde = DetectTagDataCopy(tde); if (new_tde != NULL) { new_tde->next = p->flow->tag_list; p->flow->tag_list = new_tde; (void) SC_ATOMIC_ADD(num_tags, 1); } } else if (num_tags == DETECT_TAG_MAX_TAGS) { SCLogDebug("Max tags for sessions reached (%"PRIu16")", num_tags); } FLOWLOCK_UNLOCK(p->flow); return updated; } /** * \brief Add a tag entry for a host. If it already exist, update it. * * \param tag_ctx Tag context for hosts * \param tde Tag data * \param p packet * * \retval 0 if it was added, 1 if it was updated */ int TagHashAddTag(DetectTagDataEntry *tde, Packet *p) { SCEnter(); uint8_t updated = 0; uint16_t num_tags = 0; Host *host = NULL; /* Lookup host in the hash. If it doesn't exist yet it's * created. */ if (tde->flags & TAG_ENTRY_FLAG_DIR_SRC) { host = HostGetHostFromHash(&p->src); } else if (tde->flags & TAG_ENTRY_FLAG_DIR_DST) { host = HostGetHostFromHash(&p->dst); } /* no host for us */ if (host == NULL) { return -1; } if (host->tag == NULL) { /* get a new tde as the one we have is on the stack */ DetectTagDataEntry *new_tde = DetectTagDataCopy(tde); if (new_tde != NULL) { host->tag = new_tde; (void) SC_ATOMIC_ADD(num_tags, 1); } } else { /* Append the tag to the list of this host */ /* First iterate installed entries searching a duplicated sid/gid */ DetectTagDataEntry *iter = NULL; for (iter = host->tag; iter != NULL; iter = iter->next) { num_tags++; if (iter->sid == tde->sid && iter->gid == tde->gid) { iter->cnt_match++; /* If so, update data, unless the maximum MATCH limit is * reached. This prevents possible DOS attacks */ if (iter->cnt_match < DETECT_TAG_MATCH_LIMIT) { /* Reset time and counters */ iter->first_ts = iter->last_ts = tde->first_ts; iter->packets = 0; iter->bytes = 0; } updated = 1; break; } } /* If there was no entry of this rule, append the new tde */ if (updated == 0 && num_tags < DETECT_TAG_MAX_TAGS) { /* get a new tde as the one we have is on the stack */ DetectTagDataEntry *new_tde = DetectTagDataCopy(tde); if (new_tde != NULL) { (void) SC_ATOMIC_ADD(num_tags, 1); new_tde->next = host->tag; host->tag = new_tde; } } else if (num_tags == DETECT_TAG_MAX_TAGS) { SCLogDebug("Max tags for sessions reached (%"PRIu16")", num_tags); } } HostRelease(host); SCReturnInt(updated); } static void TagHandlePacketFlow(Flow *f, Packet *p) { if (f->tag_list == NULL) return; DetectTagDataEntry *tde = NULL; DetectTagDataEntry *prev = NULL; DetectTagDataEntry *iter = f->tag_list; uint8_t flag_added = 0; while (iter != NULL) { /* update counters */ iter->last_ts = p->ts.tv_sec; switch (iter->metric) { case DETECT_TAG_METRIC_PACKET: iter->packets++; break; case DETECT_TAG_METRIC_BYTES: iter->bytes += GET_PKT_LEN(p); break; } /* If this packet triggered the rule with tag, we dont need * to log it (the alert will log it) */ if (!(iter->flags & TAG_ENTRY_FLAG_SKIPPED_FIRST)) { iter->flags |= TAG_ENTRY_FLAG_SKIPPED_FIRST; } else { /* Update metrics; remove if tag expired; and set alerts */ switch (iter->metric) { case DETECT_TAG_METRIC_PACKET: if (iter->packets > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { p->flow->tag_list = iter->next; tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; case DETECT_TAG_METRIC_BYTES: if (iter->bytes > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { p->flow->tag_list = iter->next; tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; case DETECT_TAG_METRIC_SECONDS: /* last_ts handles this metric, but also a generic time based * expiration to prevent dead sessions/hosts */ if (iter->last_ts - iter->first_ts > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { p->flow->tag_list = iter->next; tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; } } prev = iter; iter = iter->next; } } void TagHandlePacketHost(Host *host, Packet *p) { DetectTagDataEntry *tde = NULL; DetectTagDataEntry *prev = NULL; DetectTagDataEntry *iter; uint8_t flag_added = 0; iter = host->tag; prev = NULL; while (iter != NULL) { /* update counters */ iter->last_ts = p->ts.tv_sec; switch (iter->metric) { case DETECT_TAG_METRIC_PACKET: iter->packets++; break; case DETECT_TAG_METRIC_BYTES: iter->bytes += GET_PKT_LEN(p); break; } /* If this packet triggered the rule with tag, we dont need * to log it (the alert will log it) */ if (!(iter->flags & TAG_ENTRY_FLAG_SKIPPED_FIRST)) { iter->flags |= TAG_ENTRY_FLAG_SKIPPED_FIRST; } else { /* Update metrics; remove if tag expired; and set alerts */ switch (iter->metric) { case DETECT_TAG_METRIC_PACKET: if (iter->packets > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); host->tag = iter; continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; case DETECT_TAG_METRIC_BYTES: if (iter->bytes > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); host->tag = iter; continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; case DETECT_TAG_METRIC_SECONDS: /* last_ts handles this metric, but also a generic time based * expiration to prevent dead sessions/hosts */ if (iter->last_ts - iter->first_ts > iter->count) { /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); continue; } else { tde = iter; iter = iter->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); host->tag = iter; continue; } } else if (flag_added == 0) { /* It's matching the tag. Add it to be logged and * update "flag_added" to add the packet once. */ p->flags |= PKT_HAS_TAG; flag_added++; } break; } } prev = iter; iter = iter->next; } } /** * \brief Search tags for src and dst. Update entries of the tag, remove if necessary * * \param de_ctx Detect context * \param det_ctx Detect thread context * \param p packet * */ void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) { /* If there's no tag, get out of here */ unsigned int current_tags = SC_ATOMIC_GET(num_tags); if (current_tags == 0) return; /* First update and get session tags */ if (p->flow != NULL) { FLOWLOCK_WRLOCK(p->flow); TagHandlePacketFlow(p->flow, p); FLOWLOCK_UNLOCK(p->flow); } Host *src = HostLookupHostFromHash(&p->src); if (src) { if (src->tag != NULL) { TagHandlePacketHost(src,p); } HostRelease(src); } Host *dst = HostLookupHostFromHash(&p->dst); if (dst) { if (dst->tag != NULL) { TagHandlePacketHost(dst,p); } HostRelease(dst); } } /** * \brief Removes the entries exceding the max timeout value * * \param tag_ctx Tag context * \param ts the current time * * \retval 1 no tags or tags removed -- host is free to go (from tag perspective) * \retval 0 still active tags */ int TagTimeoutCheck(Host *host, struct timeval *tv) { DetectTagDataEntry *tde = NULL; DetectTagDataEntry *tmp = NULL; DetectTagDataEntry *prev = NULL; int retval = 1; if (host->tag == NULL) return 1; tmp = host->tag; prev = NULL; while (tmp != NULL) { if ((tv->tv_sec - tmp->last_ts) <= TAG_MAX_LAST_TIME_SEEN) { prev = tmp; tmp = tmp->next; retval = 0; continue; } /* timed out */ if (prev != NULL) { prev->next = tmp->next; tde = tmp; tmp = tde->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); } else { host->tag = tmp->next; tde = tmp; tmp = tde->next; SCFree(tde); (void) SC_ATOMIC_SUB(num_tags, 1); } } return retval; } suricata-1.4.7/src/detect-icmp-id.c0000644000000000000000000003305312253546156013765 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias Galvan * * Implements the icmp_id keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-icmp-id.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #define PARSE_REGEX "^\\s*(\"\\s*)?([0-9]+)(\\s*\")?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectIcmpIdSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpIdRegisterTests(void); void DetectIcmpIdFree(void *); /** * \brief Registration function for icode: icmp_id */ void DetectIcmpIdRegister (void) { sigmatch_table[DETECT_ICMP_ID].name = "icmp_id"; sigmatch_table[DETECT_ICMP_ID].desc = "check for a ICMP id"; sigmatch_table[DETECT_ICMP_ID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icmp_id"; sigmatch_table[DETECT_ICMP_ID].Match = DetectIcmpIdMatch; sigmatch_table[DETECT_ICMP_ID].Setup = DetectIcmpIdSetup; sigmatch_table[DETECT_ICMP_ID].Free = DetectIcmpIdFree; sigmatch_table[DETECT_ICMP_ID].RegisterTests = DetectIcmpIdRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief This function is used to match icmp_id rule option set on a packet * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectIcmpIdData * * \retval 0 no match * \retval 1 match */ int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { uint16_t pid; DetectIcmpIdData *iid = (DetectIcmpIdData *)m->ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; if (PKT_IS_ICMPV4(p)) { switch (ICMPV4_GET_TYPE(p)){ case ICMP_ECHOREPLY: case ICMP_ECHO: case ICMP_TIMESTAMP: case ICMP_TIMESTAMPREPLY: case ICMP_INFO_REQUEST: case ICMP_INFO_REPLY: case ICMP_ADDRESS: case ICMP_ADDRESSREPLY: SCLogDebug("ICMPV4_GET_ID(p) %"PRIu16" (network byte order), " "%"PRIu16" (host byte order)", ICMPV4_GET_ID(p), ntohs(ICMPV4_GET_ID(p))); pid = ICMPV4_GET_ID(p); break; default: SCLogDebug("Packet has no id field"); return 0; } } else if (PKT_IS_ICMPV6(p)) { switch (ICMPV6_GET_TYPE(p)) { case ICMP6_ECHO_REQUEST: case ICMP6_ECHO_REPLY: SCLogDebug("ICMPV6_GET_ID(p) %"PRIu16" (network byte order), " "%"PRIu16" (host byte order)", ICMPV6_GET_ID(p), ntohs(ICMPV6_GET_ID(p))); pid = ICMPV6_GET_ID(p); break; default: SCLogDebug("Packet has no id field"); return 0; } } else { SCLogDebug("Packet not ICMPV4 nor ICMPV6"); return 0; } if (pid == iid->id) return 1; return 0; } /** * \brief This function is used to parse icmp_id option passed via icmp_id: keyword * * \param icmpidstr Pointer to the user provided icmp_id options * * \retval iid pointer to DetectIcmpIdData on success * \retval NULL on failure */ DetectIcmpIdData *DetectIcmpIdParse (char *icmpidstr) { DetectIcmpIdData *iid = NULL; char *substr[3] = {NULL, NULL, NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, icmpidstr, strlen(icmpidstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "Parse error %s", icmpidstr); goto error; } int i; const char *str_ptr; for (i = 1; i < ret; i++) { res = pcre_get_substring((char *)icmpidstr, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } substr[i-1] = (char *)str_ptr; } iid = SCMalloc(sizeof(DetectIcmpIdData)); if (unlikely(iid == NULL)) goto error; iid->id = 0; if (substr[0]!= NULL && strlen(substr[0]) != 0) { if (substr[2] == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Missing close quote in input"); goto error; } } else { if (substr[2] != NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Missing open quote in input"); goto error; } } /** \todo can ByteExtractStringUint16 do this? */ uint16_t id = 0; if (ByteExtractStringUint16(&id, 10, 0, substr[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp id %s is not " "valid", substr[1]); goto error; } iid->id = htons(id); for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } return iid; error: for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } if (iid != NULL) DetectIcmpIdFree(iid); return NULL; } /** * \brief this function is used to add the parsed icmp_id data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param icmpidstr pointer to the user provided icmp_id option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectIcmpIdSetup (DetectEngineCtx *de_ctx, Signature *s, char *icmpidstr) { DetectIcmpIdData *iid = NULL; SigMatch *sm = NULL; iid = DetectIcmpIdParse(icmpidstr); if (iid == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ICMP_ID; sm->ctx = (void *)iid; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (iid != NULL) DetectIcmpIdFree(iid); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectIcmpIdData * * \param ptr pointer to DetectIcmpIdData */ void DetectIcmpIdFree (void *ptr) { DetectIcmpIdData *iid = (DetectIcmpIdData *)ptr; SCFree(iid); } #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" /** * \test DetectIcmpIdParseTest01 is a test for setting a valid icmp_id value */ int DetectIcmpIdParseTest01 (void) { DetectIcmpIdData *iid = NULL; iid = DetectIcmpIdParse("300"); if (iid != NULL && iid->id == htons(300)) { DetectIcmpIdFree(iid); return 1; } return 0; } /** * \test DetectIcmpIdParseTest02 is a test for setting a valid icmp_id value * with spaces all around */ int DetectIcmpIdParseTest02 (void) { DetectIcmpIdData *iid = NULL; iid = DetectIcmpIdParse(" 300 "); if (iid != NULL && iid->id == htons(300)) { DetectIcmpIdFree(iid); return 1; } return 0; } /** * \test DetectIcmpIdParseTest03 is a test for setting a valid icmp_id value * with quotation marks */ int DetectIcmpIdParseTest03 (void) { DetectIcmpIdData *iid = NULL; iid = DetectIcmpIdParse("\"300\""); if (iid != NULL && iid->id == htons(300)) { DetectIcmpIdFree(iid); return 1; } return 0; } /** * \test DetectIcmpIdParseTest04 is a test for setting a valid icmp_id value * with quotation marks and spaces all around */ int DetectIcmpIdParseTest04 (void) { DetectIcmpIdData *iid = NULL; iid = DetectIcmpIdParse(" \" 300 \""); if (iid != NULL && iid->id == htons(300)) { DetectIcmpIdFree(iid); return 1; } return 0; } /** * \test DetectIcmpIdParseTest05 is a test for setting an invalid icmp_id * value with missing quotation marks */ int DetectIcmpIdParseTest05 (void) { DetectIcmpIdData *iid = NULL; iid = DetectIcmpIdParse("\"300"); if (iid == NULL) { DetectIcmpIdFree(iid); return 1; } return 0; } /** * \test DetectIcmpIdMatchTest01 is a test for checking the working of * icmp_id keyword by creating 2 rules and matching a crafted packet * against them. Only the first one shall trigger. */ int DetectIcmpIdMatchTest01 (void) { int result = 0; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(ThreadVars)); p = UTHBuildPacket(NULL, 0, IPPROTO_ICMP); p->icmpv4vars.id = htons(21781); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any (icmp_id:21781; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx, "alert icmp any any -> any any (icmp_id:21782; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { printf("sid 1 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 2)) { printf("sid 2 alerted, but should not have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); end: return result; } /** * \test DetectIcmpIdMatchTest02 is a test for checking the working of * icmp_id keyword by creating 1 rule and matching a crafted packet * against them. The packet is an ICMP packet with no "id" field, * therefore the rule should not trigger. */ int DetectIcmpIdMatchTest02 (void) { int result = 0; uint8_t raw_icmpv4[] = { 0x0b, 0x00, 0x8a, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x14, 0x25, 0x0c, 0x00, 0x00, 0xff, 0x11, 0x00, 0x00, 0x85, 0x64, 0xea, 0x5b, 0x51, 0xa6, 0xbb, 0x35, 0x59, 0x8a, 0x5a, 0xe2, 0x00, 0x14, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; IPV4Hdr ip4h; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.addr_data32[0] = 0x01020304; p->dst.addr_data32[0] = 0x04030201; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h = &ip4h; DecodeICMPV4(&th_v, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4), NULL); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any (icmp_id:0; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 alerted, but should not have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); end: SCFree(p); return result; } #endif /* UNITTESTS */ void DetectIcmpIdRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("DetectIcmpIdParseTest01", DetectIcmpIdParseTest01, 1); UtRegisterTest("DetectIcmpIdParseTest02", DetectIcmpIdParseTest02, 1); UtRegisterTest("DetectIcmpIdParseTest03", DetectIcmpIdParseTest03, 1); UtRegisterTest("DetectIcmpIdParseTest04", DetectIcmpIdParseTest04, 1); UtRegisterTest("DetectIcmpIdParseTest05", DetectIcmpIdParseTest05, 1); UtRegisterTest("DetectIcmpIdMatchTest01", DetectIcmpIdMatchTest01, 1); UtRegisterTest("DetectIcmpIdMatchTest02", DetectIcmpIdMatchTest02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/app-layer-detect-proto.h0000644000000000000000000001035212253546156015500 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __APP_LAYER_DETECT_PROTO_H__ #define __APP_LAYER_DETECT_PROTO_H__ #include "stream.h" #include "detect-content.h" #include "app-layer-parser.h" /** \brief Signature for proto detection * \todo we might just use SigMatch here */ typedef struct AlpProtoSignature_ { uint16_t ip_proto; /**< protocol (TCP/UDP) */ uint16_t proto; /**< protocol */ DetectContentData *co; /**< content match that needs to match */ struct AlpProtoSignature_ *next; /**< next signature */ struct AlpProtoSignature_ *map_next; /**< next signature with same id */ } AlpProtoSignature; #define ALP_DETECT_MAX 256 typedef struct AlpProtoDetectDirection_ { MpmCtx mpm_ctx; uint32_t id; uint16_t map[ALP_DETECT_MAX]; /**< a mapping between condition id's and protocol */ uint16_t max_len; /**< max length of all patterns, so we can limit the search */ uint16_t min_len; /**< min length of all patterns, so we can tell the stream engine to feed data to app layer as soon as it has min size data */ } AlpProtoDetectDirection; typedef struct AlpProtoDetectCtx_ { AlpProtoDetectDirection toserver; AlpProtoDetectDirection toclient; MpmPatternIdStore *mpm_pattern_id_store; /** pattern id store */ int alp_content_module_handle; /** mapping between proto id's and pattern id's: this will * be used to look up a proto by the pattern id. The pattern * id is returned by the mpm */ //uint16_t *proto_map; /** Mapping between pattern id and signature. As each signature has a * unique pattern with a unique id, we can lookup the signature by * the pattern id. */ AlpProtoSignature **map; AlpProtoSignature *head; /**< list of sigs */ AppLayerProbingParser *probing_parsers; AppLayerProbingParserInfo *probing_parsers_info; uint16_t sigs; /**< number of sigs */ } AlpProtoDetectCtx; extern AlpProtoDetectCtx alp_proto_ctx; void AlpProtoInit(AlpProtoDetectCtx *); void *AppLayerDetectProtoThread(void *td); void AppLayerDetectProtoThreadInit(void); uint16_t AppLayerDetectGetProtoPMParser(AlpProtoDetectCtx *, AlpProtoDetectThreadCtx *, uint8_t *, uint16_t, uint8_t, uint8_t); uint16_t AppLayerDetectGetProtoProbingParser(AlpProtoDetectCtx *, Flow *, uint8_t *, uint32_t, uint8_t, uint8_t); uint16_t AppLayerDetectGetProto(AlpProtoDetectCtx *, AlpProtoDetectThreadCtx *, Flow *, uint8_t *, uint32_t, uint8_t, uint8_t); void AlpProtoAdd(AlpProtoDetectCtx *, char *, uint16_t, uint16_t, char *, uint16_t, uint16_t, uint8_t); void AppLayerDetectProtoThreadSpawn(void); void AlpDetectRegisterTests(void); void AlpProtoFinalizeGlobal(AlpProtoDetectCtx *); void AlpProtoFinalizeThread(AlpProtoDetectCtx *, AlpProtoDetectThreadCtx *); void AlpProtoFinalize2Thread(AlpProtoDetectThreadCtx *); void AlpProtoDeFinalize2Thread (AlpProtoDetectThreadCtx *); void AlpProtoTestDestroy(AlpProtoDetectCtx *); void AlpProtoDestroy(void); #endif /* __APP_LAYER_DETECT_PROTO_H__ */ suricata-1.4.7/src/detect-icode.c0000644000000000000000000003515412253546156013532 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias * * Implements icode keyword support */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-icode.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" /** *\brief Regex for parsing our icode options */ #define PARSE_REGEX "^\\s*(<|>)?\\s*([0-9]+)\\s*(?:<>\\s*([0-9]+))?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectICodeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectICodeSetup(DetectEngineCtx *, Signature *, char *); void DetectICodeRegisterTests(void); void DetectICodeFree(void *); /** * \brief Registration function for icode: keyword */ void DetectICodeRegister (void) { sigmatch_table[DETECT_ICODE].name = "icode"; sigmatch_table[DETECT_ICODE].desc = "match on specific ICMP id-value"; sigmatch_table[DETECT_ICODE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icode"; sigmatch_table[DETECT_ICODE].Match = DetectICodeMatch; sigmatch_table[DETECT_ICODE].Setup = DetectICodeSetup; sigmatch_table[DETECT_ICODE].Free = DetectICodeFree; sigmatch_table[DETECT_ICODE].RegisterTests = DetectICodeRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief This function is used to match icode rule option set on a packet with those passed via icode: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectICodeData * * \retval 0 no match * \retval 1 match */ int DetectICodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { int ret = 0; uint8_t picode; DetectICodeData *icd = (DetectICodeData *)m->ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; if (PKT_IS_ICMPV4(p)) { picode = ICMPV4_GET_CODE(p); } else if (PKT_IS_ICMPV6(p)) { picode = ICMPV6_GET_CODE(p); } else { /* Packet not ICMPv4 nor ICMPv6 */ return ret; } switch(icd->mode) { case DETECT_ICODE_EQ: ret = (picode == icd->code1) ? 1 : 0; break; case DETECT_ICODE_LT: ret = (picode < icd->code1) ? 1 : 0; break; case DETECT_ICODE_GT: ret = (picode > icd->code1) ? 1 : 0; break; case DETECT_ICODE_RN: ret = (picode >= icd->code1 && picode <= icd->code2) ? 1 : 0; break; } return ret; } /** * \brief This function is used to parse icode options passed via icode: keyword * * \param icodestr Pointer to the user provided icode options * * \retval icd pointer to DetectICodeData on success * \retval NULL on failure */ DetectICodeData *DetectICodeParse(char *icodestr) { DetectICodeData *icd = NULL; char *args[3] = {NULL, NULL, NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, icodestr, strlen(icodestr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, icodestr); goto error; } int i; const char *str_ptr; for (i = 1; i < ret; i++) { res = pcre_get_substring((char *)icodestr, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i-1] = (char *)str_ptr; } icd = SCMalloc(sizeof(DetectICodeData)); if (unlikely(icd == NULL)) goto error; icd->code1 = 0; icd->code2 = 0; icd->mode = 0; /* we have either "<" or ">" */ if (args[0] != NULL && strlen(args[0]) != 0) { /* we have a third part ("<> y"), therefore it's invalid */ if (args[2] != NULL) { SCLogError(SC_ERR_INVALID_VALUE, "icode: invalid value"); goto error; } /* we have only a comparison ("<", ">") */ if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not " "valid", args[1]); goto error; } if ((strcmp(args[0], ">")) == 0) icd->mode = DETECT_ICODE_GT; else icd->mode = DETECT_ICODE_LT; } else { /* no "<", ">" */ /* we have a range ("<>") */ if (args[2] != NULL) { icd->mode = (uint8_t) DETECT_ICODE_RN; if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not " "valid", args[1]); goto error; } if (ByteExtractStringUint8(&icd->code2, 10, 0, args[2]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not " "valid", args[2]); goto error; } /* we check that the first given value in the range is less than the second, otherwise we swap them */ if (icd->code1 > icd->code2) { uint8_t temp = icd->code1; icd->code1 = icd->code2; icd->code2 = temp; } } else { /* we have an equality */ icd->mode = DETECT_ICODE_EQ; if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not " "valid", args[1]); goto error; } } } for (i = 0; i < (ret-1); i++) { if (args[i] != NULL) SCFree(args[i]); } return icd; error: for (i = 0; i < (ret-1) && i < 3; i++) { if (args[i] != NULL) SCFree(args[i]); } if (icd != NULL) DetectICodeFree(icd); return NULL; } /** * \brief this function is used to add the parsed icode data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param icodestr pointer to the user provided icode options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectICodeSetup(DetectEngineCtx *de_ctx, Signature *s, char *icodestr) { DetectICodeData *icd = NULL; SigMatch *sm = NULL; icd = DetectICodeParse(icodestr); if (icd == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ICODE; sm->ctx = (void *)icd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (icd != NULL) DetectICodeFree(icd); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectICodeData * * \param ptr pointer to DetectICodeData */ void DetectICodeFree(void *ptr) { DetectICodeData *icd = (DetectICodeData *)ptr; SCFree(icd); } #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" /** * \test DetectICodeParseTest01 is a test for setting a valid icode value */ int DetectICodeParseTest01(void) { DetectICodeData *icd = NULL; int result = 0; icd = DetectICodeParse("8"); if (icd != NULL) { if (icd->code1 == 8 && icd->mode == DETECT_ICODE_EQ) result = 1; DetectICodeFree(icd); } return result; } /** * \test DetectICodeParseTest02 is a test for setting a valid icode value * with ">" operator */ int DetectICodeParseTest02(void) { DetectICodeData *icd = NULL; int result = 0; icd = DetectICodeParse(">8"); if (icd != NULL) { if (icd->code1 == 8 && icd->mode == DETECT_ICODE_GT) result = 1; DetectICodeFree(icd); } return result; } /** * \test DetectICodeParseTest03 is a test for setting a valid icode value * with "<" operator */ int DetectICodeParseTest03(void) { DetectICodeData *icd = NULL; int result = 0; icd = DetectICodeParse("<8"); if (icd != NULL) { if (icd->code1 == 8 && icd->mode == DETECT_ICODE_LT) result = 1; DetectICodeFree(icd); } return result; } /** * \test DetectICodeParseTest04 is a test for setting a valid icode value * with "<>" operator */ int DetectICodeParseTest04(void) { DetectICodeData *icd = NULL; int result = 0; icd = DetectICodeParse("8<>20"); if (icd != NULL) { if (icd->code1 == 8 && icd->code2 == 20 && icd->mode == DETECT_ICODE_RN) result = 1; DetectICodeFree(icd); } return result; } /** * \test DetectICodeParseTest05 is a test for setting a valid icode value * with spaces all around */ int DetectICodeParseTest05(void) { DetectICodeData *icd = NULL; int result = 0; icd = DetectICodeParse(" 8 "); if (icd != NULL) { if (icd->code1 == 8 && icd->mode == DETECT_ICODE_EQ) result = 1; DetectICodeFree(icd); } return result; } /** * \test DetectICodeParseTest06 is a test for setting a valid icode value * with ">" operator and spaces all around */ int DetectICodeParseTest06(void) { DetectICodeData *icd = NULL; int result = 0; icd = DetectICodeParse(" > 8 "); if (icd != NULL) { if (icd->code1 == 8 && icd->mode == DETECT_ICODE_GT) result = 1; DetectICodeFree(icd); } return result; } /** * \test DetectICodeParseTest07 is a test for setting a valid icode value * with "<>" operator and spaces all around */ int DetectICodeParseTest07(void) { DetectICodeData *icd = NULL; int result = 0; icd = DetectICodeParse(" 8 <> 20 "); if (icd != NULL) { if (icd->code1 == 8 && icd->code2 == 20 && icd->mode == DETECT_ICODE_RN) result = 1; DetectICodeFree(icd); } return result; } /** * \test DetectICodeParseTest08 is a test for setting an invalid icode value */ int DetectICodeParseTest08(void) { DetectICodeData *icd = NULL; icd = DetectICodeParse("> 8 <> 20"); if (icd == NULL) return 1; DetectICodeFree(icd); return 0; } /** * \test DetectICodeMatchTest01 is a test for checking the working of icode * keyword by creating 5 rules and matching a crafted packet against * them. 4 out of 5 rules shall trigger. */ int DetectICodeMatchTest01(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(NULL, 0, IPPROTO_ICMP); p->icmpv4h->code = 10; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert icmp any any -> any any (icode:10; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert icmp any any -> any any (icode:<15; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert icmp any any -> any any (icode:>20; sid:3;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert icmp any any -> any any (icode:8<>20; sid:4;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert icmp any any -> any any (icode:20<>8; sid:5;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { SCLogDebug("sid 1 did not alert, but should have"); goto cleanup; } else if (PacketAlertCheck(p, 2) == 0) { SCLogDebug("sid 2 did not alert, but should have"); goto cleanup; } else if (PacketAlertCheck(p, 3)) { SCLogDebug("sid 3 alerted, but should not have"); goto cleanup; } else if (PacketAlertCheck(p, 4) == 0) { SCLogDebug("sid 4 did not alert, but should have"); goto cleanup; } else if (PacketAlertCheck(p, 5) == 0) { SCLogDebug("sid 5 did not alert, but should have"); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); end: return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectICode */ void DetectICodeRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectICodeParseTest01", DetectICodeParseTest01, 1); UtRegisterTest("DetectICodeParseTest02", DetectICodeParseTest02, 1); UtRegisterTest("DetectICodeParseTest03", DetectICodeParseTest03, 1); UtRegisterTest("DetectICodeParseTest04", DetectICodeParseTest04, 1); UtRegisterTest("DetectICodeParseTest05", DetectICodeParseTest05, 1); UtRegisterTest("DetectICodeParseTest06", DetectICodeParseTest06, 1); UtRegisterTest("DetectICodeParseTest07", DetectICodeParseTest07, 1); UtRegisterTest("DetectICodeParseTest08", DetectICodeParseTest08, 1); UtRegisterTest("DetectICodeMatchTest01", DetectICodeMatchTest01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-classification-config.c0000644000000000000000000006157612253546156016421 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Used for parsing a classification.config file */ #include "suricata-common.h" #include "detect.h" #include "detect-engine.h" #include "util-hash.h" #include "conf.h" #include "util-classification-config.h" #include "util-unittest.h" #include "util-error.h" #include "util-debug.h" #include "util-fmemopen.h" /* Regex to parse the classtype argument from a Signature. The first substring * holds the classtype name, the second substring holds the classtype the * classtype description, and the third argument holds the priority */ #define DETECT_CLASSCONFIG_REGEX "^\\s*config\\s*classification\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*,\\s*(.+)\\s*,\\s*(\\d+)\\s*$" /* Default path for the classification.config file */ #if defined OS_WIN32 || defined __CYGWIN__ #define SC_CLASS_CONF_DEF_CONF_FILEPATH CONFIG_DIR "\\\\classification.config" #else #define SC_CLASS_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/classification.config" #endif /* Holds a pointer to the default path for the classification.config file */ static const char *default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH; static FILE *fd = NULL; static pcre *regex = NULL; static pcre_extra *regex_study = NULL; uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datalen); char SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2); void SCClassConfClasstypeHashFree(void *ch); static char *SCClassConfGetConfFilename(void); /** * \brief Inits the context to be used by the Classification Config parsing API. * * This function initializes the hash table to be used by the Detection * Engine Context to hold the data from the classification.config file, * obtains the file desc to parse the classification.config file, and * inits the regex used to parse the lines from classification.config * file. * * \param de_ctx Pointer to the Detection Engine Context. * * \retval 0 On success. * \retval -1 On failure. */ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) { char *filename = NULL; const char *eb = NULL; int eo; int opts = 0; /* init the hash table to be used by the classification config Classtypes */ de_ctx->class_conf_ht = HashTableInit(4096, SCClassConfClasstypeHashFunc, SCClassConfClasstypeHashCompareFunc, SCClassConfClasstypeHashFree); if (de_ctx->class_conf_ht == NULL) { SCLogError(SC_ERR_HASH_TABLE_INIT, "Error initializing the hash " "table"); goto error; } /* if it is not NULL, use the file descriptor. The hack so that we can * avoid using a dummy classification file for testing purposes and * instead use an input stream against a buffer containing the * classification strings */ if (fd == NULL) { filename = SCClassConfGetConfFilename(); if ( (fd = fopen(filename, "r")) == NULL) { SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } } regex = pcre_compile(DETECT_CLASSCONFIG_REGEX, opts, &eb, &eo, NULL); if (regex == NULL) { SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", DETECT_CLASSCONFIG_REGEX, eo, eb); goto error; } regex_study = pcre_study(regex, 0, &eb); if (eb != NULL) { SCLogDebug("pcre study failed: %s", eb); goto error; } return 0; error: if (de_ctx->class_conf_ht != NULL) { HashTableFree(de_ctx->class_conf_ht); de_ctx->class_conf_ht = NULL; } if (fd != NULL) { fclose(fd); fd = NULL; } if (regex != NULL) { pcre_free(regex); regex = NULL; } if (regex_study != NULL) { pcre_free(regex_study); regex_study = NULL; } return -1; } /** * \brief Returns the path for the Classification Config file. We check if we * can retrieve the path from the yaml conf file. If it is not present, * return the default path for the classification file which is * "./classification.config". * * \retval log_filename Pointer to a string containing the path for the * Classification Config file. */ static char *SCClassConfGetConfFilename(void) { char *log_filename = NULL; if (ConfGet("classification-file", &log_filename) != 1) { log_filename = (char *)default_file_path; } return log_filename; } /** * \brief Releases resources used by the Classification Config API. */ static void SCClassConfDeInitLocalResources(DetectEngineCtx *de_ctx) { fclose(fd); default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH; fd = NULL; if (regex != NULL) { pcre_free(regex); regex = NULL; } if (regex_study != NULL) { pcre_free(regex_study); regex_study = NULL; } return; } /** * \brief Releases resources used by the Classification Config API. */ void SCClassConfDeInitContext(DetectEngineCtx *de_ctx) { if (de_ctx->class_conf_ht != NULL) HashTableFree(de_ctx->class_conf_ht); de_ctx->class_conf_ht = NULL; return; } /** * \brief Converts a string to lowercase. * * \param str Pointer to the string to be converted. */ static char *SCClassConfStringToLowercase(const char *str) { char *new_str = NULL; char *temp_str = NULL; if ( (new_str = SCStrdup(str)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } temp_str = new_str; while (*temp_str != '\0') { *temp_str = tolower((unsigned char)*temp_str); temp_str++; } return new_str; } /** * \brief Parses a line from the classification file and adds it to Classtype * hash table in DetectEngineCtx, i.e. DetectEngineCtx->class_conf_ht. * * \param rawstr Pointer to the string to be parsed. * \param index Relative index of the string to be parsed. * \param de_ctx Pointer to the Detection Engine Context. * * \retval 0 On success. * \retval -1 On failure. */ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx) { const char *ct_name = NULL; const char *ct_desc = NULL; const char *ct_priority_str = NULL; int ct_priority = 0; uint8_t ct_id = index; SCClassConfClasstype *ct_new = NULL; SCClassConfClasstype *ct_lookup = NULL; #define MAX_SUBSTRINGS 30 int ret = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30); if (ret < 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid Classtype in " "classification.config file"); goto error; } /* retrieve the classtype name */ ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name); if (ret < 0) { SCLogInfo("pcre_get_substring() failed"); goto error; } /* retrieve the classtype description */ ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &ct_desc); if (ret < 0) { SCLogInfo("pcre_get_substring() failed"); goto error; } /* retrieve the classtype priority */ ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &ct_priority_str); if (ret < 0) { SCLogInfo("pcre_get_substring() failed"); goto error; } if (ct_priority_str == NULL) { goto error; } ct_priority = atoi(ct_priority_str); /* Create a new instance of the parsed Classtype string */ ct_new = SCClassConfAllocClasstype(ct_id, ct_name, ct_desc, ct_priority); if (ct_new == NULL) goto error; /* Check if the Classtype is present in the HashTable. In case it's present * ignore it, as it is a duplicate. If not present, add it to the table */ ct_lookup = HashTableLookup(de_ctx->class_conf_ht, ct_new, 0); if (ct_lookup == NULL) { if (HashTableAdd(de_ctx->class_conf_ht, ct_new, 0) < 0) SCLogDebug("HashTable Add failed"); } else { SCLogDebug("Duplicate classtype found inside classification.config"); if (ct_new->classtype_desc) SCFree(ct_new->classtype_desc); if (ct_new->classtype) SCFree(ct_new->classtype); SCFree(ct_new); } if (ct_name) SCFree((char *)ct_name); if (ct_desc) SCFree((char *)ct_desc); if (ct_priority_str) SCFree((char *)ct_priority_str); return 0; error: if (ct_name) SCFree((char *)ct_name); if (ct_desc) SCFree((char *)ct_desc); if (ct_priority_str) SCFree((char *)ct_priority_str); return -1; } /** * \brief Checks if a string is a comment or a blank line. * * Comments lines are lines of the following format - * "# This is a comment string" or * " # This is a comment string". * * \param line String that has to be checked * * \retval 1 On the argument string being a comment or blank line * \retval 0 Otherwise */ static int SCClassConfIsLineBlankOrComment(char *line) { while (*line != '\0') { /* we have a comment */ if (*line == '#') return 1; /* this line is neither a comment line, nor a blank line */ if (!isspace((unsigned char)*line)) return 0; line++; } /* we have a blank line */ return 1; } /** * \brief Parses the Classification Config file and updates the * DetectionEngineCtx->class_conf_ht with the Classtype information. * * \param de_ctx Pointer to the Detection Engine Context. */ void SCClassConfParseFile(DetectEngineCtx *de_ctx) { char line[1024]; uint8_t i = 1; while (fgets(line, sizeof(line), fd) != NULL) { if (SCClassConfIsLineBlankOrComment(line)) continue; SCClassConfAddClasstype(line, i, de_ctx); i++; } #ifdef UNITTESTS SCLogInfo("Added \"%d\" classification types from the classification file", de_ctx->class_conf_ht->count); #endif return; } /** * \brief Returns a new SCClassConfClasstype instance. The classtype string * is converted into lowercase, before being assigned to the instance. * * \param classtype Pointer to the classification type. * \param classtype_desc Pointer to the classification type description. * \param priority Holds the priority for the classification type. * * \retval ct Pointer to the new instance of SCClassConfClasstype on success; * NULL on failure. */ SCClassConfClasstype *SCClassConfAllocClasstype(uint8_t classtype_id, const char *classtype, const char *classtype_desc, int priority) { SCClassConfClasstype *ct = NULL; if (classtype == NULL) return NULL; if ( (ct = SCMalloc(sizeof(SCClassConfClasstype))) == NULL) return NULL; memset(ct, 0, sizeof(SCClassConfClasstype)); if ( (ct->classtype = SCClassConfStringToLowercase(classtype)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } if (classtype_desc != NULL && (ct->classtype_desc = SCStrdup(classtype_desc)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } ct->classtype_id = classtype_id; ct->priority = priority; return ct; } /** * \brief Frees a SCClassConfClasstype instance * * \param Pointer to the SCClassConfClasstype instance that has to be freed */ void SCClassConfDeAllocClasstype(SCClassConfClasstype *ct) { if (ct != NULL) { if (ct->classtype != NULL) SCFree(ct->classtype); if (ct->classtype_desc != NULL) SCFree(ct->classtype_desc); SCFree(ct); } return; } /** * \brief Hashing function to be used to hash the Classtype name. Would be * supplied as an argument to the HashTableInit function for * DetectEngineCtx->class_conf_ht. * * \param ht Pointer to the HashTable. * \param data Pointer to the data to be hashed. In this case, the data * would be a pointer to a SCClassConfClasstype instance. * \param datalen Not used by this function. */ uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datalen) { SCClassConfClasstype *ct = (SCClassConfClasstype *)data; uint32_t hash = 0; int i = 0; int len = strlen(ct->classtype); for (i = 0; i < len; i++) hash += tolower((unsigned char)(ct->classtype)[i]); hash = hash % ht->array_size; return hash; } /** * \brief Used to compare two Classtypes that have been stored in the HashTable. * This function is supplied as an argument to the HashTableInit function * for DetectionEngineCtx->class_conf_ct. * * \param data1 Pointer to the first SCClassConfClasstype to be compared. * \param len1 Not used by this function. * \param data2 Pointer to the second SCClassConfClasstype to be compared. * \param len2 Not used by this function. * * \retval 1 On data1 and data2 being equal. * \retval 0 On data1 and data2 not being equal. */ char SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) { SCClassConfClasstype *ct1 = (SCClassConfClasstype *)data1; SCClassConfClasstype *ct2 = (SCClassConfClasstype *)data2; int len1 = 0; int len2 = 0; if (ct1 == NULL || ct2 == NULL) return 0; if (ct1->classtype == NULL || ct2->classtype == NULL) return 0; len1 = strlen(ct1->classtype); len2 = strlen(ct2->classtype); if (len1 == len2 && memcmp(ct1->classtype, ct2->classtype, len1) == 0) { SCLogDebug("Match found inside Classification-Config hash function"); return 1; } return 0; } /** * \brief Used to free the Classification Config Hash Data that was stored in * DetectEngineCtx->class_conf_ht Hashtable. * * \param ch Pointer to the data that has to be freed. */ void SCClassConfClasstypeHashFree(void *ch) { SCClassConfDeAllocClasstype(ch); return; } /** * \brief Loads the Classtype info from the classification.config file. * * The classification.config file contains the different classtypes, * that can be used to label Signatures. Each line of the file should * have the following format - * classtype_name, classtype_description, priority * None of the above parameters should hold a quote inside the file. * * \param de_ctx Pointer to the Detection Engine Context that should be updated * with Classtype information. */ void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx) { if (SCClassConfInitContextAndLocalResources(de_ctx) == -1) { SCLogInfo("Please check the \"classification-file\" option in your suricata.yaml file"); exit(EXIT_FAILURE); } SCClassConfParseFile(de_ctx); SCClassConfDeInitLocalResources(de_ctx); return; } /** * \brief Gets the classtype from the corresponding hash table stored * in the Detection Engine Context's class conf ht, given the * classtype name. * * \param ct_name Pointer to the classtype name that has to be looked up. * \param de_ctx Pointer to the Detection Engine Context. * * \retval lookup_ct_info Pointer to the SCClassConfClasstype instance from * the hash table on success; NULL on failure. */ SCClassConfClasstype *SCClassConfGetClasstype(const char *ct_name, DetectEngineCtx *de_ctx) { SCClassConfClasstype *ct_info = SCClassConfAllocClasstype(0, ct_name, NULL, 0); if (ct_info == NULL) return NULL; SCClassConfClasstype *lookup_ct_info = HashTableLookup(de_ctx->class_conf_ht, ct_info, 0); SCClassConfDeAllocClasstype(ct_info); return lookup_ct_info; } /*----------------------------------Unittests---------------------------------*/ #ifdef UNITTESTS /** * \brief Creates a dummy classification file, with all valid Classtypes, for * testing purposes. * * \file_path Pointer to the file_path for the dummy classification file. */ void SCClassConfGenerateValidDummyClassConfigFD01(void) { const char *buffer = "config classification: nothing-wrong,Nothing Wrong With Us,3\n" "config classification: unknown,Unknown are we,3\n" "config classification: bad-unknown,We think it's bad, 2\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); return; } /** * \brief Creates a dummy classification file, with some valid Classtypes and a * couple of invalid Classtypes, for testing purposes. * * \file_path Pointer to the file_path for the dummy classification file. */ void SCClassConfGenerateInValidDummyClassConfigFD02(void) { const char *buffer = "config classification: not-suspicious,Not Suspicious Traffic,3\n" "onfig classification: unknown,Unknown Traffic,3\n" "config classification: _badunknown,Potentially Bad Traffic, 2\n" "config classification: bamboola1,Unknown Traffic,3\n" "config classification: misc-activity,Misc activity,-1\n" "config classification: policy-violation,Potential Corporate " "config classification: bamboola,Unknown Traffic,3\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); return; } /** * \brief Creates a dummy classification file, with all invalid Classtypes, for * testing purposes. * * \file_path Pointer to the file_path for the dummy classification file. */ void SCClassConfGenerateInValidDummyClassConfigFD03(void) { const char *buffer = "conig classification: not-suspicious,Not Suspicious Traffic,3\n" "onfig classification: unknown,Unknown Traffic,3\n" "config classification: _badunknown,Potentially Bad Traffic, 2\n" "config classification: misc-activity,Misc activity,-1\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); return; } /** * \brief Deletes a file, whose path is specified as the argument. * * \file_path Pointer to the file_path that has to be deleted. */ void SCClassConfDeleteDummyClassificationConfigFD(void) { if (fd != NULL) { fclose(fd); fd = NULL; } return; } /** * \test Check that the classification file is loaded and the detection engine * content class_conf_hash_table loaded with the classtype data. */ int SCClassConfTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 0; if (de_ctx == NULL) return result; SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); if (de_ctx->class_conf_ht == NULL) return result; result = (de_ctx->class_conf_ht->count == 3); if (result == 0) printf("de_ctx->class_conf_ht->count %u: ", de_ctx->class_conf_ht->count); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check that invalid classtypes present in the classification config file * aren't loaded. */ int SCClassConfTest02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 0; if (de_ctx == NULL) return result; SCClassConfGenerateInValidDummyClassConfigFD03(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); if (de_ctx->class_conf_ht == NULL) return result; result = (de_ctx->class_conf_ht->count == 0); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check that only valid classtypes are loaded into the hash table from * the classfication.config file. */ int SCClassConfTest03(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 0; if (de_ctx == NULL) return result; SCClassConfGenerateInValidDummyClassConfigFD02(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); if (de_ctx->class_conf_ht == NULL) return result; result = (de_ctx->class_conf_ht->count == 3); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the classtype info from the classification.config file have * been loaded into the hash table. */ int SCClassConfTest04(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 1; if (de_ctx == NULL) return 0; SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); if (de_ctx->class_conf_ht == NULL) return 0; result = (de_ctx->class_conf_ht->count == 3); result &= (SCClassConfGetClasstype("unknown", de_ctx) != NULL); result &= (SCClassConfGetClasstype("unKnoWn", de_ctx) != NULL); result &= (SCClassConfGetClasstype("bamboo", de_ctx) == NULL); result &= (SCClassConfGetClasstype("bad-unknown", de_ctx) != NULL); result &= (SCClassConfGetClasstype("BAD-UNKnOWN", de_ctx) != NULL); result &= (SCClassConfGetClasstype("bed-unknown", de_ctx) == NULL); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the classtype info from the invalid classification.config file * have not been loaded into the hash table, and cross verify to check * that the hash table contains no classtype data. */ int SCClassConfTest05(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 1; if (de_ctx == NULL) return 0; SCClassConfGenerateInValidDummyClassConfigFD03(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); if (de_ctx->class_conf_ht == NULL) return 0; result = (de_ctx->class_conf_ht->count == 0); result &= (SCClassConfGetClasstype("unknown", de_ctx) == NULL); result &= (SCClassConfGetClasstype("unKnoWn", de_ctx) == NULL); result &= (SCClassConfGetClasstype("bamboo", de_ctx) == NULL); result &= (SCClassConfGetClasstype("bad-unknown", de_ctx) == NULL); result &= (SCClassConfGetClasstype("BAD-UNKnOWN", de_ctx) == NULL); result &= (SCClassConfGetClasstype("bed-unknown", de_ctx) == NULL); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the classtype info from the classification.config file have * been loaded into the hash table. */ int SCClassConfTest06(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 1; if (de_ctx == NULL) return 0; SCClassConfGenerateInValidDummyClassConfigFD02(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); if (de_ctx->class_conf_ht == NULL) return 0; result = (de_ctx->class_conf_ht->count == 3); result &= (SCClassConfGetClasstype("unknown", de_ctx) == NULL); result &= (SCClassConfGetClasstype("not-suspicious", de_ctx) != NULL); result &= (SCClassConfGetClasstype("bamboola1", de_ctx) != NULL); result &= (SCClassConfGetClasstype("bamboola1", de_ctx) != NULL); result &= (SCClassConfGetClasstype("BAMBOolA1", de_ctx) != NULL); result &= (SCClassConfGetClasstype("unkNOwn", de_ctx) == NULL); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ /** * \brief This function registers unit tests for Classification Config API. */ void SCClassConfRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCClassConfTest01", SCClassConfTest01, 1); UtRegisterTest("SCClassConfTest02", SCClassConfTest02, 1); UtRegisterTest("SCClassConfTest03", SCClassConfTest03, 1); UtRegisterTest("SCClassConfTest04", SCClassConfTest04, 1); UtRegisterTest("SCClassConfTest05", SCClassConfTest05, 1); UtRegisterTest("SCClassConfTest06", SCClassConfTest06, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-window.c0000644000000000000000000002436312253546156013756 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * Implements the window keyword. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-window.h" #include "flow.h" #include "flow-var.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-byte.h" /** * \brief Regex for parsing our window option */ #define PARSE_REGEX "^\\s*([!])?\\s*([0-9]{1,9}+)\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectWindowSetup(DetectEngineCtx *, Signature *, char *); void DetectWindowRegisterTests(void); void DetectWindowFree(void *); /** * \brief Registration function for window: keyword */ void DetectWindowRegister (void) { sigmatch_table[DETECT_WINDOW].name = "window"; sigmatch_table[DETECT_WINDOW].desc = "check for a specific TCP window size"; sigmatch_table[DETECT_WINDOW].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Window"; sigmatch_table[DETECT_WINDOW].Match = DetectWindowMatch; sigmatch_table[DETECT_WINDOW].Setup = DetectWindowSetup; sigmatch_table[DETECT_WINDOW].Free = DetectWindowFree; sigmatch_table[DETECT_WINDOW].RegisterTests = DetectWindowRegisterTests; const char *eb; int eo; int opts = 0; #ifdef WINDOW_DEBUG printf("detect-window: Registering window rule option\n"); #endif parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /** * \brief This function is used to match the window size on a packet * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectWindowData * * \retval 0 no match * \retval 1 match */ int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectWindowData *wd = (DetectWindowData *)m->ctx; if ( !(PKT_IS_TCP(p)) || wd == NULL || PKT_IS_PSEUDOPKT(p)) { return 0; } if ( (!wd->negated && wd->size == TCP_GET_WINDOW(p)) || (wd->negated && wd->size != TCP_GET_WINDOW(p))) { return 1; } return 0; } /** * \brief This function is used to parse window options passed via window: keyword * * \param windowstr Pointer to the user provided window options (negation! and size) * * \retval wd pointer to DetectWindowData on success * \retval NULL on failure */ DetectWindowData *DetectWindowParse(char *windowstr) { DetectWindowData *wd = NULL; char *args[3] = {NULL,NULL,NULL}; /* PR: Why PCRE MAX_SUBSTRING must be multiple of 3? */ #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, windowstr, strlen(windowstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 3) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, windowstr); goto error; } wd = SCMalloc(sizeof(DetectWindowData)); if (unlikely(wd == NULL)) goto error; if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[0] = (char *)str_ptr; /* Detect if it's negated */ if (args[0][0] == '!') wd->negated = 1; else wd->negated = 0; if (ret > 2) { res = pcre_get_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* Get the window size if it's a valid value (in packets, we should alert if this doesn't happend from decode) */ if (-1 == ByteExtractStringUint16(&wd->size, 10, 0, str_ptr)) { goto error; } } } int i = 0; for (i = 0; i < (ret -1); i++){ if (args[i] != NULL) SCFree(args[i]); } return wd; error: for (i = 0; i < (ret -1) && i < 3; i++){ if (args[i] != NULL) SCFree(args[i]); } if (wd != NULL) DetectWindowFree(wd); return NULL; } /** * \brief this function is used to add the parsed window sizedata into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param windowstr pointer to the user provided window options * * \retval 0 on Success * \retval -1 on Failure */ int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, char *windowstr) { DetectWindowData *wd = NULL; SigMatch *sm = NULL; wd = DetectWindowParse(windowstr); if (wd == 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_WINDOW; sm->ctx = (void *)wd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (wd != NULL) DetectWindowFree(wd); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectWindowData * * \param wd pointer to DetectWindowData */ void DetectWindowFree(void *ptr) { DetectWindowData *wd = (DetectWindowData *)ptr; SCFree(wd); } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectWindowTestParse01 is a test to make sure that we set the size correctly * when given valid window opt */ int DetectWindowTestParse01 (void) { int result = 0; DetectWindowData *wd = NULL; wd = DetectWindowParse("35402"); if (wd != NULL &&wd->size==35402) { DetectWindowFree(wd); result = 1; } return result; } /** * \test DetectWindowTestParse02 is a test for setting the window opt negated */ int DetectWindowTestParse02 (void) { int result = 0; DetectWindowData *wd = NULL; wd = DetectWindowParse("!35402"); if (wd != NULL) { if (wd->negated == 1 && wd->size==35402) { result = 1; } else { printf("expected wd->negated=1 and wd->size=35402\n"); } DetectWindowFree(wd); } return result; } /** * \test DetectWindowTestParse03 is a test to check for an empty value */ int DetectWindowTestParse03 (void) { int result = 0; DetectWindowData *wd = NULL; wd = DetectWindowParse(""); if (wd == NULL) { result = 1; } else { printf("expected a NULL pointer (It was an empty string)\n"); } DetectWindowFree(wd); return result; } /** * \test DetectWindowTestParse03 is a test to check for a big value */ int DetectWindowTestParse04 (void) { int result = 0; DetectWindowData *wd = NULL; wd = DetectWindowParse("1235402"); if (wd != NULL) { printf("expected a NULL pointer (It was exceeding the MAX window size)\n"); DetectWindowFree(wd); }else result=1; return result; } /** * \test DetectWindowTestPacket01 is a test to check window with constructed packets */ int DetectWindowTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; /* TCP wwindow = 40 */ p[0]->tcph->th_win = htons(40); /* TCP window = 41 */ p[1]->tcph->th_win = htons(41); char *sigs[2]; sigs[0]= "alert tcp any any -> any any (msg:\"Testing window 1\"; window:40; sid:1;)"; sigs[1]= "alert tcp any any -> any any (msg:\"Testing window 2\"; window:41; sid:2;)"; uint32_t sid[2] = {1, 2}; uint32_t results[3][2] = { /* packet 0 match sid 1 but should not match sid 2 */ {1, 0}, /* packet 1 should not match */ {0, 1}, /* packet 2 should not match */ {0, 0} }; result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2); UTHFreePackets(p, 3); end: return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectWindow */ void DetectWindowRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectWindowTestParse01", DetectWindowTestParse01, 1); UtRegisterTest("DetectWindowTestParse02", DetectWindowTestParse02, 1); UtRegisterTest("DetectWindowTestParse03", DetectWindowTestParse03, 1); UtRegisterTest("DetectWindowTestParse04", DetectWindowTestParse04, 1); UtRegisterTest("DetectWindowTestPacket01" , DetectWindowTestPacket01 , 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-engine-hsbd.h0000644000000000000000000000312712253546156014632 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HSBD_H__ #define __DETECT_ENGINE_HSBD_H__ #define ENGINE_HSBD_BUFFER_LIMIT 20000 #include "app-layer-htp.h" int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags); int DetectEngineInspectHttpServerBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id); void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx); void DetectEngineHttpServerBodyRegisterTests(void); #endif /* __DETECT_ENGINE_HSBD_H__ */ suricata-1.4.7/src/util-reference-config.h0000644000000000000000000000344612253546156015361 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_REFERENCE_CONFIG_H__ #define __UTIL_REFERENCE_CONFIG_H__ /** * \brief Holds a reference from the file - reference.config. */ typedef struct SCRConfReference_ { /* The system name. This is the primary key for a reference. */ char *system; /* The url for the above reference */ char *url; } SCRConfReference; SCRConfReference *SCRConfAllocSCRConfReference(const char *, const char *); void SCRConfDeAllocSCRConfReference(SCRConfReference *); int SCRConfLoadReferenceConfigFile(DetectEngineCtx *); void SCRConfDeInitContext(DetectEngineCtx *); SCRConfReference *SCRConfGetReference(const char *, DetectEngineCtx *); void SCRConfRegisterTests(void); /* these below functions are only used by unittests */ void SCRConfGenerateValidDummyReferenceConfigFD01(void); void SCRConfGenerateInValidDummyReferenceConfigFD02(void); void SCRConfGenerateInValidDummyReferenceConfigFD03(void); void SCRConfDeleteDummyReferenceConfigFD(void); #endif /* __UTIL_REFERENCE_CONFIG_H__ */ suricata-1.4.7/src/flow-util.c0000644000000000000000000000750212253546156013117 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Flow utility functions */ #include "suricata-common.h" #include "threads.h" #include "flow.h" #include "flow-private.h" #include "flow-util.h" #include "flow-var.h" #include "app-layer.h" #include "util-var.h" #include "util-debug.h" #include "detect.h" #include "detect-engine-state.h" /** \brief allocate a flow * * We check against the memuse counter. If it passes that check we increment * the counter first, then we try to alloc. * * \retval f the flow or NULL on out of memory */ Flow *FlowAlloc(void) { Flow *f; if (!(FLOW_CHECK_MEMCAP(sizeof(Flow)))) { return NULL; } (void) SC_ATOMIC_ADD(flow_memuse, sizeof(Flow)); f = SCMalloc(sizeof(Flow)); if (unlikely(f == NULL)) { (void)SC_ATOMIC_SUB(flow_memuse, sizeof(Flow)); return NULL; } FLOW_INITIALIZE(f); return f; } /** * \brief cleanup & free the memory of a flow * * \param f flow to clear & destroy */ void FlowFree(Flow *f) { FLOW_DESTROY(f); SCFree(f); (void) SC_ATOMIC_SUB(flow_memuse, sizeof(Flow)); } /** * \brief Function to map the protocol to the defined FLOW_PROTO_* enumeration. * * \param proto protocol which is needed to be mapped */ uint8_t FlowGetProtoMapping(uint8_t proto) { switch (proto) { case IPPROTO_TCP: return FLOW_PROTO_TCP; case IPPROTO_UDP: return FLOW_PROTO_UDP; case IPPROTO_ICMP: return FLOW_PROTO_ICMP; case IPPROTO_SCTP: return FLOW_PROTO_SCTP; default: return FLOW_PROTO_DEFAULT; } } /* initialize the flow from the first packet * we see from it. */ void FlowInit(Flow *f, Packet *p) { SCEnter(); SCLogDebug("flow %p", f); f->proto = p->proto; f->recursion_level = p->recursion_level; if (PKT_IS_IPV4(p)) { FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, &f->src); FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, &f->dst); f->flags |= FLOW_IPV4; } else if (PKT_IS_IPV6(p)) { FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, &f->src); FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, &f->dst); f->flags |= FLOW_IPV6; } #ifdef DEBUG /* XXX handle default */ else { printf("FIXME: %s:%s:%" PRId32 "\n", __FILE__, __FUNCTION__, __LINE__); } #endif if (p->tcph != NULL) { /* XXX MACRO */ SET_TCP_SRC_PORT(p,&f->sp); SET_TCP_DST_PORT(p,&f->dp); } else if (p->udph != NULL) { /* XXX MACRO */ SET_UDP_SRC_PORT(p,&f->sp); SET_UDP_DST_PORT(p,&f->dp); } else if (p->icmpv4h != NULL) { f->type = p->type; f->code = p->code; } else if (p->icmpv6h != NULL) { f->type = p->type; f->code = p->code; } else if (p->sctph != NULL) { /* XXX MACRO */ SET_SCTP_SRC_PORT(p,&f->sp); SET_SCTP_DST_PORT(p,&f->dp); } /* XXX handle default */ #ifdef DEBUG else { printf("FIXME: %s:%s:%" PRId32 "\n", __FILE__, __FUNCTION__, __LINE__); } #endif COPY_TIMESTAMP(&p->ts, &f->startts); f->protomap = FlowGetProtoMapping(f->proto); SCReturn; } suricata-1.4.7/src/util-mpm-b2gm.h0000644000000000000000000000707212253546156013575 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_MPM_B2GM_H__ #define __UTIL_MPM_B2GM_H__ #include "util-mpm.h" #include "util-bloomfilter.h" #define B2GM_HASHSHIFT_MAX 8 #define B2GM_HASHSHIFT_HIGHER 7 #define B2GM_HASHSHIFT_HIGH 6 #define B2GM_HASHSHIFT_MEDIUM 5 #define B2GM_HASHSHIFT_LOW 4 #define B2GM_HASHSHIFT_LOWEST 3 //#define B2GM_TYPE uint64_t #define B2GM_TYPE uint32_t //#define B2GM_TYPE uint16_t //#define B2GM_TYPE uint8_t //#define B2GM_WORD_SIZE 64 #define B2GM_WORD_SIZE 32 //#define B2GM_WORD_SIZE 16 //#define B2GM_WORD_SIZE 8 #define B2GM_Q 2 #define B2GM_SEARCHFUNC B2gmSearchBNDMq //#define B2GM_SEARCHFUNC B2gmSearch //#define B2GM_COUNTERS #define B2GM_FLAG_NOCASE 0x01 #define B2GM_FLAG_FINAL 0x02 typedef struct B2gmPattern_ { uint8_t len; uint8_t flags; uint16_t id; #if __WORDSIZE == 64 uint32_t pad; #endif uint8_t *pat; struct B2gmPattern_ *next; } B2gmPattern; typedef struct B2gmPattern1_ { uint8_t flags; uint8_t pat; uint16_t id; } B2gmPattern1; typedef struct B2gmLookup_ { uint16_t pminlen; uint8_t pminlenb; /* bloom */ uint8_t pad0; #if __WORDSIZE == 64 uint32_t pad1; #endif BloomFilter *bloom; B2gmPattern *hash; } B2gmLookup; typedef struct B2gmCtx_ { /* we store our own multi byte search func ptr here for B2gmSearch1 */ uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* hash for looking up the idx in the pattern array */ uint16_t *ha1; uint8_t *patterns1; /* we store our own multi byte search func ptr here for B2gmSearch1 */ //uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); uint16_t pat_1_cnt; uint16_t pat_x_cnt; #if __WORDSIZE == 64 uint32_t pad1; #endif B2GM_TYPE *B2GM; B2GM_TYPE m; #if __WORDSIZE == 64 uint32_t pad0; #endif B2gmLookup *lookup; /* pattern arrays */ B2gmPattern **parray; /* hash used during ctx initialization */ B2gmPattern **init_hash; //uint8_t s0; uint32_t hash_size; } B2gmCtx; typedef struct B2gmThreadCtx_ { #ifdef B2GM_COUNTERS uint32_t stat_pminlen_calls; uint32_t stat_pminlen_total; uint32_t stat_bloom_calls; uint32_t stat_bloom_hits; uint32_t stat_calls; uint32_t stat_m_total; uint32_t stat_d0; uint32_t stat_d0_hashloop; uint32_t stat_loop_match; uint32_t stat_loop_no_match; uint32_t stat_num_shift; uint32_t stat_total_shift; uint32_t stat_test_buf; uint32_t stat_test_buf_ok; uint32_t stat_test_buf_fail; #endif /* B2GM_COUNTERS */ } B2gmThreadCtx; void MpmB2gmRegister(void); #endif /* __UTIL_MPM_B2GM_H__ */ suricata-1.4.7/src/util-magic.h0000644000000000000000000000205112253546156013227 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_MAGIC_H__ #define __UTIL_MAGIC_H__ #include int MagicInit(void); void MagicDeinit(void); char *MagicGlobalLookup(uint8_t *, uint32_t); char *MagicThreadLookup(magic_t *, uint8_t *, uint32_t); void MagicRegisterTests(void); #endif /* __UTIL_MAGIC_H__ */ suricata-1.4.7/src/ptxdump.py0000644000000000000000000000410712253546156013102 00000000000000#!/usr/bin/env python from string import * import os, getopt, sys, platform header = '''/* Auto-generated by ptxdump.py DO NOT EDIT * * This file contains the ptx code of the Cuda kernels. * A kernel is identified by its name and the compute capability (e.g. _sm_10). */ ''' def FormatCharHex(d): s = hex(ord(d)) if len(s) == 3: s = "0x0" + s[2] return s def CleanFileName(f): v = f.replace("-","_") v = v.replace(".ptx","") return v if not(len(sys.argv[1:]) >= 2): print("Usage: ptx2c.py ") print("Description: creates a header file containing the ptx files as character array" + os.linesep) sys.exit(0) out_h = sys.argv[1] + ".h" out = open(out_h, 'w') out.writelines(header) out.writelines("#ifdef __SC_CUDA_SUPPORT__\n") out.writelines("#ifndef __ptxdump_h__\n") out.writelines("#define __ptxdump_h__\n\n") # write char arrays for file in sys.argv[2:]: in_ptx = open(file, 'r') source = in_ptx.read() source_len = len(source) varname = CleanFileName(file) out.writelines("const unsigned char " + varname + "[" + str(source_len+1) + "] = {\n") newlinecnt = 0 for i in range(0, source_len): out.write(FormatCharHex(source[i]) + ", ") newlinecnt += 1 if newlinecnt == 16: newlinecnt = 0 out.write("\n") out.write("0x00\n};\n\n") print(sys.argv[0] + ": CUmodule " + varname + " packed successfully") # write retrieval function out.writelines("const unsigned char* SCCudaPtxDumpGetModule(const char* module){\n"); for file in sys.argv[2:]: out.writelines('\tif (!strcmp(module, "' + file.replace(".ptx","")+'"))\n') out.writelines("\t\treturn " + CleanFileName(file)+";\n") out.writelines('\tSCLogError(SC_ERR_FATAL, "Error in SCCudaPtxDumpGetModule, module %s not found. Exiting...",module);\n') out.writelines("\texit(EXIT_FAILURE);\n") out.writelines("};\n") out.writelines("#endif /* __ptxdump_h__ */\n") out.writelines("#endif /* __SC_CUDA_SUPPORT__ */\n") print(sys.argv[0] + ": " + out_h + " written successfully") in_ptx.close() out.close() suricata-1.4.7/src/detect-engine-hrhd.h0000644000000000000000000000244112253546156014635 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HRHD_H__ #define __DETECT_ENGINE_HRHD_H__ #include "app-layer-htp.h" int DetectEngineInspectHttpRawHeader(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *, Flow *, HtpState *, uint8_t); void DetectEngineHttpRawHeaderRegisterTests(void); #endif /* __DETECT_ENGINE_HHD_H__ */ suricata-1.4.7/src/detect-engine-file.h0000644000000000000000000000212212253546156014623 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_FILE_H__ #define __DETECT_ENGINE_FILE_H__ int DetectFileInspectHttp(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id); #endif /* __DETECT_ENGINE_FILE_H__ */ suricata-1.4.7/src/detect-http-cookie.h0000644000000000000000000000207212253546156014673 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh */ #ifndef _DETECT_HTTP_COOKIE_H #define _DETECT_HTTP_COOKIE_H /* prototypes */ void DetectHttpCookieRegister (void); int DetectHttpCookieDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Flow *, uint8_t, void *); #endif /* _DETECT_HTTP_COOKIE_H */ suricata-1.4.7/src/win32-syslog.h0000644000000000000000000000672112253546156013464 00000000000000/** * syslog.h does not exist in the mingw environment, this file replaces it */ /* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)syslog.h 8.1 (Berkeley) 6/2/93 */ #ifndef __WIN32_SYSLOG_H__ #define __WIN32_SYSLOG_H__ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but significant condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ #define LOG_KERN (0<<3) /* kernel messages */ #define LOG_USER (1<<3) /* random user-level messages */ #define LOG_MAIL (2<<3) /* mail system */ #define LOG_DAEMON (3<<3) /* system daemons */ #define LOG_AUTH (4<<3) /* security/authorization messages */ #define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ #define LOG_LPR (6<<3) /* line printer subsystem */ #define LOG_NEWS (7<<3) /* network news subsystem */ #define LOG_UUCP (8<<3) /* UUCP subsystem */ #define LOG_CRON (9<<3) /* clock daemon */ #define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */ #define LOG_FTP (11<<3) /* ftp daemon */ /* other codes through 15 reserved for system use */ #define LOG_LOCAL0 (16<<3) /* reserved for local use */ #define LOG_LOCAL1 (17<<3) /* reserved for local use */ #define LOG_LOCAL2 (18<<3) /* reserved for local use */ #define LOG_LOCAL3 (19<<3) /* reserved for local use */ #define LOG_LOCAL4 (20<<3) /* reserved for local use */ #define LOG_LOCAL5 (21<<3) /* reserved for local use */ #define LOG_LOCAL6 (22<<3) /* reserved for local use */ #define LOG_LOCAL7 (23<<3) /* reserved for local use */ /* * The current win32 implementation of syslog is dummy and does nothing. */ #define closelog() #define openlog(__ident, __option, __facility) #define setlogmask (__mask) #define syslog(__pri, __fmt, __param) #endif suricata-1.4.7/src/runmode-pfring.c0000644000000000000000000004175712253546156014143 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-pfring.h" #include "source-pfring.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "util-runmodes.h" #include "util-device.h" static const char *default_mode_auto = NULL; static const char *default_mode_autofp = NULL; #define PFRING_CONF_V1 1 #define PFRING_CONF_V2 2 const char *RunModeIdsPfringGetDefaultMode(void) { #ifdef HAVE_PFRING return default_mode_autofp; #else return NULL; #endif } void RunModeIdsPfringRegister(void) { default_mode_auto = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PFRING, "auto", "Multi threaded pfring mode", RunModeIdsPfringAuto); default_mode_autofp = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PFRING, "autofp", "Multi threaded pfring mode. Packets from " "each flow are assigned to a single detect " "thread, unlike \"pfring_auto\" where packets " "from the same flow can be processed by any " "detect thread", RunModeIdsPfringAutoFp); RunModeRegisterNewRunMode(RUNMODE_PFRING, "single", "Single threaded pfring mode", RunModeIdsPfringSingle); RunModeRegisterNewRunMode(RUNMODE_PFRING, "workers", "Workers pfring mode, each thread does all" " tasks from acquisition to logging", RunModeIdsPfringWorkers); return; } void PfringDerefConfig(void *conf) { PfringIfaceConfig *pfp = (PfringIfaceConfig *)conf; if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { #ifdef HAVE_PFRING_SET_BPF_FILTER if (pfp->bpf_filter) { SCFree(pfp->bpf_filter); } #endif SCFree(pfp); } } /** * \brief extract information from config file * * The returned structure will be freed by the thread init function. * This is thus necessary to or copy the structure before giving it * to thread or to reparse the file for each thread (and thus have * new structure. * * If old config system is used, then return the smae parameters * value for each interface. * * \return a PfringIfaceConfig corresponding to the interface name */ void *OldParsePfringConfig(const char *iface) { char *threadsstr = NULL; PfringIfaceConfig *pfconf = SCMalloc(sizeof(*pfconf)); char *tmpclusterid; #ifdef HAVE_PFRING_CLUSTER_TYPE char *tmpctype = NULL; cluster_type default_ctype = CLUSTER_ROUND_ROBIN; #endif if (unlikely(pfconf == NULL)) { return NULL; } if (iface == NULL) { SCFree(pfconf); return NULL; } strlcpy(pfconf->iface, iface, sizeof(pfconf->iface)); pfconf->threads = 1; pfconf->cluster_id = 1; #ifdef HAVE_PFRING_CLUSTER_TYPE pfconf->ctype = default_ctype; #endif pfconf->DerefFunc = PfringDerefConfig; pfconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; SC_ATOMIC_INIT(pfconf->ref); (void) SC_ATOMIC_ADD(pfconf->ref, 1); /* Find initial node */ if (ConfGet("pfring.threads", &threadsstr) != 1) { pfconf->threads = 1; } else { if (threadsstr != NULL) { pfconf->threads = (uint8_t)atoi(threadsstr); } } if (pfconf->threads == 0) { pfconf->threads = 1; } SC_ATOMIC_RESET(pfconf->ref); (void) SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); if (ConfGet("pfring.cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use cluster-id %" PRId32, pfconf->cluster_id); } #ifdef HAVE_PFRING_CLUSTER_TYPE if (ConfGet("pfring.cluster-type", &tmpctype) != 1) { SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type fron config"); } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogInfo("Using round-robin cluster mode for PF_RING (iface %s)", pfconf->iface); pfconf->ctype = (cluster_type)tmpctype; } else if (strcmp(tmpctype, "cluster_flow") == 0) { SCLogInfo("Using flow cluster mode for PF_RING (iface %s)", pfconf->iface); pfconf->ctype = (cluster_type)tmpctype; } else { SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); SCFree(pfconf); return NULL; } #endif return pfconf; } /** * \brief extract information from config file * * The returned structure will be freed by the thread init function. * This is thus necessary to or copy the structure before giving it * to thread or to reparse the file for each thread (and thus have * new structure. * * If old config system is used, then return the smae parameters * value for each interface. * * \return a PfringIfaceConfig corresponding to the interface name */ void *ParsePfringConfig(const char *iface) { char *threadsstr = NULL; ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *pf_ring_node; PfringIfaceConfig *pfconf = SCMalloc(sizeof(*pfconf)); char *tmpclusterid; char *tmpctype = NULL; #ifdef HAVE_PFRING_CLUSTER_TYPE cluster_type default_ctype = CLUSTER_ROUND_ROBIN; int getctype = 0; #endif #ifdef HAVE_PFRING_SET_BPF_FILTER char *bpf_filter = NULL; #endif /* HAVE_PFRING_SET_BPF_FILTER */ if (unlikely(pfconf == NULL)) { return NULL; } if (iface == NULL) { SCFree(pfconf); return NULL; } memset(pfconf, 0, sizeof(PfringIfaceConfig)); strlcpy(pfconf->iface, iface, sizeof(pfconf->iface)); pfconf->threads = 1; pfconf->cluster_id = 1; #ifdef HAVE_PFRING_CLUSTER_TYPE pfconf->ctype = (cluster_type)default_ctype; #endif pfconf->DerefFunc = PfringDerefConfig; SC_ATOMIC_INIT(pfconf->ref); (void) SC_ATOMIC_ADD(pfconf->ref, 1); /* Find initial node */ pf_ring_node = ConfGetNode("pfring"); if (pf_ring_node == NULL) { SCLogInfo("Unable to find pfring config using default value"); return pfconf; } if_root = ConfNodeLookupKeyValue(pf_ring_node, "interface", iface); if_default = ConfNodeLookupKeyValue(pf_ring_node, "interface", "default"); if (if_root == NULL && if_default == NULL) { /* Switch to old mode */ if_root = pf_ring_node; SCLogInfo("Unable to find pfring config for " "interface %s, using default value or 1.0 " "configuration system. ", iface); return pfconf; } /* If there is no setting for current interface use default one as main iface */ if (if_root == NULL) { if_root = if_default; if_default = NULL; } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { pfconf->threads = 1; } else { if (threadsstr != NULL) { pfconf->threads = (uint8_t)atoi(threadsstr); } } if (pfconf->threads == 0) { pfconf->threads = 1; } SC_ATOMIC_RESET(pfconf->ref); (void) SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); /* command line value has precedence */ if (ConfGet("pfring.cluster-id", &tmpclusterid) == 1) { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use command-line provided cluster-id %" PRId32, pfconf->cluster_id); } else { if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Could not get cluster-id from config"); } else { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use cluster-id %" PRId32, pfconf->cluster_id); } } #ifdef HAVE_PFRING_SET_BPF_FILTER /*load pfring bpf filter*/ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { pfconf->bpf_filter = SCStrdup(bpf_filter); SCLogDebug("Going to use command-line provided bpf filter %s", pfconf->bpf_filter); } } else { if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { pfconf->bpf_filter = SCStrdup(bpf_filter); SCLogDebug("Going to use bpf filter %s", pfconf->bpf_filter); } } } #endif /* HAVE_PFRING_SET_BPF_FILTER */ #ifdef HAVE_PFRING_CLUSTER_TYPE if (ConfGet("pfring.cluster-type", &tmpctype) == 1) { SCLogDebug("Going to use command-line provided cluster-type"); getctype = 1; } else { if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED, "Could not get cluster-type fron config"); } else { getctype = 1; } } if (getctype) { if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogInfo("Using round-robin cluster mode for PF_RING (iface %s)", pfconf->iface); pfconf->ctype = CLUSTER_ROUND_ROBIN; } else if (strcmp(tmpctype, "cluster_flow") == 0) { SCLogInfo("Using flow cluster mode for PF_RING (iface %s)", pfconf->iface); pfconf->ctype = CLUSTER_FLOW; } else { SCLogError(SC_ERR_INVALID_CLUSTER_TYPE, "invalid cluster-type %s", tmpctype); SCFree(pfconf); return NULL; } } #endif /* HAVE_PFRING_CLUSTER_TYPE */ if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (strcmp(tmpctype, "yes") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (strcmp(tmpctype, "no") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "rx-only") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_RXONLY; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", pfconf->iface); } } return pfconf; } int PfringConfigGeThreadsCount(void *conf) { PfringIfaceConfig *pfp = (PfringIfaceConfig *)conf; return pfp->threads; } int PfringConfLevel() { char *def_dev; /* 1.0 config should return a string */ if (ConfGet("pfring.interface", &def_dev) != 1) { return PFRING_CONF_V2; } else { return PFRING_CONF_V1; } return PFRING_CONF_V2; } #ifdef HAVE_PFRING static int GetDevAndParser(char **live_dev, ConfigIfaceParserFunc *parser) { ConfGet("pfring.live-interface", live_dev); /* determine which config type we have */ if (PfringConfLevel() > PFRING_CONF_V1) { *parser = ParsePfringConfig; } else { SCLogInfo("Using 1.0 style configuration for pfring"); *parser = OldParsePfringConfig; /* In v1: try to get interface name from config */ if (*live_dev == NULL) { if (ConfGet("pfring.interface", live_dev) == 1) { SCLogInfo("Using interface %s", *live_dev); LiveRegisterDevice(*live_dev); } else { SCLogInfo("No interface found, problem incoming"); *live_dev = NULL; } } } return 0; } #endif /** * \brief RunModeIdsPfringAuto set up the following thread packet handlers: * - Receive thread (from pfring) * - Decode thread * - Stream thread * - Detect: If we have only 1 cpu, it will setup one Detect thread * If we have more than one, it will setup num_cpus - 1 * starting from the second cpu available. * - Respond/Reject thread * - Outputs thread * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * * \param de_ctx Pointer to the Detection Engine. * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ int RunModeIdsPfringAuto(DetectEngineCtx *de_ctx) { SCEnter(); /* We include only if pfring is enabled */ #ifdef HAVE_PFRING int ret; char *live_dev = NULL; ConfigIfaceParserFunc tparser; RunModeInitialize(); TimeModeSetLive(); ret = GetDevAndParser(&live_dev, &tparser); if (ret != 0) { SCLogError(SC_ERR_MISSING_CONFIG_PARAM, "Unable to get parser and interface params"); exit(EXIT_FAILURE); } ret = RunModeSetLiveCaptureAuto(de_ctx, tparser, PfringConfigGeThreadsCount, "ReceivePfring", "DecodePfring", "RxPFR", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); exit(EXIT_FAILURE); } #endif /* HAVE_PFRING */ return 0; } int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); /* We include only if pfring is enabled */ #ifdef HAVE_PFRING int ret; char *live_dev = NULL; ConfigIfaceParserFunc tparser; RunModeInitialize(); TimeModeSetLive(); ret = GetDevAndParser(&live_dev, &tparser); if (ret != 0) { SCLogError(SC_ERR_MISSING_CONFIG_PARAM, "Unable to get parser and interface params"); exit(EXIT_FAILURE); } ret = RunModeSetLiveCaptureAutoFp(de_ctx, tparser, PfringConfigGeThreadsCount, "ReceivePfring", "DecodePfring", "RxPFR", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsPfringAutoFp initialised"); #endif /* HAVE_PFRING */ return 0; } int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx) { SCEnter(); /* We include only if pfring is enabled */ #ifdef HAVE_PFRING int ret; char *live_dev = NULL; ConfigIfaceParserFunc tparser; RunModeInitialize(); TimeModeSetLive(); ret = GetDevAndParser(&live_dev, &tparser); if (ret != 0) { SCLogError(SC_ERR_MISSING_CONFIG_PARAM, "Unable to get parser and interface params"); exit(EXIT_FAILURE); } ret = RunModeSetLiveCaptureSingle(de_ctx, tparser, PfringConfigGeThreadsCount, "ReceivePfring", "DecodePfring", "RxPFR", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsPfringSingle initialised"); #endif /* HAVE_PFRING */ return 0; } int RunModeIdsPfringWorkers(DetectEngineCtx *de_ctx) { SCEnter(); /* We include only if pfring is enabled */ #ifdef HAVE_PFRING int ret; char *live_dev = NULL; ConfigIfaceParserFunc tparser; RunModeInitialize(); TimeModeSetLive(); ret = GetDevAndParser(&live_dev, &tparser); if (ret != 0) { SCLogError(SC_ERR_MISSING_CONFIG_PARAM, "Unable to get parser and interface params"); exit(EXIT_FAILURE); } ret = RunModeSetLiveCaptureWorkers(de_ctx, tparser, PfringConfigGeThreadsCount, "ReceivePfring", "DecodePfring", "RxPFR", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsPfringWorkers initialised"); #endif /* HAVE_PFRING */ return 0; } suricata-1.4.7/src/app-layer-detect-proto.c0000644000000000000000000016603412253546156015504 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien * * A simple application layer (L7) protocol detector. It works by allowing * developers to set a series of patterns that if exactly matching indicate * that the session is a certain protocol. * * \todo More advanced detection methods, regex maybe. * \todo Fall back to port based classification if other detection fails. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-content.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "util-print.h" #include "util-pool.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "flow.h" #include "flow-util.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-detect-proto.h" #include "util-spm.h" #include "util-cuda.h" #include "util-cuda-handlers.h" #include "util-mpm-b2g-cuda.h" #include "util-debug.h" #define INSPECT_BYTES 32 /* undef __SC_CUDA_SUPPORT__. We will get back to this later. Need to * analyze the performance of cuda support for app layer */ #undef __SC_CUDA_SUPPORT__ /** global app layer detection context */ AlpProtoDetectCtx alp_proto_ctx; /** \brief Initialize the app layer proto detection */ void AlpProtoInit(AlpProtoDetectCtx *ctx) { memset(ctx, 0x00, sizeof(AlpProtoDetectCtx)); #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(&ctx->toserver.mpm_ctx, MPM_B2G, -1); MpmInitCtx(&ctx->toclient.mpm_ctx, MPM_B2G, -1); #else ctx->alp_content_module_handle = SCCudaHlRegisterModule("SC_ALP_CONTENT_B2G_CUDA"); MpmInitCtx(&ctx->toserver.mpm_ctx, MPM_B2G_CUDA, ctx->alp_content_module_handle); MpmInitCtx(&ctx->toclient.mpm_ctx, MPM_B2G_CUDA, ctx->alp_content_module_handle); #endif memset(&ctx->toserver.map, 0x00, sizeof(ctx->toserver.map)); memset(&ctx->toclient.map, 0x00, sizeof(ctx->toclient.map)); ctx->toserver.id = 0; ctx->toclient.id = 0; ctx->toclient.min_len = INSPECT_BYTES; ctx->toserver.min_len = INSPECT_BYTES; ctx->mpm_pattern_id_store = MpmPatternIdTableInitHash(); } /** * \brief Turn a proto detection into a AlpProtoSignature and store it * in the ctx. * * \param ctx the contex * \param co the content match * \param proto the proto id * \initonly */ static void AlpProtoAddSignature(AlpProtoDetectCtx *ctx, DetectContentData *co, uint16_t ip_proto, uint16_t proto) { AlpProtoSignature *s = SCMalloc(sizeof(AlpProtoSignature)); if (unlikely(s == NULL)) { SCLogError(SC_ERR_FATAL, "Error allocating memory. Signature not loaded. Not enough memory so.. exiting.."); exit(EXIT_FAILURE); } memset(s, 0x00, sizeof(AlpProtoSignature)); s->ip_proto = ip_proto; s->proto = proto; s->co = co; if (ctx->head == NULL) { ctx->head = s; } else { s->next = ctx->head; ctx->head = s; } ctx->sigs++; } #ifdef UNITTESTS /** \brief free a AlpProtoSignature, recursively free any next sig */ static void AlpProtoFreeSignature(AlpProtoSignature *s) { if (s == NULL) return; DetectContentFree(s->co); s->co = NULL; s->proto = 0; AlpProtoSignature *next_s = s->next; SCFree(s); AlpProtoFreeSignature(next_s); } #endif /** * \brief Match a AlpProtoSignature against a buffer * * \param s signature * \param buf pointer to buffer * \param buflen length of the buffer * \param ip_proto packet's ip_proto * * \retval proto the detected proto or ALPROTO_UNKNOWN if no match */ static uint16_t AlpProtoMatchSignature(AlpProtoSignature *s, uint8_t *buf, uint16_t buflen, uint16_t ip_proto) { SCEnter(); uint16_t proto = ALPROTO_UNKNOWN; if (s->ip_proto != ip_proto) { goto end; } if (s->co->offset > buflen) { SCLogDebug("s->co->offset (%"PRIu16") > buflen (%"PRIu16")", s->co->offset, buflen); goto end; } if (s->co->depth > buflen) { SCLogDebug("s->co->depth (%"PRIu16") > buflen (%"PRIu16")", s->co->depth, buflen); goto end; } uint8_t *sbuf = buf + s->co->offset; uint16_t sbuflen = s->co->depth - s->co->offset; SCLogDebug("s->co->offset (%"PRIu16") s->co->depth (%"PRIu16")", s->co->offset, s->co->depth); uint8_t *found = SpmSearch(sbuf, sbuflen, s->co->content, s->co->content_len); if (found != NULL) { proto = s->proto; } end: SCReturnInt(proto); } /** * \brief Add a proto detection string to the detection ctx. * * \param ctx The detection ctx * \param ip_proto The IP proto (TCP, UDP, etc) * \param al_proto Application layer proto * \param content A content string in the 'content:"some|20|string"' format. * \param depth Depth setting for the content. E.g. 4 means that the content has to match in the first 4 bytes of the stream. * \param offset Offset setting for the content. E.g. 4 mean that the content has to match after the first 4 bytes of the stream. * \param flags Set STREAM_TOCLIENT or STREAM_TOSERVER for the direction in which to try to match the content. */ void AlpProtoAdd(AlpProtoDetectCtx *ctx, char *name, uint16_t ip_proto, uint16_t al_proto, char *content, uint16_t depth, uint16_t offset, uint8_t flags) { if (al_proto_table[al_proto].name != NULL) { BUG_ON(strcmp(al_proto_table[al_proto].name, name) != 0); } else { al_proto_table[al_proto].name = name; } DetectContentData *cd = DetectContentParseEncloseQuotes(content); if (cd == NULL) { return; } cd->depth = depth; cd->offset = offset; cd->id = DetectContentGetId(ctx->mpm_pattern_id_store, cd); //PrintRawDataFp(stdout,cd->content,cd->content_len); SCLogDebug("cd->depth %"PRIu16" and cd->offset %"PRIu16" cd->id %"PRIu32"", cd->depth, cd->offset, cd->id); AlpProtoDetectDirection *dir; if (flags & STREAM_TOCLIENT) { dir = &ctx->toclient; } else { dir = &ctx->toserver; } mpm_table[dir->mpm_ctx.mpm_type].AddPattern(&dir->mpm_ctx, cd->content, cd->content_len, cd->offset, cd->depth, cd->id, cd->id, 0); BUG_ON(dir->id == ALP_DETECT_MAX); dir->map[dir->id] = al_proto; dir->id++; if (depth > dir->max_len) dir->max_len = depth; /* set the min_len for the stream engine to set the min smsg size for app layer*/ if (depth < dir->min_len) dir->min_len = depth; /* finally turn into a signature and add to the ctx */ AlpProtoAddSignature(ctx, cd, ip_proto, al_proto); } #ifdef UNITTESTS void AlpProtoTestDestroy(AlpProtoDetectCtx *ctx) { mpm_table[ctx->toserver.mpm_ctx.mpm_type].DestroyCtx(&ctx->toserver.mpm_ctx); mpm_table[ctx->toclient.mpm_ctx.mpm_type].DestroyCtx(&ctx->toclient.mpm_ctx); AlpProtoFreeSignature(ctx->head); AppLayerFreeProbingParsers(ctx->probing_parsers); ctx->probing_parsers = NULL; AppLayerFreeProbingParsersInfo(ctx->probing_parsers_info); ctx->probing_parsers_info = NULL; } #endif void AlpProtoDestroy() { SCEnter(); mpm_table[alp_proto_ctx.toserver.mpm_ctx.mpm_type].DestroyCtx(&alp_proto_ctx.toserver.mpm_ctx); mpm_table[alp_proto_ctx.toclient.mpm_ctx.mpm_type].DestroyCtx(&alp_proto_ctx.toclient.mpm_ctx); MpmPatternIdTableFreeHash(alp_proto_ctx.mpm_pattern_id_store); AppLayerFreeProbingParsers(alp_proto_ctx.probing_parsers); alp_proto_ctx.probing_parsers = NULL; AppLayerFreeProbingParsersInfo(alp_proto_ctx.probing_parsers_info); alp_proto_ctx.probing_parsers_info = NULL; SCReturn; } void AlpProtoFinalizeThread(AlpProtoDetectCtx *ctx, AlpProtoDetectThreadCtx *tctx) { uint32_t sig_maxid = 0; uint32_t pat_maxid = ctx->mpm_pattern_id_store ? ctx->mpm_pattern_id_store->max_id : 0; memset(tctx, 0x00, sizeof(AlpProtoDetectThreadCtx)); if (ctx->toclient.id > 0) { //sig_maxid = ctx->toclient.id; mpm_table[ctx->toclient.mpm_ctx.mpm_type].InitThreadCtx(&ctx->toclient.mpm_ctx, &tctx->toclient.mpm_ctx, sig_maxid); PmqSetup(&tctx->toclient.pmq, sig_maxid, pat_maxid); } if (ctx->toserver.id > 0) { //sig_maxid = ctx->toserver.id; mpm_table[ctx->toserver.mpm_ctx.mpm_type].InitThreadCtx(&ctx->toserver.mpm_ctx, &tctx->toserver.mpm_ctx, sig_maxid); PmqSetup(&tctx->toserver.pmq, sig_maxid, pat_maxid); } int i; for (i = 0; i < ALPROTO_MAX; i++) { tctx->alproto_local_storage[i] = AppLayerGetProtocolParserLocalStorage(i); } return; } void AlpProtoDeFinalize2Thread(AlpProtoDetectThreadCtx *tctx) { if (alp_proto_ctx.toclient.id > 0) { mpm_table[alp_proto_ctx.toclient.mpm_ctx.mpm_type].DestroyThreadCtx (&alp_proto_ctx.toclient.mpm_ctx, &tctx->toclient.mpm_ctx); PmqFree(&tctx->toclient.pmq); } if (alp_proto_ctx.toserver.id > 0) { mpm_table[alp_proto_ctx.toserver.mpm_ctx.mpm_type].DestroyThreadCtx (&alp_proto_ctx.toserver.mpm_ctx, &tctx->toserver.mpm_ctx); PmqFree(&tctx->toserver.pmq); } } /** \brief to be called by ReassemblyThreadInit * \todo this is a hack, we need a proper place to store the global ctx */ void AlpProtoFinalize2Thread(AlpProtoDetectThreadCtx *tctx) { AlpProtoFinalizeThread(&alp_proto_ctx, tctx); return; } void AlpProtoFinalizeGlobal(AlpProtoDetectCtx *ctx) { if (ctx == NULL) return; mpm_table[ctx->toclient.mpm_ctx.mpm_type].Prepare(&ctx->toclient.mpm_ctx); mpm_table[ctx->toserver.mpm_ctx.mpm_type].Prepare(&ctx->toserver.mpm_ctx); #ifdef __SC_CUDA_SUPPORT__ CUcontext context; if (SCCudaCtxPopCurrent(&context) == -1) exit(EXIT_FAILURE); if (B2gCudaStartDispatcherThreadAPC("SC_ALP_CONTENT_B2G_CUDA") == -1) exit(EXIT_FAILURE); #endif /* allocate and initialize the mapping between pattern id and signature */ ctx->map = (AlpProtoSignature **)SCMalloc(ctx->sigs * sizeof(AlpProtoSignature *)); if (ctx->map == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "%s", strerror(errno)); return; } memset(ctx->map, 0x00, ctx->sigs * sizeof(AlpProtoSignature *)); AlpProtoSignature *s = ctx->head; AlpProtoSignature *temp = NULL; for ( ; s != NULL; s = s->next) { BUG_ON(s->co == NULL); if (ctx->map[s->co->id] == NULL) { ctx->map[s->co->id] = s; } else { temp = ctx->map[s->co->id]; while (temp->map_next != NULL) temp = temp->map_next; temp->map_next = s; } } } void AppLayerDetectProtoThreadInit(void) { AlpProtoInit(&alp_proto_ctx); RegisterAppLayerParsers(); AlpProtoFinalizeGlobal(&alp_proto_ctx); return; } /** * \brief Get the app layer proto based on a buffer using a Patter matcher * parser. * * \param ctx Global app layer detection context * \param tctx Thread app layer detection context * \param buf Pointer to the buffer to inspect * \param buflen Lenght of the buffer * \param flags Flags. * * \retval proto App Layer proto, or ALPROTO_UNKNOWN if unknown */ uint16_t AppLayerDetectGetProtoPMParser(AlpProtoDetectCtx *ctx, AlpProtoDetectThreadCtx *tctx, uint8_t *buf, uint16_t buflen, uint8_t flags, uint8_t ipproto) { SCEnter(); AlpProtoDetectDirection *dir; AlpProtoDetectDirectionThread *tdir; if (flags & STREAM_TOSERVER) { dir = &ctx->toserver; tdir = &tctx->toserver; } else { dir = &ctx->toclient; tdir = &tctx->toclient; } if (dir->id == 0) { SCReturnUInt(ALPROTO_UNKNOWN); } /* see if we can limit the data we inspect */ uint16_t searchlen = buflen; if (searchlen > dir->max_len) searchlen = dir->max_len; uint16_t proto = ALPROTO_UNKNOWN; uint32_t cnt = 0; /* do the mpm search */ #ifndef __SC_CUDA_SUPPORT__ cnt = mpm_table[dir->mpm_ctx.mpm_type].Search(&dir->mpm_ctx, &tdir->mpm_ctx, &tdir->pmq, buf, searchlen); #else Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) goto end; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->cuda_done = 0; p->cuda_free_packet = 1; p->cuda_search = 0; p->cuda_mpm_ctx = &dir->mpm_ctx; p->cuda_mtc = &tdir->mpm_ctx; p->cuda_pmq = &tdir->pmq; p->payload = buf; p->payload_len = searchlen; B2gCudaPushPacketTo_tv_CMB2_APC(p); SCMutexLock(&p->cuda_mutex_q); SCCondWait(&p->cuda_cond_q, &p->cuda_mutex_q); p->cuda_done = 1; SCMutexUnlock(&p->cuda_mutex_q); cnt = p->cuda_matches; #endif SCLogDebug("search cnt %" PRIu32 "", cnt); if (cnt == 0) { proto = ALPROTO_UNKNOWN; goto end; } /* We just work with the first match */ uint16_t patid = tdir->pmq.pattern_id_array[0]; SCLogDebug("array count is %"PRIu32" patid %"PRIu16"", tdir->pmq.pattern_id_array_cnt, patid); AlpProtoSignature *s = ctx->map[patid]; if (s == NULL) { goto end; } uint8_t s_cnt = 1; while (proto == ALPROTO_UNKNOWN && s != NULL) { proto = AlpProtoMatchSignature(s, buf, buflen, ipproto); s = s->map_next; if (s == NULL && s_cnt < tdir->pmq.pattern_id_array_cnt) { patid = tdir->pmq.pattern_id_array[s_cnt]; s = ctx->map[patid]; s_cnt++; } } end: PmqReset(&tdir->pmq); if (mpm_table[dir->mpm_ctx.mpm_type].Cleanup != NULL) { mpm_table[dir->mpm_ctx.mpm_type].Cleanup(&tdir->mpm_ctx); } #if 0 printf("AppLayerDetectGetProto: returning %" PRIu16 " (%s): ", proto, flags & STREAM_TOCLIENT ? "TOCLIENT" : "TOSERVER"); switch (proto) { case ALPROTO_HTTP: printf("HTTP: "); /* print the first 32 bytes */ if (buflen > 0) { PrintRawUriFp(stdout,buf,(buflen>32)?32:buflen); } printf("\n"); break; case ALPROTO_FTP: printf("FTP\n"); break; case ALPROTO_SSL: printf("SSL\n"); break; case ALPROTO_SSH: printf("SSH\n"); break; case ALPROTO_TLS: printf("TLS\n"); break; case ALPROTO_IMAP: printf("IMAP\n"); break; case ALPROTO_SMTP: printf("SMTP\n"); break; case ALPROTO_JABBER: printf("JABBER\n"); break; case ALPROTO_MSN: printf("MSN\n"); break; case ALPROTO_SMB: printf("SMB\n"); break; case ALPROTO_SMB2: printf("SMB2\n"); break; case ALPROTO_DCERPC: printf("DCERPC\n"); break; case ALPROTO_UNKNOWN: default: printf("UNKNOWN (%u): cnt was %u (", proto, cnt); /* print the first 32 bytes */ if (buflen > 0) { PrintRawUriFp(stdout,buf,(buflen>32)?32:buflen); } printf(")\n"); break; } #endif SCReturnUInt(proto); } /** * \brief Call the probing parser if it exists for this src or dst port. */ uint16_t AppLayerDetectGetProtoProbingParser(AlpProtoDetectCtx *ctx, Flow *f, uint8_t *buf, uint32_t buflen, uint8_t flags, uint8_t ipproto) { AppLayerProbingParserElement *pe = NULL; AppLayerProbingParser *probing_parsers = ctx->probing_parsers; AppLayerProbingParser *pp = NULL; uint32_t *al_proto_masks; if (flags & STREAM_TOSERVER) { pp = AppLayerGetProbingParsers(probing_parsers, ipproto, f->dp); al_proto_masks = &f->probing_parser_toserver_al_proto_masks; if (pp == NULL) { SCLogDebug("toserver-No probing parser registered for port %"PRIu16, f->dp); if (f->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE) { f->flags |= FLOW_TS_PM_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } f->flags |= FLOW_TS_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } pe = pp->toserver; } else { pp = AppLayerGetProbingParsers(probing_parsers, ipproto, f->sp); al_proto_masks = &f->probing_parser_toclient_al_proto_masks; if (pp == NULL) { SCLogDebug("toclient-No probing parser registered for port %"PRIu16, f->sp); if (f->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE) { f->flags |= FLOW_TC_PM_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } f->flags |= FLOW_TC_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } pe = pp->toclient; } while (pe != NULL) { if ((buflen < pe->min_depth) || (al_proto_masks[0] & pe->al_proto_mask)) { pe = pe->next; continue; } int alproto = pe->ProbingParser(buf, buflen); if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) return alproto; if (alproto == ALPROTO_FAILED || (pe->max_depth != 0 && buflen > pe->max_depth)) { al_proto_masks[0] |= pe->al_proto_mask; } pe = pe->next; } if (flags & STREAM_TOSERVER) { if (al_proto_masks[0] == pp->toserver_al_proto_mask) { if (f->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE) { f->flags |= FLOW_TS_PM_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } f->flags |= FLOW_TS_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } } else { if (al_proto_masks[0] == pp->toclient_al_proto_mask) { if (f->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE) { f->flags |= FLOW_TC_PM_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } f->flags |= FLOW_TC_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } } return ALPROTO_UNKNOWN; } /** * \brief Get the app layer proto. * * \param ctx Global app layer detection context. * \param tctx Thread app layer detection context. * \param f Pointer to the flow. * \param buf Pointer to the buffer to inspect. * \param buflen Lenght of the buffer. * \param flags Flags. * * \retval proto App Layer proto, or ALPROTO_UNKNOWN if unknown */ uint16_t AppLayerDetectGetProto(AlpProtoDetectCtx *ctx, AlpProtoDetectThreadCtx *tctx, Flow *f, uint8_t *buf, uint32_t buflen, uint8_t flags, uint8_t ipproto) { uint16_t alproto = ALPROTO_UNKNOWN; if (flags & STREAM_TOSERVER) { if (buflen >= alp_proto_ctx.toserver.max_len) { if (f->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE) { /* the PM parser has already tried and failed. Now it is * upto the probing parser */ ; } else { alproto = AppLayerDetectGetProtoPMParser(ctx, tctx, buf, buflen, flags, ipproto); if (alproto != ALPROTO_UNKNOWN) return alproto; /* the alproto hasn't been detected at this point */ if (f->flags & FLOW_TS_PP_ALPROTO_DETECT_DONE) { f->flags |= FLOW_TS_PM_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } f->flags |= FLOW_TS_PM_ALPROTO_DETECT_DONE; } } else { alproto = AppLayerDetectGetProtoPMParser(ctx, tctx, buf, buflen, flags, ipproto); if (alproto != ALPROTO_UNKNOWN) return alproto; } /* If we have reached here, the PM parser has failed to detect the * alproto */ return AppLayerDetectGetProtoProbingParser(ctx, f, buf, buflen, flags, ipproto); /* STREAM_TOCLIENT */ } else { if (buflen >= alp_proto_ctx.toclient.max_len) { if (f->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE) { ; } else { alproto = AppLayerDetectGetProtoPMParser(ctx, tctx, buf, buflen, flags, ipproto); if (alproto != ALPROTO_UNKNOWN) return alproto; if (f->flags & FLOW_TC_PP_ALPROTO_DETECT_DONE) { f->flags |= FLOW_TC_PM_PP_ALPROTO_DETECT_DONE; return ALPROTO_UNKNOWN; } f->flags |= FLOW_TC_PM_ALPROTO_DETECT_DONE; } } else { alproto = AppLayerDetectGetProtoPMParser(ctx, tctx, buf, buflen, flags, ipproto); if (alproto != ALPROTO_UNKNOWN) return alproto; } return AppLayerDetectGetProtoProbingParser(ctx, f, buf, buflen, flags, ipproto); } } /* VJ Originally I thought of having separate app layer * handling threads, leaving this here in case we'll revisit that */ #if 0 void *AppLayerDetectProtoThread(void *td) { ThreadVars *tv = (ThreadVars *)td; char run = TRUE; /* get the stream msg queue for this thread */ StreamMsgQueue *stream_q = StreamMsgQueueGetByPort(0); TmThreadsSetFlag(tv, THV_INIT_DONE); /* main loop */ while(run) { if (TmThreadsCheckFlag(tv, THV_PAUSE)) { TmThreadsSetFlag(tv, THV_PAUSED); TmThreadTestThreadUnPaused(tv); TmThreadsUnsetFlag(tv, THV_PAUSED); } /* grab a msg, can return NULL on signals */ StreamMsg *smsg = StreamMsgGetFromQueue(stream_q); if (smsg != NULL) { AppLayerHandleMsg(smsg, TRUE); } if (TmThreadsCheckFlag(tv, THV_KILL)) { SCPerfSyncCounters(tv, 0); run = 0; } } pthread_exit((void *) 0); } void AppLayerDetectProtoThreadSpawn() { ThreadVars *tv_applayerdetect = NULL; tv_applayerdetect = TmThreadCreateMgmtThread("AppLayerDetectProtoThread", AppLayerDetectProtoThread, 0); if (tv_applayerdetect == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(1); } if (TmThreadSpawn(tv_applayerdetect) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(1); } #ifdef DEBUG printf("AppLayerDetectProtoThread thread created\n"); #endif return; } #endif #ifdef UNITTESTS int AlpDetectTest01(void) { char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } buf = SCStrdup("GET"); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOSERVER); if (ctx.toserver.id != 1) { r = 0; } SCFree(buf); AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest02(void) { char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } buf = SCStrdup("220 "); AlpProtoAdd(&ctx, "ftp", IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 2) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_FTP) { r = 0; } AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest03(void) { uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } buf = SCStrdup("220 "); AlpProtoAdd(&ctx, "ftp", IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 2) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_FTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif uint32_t cnt = mpm_table[ctx.toclient.mpm_ctx.mpm_type].Search(&ctx.toclient.mpm_ctx, &tctx.toclient.mpm_ctx, NULL, l7data, sizeof(l7data)); if (cnt != 1) { printf("cnt %u != 1: ", cnt); r = 0; } AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest04(void) { uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; char *buf = SCStrdup("200 "); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif uint32_t cnt = mpm_table[ctx.toclient.mpm_ctx.mpm_type].Search(&ctx.toclient.mpm_ctx, &tctx.toclient.mpm_ctx, &tctx.toclient.pmq, l7data, sizeof(l7data)); if (cnt != 1) { printf("cnt %u != 1: ", cnt); r = 0; } AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest05(void) { uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\nBlahblah"; char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } buf = SCStrdup("220 "); AlpProtoAdd(&ctx, "ftp", IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 2) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_FTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT, IPPROTO_TCP); if (proto != ALPROTO_HTTP) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest06(void) { uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n"; char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } buf = SCStrdup("220 "); AlpProtoAdd(&ctx, "ftp", IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 2) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_FTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT, IPPROTO_TCP); if (proto != ALPROTO_FTP) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_FTP); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest07(void) { uint8_t l7data[] = "220 Welcome to the OISF HTTP/FTP server\r\n"; char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT, IPPROTO_TCP); if (proto != ALPROTO_UNKNOWN) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_UNKNOWN); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest08(void) { uint8_t l7data[] = "\x00\x00\x00\x85" // NBSS "\xff\x53\x4d\x42\x72\x00\x00\x00" // SMB "\x00\x18\x53\xc8\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\xff\xfe\x00\x00\x00\x00" "\x00" // WordCount "\x62\x00" // ByteCount "\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20" "\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73" "\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c" "\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54" "\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"; char *buf = SCStrdup("|ff|SMB"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "smb", IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_SMB) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT, IPPROTO_TCP); if (proto != ALPROTO_SMB) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_SMB); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest09(void) { uint8_t l7data[] = "\x00\x00\x00\x66" // NBSS "\xfe\x53\x4d\x42\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00" // SMB2 "\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x24\x00\x01\x00x00\x00\x00\x00\x00\x00\x0\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x02"; char *buf = SCStrdup("|fe|SMB"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "smb2", IPPROTO_TCP, ALPROTO_SMB2, buf, 8, 4, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_SMB2) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT, IPPROTO_TCP); if (proto != ALPROTO_SMB2) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_SMB2); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest10(void) { uint8_t l7data[] = "\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00\x00\x00" "\x00\x00\x00\x00\xd0\x16\xd0\x16\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00" "\x01\x00\xb8\x4a\x9f\x4d\x1c\x7d\xcf\x11\x86\x1e\x00\x20\xaf\x6e\x7c\x57" "\x00\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10" "\x48\x60\x02\x00\x00\x00"; char *buf = SCStrdup("|05 00|"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "dcerpc", IPPROTO_TCP, ALPROTO_DCERPC, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_DCERPC) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT, IPPROTO_TCP); if (proto != ALPROTO_DCERPC) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_DCERPC); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } /** \test why we still get http for connect... obviously because we also match on the reply, duh */ int AlpDetectTest11(void) { uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, "POST", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, "TRACE", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS", 7, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOCLIENT); if (ctx.toserver.id != 6) { printf("ctx.toserver.id %u != 6: ", ctx.toserver.id); r = 0; } if (ctx.toserver.map[ctx.toserver.id - 1] != ALPROTO_HTTP) { printf("ctx.toserver.id %u != %u: ", ctx.toserver.map[ctx.toserver.id - 1],ALPROTO_HTTP); r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data, sizeof(l7data), STREAM_TOCLIENT, IPPROTO_TCP); if (proto == ALPROTO_HTTP) { printf("proto %" PRIu8 " == %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data_resp, sizeof(l7data_resp), STREAM_TOSERVER, IPPROTO_TCP); if (proto != ALPROTO_HTTP) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } AlpProtoTestDestroy(&ctx); return r; } /** \test AlpProtoSignature test */ int AlpDetectTest12(void) { AlpProtoDetectCtx ctx; int r = 0; AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); AlpProtoFinalizeGlobal(&ctx); if (ctx.head == NULL) { printf("ctx.head == NULL: "); goto end; } if (ctx.head->proto != ALPROTO_HTTP) { printf("ctx.head->proto != ALPROTO_HTTP: "); goto end; } if (ctx.sigs != 1) { printf("ctx.sigs %"PRIu16", expected 1: ", ctx.sigs); goto end; } if (ctx.map == NULL) { printf("no mapping: "); goto end; } if (ctx.map[ctx.head->co->id] != ctx.head) { printf("wrong sig: "); goto end; } r = 1; end: return r; } /** * \test What about if we add some sigs only for udp but call for tcp? * It should not detect any proto */ int AlpDetectTest13(void) { uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "POST", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "TRACE", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "OPTIONS", 7, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOCLIENT); if (ctx.toserver.id != 6) { printf("ctx.toserver.id %u != 6: ", ctx.toserver.id); r = 0; } if (ctx.toserver.map[ctx.toserver.id - 1] != ALPROTO_HTTP) { printf("ctx.toserver.id %u != %u: ", ctx.toserver.map[ctx.toserver.id - 1],ALPROTO_HTTP); r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data, sizeof(l7data), STREAM_TOCLIENT, IPPROTO_TCP); if (proto == ALPROTO_HTTP) { printf("proto %" PRIu8 " == %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data_resp, sizeof(l7data_resp), STREAM_TOSERVER, IPPROTO_TCP); if (proto == ALPROTO_HTTP) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } AlpProtoTestDestroy(&ctx); return r; } /** * \test What about if we add some sigs only for udp calling it for UDP? * It should detect ALPROTO_HTTP (over udp). This is just a check * to ensure that TCP/UDP differences work correctly. */ int AlpDetectTest14(void) { uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; AlpProtoInit(&ctx); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "POST", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "TRACE", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "OPTIONS", 7, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, "http", IPPROTO_UDP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOCLIENT); if (ctx.toserver.id != 6) { printf("ctx.toserver.id %u != 6: ", ctx.toserver.id); r = 0; } if (ctx.toserver.map[ctx.toserver.id - 1] != ALPROTO_HTTP) { printf("ctx.toserver.id %u != %u: ", ctx.toserver.map[ctx.toserver.id - 1],ALPROTO_HTTP); r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data, sizeof(l7data), STREAM_TOCLIENT, IPPROTO_UDP); if (proto == ALPROTO_HTTP) { printf("proto %" PRIu8 " == %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } proto = AppLayerDetectGetProtoPMParser(&ctx, &tctx, l7data_resp, sizeof(l7data_resp), STREAM_TOSERVER, IPPROTO_UDP); if (proto != ALPROTO_HTTP) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } AlpProtoTestDestroy(&ctx); return r; } /** \test test if the engine detect the proto and match with it */ static int AlpDetectTestSig1(void) { int result = 0; Flow *f = NULL; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); if (p == NULL) { printf("packet setup failed: "); goto end; } f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); if (f == NULL) { printf("flow setup failed: "); goto end; } f->protoctx = &ssn; p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f->alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(msg:\"Test content option\"; " "sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); UTHFreeFlow(f); return result; } /** \test test if the engine detect the proto on a non standar port * and match with it */ static int AlpDetectTestSig2(void) { int result = 0; Flow *f = NULL; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacketSrcDstPorts(http_buf1, http_buf1_len, IPPROTO_TCP, 12345, 88); f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f->alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any " "(msg:\"http over non standar port\"; " "sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); UTHFreeFlow(f); return result; } /** \test test if the engine detect the proto and doesn't match * because the sig expects another proto (ex ftp)*/ static int AlpDetectTestSig3(void) { int result = 0; Flow *f = NULL; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f->alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ftp any any -> any any " "(msg:\"Test content option\"; " "sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not (it's not ftp): "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); UTHFreeFlow(f); return result; } /** \test test if the engine detect the proto and doesn't match * because the packet has another proto (ex ftp) */ static int AlpDetectTestSig4(void) { int result = 0; Flow *f = NULL; uint8_t http_buf1[] = "MPUT one\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacketSrcDstPorts(http_buf1, http_buf1_len, IPPROTO_TCP, 12345, 88); f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f->alproto = ALPROTO_FTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any " "(msg:\"http over non standar port\"; " "sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, f, ALPROTO_FTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted, but it should not (it's ftp): "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); UTHFreeFlow(f); return result; } /** \test test if the engine detect the proto and match with it * and also against a content option */ static int AlpDetectTestSig5(void) { int result = 0; Flow *f = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP); f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f->alproto = ALPROTO_HTTP; f->proto = IPPROTO_TCP; p->flags |= PKT_STREAM_ADD; p->flags |= PKT_STREAM_EOF; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); if (stream_msg == NULL) { printf("no stream_msg: "); goto end; } memcpy(stream_msg->data.data, http_buf1, http_buf1_len); stream_msg->data.data_len = http_buf1_len; ssn.toserver_smsg_head = stream_msg; ssn.toserver_smsg_tail = stream_msg; de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(msg:\"Test content option\"; " "content:\"one\"; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); UTHFreeFlow(f); return result; } #endif /* UNITTESTS */ void AlpDetectRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("AlpDetectTest01", AlpDetectTest01, 1); UtRegisterTest("AlpDetectTest02", AlpDetectTest02, 1); UtRegisterTest("AlpDetectTest03", AlpDetectTest03, 1); UtRegisterTest("AlpDetectTest04", AlpDetectTest04, 1); UtRegisterTest("AlpDetectTest05", AlpDetectTest05, 1); UtRegisterTest("AlpDetectTest06", AlpDetectTest06, 1); UtRegisterTest("AlpDetectTest07", AlpDetectTest07, 1); UtRegisterTest("AlpDetectTest08", AlpDetectTest08, 1); UtRegisterTest("AlpDetectTest09", AlpDetectTest09, 1); UtRegisterTest("AlpDetectTest10", AlpDetectTest10, 1); UtRegisterTest("AlpDetectTest11", AlpDetectTest11, 1); UtRegisterTest("AlpDetectTest12", AlpDetectTest12, 1); UtRegisterTest("AlpDetectTest13", AlpDetectTest13, 1); UtRegisterTest("AlpDetectTest14", AlpDetectTest14, 1); UtRegisterTest("AlpDetectTestSig1", AlpDetectTestSig1, 1); UtRegisterTest("AlpDetectTestSig2", AlpDetectTestSig2, 1); UtRegisterTest("AlpDetectTestSig3", AlpDetectTestSig3, 1); UtRegisterTest("AlpDetectTestSig4", AlpDetectTestSig4, 1); UtRegisterTest("AlpDetectTestSig5", AlpDetectTestSig5, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-parse.c0000644000000000000000000030277612253546156013570 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * signature parser */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-address.h" #include "detect-engine-port.h" #include "detect-engine-mpm.h" #include "detect-content.h" #include "detect-pcre.h" #include "detect-uricontent.h" #include "detect-reference.h" #include "detect-ipproto.h" #include "detect-flow.h" #include "flow.h" #include "util-rule-vars.h" #include "conf.h" #include "conf-yaml-loader.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "util-classification-config.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "string.h" #include "detect-parse.h" #include "detect-engine-iponly.h" #include "app-layer-detect-proto.h" extern int sc_set_caps; static pcre *config_pcre = NULL; static pcre *option_pcre = NULL; static pcre_extra *config_pcre_extra = NULL; static pcre_extra *option_pcre_extra = NULL; static uint32_t dbg_srcportany_cnt = 0; static uint32_t dbg_dstportany_cnt = 0; /* Context of the app layer proto detection */ extern AlpProtoDetectCtx alp_proto_ctx; /** * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table. */ typedef struct SigDuplWrapper_ { /* the signature we want to wrap */ Signature *s; /* the signature right before the above signatue in the det_ctx->sig_list */ Signature *s_prev; } SigDuplWrapper; #define CONFIG_PARTS 8 #define CONFIG_ACTION 0 #define CONFIG_PROTO 1 #define CONFIG_SRC 2 #define CONFIG_SP 3 #define CONFIG_DIREC 4 #define CONFIG_DST 5 #define CONFIG_DP 6 #define CONFIG_OPTS 7 // action protocol src sp dir dst dp options #define CONFIG_PCRE "^([A-z]+)\\s+([A-z0-9\\-]+)\\s+([\\[\\]A-z0-9\\.\\:_\\$\\!\\-,\\/]+)\\s+([\\:A-z0-9_\\$\\!,]+)\\s+(-\\>|\\<\\>|\\<\\-)\\s+([\\[\\]A-z0-9\\.\\:_\\$\\!\\-,/]+)\\s+([\\:A-z0-9_\\$\\!,]+)(?:\\s+\\((.*)?(?:\\s*)\\))?(?:(?:\\s*)\\n)?\\s*$" #define OPTION_PARTS 3 #define OPTION_PCRE "^\\s*([A-z_0-9-\\.]+)(?:\\s*\\:\\s*(.*)(?prev = NULL; sm->next = NULL; return sm; } /** \brief free a SigMatch * \param sm SigMatch to free. */ void SigMatchFree(SigMatch *sm) { if (sm == NULL) return; /** free the ctx, for that we call the Free func */ if (sm->ctx != NULL) { if (sigmatch_table[sm->type].Free != NULL) { sigmatch_table[sm->type].Free(sm->ctx); } } SCFree(sm); } /* Get the detection module by name */ SigTableElmt *SigTableGet(char *name) { SigTableElmt *st = NULL; int i = 0; for (i = 0; i < DETECT_TBLSIZE; i++) { st = &sigmatch_table[i]; if (st->name != NULL) { if (strcasecmp(name,st->name) == 0) return st; } } return NULL; } /** * \brief Append a SigMatch to the list type. * * \param s Signature. * \param new The sig match to append. * \param list The list to append to. */ void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list) { if (s->sm_lists[list] == NULL) { s->sm_lists[list] = new; s->sm_lists_tail[list] = new; new->next = NULL; new->prev = NULL; } else { SigMatch *cur = s->sm_lists_tail[list]; cur->next = new; new->prev = cur; new->next = NULL; s->sm_lists_tail[list] = new; } new->idx = s->sm_cnt; s->sm_cnt++; } void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list) { if (sm == s->sm_lists[sm_list]) { s->sm_lists[sm_list] = sm->next; } if (sm == s->sm_lists_tail[sm_list]) { s->sm_lists_tail[sm_list] = sm->prev; } if (sm->prev != NULL) sm->prev->next = sm->next; if (sm->next != NULL) sm->next->prev = sm->prev; return; } /** * \brief Returns a pointer to the last SigMatch instance of a particular type * in a Signature of the payload list. * * \param s Pointer to the tail of the sigmatch list * \param type SigMatch type which has to be searched for in the Signature. * * \retval match Pointer to the last SigMatch instance of type 'type'. */ static inline SigMatch *SigMatchGetLastSM(SigMatch *sm, uint8_t type) { while (sm != NULL) { if (sm->type == type) { return sm; } sm = sm->prev; } return NULL; } SigMatch *SigMatchGetLastSMFromLists(Signature *s, int args, ...) { if (args == 0 || args % 2 != 0) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "You need to send an even no of args " "(non zero as well) to this function, since we need a " "SigMatch list for every SigMatch type(send a map of sm_type " "and sm_list) sent"); /* as this is a bug we should abort to ease debugging */ BUG_ON(1); } SigMatch *sm_list[args / 2]; int sm_type[args / 2]; int list_index = 0; va_list ap; int i = 0, j = 0; va_start(ap, args); for (i = 0; i < args; i += 2) { sm_type[list_index] = va_arg(ap, int); sm_list[list_index] = va_arg(ap, SigMatch *); if (sm_list[list_index] != NULL) list_index++; } va_end(ap); if (list_index == 0) return NULL; SigMatch *sm[list_index]; int sm_entries = 0; for (i = 0; i < list_index; i++) { sm[sm_entries] = SigMatchGetLastSM(sm_list[i], sm_type[i]); if (sm[sm_entries] != NULL) sm_entries++; } if (sm_entries == 0) return NULL; SigMatch *temp_sm = NULL; for (i = 1; i < sm_entries; i++) { for (j = i - 1; j >= 0; j--) { if (sm[j + 1]->idx > sm[j]->idx) { temp_sm = sm[j + 1]; sm[j + 1] = sm[j]; sm[j] = temp_sm; continue; } break; } } return sm[0]; } void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, SigMatch **src_sm_list, SigMatch **src_sm_list_tail, SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) { /* we won't do any checks for args */ if (sm->prev != NULL) sm->prev->next = sm->next; if (sm->next != NULL) sm->next->prev = sm->prev; if (sm == *src_sm_list) *src_sm_list = sm->next; if (sm == *src_sm_list_tail) *src_sm_list_tail = sm->prev; if (*dst_sm_list == NULL) { *dst_sm_list = sm; *dst_sm_list_tail = sm; sm->next = NULL; sm->prev = NULL; } else { SigMatch *cur = *dst_sm_list_tail; cur->next = sm; sm->prev = cur; sm->next = NULL; *dst_sm_list_tail = sm; } return; } int SigMatchListSMBelongsTo(Signature *s, SigMatch *key_sm) { int list = 0; for (list = 0; list < DETECT_SM_LIST_MAX; list++) { SigMatch *sm = s->sm_lists[list]; while (sm != NULL) { if (sm == key_sm) return list; sm = sm->next; } } SCLogError(SC_ERR_INVALID_SIGNATURE, "Unable to find the sm in any of the " "sm lists"); return -1; } void SigParsePrepare(void) { char *regexstr = CONFIG_PCRE; const char *eb; int eo; int opts = 0; opts |= PCRE_UNGREEDY; config_pcre = pcre_compile(regexstr, opts, &eb, &eo, NULL); if(config_pcre == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", regexstr, eo, eb); exit(1); } config_pcre_extra = pcre_study(config_pcre, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); exit(1); } regexstr = OPTION_PCRE; opts |= PCRE_UNGREEDY; option_pcre = pcre_compile(regexstr, opts, &eb, &eo, NULL); if(option_pcre == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", regexstr, eo, eb); exit(1); } option_pcre_extra = pcre_study(option_pcre, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); exit(1); } } static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { #define MAX_SUBSTRINGS 30 int ov[MAX_SUBSTRINGS]; int ret = 0, i = 0; SigTableElmt *st = NULL; char *optname = NULL, *optvalue = NULL, *optmore = NULL; const char **arr = SCCalloc(OPTION_PARTS+1, sizeof(char *)); if (unlikely(arr == NULL)) return -1; ret = pcre_exec(option_pcre, option_pcre_extra, optstr, strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS); /* if successful, we either have: * 2: keyword w/o value * 3: keyword w value, final opt OR keyword w/o value, more options coming * 4: keyword w value, more options coming */ if (ret != 2 && ret != 3 && ret != 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec failed: ret %" PRId32 ", optstr \"%s\"", ret, optstr); goto error; } /* extract the substrings */ for (i = 1; i <= ret-1; i++) { if (pcre_get_substring(optstr, ov, MAX_SUBSTRINGS, i, &arr[i-1]) < 0) { goto error; } //printf("SigParseOptions: arr[%" PRId32 "] = \"%s\"\n", i-1, arr[i-1]); } arr[i-1]=NULL; /* Call option parsing */ st = SigTableGet((char *)arr[0]); if (st == NULL) { SCLogError(SC_ERR_RULE_KEYWORD_UNKNOWN, "unknown rule keyword '%s'.", (char *)arr[0]); goto error; } if (st->flags & SIGMATCH_NOOPT) { optname = (char *)arr[0]; optvalue = NULL; if (ret == 3) optmore = (char *)arr[1]; else if (ret == 4) optmore = (char *)arr[2]; else optmore = NULL; } else { optname = (char *)arr[0]; optvalue = (char *)arr[1]; if (ret == 4) optmore = (char *)arr[2]; else optmore = NULL; } /* setup may or may not add a new SigMatch to the list */ if (st->Setup(de_ctx, s, optvalue) < 0) { SCLogDebug("\"%s\" failed to setup", st->name); goto error; } if (ret == 4 && optmore != NULL) { //printf("SigParseOptions: recursive call for more options... (s:%p,m:%p)\n", s, m); if (optname) pcre_free_substring(optname); if (optvalue) pcre_free_substring(optvalue); if (optstr) SCFree(optstr); //if (optmore) pcre_free_substring(optmore); if (arr != NULL) pcre_free_substring_list(arr); return SigParseOptions(de_ctx, s, optmore); } if (optname) pcre_free_substring(optname); if (optvalue) pcre_free_substring(optvalue); if (optmore) pcre_free_substring(optmore); if (optstr) SCFree(optstr); if (arr != NULL) pcre_free_substring_list(arr); return 0; error: if (optname) pcre_free_substring(optname); if (optvalue) pcre_free_substring(optvalue); if (optmore) pcre_free_substring(optmore); if (optstr) SCFree(optstr); if (arr != NULL) pcre_free_substring_list(arr); return -1; } /* XXX implement this for real * */ int SigParseAddress(Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); /* pass on to the address(list) parser */ if (flag == 0) { if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_SRC_ANY; if (DetectAddressParse(&s->src, (char *)addrstr) < 0) goto error; } else { if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_DST_ANY; if (DetectAddressParse(&s->dst, (char *)addrstr) < 0) goto error; } return 0; error: return -1; } /** * \brief Parses the protocol supplied by the Signature. * * http://www.iana.org/assignments/protocol-numbers * * \param s Pointer to the Signature instance to which the parsed * protocol has to be added. * \param protostr Pointer to the character string containing the protocol name. * * \retval 0 On successfully parsing the protocl sent as the argument. * \retval -1 On failure */ int SigParseProto(Signature *s, const char *protostr) { SCEnter(); int r = DetectProtoParse(&s->proto, (char *)protostr); if (r < 0) { s->alproto = AppLayerGetProtoByName(protostr); if (s->alproto != ALPROTO_UNKNOWN) { /* indicate that the signature is app-layer */ s->flags |= SIG_FLAG_APPLAYER; /* We are going to set ip proto from the * registered applayer signatures for proto detection */ AlpProtoSignature *als = alp_proto_ctx.head; while (als != NULL) { if (als->proto == s->alproto) { /* Set the ipproto that this AL proto detection sig needs * Note that an AL proto can be present in more than one * IP proto (over TCP, UDP..) */ s->proto.proto[als->ip_proto / 8] |= 1 << (als->ip_proto % 8); } als = als->next; } SCReturnInt(0); } AppLayerProbingParserInfo *ppi = AppLayerGetProbingParserInfo(alp_proto_ctx.probing_parsers_info, protostr); if (ppi != NULL) { /* indicate that the signature is app-layer */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ppi->al_proto; s->proto.proto[ppi->ip_proto / 8] |= 1 << (ppi->ip_proto % 8); SCReturnInt(0); } SCLogError(SC_ERR_UNKNOWN_PROTOCOL, "protocol \"%s\" cannot be used " "in a signature", protostr); SCReturnInt(-1); } /* if any of these flags are set they are set in a mutually exclusive * manner */ if (s->proto.flags & DETECT_PROTO_ONLY_PKT) { s->flags |= SIG_FLAG_REQUIRE_PACKET; } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) { s->flags |= SIG_FLAG_REQUIRE_STREAM; } SCReturnInt(0); } /** * \brief Parses the port(source or destination) field, from a Signature. * * \param s Pointer to the signature which has to be updated with the * port information. * \param portstr Pointer to the character string containing the port info. * \param Flag which indicates if the portstr received is src or dst * port. For src port: flag = 0, dst port: flag = 1. * * \retval 0 On success. * \retval -1 On failure. */ int SigParsePort(Signature *s, const char *portstr, char flag) { int r = 0; /* XXX VJ exclude handling this for none UDP/TCP proto's */ SCLogDebug("Port group \"%s\" to be parsed", portstr); if (flag == 0) { if (strcasecmp(portstr, "any") == 0) s->flags |= SIG_FLAG_SP_ANY; r = DetectPortParse(&s->sp, (char *)portstr); } else if (flag == 1) { if (strcasecmp(portstr, "any") == 0) s->flags |= SIG_FLAG_DP_ANY; r = DetectPortParse(&s->dp, (char *)portstr); } if (r < 0) return -1; return 0; } /** \retval 1 valid * \retval 0 invalid */ static int SigParseActionRejectValidate(const char *action) { #ifdef HAVE_LIBNET11 #ifdef HAVE_LIBCAP_NG if (sc_set_caps == TRUE) { SCLogError(SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG, "Libnet 1.1 is " "incompatible with POSIX based capabilities with privs dropping. " "For rejects to work, run as root/super user."); return 0; } #endif #else /* no libnet 1.1 */ SCLogError(SC_ERR_LIBNET_REQUIRED_FOR_ACTION, "Libnet 1.1.x is " "required for action \"%s\" but is not compiled into Suricata", action); return 0; #endif return 1; } /** * \brief Parses the action that has been used by the Signature and allots it * to its Signature instance. * * \param s Pointer to the Signature instance to which the action belongs. * \param action Pointer to the action string used by the Signature. * * \retval 0 On successfully parsing the action string and adding it to the * Signature. * \retval -1 On failure. */ int SigParseAction(Signature *s, const char *action) { if (strcasecmp(action, "alert") == 0) { s->action = ACTION_ALERT; return 0; } else if (strcasecmp(action, "drop") == 0) { s->action = ACTION_DROP; return 0; } else if (strcasecmp(action, "pass") == 0) { s->action = ACTION_PASS; return 0; } else if (strcasecmp(action, "reject") == 0) { if (!(SigParseActionRejectValidate(action))) return -1; s->action = ACTION_REJECT|ACTION_DROP; return 0; } else if (strcasecmp(action, "rejectsrc") == 0) { if (!(SigParseActionRejectValidate(action))) return -1; s->action = ACTION_REJECT|ACTION_DROP; return 0; } else if (strcasecmp(action, "rejectdst") == 0) { if (!(SigParseActionRejectValidate(action))) return -1; s->action = ACTION_REJECT_DST|ACTION_DROP; return 0; } else if (strcasecmp(action, "rejectboth") == 0) { if (!(SigParseActionRejectValidate(action))) return -1; s->action = ACTION_REJECT_BOTH|ACTION_DROP; return 0; } else { SCLogError(SC_ERR_INVALID_ACTION,"An invalid action \"%s\" was given",action); return -1; } } /** * \internal * \brief split a signature string into a few blocks for further parsing */ static int SigParseBasics(Signature *s, char *sigstr, char ***result, uint8_t addrs_direction) { #define MAX_SUBSTRINGS 30 int ov[MAX_SUBSTRINGS]; int ret = 0, i = 0; const char **arr = SCCalloc(CONFIG_PARTS + 1, sizeof(char *)); if (unlikely(arr == NULL)) return -1; ret = pcre_exec(config_pcre, config_pcre_extra, sigstr, strlen(sigstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 8 && ret != 9) { SCLogDebug("pcre_exec failed: ret %" PRId32 ", sigstr \"%s\"", ret, sigstr); goto error; } for (i = 1; i <= ret - 1; i++) { if (pcre_get_substring(sigstr, ov, MAX_SUBSTRINGS, i, &arr[i - 1]) < 0) goto error; //printf("SigParseBasics: arr[%" PRId32 "] = \"%s\"\n", i-1, arr[i-1]); } arr[i - 1] = NULL; /* Parse Action */ if (SigParseAction(s, arr[CONFIG_ACTION]) < 0) goto error; /* Parse Proto */ if (SigParseProto(s, arr[CONFIG_PROTO]) < 0) goto error; if (strcmp(arr[CONFIG_DIREC], "<-") == 0) { SCLogError(SC_ERR_INVALID_DIRECTION, "\"<-\" is not a valid direction modifier, \"->\" and \"<>\" are supported."); goto error; } /* Check if it is bidirectional */ if (strcmp(arr[CONFIG_DIREC], "<>") == 0) s->init_flags |= SIG_FLAG_INIT_BIDIREC; /* Parse Address & Ports */ if (SigParseAddress(s, arr[CONFIG_SRC], SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; if (SigParseAddress(s, arr[CONFIG_DST], SIG_DIREC_DST ^ addrs_direction) < 0) goto error; /* For IPOnly */ if (IPOnlySigParseAddress(s, arr[CONFIG_SRC], SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; if (IPOnlySigParseAddress(s, arr[CONFIG_DST], SIG_DIREC_DST ^ addrs_direction) < 0) goto error; /* For "ip" we parse the ports as well, even though they will be just "any". * We do this for later sgh building for the tcp and udp protocols. */ if (DetectProtoContainsProto(&s->proto, IPPROTO_TCP) || DetectProtoContainsProto(&s->proto, IPPROTO_UDP) || DetectProtoContainsProto(&s->proto, IPPROTO_SCTP)) { if (SigParsePort(s, arr[CONFIG_SP], SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; if (SigParsePort(s, arr[CONFIG_DP], SIG_DIREC_DST ^ addrs_direction) < 0) goto error; } *result = (char **)arr; return 0; error: if (arr != NULL) { for (i = 1; i <= ret - 1; i++) { if (arr[i - 1] == NULL) continue; pcre_free_substring(arr[i - 1]); } SCFree(arr); } *result = NULL; return -1; } /** * \brief parse a signature * * \param de_ctx detection engine ctx to add it to * \param s memory structure to store the signature in * \param sigstr the raw signature as a null terminated string * \param addrs_direction direction (for bi-directional sigs) * * \param -1 parse error * \param 0 ok */ int SigParse(DetectEngineCtx *de_ctx, Signature *s, char *sigstr, uint8_t addrs_direction) { SCEnter(); char **basics; s->sig_str = sigstr; int ret = SigParseBasics(s, sigstr, &basics, addrs_direction); if (ret < 0 || basics == NULL) { SCLogDebug("SigParseBasics failed"); SCReturnInt(-1); } #ifdef DEBUG if (SCLogDebugEnabled()) { int i; for (i = 0; basics[i] != NULL; i++) { SCLogDebug("basics[%" PRId32 "]: %p, %s", i, basics[i], basics[i]); } } #endif /* DEBUG */ /* we can have no options, so make sure we have them */ if (basics[CONFIG_OPTS] != NULL) { ret = SigParseOptions(de_ctx, s, SCStrdup(basics[CONFIG_OPTS])); SCLogDebug("ret from SigParseOptions %d", ret); } /* cleanup */ int i = 0; while (basics[i] != NULL) { SCFree(basics[i]); i++; } SCFree(basics); s->sig_str = NULL; DetectIPProtoRemoveAllSMs(s); SCReturnInt(ret); } Signature *SigAlloc (void) { Signature *sig = SCMalloc(sizeof(Signature)); if (unlikely(sig == NULL)) return NULL; memset(sig, 0, sizeof(Signature)); /* assign it to -1, so that we can later check if the value has been * overwritten after the Signature has been parsed, and if it hasn't been * overwritten, we can then assign the default value of 3 */ sig->prio = -1; return sig; } /** * \internal * \brief Free Reference list * * \param s Pointer to the signature */ static void SigRefFree (Signature *s) { SCEnter(); DetectReference *ref = NULL; DetectReference *next_ref = NULL; if (s == NULL) { SCReturn; } SCLogDebug("s %p, s->references %p", s, s->references); for (ref = s->references; ref != NULL;) { next_ref = ref->next; DetectReferenceFree(ref); ref = next_ref; } s->references = NULL; SCReturn; } void SigFree(Signature *s) { if (s == NULL) return; if (s->CidrDst != NULL) IPOnlyCIDRListFree(s->CidrDst); if (s->CidrSrc != NULL) IPOnlyCIDRListFree(s->CidrSrc); int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { SigMatch *sm = s->sm_lists[i], *nsm; while (sm != NULL) { nsm = sm->next; SigMatchFree(sm); sm = nsm; } } DetectAddressHeadCleanup(&s->src); DetectAddressHeadCleanup(&s->dst); if (s->sp != NULL) { DetectPortCleanupList(s->sp); } if (s->dp != NULL) { DetectPortCleanupList(s->dp); } if (s->msg != NULL) SCFree(s->msg); if (s->addr_src_match4 != NULL) { SCFree(s->addr_src_match4); } if (s->addr_dst_match4 != NULL) { SCFree(s->addr_dst_match4); } if (s->addr_src_match6 != NULL) { SCFree(s->addr_src_match6); } if (s->addr_dst_match6 != NULL) { SCFree(s->addr_dst_match6); } SigRefFree(s); SCFree(s); } /** * \internal * \brief build address match array for cache efficient matching * * \param s the signature */ static void SigBuildAddressMatchArray(Signature *s) { /* source addresses */ uint16_t cnt = 0; uint16_t idx = 0; DetectAddress *da = s->src.ipv4_head; for ( ; da != NULL; da = da->next) { cnt++; } if (cnt > 0) { s->addr_src_match4 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv4)); if (s->addr_src_match4 == NULL) { exit(EXIT_FAILURE); } for (da = s->src.ipv4_head; da != NULL; da = da->next) { s->addr_src_match4[idx].ip = ntohl(da->ip.addr_data32[0]); s->addr_src_match4[idx].ip2 = ntohl(da->ip2.addr_data32[0]); idx++; } s->addr_src_match4_cnt = cnt; } /* destination addresses */ cnt = 0; idx = 0; da = s->dst.ipv4_head; for ( ; da != NULL; da = da->next) { cnt++; } if (cnt > 0) { s->addr_dst_match4 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv4)); if (s->addr_dst_match4 == NULL) { exit(EXIT_FAILURE); } for (da = s->dst.ipv4_head; da != NULL; da = da->next) { s->addr_dst_match4[idx].ip = ntohl(da->ip.addr_data32[0]); s->addr_dst_match4[idx].ip2 = ntohl(da->ip2.addr_data32[0]); idx++; } s->addr_dst_match4_cnt = cnt; } /* source addresses IPv6 */ cnt = 0; idx = 0; da = s->src.ipv6_head; for ( ; da != NULL; da = da->next) { cnt++; } if (cnt > 0) { s->addr_src_match6 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv6)); if (s->addr_src_match6 == NULL) { exit(EXIT_FAILURE); } for (da = s->src.ipv6_head; da != NULL; da = da->next) { s->addr_src_match6[idx].ip[0] = ntohl(da->ip.addr_data32[0]); s->addr_src_match6[idx].ip[1] = ntohl(da->ip.addr_data32[1]); s->addr_src_match6[idx].ip[2] = ntohl(da->ip.addr_data32[2]); s->addr_src_match6[idx].ip[3] = ntohl(da->ip.addr_data32[3]); s->addr_src_match6[idx].ip2[0] = ntohl(da->ip2.addr_data32[0]); s->addr_src_match6[idx].ip2[1] = ntohl(da->ip2.addr_data32[1]); s->addr_src_match6[idx].ip2[2] = ntohl(da->ip2.addr_data32[2]); s->addr_src_match6[idx].ip2[3] = ntohl(da->ip2.addr_data32[3]); idx++; } s->addr_src_match6_cnt = cnt; } /* destination addresses IPv6 */ cnt = 0; idx = 0; da = s->dst.ipv6_head; for ( ; da != NULL; da = da->next) { cnt++; } if (cnt > 0) { s->addr_dst_match6 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv6)); if (s->addr_dst_match6 == NULL) { exit(EXIT_FAILURE); } for (da = s->dst.ipv6_head; da != NULL; da = da->next) { s->addr_dst_match6[idx].ip[0] = ntohl(da->ip.addr_data32[0]); s->addr_dst_match6[idx].ip[1] = ntohl(da->ip.addr_data32[1]); s->addr_dst_match6[idx].ip[2] = ntohl(da->ip.addr_data32[2]); s->addr_dst_match6[idx].ip[3] = ntohl(da->ip.addr_data32[3]); s->addr_dst_match6[idx].ip2[0] = ntohl(da->ip2.addr_data32[0]); s->addr_dst_match6[idx].ip2[1] = ntohl(da->ip2.addr_data32[1]); s->addr_dst_match6[idx].ip2[2] = ntohl(da->ip2.addr_data32[2]); s->addr_dst_match6[idx].ip2[3] = ntohl(da->ip2.addr_data32[3]); idx++; } s->addr_dst_match6_cnt = cnt; } } /** * \internal * \brief validate a just parsed signature for internal inconsistencies * * \param s just parsed signature * * \retval 0 invalid * \retval 1 valid */ static int SigValidate(Signature *s) { uint32_t u = 0; SigMatch *sm, *pm; SCEnter(); if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && (s->flags & SIG_FLAG_REQUIRE_STREAM)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't mix packet keywords with " "tcp-stream or flow:only_stream. Invalidating signature."); SCReturnInt(0); } for (sm = s->sm_lists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_FLOW) { DetectFlowData *fd = (DetectFlowData *)sm->ctx; if (fd == NULL) continue; if (fd->flags & FLOW_PKT_TOCLIENT) { /* check for uricontent + from_server/to_client */ if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use uricontent " "/http_uri , raw_uri, http_client_body, " "http_method, http_user_agent keywords " "with flow:to_client or flow:from_server"); SCReturnInt(0); } } else if (fd->flags & FLOW_PKT_TOSERVER) { /* check for uricontent + from_server/to_client */ if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use http_" "server_body, http_stat_msg, http_stat_code " "with flow:to_server or flow:from_client"); SCReturnInt(0); } } } } if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) { SCLogError(SC_ERR_INVALID_SIGNATURE,"http_raw_header signature " "without a flow direction. Use flow:to_server for " "inspecting request headers or flow:to_client for " "inspecting response headers."); SCReturnInt(0); } #ifndef HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW if (s->flags & SIG_FLAG_TOCLIENT) { SCLogError(SC_ERR_INVALID_SIGNATURE,"http_raw_header signature with " "to_client flow direction. See issues #389 and #397. Update " "libhtp to at least 0.2.7."); SCReturnInt(0); } #endif /* HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW */ } if (s->alproto == ALPROTO_DCERPC) { /* \todo We haven't covered dce rpc cases now. They need special * treatment, since they do allow distance, within without a * previous content, but with respect to the stub buffer */ ; } else { SigMatch *sm; for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)sm->ctx; if ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_PCRE, sm->prev, DETECT_BYTEJUMP, sm->prev); if (pm == NULL) { SCLogError(SC_ERR_DISTANCE_MISSING_CONTENT, "within needs two " "preceding content or uricontent options"); SCReturnInt(0); } else { break; } } else { break; } } } } if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { for (sm = s->sm_lists[DETECT_SM_LIST_HHHDMATCH]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_NOCASE) { SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http_host keyword " "specified along with \"nocase\". " "Since the hostname buffer we match against " "is actually lowercase. So having a " "nocase is redundant."); } else { for (u = 0; u < cd->content_len; u++) { if (isupper(cd->content[u])) break; } if (u != cd->content_len) { SCLogWarning(SC_ERR_INVALID_SIGNATURE, "A pattern with " "uppercase chars detected for http_host. " "Since the hostname buffer we match against " "is lowercase only, please specify a " "lowercase pattern."); SCReturnInt(0); } } } } } if (s->flags & SIG_FLAG_REQUIRE_PACKET) { pm = SigMatchGetLastSMFromLists(s, 24, DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature has" " replace keyword linked with a modified content" " keyword (http_*, dce_*). It only supports content on" " raw payload"); SCReturnInt(0); } if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] || s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " "specific matches (like dsize, flags, ttl) with stream / " "state matching by matching on app layer proto (like using " "http_* keywords)."); SCReturnInt(0); } } /* TCP: pkt vs stream vs depth/offset */ if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) { if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) { s->flags |= SIG_FLAG_REQUIRE_STREAM; sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT && (((DetectContentData *)(sm->ctx))->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) { s->flags |= SIG_FLAG_REQUIRE_PACKET; break; } sm = sm->next; } } } #ifdef DEBUG int i; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { if (s->sm_lists[i] != NULL) { for (sm = s->sm_lists[i]; sm != NULL; sm = sm->next) { BUG_ON(sm == sm->prev); BUG_ON(sm == sm->next); } } } #endif SCReturnInt(1); } /** * \internal * \brief Helper function for SigInit(). */ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, uint8_t dir) { Signature *sig = SigAlloc(); if (sig == NULL) goto error; /* default gid to 1 */ sig->gid = 1; if (SigParse(de_ctx, sig, sigstr, dir) < 0) goto error; /* signature priority hasn't been overwritten. Using default priority */ if (sig->prio == -1) sig->prio = 3; sig->num = de_ctx->signum; de_ctx->signum++; SigMatch *sm; /* set mpm_content_len */ /* determine the length of the longest pattern in the sig */ if (sig->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { sig->mpm_content_maxlen = 0; for (sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd == NULL) continue; if (sig->mpm_content_maxlen == 0) sig->mpm_content_maxlen = cd->content_len; if (sig->mpm_content_maxlen < cd->content_len) sig->mpm_content_maxlen = cd->content_len; } } } if (sig->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { sig->mpm_uricontent_maxlen = 0; for (sm = sig->sm_lists[DETECT_SM_LIST_UMATCH]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud == NULL) continue; if (sig->mpm_uricontent_maxlen == 0) sig->mpm_uricontent_maxlen = ud->content_len; if (sig->mpm_uricontent_maxlen < ud->content_len) sig->mpm_uricontent_maxlen = ud->content_len; } } } /* set the packet and app layer flags, but only if the * app layer flag wasn't already set in which case we * only consider the app layer */ if (!(sig->flags & SIG_FLAG_APPLAYER)) { if (sig->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; for ( ; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].AppLayerMatch != NULL) sig->flags |= SIG_FLAG_APPLAYER; if (sigmatch_table[sm->type].Match != NULL) sig->init_flags |= SIG_FLAG_INIT_PACKET; } } else { sig->init_flags |= SIG_FLAG_INIT_PACKET; } } if (sig->sm_lists[DETECT_SM_LIST_UMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_DMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_AMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HSBDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HRHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HMDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HCDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HRUDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_FILEMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HSMDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HSCDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HUADMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HHHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; if (!(sig->init_flags & SIG_FLAG_INIT_FLOW)) { sig->flags |= SIG_FLAG_TOSERVER; sig->flags |= SIG_FLAG_TOCLIENT; } SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s", sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set", sig->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set"); SigBuildAddressMatchArray(sig); /* validate signature, SigValidate will report the error reason */ if (SigValidate(sig) == 0) { goto error; } return sig; error: if (sig != NULL) { SigFree(sig); } if (de_ctx->failure_fatal == 1) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature parsing failed: " "\"%s\"", sigstr); exit(EXIT_FAILURE); } return NULL; } /** * \brief Parses a signature and adds it to the Detection Engine Context. * * \param de_ctx Pointer to the Detection Engine Context. * \param sigstr Pointer to a character string containing the signature to be * parsed. * * \retval Pointer to the Signature instance on success; NULL on failure. */ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) { SCEnter(); uint32_t oldsignum = de_ctx->signum; Signature *sig; if ((sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL)) == NULL) { goto error; } if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) { sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED); if (sig->next == NULL) { goto error; } } SCReturnPtr(sig, "Signature"); error: if (sig != NULL) { SigFree(sig); } if (de_ctx->failure_fatal == 1) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature parsing failed: " "\"%s\"", sigstr); exit(EXIT_FAILURE); } /* if something failed, restore the old signum count * since we didn't install it */ de_ctx->signum = oldsignum; SCReturnPtr(NULL, "Signature"); } /** * \brief The hash free function to be the used by the hash table - * DetectEngineCtx->dup_sig_hash_table. * * \param data Pointer to the data, in our case SigDuplWrapper to be freed. */ void DetectParseDupSigFreeFunc(void *data) { if (data != NULL) SCFree(data); return; } /** * \brief The hash function to be the used by the hash table - * DetectEngineCtx->dup_sig_hash_table. * * \param ht Pointer to the hash table. * \param data Pointer to the data, in our case SigDuplWrapper. * \param datalen Not used in our case. * * \retval sw->s->id The generated hash value. */ uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen) { SigDuplWrapper *sw = (SigDuplWrapper *)data; return (sw->s->id % ht->array_size); } /** * \brief The Compare function to be used by the hash table - * DetectEngineCtx->dup_sig_hash_table. * * \param data1 Pointer to the first SigDuplWrapper. * \param len1 Not used. * \param data2 Pointer to the second SigDuplWrapper. * \param len2 Not used. * * \retval 1 If the 2 SigDuplWrappers sent as args match. * \retval 0 If the 2 SigDuplWrappers sent as args do not match. */ char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { SigDuplWrapper *sw1 = (SigDuplWrapper *)data1; SigDuplWrapper *sw2 = (SigDuplWrapper *)data2; if (sw1 == NULL || sw2 == NULL || sw1->s == NULL || sw2->s == NULL) return 0; /* sid and gid match required */ if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1; return 0; } /** * \brief Initializes the hash table that is used to cull duplicate sigs. * * \param de_ctx Pointer to the detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx) { de_ctx->dup_sig_hash_table = HashListTableInit(15000, DetectParseDupSigHashFunc, DetectParseDupSigCompareFunc, DetectParseDupSigFreeFunc); if (de_ctx->dup_sig_hash_table == NULL) return -1; return 0; } /** * \brief Frees the hash table that is used to cull duplicate sigs. * * \param de_ctx Pointer to the detection engine context that holds this table. */ void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->dup_sig_hash_table != NULL) HashListTableFree(de_ctx->dup_sig_hash_table); de_ctx->dup_sig_hash_table = NULL; return; } /** * \brief Check if a signature is a duplicate. * * There are 3 types of return values for this function. * * - 0, which indicates that the Signature is not a duplicate * and has to be added to the detection engine list. * - 1, Signature is duplicate, and the existing signature in * the list shouldn't be replaced with this duplicate. * - 2, Signature is duplicate, and the existing signature in * the list should be replaced with this duplicate. * * \param de_ctx Pointer to the detection engine context. * \param sig Pointer to the Signature that has to be checked. * * \retval 2 If Signature is duplicate and the existing signature in * the list should be chucked out and replaced with this. * \retval 1 If Signature is duplicate, and should be chucked out. * \retval 0 If Signature is not a duplicate. */ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, Signature *sig) { /* we won't do any NULL checks on the args */ /* return value */ int ret = 0; SigDuplWrapper *sw_dup = NULL; SigDuplWrapper *sw = NULL; /* used for making a duplicate_sig_hash_table entry */ sw = SCMalloc(sizeof(SigDuplWrapper)); if (unlikely(sw == NULL)) { exit(EXIT_FAILURE); } memset(sw, 0, sizeof(SigDuplWrapper)); sw->s = sig; /* check if we have a duplicate entry for this signature */ sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0); /* we don't have a duplicate entry for this sig */ if (sw_dup == NULL) { /* add it to the hash table */ HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0); /* add the s_prev entry for the previously loaded sw in the hash_table */ if (de_ctx->sig_list != NULL) { SigDuplWrapper *sw_old = NULL; SigDuplWrapper sw_tmp; memset(&sw_tmp, 0, sizeof(SigDuplWrapper)); /* the topmost sig would be the last loaded sig */ sw_tmp.s = de_ctx->sig_list; sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)&sw_tmp, 0); /* sw_old == NULL case is impossible */ sw_old->s_prev = sig; } ret = 0; goto end; } /* if we have reached here we have a duplicate entry for this signature. * Check the signature revision. Store the signature with the latest rev * and discard the other one */ if (sw->s->rev <= sw_dup->s->rev) { ret = 1; goto end; } /* the new sig is of a newer revision than the one that is already in the * list. Remove the old sig from the list */ if (sw_dup->s_prev == NULL) { SigDuplWrapper sw_temp; memset(&sw_temp, 0, sizeof(SigDuplWrapper)); if (sw_dup->s->init_flags & SIG_FLAG_INIT_BIDIREC) { sw_temp.s = sw_dup->s->next->next; de_ctx->sig_list = sw_dup->s->next->next; SigFree(sw_dup->s->next); } else { sw_temp.s = sw_dup->s->next; de_ctx->sig_list = sw_dup->s->next; } SigDuplWrapper *sw_next = NULL; if (sw_temp.s != NULL) { sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)&sw_temp, 0); sw_next->s_prev = sw_dup->s_prev; } SigFree(sw_dup->s); } else { SigDuplWrapper sw_temp; memset(&sw_temp, 0, sizeof(SigDuplWrapper)); if (sw_dup->s->init_flags & SIG_FLAG_INIT_BIDIREC) { sw_temp.s = sw_dup->s->next->next; sw_dup->s_prev->next = sw_dup->s->next->next; SigFree(sw_dup->s->next); } else { sw_temp.s = sw_dup->s->next; sw_dup->s_prev->next = sw_dup->s->next; } SigDuplWrapper *sw_next = NULL; if (sw_temp.s != NULL) { sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)&sw_temp, 0); sw_next->s_prev = sw_dup->s_prev;; } SigFree(sw_dup->s); } /* make changes to the entry to reflect the presence of the new sig */ sw_dup->s = sig; sw_dup->s_prev = NULL; /* this is duplicate, but a duplicate that replaced the existing sig entry */ ret = 2; SCFree(sw); end: return ret; } /** * \brief Parse and append a Signature into the Detection Engine Context * signature list. * * If the signature is bidirectional it should append two signatures * (with the addresses switched) into the list. Also handle duplicate * signatures. In case of duplicate sigs, use the ones that have the * latest revision. We use the sid and the msg to identifiy duplicate * sigs. If 2 sigs have the same sid and gid, they are duplicates. * * \param de_ctx Pointer to the Detection Engine Context. * \param sigstr Pointer to a character string containing the signature to be * parsed. * \param sig_file Pointer to a character string containing the filename from * which signature is read * \param lineno Line number from where signature is read * * \retval Pointer to the head Signature in the detection engine ctx sig_list * on success; NULL on failure. */ Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, char *sigstr) { Signature *sig = SigInit(de_ctx, sigstr); if (sig == NULL) { return NULL; } /* checking for the status of duplicate signature */ int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig); /* a duplicate signature that should be chucked out. Check the previously * called function details to understand the different return values */ if (dup_sig == 1) { SCLogError(SC_ERR_DUPLICATE_SIG, "Duplicate signature \"%s\"", sigstr); goto error; } else if (dup_sig == 2) { SCLogWarning(SC_ERR_DUPLICATE_SIG, "Signature with newer revision," " so the older sig replaced by this new signature \"%s\"", sigstr); } if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) { if (sig->next != NULL) { sig->next->next = de_ctx->sig_list; } else { goto error; } } else { /* if this sig is the first one, sig_list should be null */ sig->next = de_ctx->sig_list; } de_ctx->sig_list = sig; /** * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one * so if the signature is bidirectional, the returned sig will point through "next" ptr * to the cloned signatures with the switched addresses */ return (dup_sig == 0 || dup_sig == 2) ? sig : NULL; error: if (sig != NULL) SigFree(sig); return NULL; } /** * \brief Parse a content string, ie "abc|DE|fgh" * * \param content_str null terminated string containing the content * \param result result pointer to pass the fully parsed byte array * \param result_len size of the resulted data * \param flags flags to be set by this parsing function * * \retval -1 error * \retval 0 ok * * \initonly */ int DetectParseContentString (char *contentstr, uint8_t **result, uint16_t *result_len, uint32_t *result_flags) { char *str = NULL; char *temp = NULL; uint16_t len; uint16_t pos = 0; uint16_t slen = 0; uint8_t *content = NULL; uint16_t content_len = 0; uint32_t flags = 0; if ((temp = SCStrdup(contentstr)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory. Exiting..."); exit(EXIT_FAILURE); } if (strlen(temp) == 0) { SCFree(temp); return -1; } /* skip the first spaces */ slen = strlen(temp); while (pos < slen && isspace((unsigned char)temp[pos])) { pos++; } if (temp[pos] == '!') { SCFree(temp); if ((temp = SCStrdup(contentstr + pos + 1)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "error allocating memory. exiting..."); exit(EXIT_FAILURE); } pos = 0; flags |= DETECT_CONTENT_NEGATED; SCLogDebug("negation in place"); } if (temp[pos] == '\"' && strlen(temp + pos) == 1) goto error; if (temp[pos] == '\"' && temp[pos + strlen(temp + pos) - 1] == '\"') { if ((str = SCStrdup(temp + pos + 1)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "error allocating memory. exiting..."); exit(EXIT_FAILURE); } str[strlen(temp) - pos - 2] = '\0'; } else if (temp[pos] == '\"' || temp[pos + strlen(temp + pos) - 1] == '\"') { goto error; } else { if ((str = SCStrdup(temp + pos)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "error allocating memory. exiting..."); exit(EXIT_FAILURE); } } SCFree(temp); temp = NULL; len = strlen(str); if (len == 0) goto error; //SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len); char converted = 0; { uint16_t i, x; uint8_t bin = 0; uint8_t escape = 0; uint8_t binstr[3] = ""; uint8_t binpos = 0; uint16_t bin_count = 0; for (i = 0, x = 0; i < len; i++) { // SCLogDebug("str[%02u]: %c", i, str[i]); if (str[i] == '|') { bin_count++; if (bin) { bin = 0; } else { bin = 1; } } else if(!escape && str[i] == '\\') { escape = 1; } else { if (bin) { if (isdigit((unsigned char)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') { // SCLogDebug("part of binary: %c", str[i]); binstr[binpos] = (char)str[i]; binpos++; if (binpos == 2) { uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF; binpos = 0; str[x] = c; x++; converted = 1; } } else if (str[i] == ' ') { // SCLogDebug("space as part of binary string"); } } else if (escape) { if (str[i] == ':' || str[i] == ';' || str[i] == '\\' || str[i] == '\"') { str[x] = str[i]; x++; } else { //SCLogDebug("Can't escape %c", str[i]); goto error; } escape = 0; converted = 1; } else { str[x] = str[i]; x++; } } } if (bin_count % 2 != 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid hex code assembly in " "content - %s. Invalidating signature", str); goto error; } #if 0//def DEBUG if (SCLogDebugEnabled()) { for (i = 0; i < x; i++) { if (isprint(str[i])) SCLogDebug("%c", str[i]); else SCLogDebug("\\x%02u", str[i]); } SCLogDebug(""); } #endif if (converted) { len = x; } } content = SCMalloc(len); if (unlikely(content == NULL)) { exit(EXIT_FAILURE); } memcpy(content, str, len); content_len = len; SCFree(str); *result = content; *result_len = content_len; *result_flags = flags; SCLogDebug("flags %02X, result_flags %02X", flags, *result_flags); return 0; error: SCFree(str); SCFree(temp); if (content != NULL) SCFree(content); return -1; } /* * TESTS */ #ifdef UNITTESTS int SigParseTest01 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)"); if (sig == NULL) result = 0; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } int SigParseTest02 (void) { int result = 0; Signature *sig = NULL; DetectPort *port = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); if (sig == NULL) { goto end; } int r = DetectPortParse(&port, "0:20"); if (r < 0) goto end; if (DetectPortCmp(sig->sp, port) == PORT_EQ) { result = 1; } else { DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": "); } end: if (port != NULL) DetectPortCleanupList(port); if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test SigParseTest03 test for invalid direction operator in rule */ int SigParseTest03 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)"); if (sig != NULL) { result = 0; printf("expected NULL got sig ptr %p: ",sig); } end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } int SigParseTest04 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)"); if (sig == NULL) result = 0; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Port validation */ int SigParseTest05 (void) { int result = 0; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)"); if (sig == NULL) { result = 1; } else { printf("signature didn't fail to parse as we expected: "); } end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Parsing bug debugging at 2010-03-18 */ int SigParseTest06 (void) { int result = 0; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; nocase; http_method; uricontent:\"/uri/\"; nocase; content:\"Host|3A| abc\"; nocase; sid:1; rev:1;)"); if (sig != NULL) { result = 1; } else { printf("signature failed to parse: "); } end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing duplicate sigs. */ int SigParseTest07(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing duplicate sigs. */ int SigParseTest08(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)"); result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL && de_ctx->sig_list->rev == 2); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing duplicate sigs. */ int SigParseTest09(void) { int result = 1; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)"); result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && de_ctx->sig_list->rev == 2); if (result == 0) goto end; result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && de_ctx->sig_list->next->rev == 6); if (result == 0) goto end; DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)"); result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && de_ctx->sig_list->rev == 2); if (result == 0) goto end; result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && de_ctx->sig_list->next->rev == 6); if (result == 0) goto end; DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)"); result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && de_ctx->sig_list->rev == 4); if (result == 0) goto end; result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && de_ctx->sig_list->next->rev == 6); if (result == 0) goto end; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing duplicate sigs. */ int SigParseTest10(void) { int result = 1; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)"); result &= ((de_ctx->sig_list->id == 2) && (de_ctx->sig_list->next->id == 3) && (de_ctx->sig_list->next->next->id == 5) && (de_ctx->sig_list->next->next->next->id == 4) && (de_ctx->sig_list->next->next->next->next->id == 1)); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing sig with trailing space(s) as reported by * Morgan Cox on oisf-users. */ int SigParseTest11(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; Signature *s = NULL; s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\";) "); if (s == NULL) { printf("sig 1 didn't parse: "); goto end; } s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) "); if (s == NULL) { printf("sig 2 didn't parse: "); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test file_data with rawbytes */ static int SigParseTest12(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; Signature *s = NULL; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)"); if (s != NULL) { printf("sig 1 should have given an error: "); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test packet/stream sig */ static int SigParseTest13(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; Signature *s = NULL; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; } if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { printf("sig doesn't have stream flag set\n"); goto end; } if (s->flags & SIG_FLAG_REQUIRE_PACKET) { printf("sig has packet flag set\n"); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test packet/stream sig */ static int SigParseTest14(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; Signature *s = NULL; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; } if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { printf("sig doesn't have packet flag set\n"); goto end; } if (s->flags & SIG_FLAG_REQUIRE_STREAM) { printf("sig has stream flag set\n"); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test packet/stream sig */ static int SigParseTest15(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; Signature *s = NULL; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; } if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { printf("sig doesn't have packet flag set\n"); goto end; } if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { printf("sig doesn't have stream flag set\n"); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test packet/stream sig */ static int SigParseTest16(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; Signature *s = NULL; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; } if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { printf("sig doesn't have packet flag set\n"); goto end; } if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { printf("sig doesn't have stream flag set\n"); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test packet/stream sig */ static int SigParseTest17(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; Signature *s = NULL; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; } if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { printf("sig doesn't have packet flag set\n"); goto end; } if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { printf("sig doesn't have stream flag set\n"); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ int SigParseBidirecTest06 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ int SigParseBidirecTest07 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ int SigParseBidirecTest08 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ int SigParseBidirecTest09 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ int SigParseBidirecTest10 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ int SigParseBidirecTest11 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ int SigParseBidirecTest12 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (valid) */ int SigParseBidirecTest13 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig != NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (valid) */ int SigParseBidirecTest14 (void) { int result = 1; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig != NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Ensure that we don't set bidirectional in a * normal (one direction) Signature */ int SigTestBidirec01 (void) { Signature *sig = NULL; int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)"); if (sig == NULL) goto end; if (sig->next != NULL) goto end; if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) goto end; if (de_ctx->signum != 1) goto end; result = 1; end: if (de_ctx != NULL) { SigCleanSignatures(de_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } return result; } /** \test Ensure that we set a bidirectional Signature correctly */ int SigTestBidirec02 (void) { int result = 0; Signature *sig = NULL; Signature *copy = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)"); if (sig == NULL) goto end; if (de_ctx->sig_list != sig) goto end; if (!(sig->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; if (sig->next == NULL) goto end; if (de_ctx->signum != 2) goto end; copy = sig->next; if (copy->next != NULL) goto end; if (!(copy->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; result = 1; end: if (de_ctx != NULL) { SigCleanSignatures(de_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } return result; } /** \test Ensure that we set a bidirectional Signature correctly * and we install it with the rest of the signatures, checking * also that it match with the correct addr directions */ int SigTestBidirec03 (void) { int result = 0; Signature *sig = NULL; Packet *p = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; char *sigs[3]; sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)"; sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)"; sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)"; UTHAppendSigs(de_ctx, sigs, 3); /* Checking that bidirectional rules are set correctly */ sig = de_ctx->sig_list; if (sig == NULL) goto end; if (sig->next == NULL) goto end; if (sig->next->next == NULL) goto end; if (sig->next->next->next == NULL) goto end; if (sig->next->next->next->next != NULL) goto end; if (de_ctx->signum != 4) goto end; uint8_t rawpkt1_ether[] = { 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c, 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00, 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06, 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8, 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2, 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18, 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45, 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50, 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f, 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e, 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d, 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67, 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a, 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30, 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55, 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20, 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20, 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72, 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e, 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b, 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39, 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75, 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34, 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79, 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f, 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34, 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74, 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68, 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c, 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f, 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d, 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63, 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d, 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c, 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e, 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61, 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75, 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30, 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65, 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64, 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69, 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74, 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65, 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38, 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74, 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e, 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e, 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d, 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33, 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e, 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20, 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69, 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */ FlowInitConfig(FLOW_QUIET); p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether)); if (p == NULL) { SCLogDebug("Error building packet"); goto end; } UTHMatchPackets(de_ctx, &p, 1); uint32_t sids[3] = {1, 2, 3}; uint32_t results[3] = {1, 1, 1}; result = UTHCheckPacketMatchResults(p, sids, results, 1); end: if (p != NULL) SCFree(p); if (de_ctx != NULL) { SigCleanSignatures(de_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } FlowShutdown(); return result; } /** \test Ensure that we set a bidirectional Signature correctly * and we install it with the rest of the signatures, checking * also that it match with the correct addr directions */ int SigTestBidirec04 (void) { int result = 0; Signature *sig = NULL; Packet *p = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)"); if (sig == NULL) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)"); if (sig == NULL) goto end; if ( !(sig->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; if (sig->next == NULL) goto end; if (sig->next->next == NULL) goto end; if (sig->next->next->next != NULL) goto end; if (de_ctx->signum != 3) goto end; sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)"); if (sig == NULL) goto end; if (sig->next == NULL) goto end; if (sig->next->next == NULL) goto end; if (sig->next->next->next == NULL) goto end; if (sig->next->next->next->next != NULL) goto end; if (de_ctx->signum != 4) goto end; uint8_t rawpkt1_ether[] = { 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c, 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00, 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06, 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8, 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2, 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18, 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45, 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50, 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f, 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e, 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d, 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67, 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a, 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30, 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55, 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20, 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20, 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72, 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e, 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b, 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39, 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75, 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34, 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79, 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f, 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34, 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74, 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68, 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c, 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f, 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d, 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63, 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d, 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c, 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e, 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61, 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75, 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30, 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65, 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64, 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69, 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74, 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65, 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38, 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74, 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e, 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e, 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d, 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33, 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e, 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20, 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69, 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */ p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether), NULL); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* At this point we have a list of 4 signatures. The last one is a copy of the second one. If we receive a packet with source 192.168.1.1 80, all the sids should match */ SigGroupBuild(de_ctx); //PatternMatchPrepare(mpm_ctx, MPM_B2G); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */ if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 && PacketAlertCheck(p, 2) == 1) { result = 1; } FlowShutdown(); //PatternMatchDestroy(mpm_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: if (de_ctx != NULL) { SigCleanSignatures(de_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } if (p != NULL) SCFree(p); return result; } /** * \test check that we don't allow invalid negation options */ static int SigParseTestNegation01 (void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tcp !any any -> any any (msg:\"SigTest41-01 src address is !any \"; classtype:misc-activity; sid:410001; rev:1;)"); if (s != NULL) { SigFree(s); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test check that we don't allow invalid negation options */ static int SigParseTestNegation02 (void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; classtype:misc-activity; sid:410002; rev:1;)"); if (s != NULL) { SigFree(s); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test check that we don't allow invalid negation options */ static int SigParseTestNegation03 (void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)"); if (s != NULL) { SigFree(s); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test check that we don't allow invalid negation options */ static int SigParseTestNegation04 (void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tcp any any -> any [80,!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)"); if (s != NULL) { SigFree(s); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test check that we don't allow invalid negation options */ static int SigParseTestNegation05 (void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.2] any (msg:\"SigTest41-04 dst ip [192.168.0.2,!192.168.0.2] \"; classtype:misc-activity; sid:410004; rev:1;)"); if (s != NULL) { SigFree(s); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test check that we don't allow invalid negation options */ static int SigParseTestNegation06 (void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tcp any any -> any [100:1000,!1:20000] (msg:\"SigTest41-05 dst port [100:1000,!1:20000] \"; classtype:misc-activity; sid:410005; rev:1;)"); if (s != NULL) { SigFree(s); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test check that we don't allow invalid negation options */ static int SigParseTestNegation07 (void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (msg:\"SigTest41-06 dst ip [192.168.0.2,!192.168.0.0/24] \"; classtype:misc-activity; sid:410006; rev:1;)"); if (s != NULL) { SigFree(s); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test mpm */ int SigParseTestMpm01 (void) { int result = 0; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)"); if (sig == NULL) { printf("sig failed to init: "); goto end; } if (sig->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("sig doesn't have content list: "); goto end; } if (sig->mpm_content_maxlen != 4) { printf("mpm content max len %"PRIu16", expected 4: ", sig->mpm_content_maxlen); goto end; } if (sig->mpm_uricontent_maxlen != 0) { printf("mpm uricontent max len %"PRIu16", expected 0: ", sig->mpm_uricontent_maxlen); goto end; } result = 1; end: if (sig != NULL) SigFree(sig); DetectEngineCtxFree(de_ctx); return result; } /** * \test mpm */ int SigParseTestMpm02 (void) { int result = 0; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)"); if (sig == NULL) { printf("sig failed to init: "); goto end; } if (sig->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("sig doesn't have content list: "); goto end; } if (sig->mpm_content_maxlen != 6) { printf("mpm content max len %"PRIu16", expected 6: ", sig->mpm_content_maxlen); goto end; } if (sig->mpm_uricontent_maxlen != 0) { printf("mpm uricontent max len %"PRIu16", expected 0: ", sig->mpm_uricontent_maxlen); goto end; } result = 1; end: if (sig != NULL) SigFree(sig); DetectEngineCtxFree(de_ctx); return result; } /** * \test test tls (app layer) rule */ static int SigParseTestAppLayerTLS01(void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)"); if (s == NULL) { printf("parsing sig failed: "); goto end; } if (s->alproto == 0) { printf("alproto not set: "); goto end; } result = 1; end: if (s != NULL) SigFree(s); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test test tls (app layer) rule */ static int SigParseTestAppLayerTLS02(void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)"); if (s == NULL) { printf("parsing sig failed: "); goto end; } if (s->alproto == 0) { printf("alproto not set: "); goto end; } result = 1; end: if (s != NULL) SigFree(s); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test test tls (app layer) rule */ static int SigParseTestAppLayerTLS03(void) { int result = 0; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; tls.version:2.5; sid:410006; rev:1;)"); if (s != NULL) { SigFree(s); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ void SigParseRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SigParseTest01", SigParseTest01, 1); UtRegisterTest("SigParseTest02", SigParseTest02, 1); UtRegisterTest("SigParseTest03", SigParseTest03, 1); UtRegisterTest("SigParseTest04", SigParseTest04, 1); UtRegisterTest("SigParseTest05", SigParseTest05, 1); UtRegisterTest("SigParseTest06", SigParseTest06, 1); UtRegisterTest("SigParseTest07", SigParseTest07, 1); UtRegisterTest("SigParseTest08", SigParseTest08, 1); UtRegisterTest("SigParseTest09", SigParseTest09, 1); UtRegisterTest("SigParseTest10", SigParseTest10, 1); UtRegisterTest("SigParseTest11", SigParseTest11, 1); UtRegisterTest("SigParseTest12", SigParseTest12, 1); UtRegisterTest("SigParseTest13", SigParseTest13, 1); UtRegisterTest("SigParseTest14", SigParseTest14, 1); UtRegisterTest("SigParseTest15", SigParseTest15, 1); UtRegisterTest("SigParseTest16", SigParseTest16, 1); UtRegisterTest("SigParseTest17", SigParseTest17, 1); UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06, 1); UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07, 1); UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08, 1); UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09, 1); UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10, 1); UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11, 1); UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12, 1); UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13, 1); UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14, 1); UtRegisterTest("SigTestBidirec01", SigTestBidirec01, 1); UtRegisterTest("SigTestBidirec02", SigTestBidirec02, 1); UtRegisterTest("SigTestBidirec03", SigTestBidirec03, 1); UtRegisterTest("SigTestBidirec04", SigTestBidirec04, 1); UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01, 1); UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02, 1); UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03, 1); UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04, 1); UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05, 1); UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06, 1); UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07, 1); UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01, 1); UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02, 1); UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01, 1); UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02, 1); UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-csum.h0000644000000000000000000000220612253546156013413 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_CSUM_H__ #define __DETECT_CSUM_H__ #define DETECT_CSUM_VALID "valid" #define DETECT_CSUM_INVALID "invalid" typedef struct DetectCsumData_ { /* Indicates if the csum- keyword in a rule holds the keyvalue "valid" or "invalid" */ int16_t valid; } DetectCsumData; void DetectCsumRegister(void); #endif /* __DETECT_CSUM_H__ */ suricata-1.4.7/src/decode-tcp.h0000644000000000000000000002426412253546156013215 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \todo RAW* macro's should be returning the raw value, not the host order */ #ifndef __DECODE_TCP_H__ #define __DECODE_TCP_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 */ /* TCP flags */ #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 /** Establish a new connection reducing window */ #define TH_ECN 0x40 /** Echo Congestion flag */ #define TH_CWR 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_OPT_SACK_MIN_LEN 10 /* hdr 2, 1 pair 8 = 10 */ #define TCP_OPT_SACK_MAX_LEN 34 /* hdr 2, 4 pair 32= 34 */ /** Max valid wscale value. */ #define TCP_WSCALE_MAX 14 #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_RAW_SEQ(tcph) ntohl((tcph)->th_seq) #define TCP_GET_RAW_ACK(tcph) ntohl((tcph)->th_ack) #define TCP_GET_RAW_WINDOW(tcph) ntohs((tcph)->th_win) #define TCP_GET_RAW_URG_POINTER(tcph) ntohs((tcph)->th_urp) /** macro for getting the first timestamp from the packet. Timestamp is in host * order and either returned from the cache or from the packet directly. */ #define TCP_GET_TSVAL(p) \ (uint32_t)ntohl((*(uint32_t *)(p)->tcpvars.ts->data)) /** macro for getting the second timestamp from the packet. Timestamp is in * host order and either returned from the cache or from the packet directly. */ #define TCP_GET_TSECR(p) \ (uint32_t)ntohl((*(uint32_t *)((p)->tcpvars.ts->data+4))) /** macro for getting the wscale from the packet. */ #define TCP_GET_WSCALE(p) ((p)->tcpvars.ws ? (((*(uint8_t *)(p)->tcpvars.ws->data) <= TCP_WSCALE_MAX) ? (*(uint8_t *)((p)->tcpvars.ws->data)) : 0) : 0) #define TCP_GET_SACKOK(p) ((p)->tcpvars.sackok ? 1 : 0) #define TCP_GET_SACK_PTR(p) (p)->tcpvars.sack ? (p)->tcpvars.sack->data : NULL #define TCP_GET_SACK_CNT(p) ((p)->tcpvars.sack ? (((p)->tcpvars.sack->len - 2) / 8) : 0) #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) #define TCP_GET_SEQ(p) TCP_GET_RAW_SEQ((p)->tcph) #define TCP_GET_ACK(p) TCP_GET_RAW_ACK((p)->tcph) #define TCP_GET_WINDOW(p) TCP_GET_RAW_WINDOW((p)->tcph) #define TCP_GET_URG_POINTER(p) TCP_GET_RAW_URG_POINTER((p)->tcph) #define TCP_ISSET_FLAG_FIN(p) ((p)->tcph->th_flags & TH_FIN) #define TCP_ISSET_FLAG_SYN(p) ((p)->tcph->th_flags & TH_SYN) #define TCP_ISSET_FLAG_RST(p) ((p)->tcph->th_flags & TH_RST) #define TCP_ISSET_FLAG_PUSH(p) ((p)->tcph->th_flags & TH_PUSH) #define TCP_ISSET_FLAG_ACK(p) ((p)->tcph->th_flags & TH_ACK) #define TCP_ISSET_FLAG_URG(p) ((p)->tcph->th_flags & TH_URG) #define TCP_ISSET_FLAG_RES2(p) ((p)->tcph->th_flags & TH_RES2) #define TCP_ISSET_FLAG_RES1(p) ((p)->tcph->th_flags & TH_RES1) typedef struct TCPOpt_ { uint8_t type; uint8_t len; uint8_t *data; } TCPOpt; typedef struct TCPOptSackRecord_ { uint32_t le; /**< left edge, network order */ uint32_t re; /**< right edge, network order */ } TCPOptSackRecord; typedef struct TCPHdr_ { uint16_t th_sport; /**< source port */ uint16_t th_dport; /**< destination port */ uint32_t th_seq; /**< sequence number */ uint32_t th_ack; /**< acknowledgement number */ uint8_t th_offx2; /**< offset and reserved */ uint8_t th_flags; /**< pkt flags */ uint16_t th_win; /**< pkt window */ uint16_t th_sum; /**< checksum */ uint16_t th_urp; /**< urgent pointer */ } TCPHdr; typedef struct TCPVars_ { /* checksum computed over the tcp(for both ipv4 and ipv6) packet */ int32_t comp_csum; uint8_t tcp_opt_cnt; TCPOpt tcp_opts[TCP_OPTMAX]; /* ptrs to commonly used and needed opts */ TCPOpt *ts; TCPOpt *sack; TCPOpt *sackok; TCPOpt *ws; TCPOpt *mss; } TCPVars; #define CLEAR_TCP_PACKET(p) { \ (p)->tcph = NULL; \ (p)->tcpvars.comp_csum = -1; \ (p)->tcpvars.tcp_opt_cnt = 0; \ (p)->tcpvars.ts = NULL; \ (p)->tcpvars.sack = NULL; \ (p)->tcpvars.sackok = NULL; \ (p)->tcpvars.ws = NULL; \ (p)->tcpvars.mss = NULL; \ } void DecodeTCPRegisterTests(void); /** -------- Inline functions ------- */ static inline uint16_t TCPCalculateChecksum(uint16_t *, uint16_t *, uint16_t); static inline uint16_t TCPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t); /** * \brief Calculates the checksum for the TCP packet * * \param shdr Pointer to source address field from the IP packet. Used as a * part of the pseudoheader for computing the checksum * \param pkt Pointer to the start of the TCP packet * \param tlen Total length of the TCP packet(header + payload) * * \retval csum Checksum for the TCP packet */ static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, uint16_t tlen) { uint16_t pad = 0; uint32_t csum = shdr[0]; csum += shdr[1] + shdr[2] + shdr[3] + htons(6) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[9]; tlen -= 20; pkt += 10; while (tlen >= 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } while(tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } while(tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; } while (tlen > 1) { csum += pkt[0]; pkt += 1; tlen -= 2; } if (tlen == 1) { *(uint8_t *)(&pad) = (*(uint8_t *)pkt); csum += pad; } csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); return (uint16_t)~csum; } /** * \brief Calculates the checksum for the TCP packet * * \param shdr Pointer to source address field from the IPV6 packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the TCP packet * \param tlen Total length of the TCP packet(header + payload) * * \retval csum Checksum for the TCP packet */ static inline uint16_t TCPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, uint16_t tlen) { uint16_t pad = 0; uint32_t csum = shdr[0]; csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(6) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[9]; tlen -= 20; pkt += 10; while (tlen >= 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } while(tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } while(tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; } while (tlen > 1) { csum += pkt[0]; pkt += 1; tlen -= 2; } if (tlen == 1) { *(uint8_t *)(&pad) = (*(uint8_t *)pkt); csum += pad; } csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); return (uint16_t)~csum; } #endif /* __DECODE_TCP_H__ */ suricata-1.4.7/src/detect-dce-opnum.c0000644000000000000000000033125312253546156014335 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implements dce_opnum keyword */ #include "suricata-common.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "app-layer.h" #include "app-layer-dcerpc.h" #include "queue.h" #include "stream-tcp-reassemble.h" #include "detect-dce-opnum.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "stream-tcp.h" #define DETECT_DCE_OPNUM_PCRE_PARSE_ARGS "^\\s*([0-9]{1,5}(\\s*-\\s*[0-9]{1,5}\\s*)?)(,\\s*[0-9]{1,5}(\\s*-\\s*[0-9]{1,5})?\\s*)*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectDceOpnumSetup(DetectEngineCtx *, Signature *, char *); void DetectDceOpnumFree(void *); /** * \brief Registers the keyword handlers for the "dce_opnum" keyword. */ void DetectDceOpnumRegister(void) { const char *eb; int eo; int opts = 0; sigmatch_table[DETECT_DCE_OPNUM].name = "dce_opnum"; sigmatch_table[DETECT_DCE_OPNUM].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_OPNUM].Match = NULL; sigmatch_table[DETECT_DCE_OPNUM].AppLayerMatch = DetectDceOpnumMatch; sigmatch_table[DETECT_DCE_OPNUM].Setup = DetectDceOpnumSetup; sigmatch_table[DETECT_DCE_OPNUM].Free = DetectDceOpnumFree; sigmatch_table[DETECT_DCE_OPNUM].RegisterTests = DetectDceOpnumRegisterTests; sigmatch_table[DETECT_DCE_OPNUM].flags |= SIGMATCH_PAYLOAD; parse_regex = pcre_compile(DETECT_DCE_OPNUM_PCRE_PARSE_ARGS, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", DETECT_DCE_OPNUM_PCRE_PARSE_ARGS, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* we need to handle error?! */ return; } /** * \internal * \brief Creates and returns a new instance of DetectDceOpnumRange. * * \retval dor Pointer to the new instance DetectDceOpnumRange. */ static inline DetectDceOpnumRange *DetectDceOpnumAllocDetectDceOpnumRange(void) { DetectDceOpnumRange *dor = NULL; if ( (dor = SCMalloc(sizeof(DetectDceOpnumRange))) == NULL) return NULL; memset(dor, 0, sizeof(DetectDceOpnumRange)); dor->range1 = dor->range2 = DCE_OPNUM_RANGE_UNINITIALIZED; return dor; } /** * \internal * \brief Parses the argument sent along with the "dce_opnum" keyword. * * \param arg Pointer to the string containing the argument to be parsed. * * \retval did Pointer to a DetectDceIfaceData instance that holds the data * from the parsed arg. */ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) { DetectDceOpnumData *dod = NULL; DetectDceOpnumRange *dor = NULL; DetectDceOpnumRange *prev_dor = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *pcre_sub_str = NULL; char *dup_str = NULL; char *dup_str_temp = NULL; char *dup_str_head = NULL; char *comma_token = NULL; char *hyphen_token = NULL; ret = pcre_exec(parse_regex, parse_regex_study, arg, strlen(arg), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, arg); goto error; } res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 0, &pcre_sub_str); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if ( (dod = SCMalloc(sizeof(DetectDceOpnumData))) == NULL) goto error; memset(dod, 0, sizeof(DetectDceOpnumData)); if ( (dup_str = SCStrdup(pcre_sub_str)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); goto error; } /* free the substring */ pcre_free_substring(pcre_sub_str); /* keep a copy of the strdup string in dup_str_head so that we can free it * once we are done using it */ dup_str_head = dup_str; dup_str_temp = dup_str; while ( (comma_token = index(dup_str, ',')) != NULL) { comma_token[0] = '\0'; dup_str = comma_token + 1; dor = DetectDceOpnumAllocDetectDceOpnumRange(); if (dor == NULL) goto error; if ((hyphen_token = index(dup_str_temp, '-')) != NULL) { hyphen_token[0] = '\0'; hyphen_token++; dor->range1 = atoi(dup_str_temp); if (dor->range1 > DCE_OPNUM_RANGE_MAX) goto error; dor->range2 = atoi(hyphen_token); if (dor->range2 > DCE_OPNUM_RANGE_MAX) goto error; if (dor->range1 > dor->range2) goto error; } dor->range1 = atoi(dup_str_temp); if (dor->range1 > DCE_OPNUM_RANGE_MAX) goto error; if (prev_dor == NULL) { prev_dor = dor; dod->range = dor; } else { prev_dor->next = dor; prev_dor = dor; } dup_str_temp = dup_str; } dor = DetectDceOpnumAllocDetectDceOpnumRange(); if (dor == NULL) goto error; if ( (hyphen_token = index(dup_str, '-')) != NULL) { hyphen_token[0] = '\0'; hyphen_token++; dor->range1 = atoi(dup_str); if (dor->range1 > DCE_OPNUM_RANGE_MAX) goto error; dor->range2 = atoi(hyphen_token); if (dor->range2 > DCE_OPNUM_RANGE_MAX) goto error; if (dor->range1 > dor->range2) goto error; } dor->range1 = atoi(dup_str); if (dor->range1 > DCE_OPNUM_RANGE_MAX) goto error; if (prev_dor == NULL) { dod->range = dor; } else { prev_dor->next = dor; } if (dup_str_head != NULL) SCFree(dup_str_head); return dod; error: if (dup_str_head != NULL) SCFree(dup_str_head); DetectDceOpnumFree(dod); return NULL; } /** * \brief App layer match function for the "dce_opnum" keyword. * * \param t Pointer to the ThreadVars instance. * \param det_ctx Pointer to the DetectEngineThreadCtx. * \param f Pointer to the flow. * \param flags Pointer to the flags indicating the flow direction. * \param state Pointer to the app layer state data. * \param s Pointer to the Signature instance. * \param m Pointer to the SigMatch. * * \retval 1 On Match. * \retval 0 On no match. */ int DetectDceOpnumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); DetectDceOpnumData *dce_data = (DetectDceOpnumData *)m->ctx; DetectDceOpnumRange *dor = dce_data->range; DCERPCState *dcerpc_state = (DCERPCState *)state; if (dcerpc_state == NULL) { SCLogDebug("No DCERPCState for the flow"); SCReturnInt(0); } for ( ; dor != NULL; dor = dor->next) { if (dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED) { if (dor->range1 == dcerpc_state->dcerpc.dcerpcrequest.opnum) { SCReturnInt(1); } } else { if (dor->range1 <= dcerpc_state->dcerpc.dcerpcrequest.opnum && dor->range2 >= dcerpc_state->dcerpc.dcerpcrequest.opnum) { SCReturnInt(1); } } } SCReturnInt(0); } /** * \brief Creates a SigMatch for the "dce_opnum" keyword being sent as argument, * and appends it to the Signature(s). * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to signature for the current Signature being parsed * from the rules. * \param arg Pointer to the string holding the keyword value. * * \retval 0 on success, -1 on failure */ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectDceOpnumData *dod = NULL; SigMatch *sm = NULL; dod = DetectDceOpnumArgParse(arg); if (dod == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Error parsing dce_opnum option in " "signature"); goto error; } sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_DCE_OPNUM; sm->ctx = (void *)dod; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_DCERPC; /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; return 0; error: DetectDceOpnumFree(dod); if (sm != NULL) SCFree(sm); return -1; } void DetectDceOpnumFree(void *ptr) { DetectDceOpnumData *dod = ptr; DetectDceOpnumRange *dor = NULL; DetectDceOpnumRange *dor_temp = NULL; if (dod != NULL) { dor = dod->range; while (dor != NULL) { dor_temp = dor; dor = dor->next; SCFree(dor_temp); } SCFree(dod); } return; } /************************************Unittests*********************************/ #ifdef UNITTESTS static int DetectDceOpnumTestParse01(void) { Signature *s = SigAlloc(); int result = 0; memset(s, 0, sizeof(Signature)); result = (DetectDceOpnumSetup(NULL, s, "12") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12,24") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12,12-24") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12-14,12,121,62-78") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12,26,62,61,6513-6666") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12,26,62,61,6513--") == -1); result &= (DetectDceOpnumSetup(NULL, s, "12-14,12,121,62-8") == -1); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { SigFree(s); result &= 1; } return result; } static int DetectDceOpnumTestParse02(void) { Signature *s = SigAlloc(); int result = 0; DetectDceOpnumData *dod = NULL; DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; memset(s, 0, sizeof(Signature)); result = (DetectDceOpnumSetup(NULL, s, "12") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; dod = temp->ctx; if (dod == NULL) goto end; dor = dod->range; result &= (dor->range1 == 12 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next == NULL); } else { result = 0; } end: SigFree(s); return result; } static int DetectDceOpnumTestParse03(void) { Signature *s = SigAlloc(); int result = 0; DetectDceOpnumData *dod = NULL; DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; memset(s, 0, sizeof(Signature)); result = (DetectDceOpnumSetup(NULL, s, "12-24") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; dod = temp->ctx; if (dod == NULL) goto end; dor = dod->range; result &= (dor->range1 == 12 && dor->range2 == 24); result &= (dor->next == NULL); } else { result = 0; } end: SigFree(s); return result; } static int DetectDceOpnumTestParse04(void) { Signature *s = SigAlloc(); int result = 0; DetectDceOpnumData *dod = NULL; DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; memset(s, 0, sizeof(Signature)); result = (DetectDceOpnumSetup(NULL, s, "12-24,24,62-72,623-635,62,25,213-235") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; dod = temp->ctx; if (dod == NULL) goto end; dor = dod->range; result &= (dor->range1 == 12 && dor->range2 == 24); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 24 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 62 && dor->range2 == 72); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 623 && dor->range2 == 635); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 62 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 25 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 213 && dor->range2 == 235); if (result == 0) goto end; } else { result = 0; } end: SigFree(s); return result; } static int DetectDceOpnumTestParse05(void) { Signature *s = SigAlloc(); int result = 0; DetectDceOpnumData *dod = NULL; DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; memset(s, 0, sizeof(Signature)); result = (DetectDceOpnumSetup(NULL, s, "1,2,3,4,5,6,7") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; dod = temp->ctx; if (dod == NULL) goto end; dor = dod->range; result &= (dor->range1 == 1 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 2 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 3 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 4 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 5 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 6 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 7 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); if (result == 0) goto end; } else { result = 0; } end: SigFree(s); return result; } static int DetectDceOpnumTestParse06(void) { Signature *s = SigAlloc(); int result = 0; DetectDceOpnumData *dod = NULL; DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; memset(s, 0, sizeof(Signature)); result = (DetectDceOpnumSetup(NULL, s, "1-2,3-4,5-6,7-8") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; dod = temp->ctx; if (dod == NULL) goto end; dor = dod->range; result &= (dor->range1 == 1 && dor->range2 == 2); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 3 && dor->range2 == 4); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 5 && dor->range2 == 6); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 7 && dor->range2 == 8); if (result == 0) goto end; } else { result = 0; } end: SigFree(s); return result; } static int DetectDceOpnumTestParse07(void) { Signature *s = SigAlloc(); int result = 0; DetectDceOpnumData *dod = NULL; DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; memset(s, 0, sizeof(Signature)); result = (DetectDceOpnumSetup(NULL, s, "1-2,3-4,5-6,7-8,9") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; dod = temp->ctx; if (dod == NULL) goto end; dor = dod->range; result &= (dor->range1 == 1 && dor->range2 == 2); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 3 && dor->range2 == 4); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 5 && dor->range2 == 6); result &= (dor->next != NULL); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 7 && dor->range2 == 8); if (result == 0) goto end; dor = dor->next; result &= (dor->range1 == 9 && dor->range2 == DCE_OPNUM_RANGE_UNINITIALIZED); if (result == 0) goto end; } else { result = 0; } end: SigFree(s); return result; } /** * \test Test a valid dce_opnum entry with a bind, bind_ack and a request. */ static int DetectDceOpnumTestParse08(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x26, 0x3d, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; /* todo chop the request frag length and change the * length related parameters in the frag */ uint8_t dcerpc_request[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xec, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd4, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x83, 0xc7, 0x0b, 0x47, 0x47, 0x47, 0x47, 0x81, 0x37, 0x22, 0xa5, 0x9b, 0x4a, 0x75, 0xf4, 0xa3, 0x61, 0xd3, 0xbe, 0xdd, 0x5a, 0xfb, 0x20, 0x1e, 0xfc, 0x10, 0x8e, 0x0f, 0xa5, 0x9f, 0x4a, 0x22, 0x20, 0x9b, 0xa8, 0xd5, 0xc4, 0xff, 0xc1, 0x3f, 0xbd, 0x9b, 0x4a, 0x22, 0x2e, 0xc0, 0x7a, 0xa9, 0xfe, 0x97, 0xc9, 0xe1, 0xa9, 0xf3, 0x2f, 0x22, 0xc9, 0x9b, 0x22, 0x50, 0xa5, 0xf5, 0x4a, 0x4a, 0xce, 0x9b, 0x2f, 0x22, 0x2e, 0x6f, 0xc1, 0xe1, 0xf3, 0xa8, 0x83, 0xa2, 0x64, 0x98, 0xc1, 0x62, 0xa1, 0xa0, 0x89, 0x56, 0xa8, 0x1b, 0x8b, 0x2b, 0x2e, 0xe3, 0x7a, 0xd1, 0x03, 0xef, 0x58, 0x7c, 0x4e, 0x7d, 0x14, 0x76, 0xfa, 0xc3, 0x7f, 0x02, 0xa5, 0xbb, 0x4a, 0x89, 0x47, 0x6c, 0x12, 0xc9, 0x70, 0x18, 0x8e, 0x3a, 0x2e, 0xcb, 0x52, 0xa9, 0x67, 0x98, 0x0a, 0x1e, 0x2e, 0xc3, 0x32, 0x21, 0x7f, 0x10, 0x31, 0x3e, 0xa6, 0x61, 0xc1, 0x61, 0x85, 0x98, 0x88, 0xa9, 0xee, 0x83, 0x22, 0x51, 0xd6, 0xda, 0x4a, 0x4a, 0xc1, 0xff, 0x38, 0x47, 0xcd, 0xe9, 0x25, 0x41, 0xe4, 0xf3, 0x0d, 0x47, 0xd1, 0xcb, 0xc1, 0xd6, 0x1e, 0x95, 0x4a, 0x22, 0xa5, 0x73, 0x08, 0x22, 0xa5, 0x9b, 0xc9, 0xe6, 0xb5, 0xcd, 0x22, 0x43, 0xd7, 0xe2, 0x0b, 0x4a, 0xe9, 0xf2, 0x28, 0x50, 0xcd, 0xd7, 0x25, 0x43, 0xc1, 0x10, 0xbe, 0x99, 0xa9, 0x9b, 0x4a, 0x22, 0x4d, 0xb8, 0x4a, 0x22, 0xa5, 0x18, 0x8e, 0x2e, 0xf3, 0xc9, 0x22, 0x4e, 0xc9, 0x9b, 0x4a, 0x4a, 0x96, 0xa9, 0x64, 0x46, 0xcd, 0xec, 0x39, 0x10, 0xfa, 0xcf, 0xb5, 0x76, 0x81, 0x8f, 0xc9, 0xe6, 0xa9, 0x10, 0x82, 0x7c, 0xff, 0xc4, 0xa1, 0x0a, 0xf5, 0xcc, 0x1b, 0x74, 0xf4, 0x10, 0x81, 0xa9, 0x9d, 0x98, 0xb0, 0xa1, 0x65, 0x9f, 0xb9, 0x84, 0xd1, 0x9f, 0x13, 0x7c, 0x47, 0x76, 0x12, 0x7c, 0xfc, 0x10, 0xbb, 0x09, 0x55, 0x5a, 0xac, 0x20, 0xfa, 0x10, 0x7e, 0x15, 0xa6, 0x69, 0x12, 0xe1, 0xf7, 0xca, 0x22, 0x57, 0xd5, 0x9b, 0x4a, 0x4a, 0xd1, 0xfa, 0x38, 0x56, 0xcd, 0xcc, 0x19, 0x63, 0xf6, 0xf3, 0x2f, 0x56, 0xa5, 0x9b, 0x22, 0x51, 0xca, 0xf8, 0x21, 0x48, 0xa5, 0xf3, 0x28, 0x4b, 0xcb, 0xff, 0x22, 0x47, 0xcb, 0x9b, 0x4a, 0x4a, 0xc9, 0xf2, 0x39, 0x56, 0xcd, 0xeb, 0x3e, 0x22, 0xa5, 0xf3, 0x2b, 0x41, 0xc6, 0xfe, 0xc1, 0xfe, 0xf6, 0xca, 0xc9, 0xe1, 0xad, 0xc8, 0x1b, 0xa1, 0x66, 0x93, 0x19, 0x73, 0x26, 0x58, 0x42, 0x71, 0xf4, 0x18, 0x89, 0x2a, 0xf6, 0xca, 0xb5, 0xf5, 0x2c, 0xd8, 0x42, 0xdd, 0x72, 0x12, 0x09, 0x26, 0x5a, 0x4c, 0xc3, 0x21, 0x5a, 0x4c, 0xc3, 0x61, 0x59, 0x64, 0x9d, 0xab, 0xe6, 0x63, 0xc9, 0xc9, 0xad, 0x10, 0xa9, 0xa3, 0x49, 0x0b, 0x4b, 0x22, 0xa5, 0xcf, 0x22, 0x23, 0xa4, 0x9b, 0x4a, 0xdd, 0x31, 0xbf, 0xe2, 0x23, 0xa5, 0x9b, 0xcb, 0xe6, 0x35, 0x9a, 0x4a, 0x22, 0xcf, 0x9d, 0x20, 0x23, 0xcf, 0x99, 0xb5, 0x76, 0x81, 0x83, 0x20, 0x22, 0xcf, 0x9b, 0x20, 0x22, 0xcd, 0x99, 0x4a, 0xe6, 0x96, 0x10, 0x96, 0x71, 0xf6, 0xcb, 0x20, 0x23, 0xf5, 0xf1, 0x5a, 0x71, 0xf5, 0x64, 0x1e, 0x06, 0x9d, 0x64, 0x1e, 0x06, 0x8d, 0x5c, 0x49, 0x32, 0xa5, 0x9b, 0x4a, 0xdd, 0xf1, 0xbf, 0x56, 0xa1, 0x61, 0xbf, 0x13, 0x78, 0xf4, 0xc9, 0x1a, 0x11, 0x77, 0xc9, 0x22, 0x51, 0xc0, 0xf5, 0x2e, 0xa9, 0x61, 0xc9, 0x22, 0x50, 0xc0, 0xf8, 0x3c, 0xa9, 0x71, 0xc9, 0x1b, 0x72, 0xf4, 0x64, 0x9d, 0xb1, 0x5a, 0x4c, 0xdf, 0xa1, 0x61, 0x8b, 0x12, 0x78, 0xfc, 0xc8, 0x1f, 0x72, 0x2e, 0x77, 0x1a, 0x42, 0xcf, 0x9f, 0x10, 0x72, 0x2e, 0x47, 0xa2, 0x63, 0xa5, 0x9b, 0x4a, 0x48, 0xa5, 0xf3, 0x26, 0x4e, 0xca, 0xf8, 0x22, 0x57, 0xc4, 0xf7, 0x0b, 0x4a, 0xf3, 0xf2, 0x38, 0x56, 0xf1, 0xcd, 0xb5, 0xf5, 0x26, 0x5f, 0x5a, 0x78, 0xf7, 0xf1, 0x0a, 0x4a, 0xa5, 0x8b, 0x4a, 0x22, 0xf7, 0xf1, 0x4a, 0xdd, 0x75, 0x12, 0x0e, 0x06, 0x81, 0xc1, 0xd9, 0xca, 0xb5, 0x9b, 0x4a, 0x22, 0xc4, 0xc0, 0xb5, 0xc1, 0xc5, 0xa8, 0x8a, 0x92, 0xa1, 0x73, 0x5c, 0x22, 0xa5, 0x9b, 0x2b, 0xe1, 0xc5, 0xc9, 0x19, 0x11, 0x65, 0x73, 0x40, 0x22, 0xa5, 0x9b, 0x11, 0x78, 0xa6, 0x43, 0x61, 0xf2, 0xd0, 0x74, 0x2b, 0xe1, 0x96, 0x52, 0x1b, 0x70, 0xf6, 0x64, 0x3f, 0x22, 0x5a, 0xcf, 0x4f, 0x26, 0x20, 0x5b, 0x34, 0x23, 0x66, 0x64, 0x1f, 0xd2, 0xa5, 0x9b, 0x4a, 0x22, 0xa5, 0x9b, 0x4a, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x54, 0x58, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x43, 0x42, 0x42, 0x50, 0x5f, 0x57, 0xc3, 0x33, 0x5f, 0x37, 0x74, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0xeb, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x53, 0x69, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x73, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x44, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x6e, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x65, 0x66, 0x31, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x72, 0x65, 0x66, 0x32, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x01, 0x02, 0x03, 0x04 }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint32_t dcerpc_request_len = sizeof(dcerpc_request); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_opnum:9; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_opnum entry with only a request frag. */ static int DetectDceOpnumTestParse09(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; /* todo chop the request frag length and change the * length related parameters in the frag */ uint8_t dcerpc_request[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xec, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd4, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x83, 0xc7, 0x0b, 0x47, 0x47, 0x47, 0x47, 0x81, 0x37, 0x22, 0xa5, 0x9b, 0x4a, 0x75, 0xf4, 0xa3, 0x61, 0xd3, 0xbe, 0xdd, 0x5a, 0xfb, 0x20, 0x1e, 0xfc, 0x10, 0x8e, 0x0f, 0xa5, 0x9f, 0x4a, 0x22, 0x20, 0x9b, 0xa8, 0xd5, 0xc4, 0xff, 0xc1, 0x3f, 0xbd, 0x9b, 0x4a, 0x22, 0x2e, 0xc0, 0x7a, 0xa9, 0xfe, 0x97, 0xc9, 0xe1, 0xa9, 0xf3, 0x2f, 0x22, 0xc9, 0x9b, 0x22, 0x50, 0xa5, 0xf5, 0x4a, 0x4a, 0xce, 0x9b, 0x2f, 0x22, 0x2e, 0x6f, 0xc1, 0xe1, 0xf3, 0xa8, 0x83, 0xa2, 0x64, 0x98, 0xc1, 0x62, 0xa1, 0xa0, 0x89, 0x56, 0xa8, 0x1b, 0x8b, 0x2b, 0x2e, 0xe3, 0x7a, 0xd1, 0x03, 0xef, 0x58, 0x7c, 0x4e, 0x7d, 0x14, 0x76, 0xfa, 0xc3, 0x7f, 0x02, 0xa5, 0xbb, 0x4a, 0x89, 0x47, 0x6c, 0x12, 0xc9, 0x70, 0x18, 0x8e, 0x3a, 0x2e, 0xcb, 0x52, 0xa9, 0x67, 0x98, 0x0a, 0x1e, 0x2e, 0xc3, 0x32, 0x21, 0x7f, 0x10, 0x31, 0x3e, 0xa6, 0x61, 0xc1, 0x61, 0x85, 0x98, 0x88, 0xa9, 0xee, 0x83, 0x22, 0x51, 0xd6, 0xda, 0x4a, 0x4a, 0xc1, 0xff, 0x38, 0x47, 0xcd, 0xe9, 0x25, 0x41, 0xe4, 0xf3, 0x0d, 0x47, 0xd1, 0xcb, 0xc1, 0xd6, 0x1e, 0x95, 0x4a, 0x22, 0xa5, 0x73, 0x08, 0x22, 0xa5, 0x9b, 0xc9, 0xe6, 0xb5, 0xcd, 0x22, 0x43, 0xd7, 0xe2, 0x0b, 0x4a, 0xe9, 0xf2, 0x28, 0x50, 0xcd, 0xd7, 0x25, 0x43, 0xc1, 0x10, 0xbe, 0x99, 0xa9, 0x9b, 0x4a, 0x22, 0x4d, 0xb8, 0x4a, 0x22, 0xa5, 0x18, 0x8e, 0x2e, 0xf3, 0xc9, 0x22, 0x4e, 0xc9, 0x9b, 0x4a, 0x4a, 0x96, 0xa9, 0x64, 0x46, 0xcd, 0xec, 0x39, 0x10, 0xfa, 0xcf, 0xb5, 0x76, 0x81, 0x8f, 0xc9, 0xe6, 0xa9, 0x10, 0x82, 0x7c, 0xff, 0xc4, 0xa1, 0x0a, 0xf5, 0xcc, 0x1b, 0x74, 0xf4, 0x10, 0x81, 0xa9, 0x9d, 0x98, 0xb0, 0xa1, 0x65, 0x9f, 0xb9, 0x84, 0xd1, 0x9f, 0x13, 0x7c, 0x47, 0x76, 0x12, 0x7c, 0xfc, 0x10, 0xbb, 0x09, 0x55, 0x5a, 0xac, 0x20, 0xfa, 0x10, 0x7e, 0x15, 0xa6, 0x69, 0x12, 0xe1, 0xf7, 0xca, 0x22, 0x57, 0xd5, 0x9b, 0x4a, 0x4a, 0xd1, 0xfa, 0x38, 0x56, 0xcd, 0xcc, 0x19, 0x63, 0xf6, 0xf3, 0x2f, 0x56, 0xa5, 0x9b, 0x22, 0x51, 0xca, 0xf8, 0x21, 0x48, 0xa5, 0xf3, 0x28, 0x4b, 0xcb, 0xff, 0x22, 0x47, 0xcb, 0x9b, 0x4a, 0x4a, 0xc9, 0xf2, 0x39, 0x56, 0xcd, 0xeb, 0x3e, 0x22, 0xa5, 0xf3, 0x2b, 0x41, 0xc6, 0xfe, 0xc1, 0xfe, 0xf6, 0xca, 0xc9, 0xe1, 0xad, 0xc8, 0x1b, 0xa1, 0x66, 0x93, 0x19, 0x73, 0x26, 0x58, 0x42, 0x71, 0xf4, 0x18, 0x89, 0x2a, 0xf6, 0xca, 0xb5, 0xf5, 0x2c, 0xd8, 0x42, 0xdd, 0x72, 0x12, 0x09, 0x26, 0x5a, 0x4c, 0xc3, 0x21, 0x5a, 0x4c, 0xc3, 0x61, 0x59, 0x64, 0x9d, 0xab, 0xe6, 0x63, 0xc9, 0xc9, 0xad, 0x10, 0xa9, 0xa3, 0x49, 0x0b, 0x4b, 0x22, 0xa5, 0xcf, 0x22, 0x23, 0xa4, 0x9b, 0x4a, 0xdd, 0x31, 0xbf, 0xe2, 0x23, 0xa5, 0x9b, 0xcb, 0xe6, 0x35, 0x9a, 0x4a, 0x22, 0xcf, 0x9d, 0x20, 0x23, 0xcf, 0x99, 0xb5, 0x76, 0x81, 0x83, 0x20, 0x22, 0xcf, 0x9b, 0x20, 0x22, 0xcd, 0x99, 0x4a, 0xe6, 0x96, 0x10, 0x96, 0x71, 0xf6, 0xcb, 0x20, 0x23, 0xf5, 0xf1, 0x5a, 0x71, 0xf5, 0x64, 0x1e, 0x06, 0x9d, 0x64, 0x1e, 0x06, 0x8d, 0x5c, 0x49, 0x32, 0xa5, 0x9b, 0x4a, 0xdd, 0xf1, 0xbf, 0x56, 0xa1, 0x61, 0xbf, 0x13, 0x78, 0xf4, 0xc9, 0x1a, 0x11, 0x77, 0xc9, 0x22, 0x51, 0xc0, 0xf5, 0x2e, 0xa9, 0x61, 0xc9, 0x22, 0x50, 0xc0, 0xf8, 0x3c, 0xa9, 0x71, 0xc9, 0x1b, 0x72, 0xf4, 0x64, 0x9d, 0xb1, 0x5a, 0x4c, 0xdf, 0xa1, 0x61, 0x8b, 0x12, 0x78, 0xfc, 0xc8, 0x1f, 0x72, 0x2e, 0x77, 0x1a, 0x42, 0xcf, 0x9f, 0x10, 0x72, 0x2e, 0x47, 0xa2, 0x63, 0xa5, 0x9b, 0x4a, 0x48, 0xa5, 0xf3, 0x26, 0x4e, 0xca, 0xf8, 0x22, 0x57, 0xc4, 0xf7, 0x0b, 0x4a, 0xf3, 0xf2, 0x38, 0x56, 0xf1, 0xcd, 0xb5, 0xf5, 0x26, 0x5f, 0x5a, 0x78, 0xf7, 0xf1, 0x0a, 0x4a, 0xa5, 0x8b, 0x4a, 0x22, 0xf7, 0xf1, 0x4a, 0xdd, 0x75, 0x12, 0x0e, 0x06, 0x81, 0xc1, 0xd9, 0xca, 0xb5, 0x9b, 0x4a, 0x22, 0xc4, 0xc0, 0xb5, 0xc1, 0xc5, 0xa8, 0x8a, 0x92, 0xa1, 0x73, 0x5c, 0x22, 0xa5, 0x9b, 0x2b, 0xe1, 0xc5, 0xc9, 0x19, 0x11, 0x65, 0x73, 0x40, 0x22, 0xa5, 0x9b, 0x11, 0x78, 0xa6, 0x43, 0x61, 0xf2, 0xd0, 0x74, 0x2b, 0xe1, 0x96, 0x52, 0x1b, 0x70, 0xf6, 0x64, 0x3f, 0x22, 0x5a, 0xcf, 0x4f, 0x26, 0x20, 0x5b, 0x34, 0x23, 0x66, 0x64, 0x1f, 0xd2, 0xa5, 0x9b, 0x4a, 0x22, 0xa5, 0x9b, 0x4a, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x54, 0x58, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x43, 0x42, 0x42, 0x50, 0x5f, 0x57, 0xc3, 0x33, 0x5f, 0x37, 0x74, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0xeb, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x53, 0x69, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x73, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x44, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x6e, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x65, 0x66, 0x31, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x72, 0x65, 0x66, 0x32, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x01, 0x02, 0x03, 0x04 }; uint32_t dcerpc_request_len = sizeof(dcerpc_request); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_opnum:9; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_opnum(with multiple values) with a bind, bind_ack, * and multiple request/responses with a match test after each frag parsing. */ static int DetectDceOpnumTestParse10(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xd0, 0x8c, 0x33, 0x44, 0x22, 0xf1, 0x31, 0xaa, 0xaa, 0x90, 0x00, 0x38, 0x00, 0x10, 0x03, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x65, 0x8e, 0x00, 0x00, 0x0d, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x77, 0x69, 0x6e, 0x72, 0x65, 0x67, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x5c, 0x00, 0x5c, 0x00, 0xa8, 0xb9, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x54, 0x00, 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x0c, 0x00, 0x0c, 0x00, 0x98, 0xda, 0x14, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x73, 0x00, 0x61, 0x00, 0x33, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x41, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); uint32_t dcerpc_request2_len = sizeof(dcerpc_request2); uint32_t dcerpc_response2_len = sizeof(dcerpc_response2); uint32_t dcerpc_request3_len = sizeof(dcerpc_request3); uint32_t dcerpc_response3_len = sizeof(dcerpc_response3); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; dce_opnum:2,15,22; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCLogDebug("sending bind"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc bind failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SCLogDebug("sending bind_ack"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SCLogDebug("sending request1"); /* request1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't match, but should have: "); goto end; } SCLogDebug("sending response1"); /* response1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 did match, shouldn't have on response1: "); goto end; } /* request2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't match, but should have on request2: "); goto end; } /* response2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 did match, shouldn't have on response2: "); goto end; } /* request3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't match, but should have on request3: "); goto end; } /* response3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 did match, shouldn't have on response2: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_opnum entry(with multiple values) with multiple * request/responses. */ static int DetectDceOpnumTestParse11(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x5c, 0x00, 0x5c, 0x00, 0xa8, 0xb9, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x54, 0x00, 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x0c, 0x00, 0x0c, 0x00, 0x98, 0xda, 0x14, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x73, 0x00, 0x61, 0x00, 0x33, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x41, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); uint32_t dcerpc_request2_len = sizeof(dcerpc_request2); uint32_t dcerpc_response2_len = sizeof(dcerpc_response2); uint32_t dcerpc_request3_len = sizeof(dcerpc_request3); uint32_t dcerpc_response3_len = sizeof(dcerpc_response3); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_opnum:2-22; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); printf("AppLayerParse for dcerpcrequest1 failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); printf("no dcerpc state: "); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); printf("AppLayerParse for dcerpcresponse1 failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; /* request2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); printf("AppLayerParse for dcerpcrequest2 failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); printf("AppLayerParse for dcerpcresponse2 failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; /* request3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); printf("AppLayerParse for dcerpc request3 failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); printf("AppLayerParse for dcerpc response3 failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_opnum(with multiple values) with a bind, bind_ack, * and multiple request/responses with a match test after each frag parsing. */ static int DetectDceOpnumTestParse12(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0xfd, 0x2c, 0x34, 0x6c, 0x3c, 0xce, 0x11, 0xa8, 0x93, 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x7d, 0xd8, 0x00, 0x00, 0x0d, 0x00, 0x5c, 0x70, 0x69, 0x70, 0x65, 0x5c, 0x6c, 0x6c, 0x73, 0x72, 0x70, 0x63, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, //opnum is 0x28 0x00 0x00, 0x00, 0x00, 0x00, 0x07, 0x9f, 0x13, 0xd9, 0x2d, 0x97, 0xf4, 0x4a, 0xac, 0xc2, 0xbc, 0x70, 0xec, 0xaa, 0x9a, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x80, 0x40, 0x00, 0x44, 0x80, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x00, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x35, 0x39, 0x31, 0x63, 0x64, 0x30, 0x35, 0x38, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xd0, 0x2e, 0x08, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00 }; uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x9f, 0x13, 0xd9, 0x2d, 0x97, 0xf4, 0x4a, 0xac, 0xc2, 0xbc, 0x70, 0xec, 0xaa, 0x9a, 0xd3, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x00, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x35, 0x39, 0x31, 0x63, 0x64, 0x30, 0x35, 0x38, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65 }; uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x17, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x1d, 0x08, 0x00, 0xe8, 0x32, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x00, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x35, 0x39, 0x31, 0x63, 0x64, 0x30, 0x35, 0x38, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xd0, 0x2e, 0x08, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); uint32_t dcerpc_request2_len = sizeof(dcerpc_request2); uint32_t dcerpc_response2_len = sizeof(dcerpc_response2); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; dce_opnum:30, 40; sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* request1 */ SCLogDebug("Sending request1"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 40) { printf("dcerpc state holding invalid opnum. Holding %d, while we are " "expecting 40: ", dcerpc_state->dcerpc.dcerpcrequest.opnum); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("signature 1 didn't match, should have: "); goto end; } /* response1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 40) { printf("dcerpc state holding invalid opnum. Holding %d, while we are " "expecting 40\n", dcerpc_state->dcerpc.dcerpcrequest.opnum); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched on response 1, but shouldn't: "); goto end; } /* request2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 30) { printf("dcerpc state holding invalid opnum. Holding %d, while we are " "expecting 30\n", dcerpc_state->dcerpc.dcerpcrequest.opnum); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't match on request 2: "); goto end; } /* response2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response2, dcerpc_response2_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 30) { printf("dcerpc state holding invalid opnum. Holding %d, while we are " "expecting 30\n", dcerpc_state->dcerpc.dcerpcrequest.opnum); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched on response2, but shouldn't: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_opnum(with multiple values) with a bind, bind_ack, * and multiple request/responses with a match test after each frag parsing. */ static int DetectDceOpnumTestParse13(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x9f, 0x13, 0xd9, 0x2d, 0x97, 0xf4, 0x4a, 0xac, 0xc2, 0xbc, 0x70, 0xec, 0xaa, 0x9a, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x80, 0x40, 0x00, 0x44, 0x80, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x00, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x35, 0x39, 0x31, 0x63, 0x64, 0x30, 0x35, 0x38, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xd0, 0x2e, 0x08, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00 }; uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x9f, 0x13, 0xd9, 0x2d, 0x97, 0xf4, 0x4a, 0xac, 0xc2, 0xbc, 0x70, 0xec, 0xaa, 0x9a, 0xd3, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x00, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x35, 0x39, 0x31, 0x63, 0x64, 0x30, 0x35, 0x38, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65 }; uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x17, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x1d, 0x08, 0x00, 0xe8, 0x32, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x00, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x35, 0x39, 0x31, 0x63, 0x64, 0x30, 0x35, 0x38, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xd0, 0x2e, 0x08, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); uint32_t dcerpc_request2_len = sizeof(dcerpc_request2); uint32_t dcerpc_response2_len = sizeof(dcerpc_response2); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_opnum:30, 40; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 40) { printf("dcerpc state holding invalid opnum after request1. Holding %d, while we are " "expecting 40\n", dcerpc_state->dcerpc.dcerpcrequest.opnum); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 40) { printf("dcerpc state holding invalid opnum after response1. Holding %d, while we are " "expecting 40\n", dcerpc_state->dcerpc.dcerpcrequest.opnum); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; /* request2 */ printf("Sending Request2\n"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 30) { printf("dcerpc state holding invalid opnum after request2. Holding %d, while we are " "expecting 30\n", dcerpc_state->dcerpc.dcerpcrequest.opnum); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response2, dcerpc_response2_len); if (r != 0) { printf("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 30) { printf("dcerpc state holding invalid opnum after response2. Holding %d, while we are " "expecting 30\n", dcerpc_state->dcerpc.dcerpcrequest.opnum); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif void DetectDceOpnumRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDceOpnumTestParse01", DetectDceOpnumTestParse01, 1); UtRegisterTest("DetectDceOpnumTestParse02", DetectDceOpnumTestParse02, 1); UtRegisterTest("DetectDceOpnumTestParse03", DetectDceOpnumTestParse03, 1); UtRegisterTest("DetectDceOpnumTestParse04", DetectDceOpnumTestParse04, 1); UtRegisterTest("DetectDceOpnumTestParse05", DetectDceOpnumTestParse05, 1); UtRegisterTest("DetectDceOpnumTestParse06", DetectDceOpnumTestParse06, 1); UtRegisterTest("DetectDceOpnumTestParse07", DetectDceOpnumTestParse07, 1); UtRegisterTest("DetectDceOpnumTestParse08", DetectDceOpnumTestParse08, 1); UtRegisterTest("DetectDceOpnumTestParse09", DetectDceOpnumTestParse09, 1); UtRegisterTest("DetectDceOpnumTestParse10", DetectDceOpnumTestParse10, 1); UtRegisterTest("DetectDceOpnumTestParse11", DetectDceOpnumTestParse11, 1); UtRegisterTest("DetectDceOpnumTestParse12", DetectDceOpnumTestParse12, 1); UtRegisterTest("DetectDceOpnumTestParse13", DetectDceOpnumTestParse13, 1); #endif return; } suricata-1.4.7/src/util-spm-bs.h0000644000000000000000000000221612253546156013353 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon Crespo */ #ifndef __UTIL_SPM_BS__ #define __UTIL_SPM_BS__ #include "suricata-common.h" #include "suricata.h" uint8_t *BasicSearch(const uint8_t *, uint32_t, const uint8_t *, uint16_t); uint8_t *BasicSearchNocase(const uint8_t *, uint32_t, const uint8_t *, uint16_t); void BasicSearchInit (void); #endif /* __UTIL_SPM_BS__ */ suricata-1.4.7/src/detect-luajit.h0000644000000000000000000000303412253546156013734 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_LUAJIT_H__ #define __DETECT_LUAJIT_H__ #ifdef HAVE_LUAJIT #include #include #include typedef struct DetectLuajitThreadData { lua_State *luastate; uint32_t flags; int alproto; } DetectLuajitThreadData; typedef struct DetectLuajitData { int thread_ctx_id; int negated; char *filename; uint32_t flags; int alproto; char *buffername; /* buffer name in case of a single buffer */ } DetectLuajitData; #endif /* prototypes */ void DetectLuajitRegister (void); int DetectLuajitMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, uint8_t *buffer, uint32_t buffer_len, uint32_t offset); int DetectLuajitSetupStatesPool(int num, int reloads); #endif /* __DETECT_FILELUAJIT_H__ */ suricata-1.4.7/src/app-layer-ftp.h0000644000000000000000000000506712253546156013667 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo */ #ifndef __APP_LAYER_FTP_H__ #define __APP_LAYER_FTP_H__ typedef enum { FTP_COMMAND_UNKNOWN = 0, FTP_COMMAND_ABOR, FTP_COMMAND_ACCT, FTP_COMMAND_ALLO, FTP_COMMAND_APPE, FTP_COMMAND_CDUP, FTP_COMMAND_CHMOD, FTP_COMMAND_CWD, FTP_COMMAND_DELE, FTP_COMMAND_HELP, FTP_COMMAND_IDLE, FTP_COMMAND_LIST, FTP_COMMAND_MAIL, FTP_COMMAND_MDTM, FTP_COMMAND_MKD, FTP_COMMAND_MLFL, FTP_COMMAND_MODE, FTP_COMMAND_MRCP, FTP_COMMAND_MRSQ, FTP_COMMAND_MSAM, FTP_COMMAND_MSND, FTP_COMMAND_MSOM, FTP_COMMAND_NLST, FTP_COMMAND_NOOP, FTP_COMMAND_PASS, FTP_COMMAND_PASV, FTP_COMMAND_PORT, FTP_COMMAND_PWD, FTP_COMMAND_QUIT, FTP_COMMAND_REIN, FTP_COMMAND_REST, FTP_COMMAND_RETR, FTP_COMMAND_RMD, FTP_COMMAND_RNFR, FTP_COMMAND_RNTO, FTP_COMMAND_SITE, FTP_COMMAND_SIZE, FTP_COMMAND_SMNT, FTP_COMMAND_STAT, FTP_COMMAND_STOR, FTP_COMMAND_STOU, FTP_COMMAND_STRU, FTP_COMMAND_SYST, FTP_COMMAND_TYPE, FTP_COMMAND_UMASK, FTP_COMMAND_USER /** \todo more if missing.. */ } FtpRequestCommand; typedef uint32_t FtpRequestCommandArgOfs; typedef uint16_t FtpResponseCode; enum { FTP_FIELD_NONE = 0, FTP_FIELD_REQUEST_LINE, FTP_FIELD_REQUEST_COMMAND, FTP_FIELD_REQUEST_ARGS, FTP_FIELD_RESPONSE_LINE, FTP_FIELD_REPONSE_CODE, /* must be last */ FTP_FIELD_MAX, }; /** FTP State for app layer parser */ typedef struct FtpState_ { FtpRequestCommand command; FtpRequestCommandArgOfs arg_offset; FtpResponseCode response_code; uint32_t port_line_len; uint8_t *port_line; } FtpState; void RegisterFTPParsers(void); void FTPParserRegisterTests(void); void FTPAtExitPrintStats(void); #endif /* __APP_LAYER_FTP_H__ */ suricata-1.4.7/src/stream-tcp.c0000644000000000000000000115524012253546156013260 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Gurvinder Singh * * TCP stream tracking and reassembly engine. * * \todo - 4WHS: what if after the 2nd SYN we turn out to be normal 3WHS anyway? */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "flow-util.h" #include "conf.h" #include "conf-yaml-loader.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "util-pool.h" #include "util-checksum.h" #include "util-unittest.h" #include "util-print.h" #include "util-debug.h" #include "util-device.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream-tcp-inline.h" #include "stream-tcp-sack.h" #include "stream-tcp-util.h" #include "stream.h" #include "pkt-var.h" #include "app-layer-parser.h" #include "app-layer-protos.h" #include "util-host-os-info.h" #include "util-privs.h" #include "util-profiling.h" #include "util-misc.h" #include "util-validate.h" //#define DEBUG #define STREAMTCP_DEFAULT_SESSIONS 262144 #define STREAMTCP_DEFAULT_PREALLOC 32768 #define STREAMTCP_DEFAULT_MEMCAP (32 * 1024 * 1024) /* 32mb */ #define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP (64 * 1024 * 1024) /* 64mb */ #define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE 2560 #define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE 2560 #define STREAMTCP_NEW_TIMEOUT 60 #define STREAMTCP_EST_TIMEOUT 3600 #define STREAMTCP_CLOSED_TIMEOUT 120 #define STREAMTCP_EMERG_NEW_TIMEOUT 10 #define STREAMTCP_EMERG_EST_TIMEOUT 300 #define STREAMTCP_EMERG_CLOSED_TIMEOUT 20 TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **); TmEcode StreamTcpThreadDeinit(ThreadVars *, void *); void StreamTcpExitPrintStats(ThreadVars *, void *); static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *, PacketQueue *); void StreamTcpRegisterTests (void); void StreamTcpReturnStreamSegments (TcpStream *); void StreamTcpInitConfig(char); int StreamTcpGetFlowState(void *); void StreamTcpSetOSPolicy(TcpStream*, Packet*); void StreamTcpPseudoPacketCreateStreamEndPacket(Packet *, TcpSession *, PacketQueue *); static int StreamTcpValidateTimestamp(TcpSession * , Packet *); static int StreamTcpHandleTimestamp(TcpSession * , Packet *); static int StreamTcpValidateRst(TcpSession * , Packet *); static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *, Packet *); static Pool *ssn_pool = NULL; static SCMutex ssn_pool_mutex; #ifdef DEBUG static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */ #endif extern uint8_t engine_mode; SC_ATOMIC_DECLARE(uint64_t, st_memuse); /* stream engine running in "inline" mode. */ int stream_inline = 0; void TmModuleStreamTcpRegister (void) { tmm_modules[TMM_STREAMTCP].name = "StreamTcp"; tmm_modules[TMM_STREAMTCP].ThreadInit = StreamTcpThreadInit; tmm_modules[TMM_STREAMTCP].Func = StreamTcp; tmm_modules[TMM_STREAMTCP].ThreadExitPrintStats = StreamTcpExitPrintStats; tmm_modules[TMM_STREAMTCP].ThreadDeinit = StreamTcpThreadDeinit; tmm_modules[TMM_STREAMTCP].RegisterTests = StreamTcpRegisterTests; tmm_modules[TMM_STREAMTCP].cap_flags = 0; tmm_modules[TMM_STREAMTCP].flags = TM_FLAG_STREAM_TM; } void StreamTcpIncrMemuse(uint64_t size) { (void) SC_ATOMIC_ADD(st_memuse, size); return; } void StreamTcpDecrMemuse(uint64_t size) { (void) SC_ATOMIC_SUB(st_memuse, size); return; } void StreamTcpMemuseCounter(ThreadVars *tv, StreamTcpThread *stt) { uint64_t memusecopy = SC_ATOMIC_GET(st_memuse); SCPerfCounterSetUI64(stt->counter_tcp_memuse, tv->sc_perf_pca, memusecopy); return; } /** * \brief Check if alloc'ing "size" would mean we're over memcap * * \retval 1 if in bounds * \retval 0 if not in bounds */ int StreamTcpCheckMemcap(uint64_t size) { if (stream_config.memcap == 0 || size + SC_ATOMIC_GET(st_memuse) <= stream_config.memcap) return 1; return 0; } /** * \brief Function to return the stream back to the pool. It returns the * segments in the stream to the segment pool. * * This function is called when the flow is destroyed, so it should free * *everything* related to the tcp session. So including the app layer * data. We are guaranteed to only get here when the flow's use_cnt is 0. * * \param ssn Void ptr to the ssn. */ void StreamTcpSessionClear(void *ssnptr) { SCEnter(); StreamMsg *smsg = NULL; TcpSession *ssn = (TcpSession *)ssnptr; if (ssn == NULL) SCReturn; StreamTcpReturnStreamSegments(&ssn->client); StreamTcpReturnStreamSegments(&ssn->server); //AppLayerParserCleanupState(ssn); StreamTcpSackFreeList(&ssn->client); StreamTcpSackFreeList(&ssn->server); /* if we have (a) smsg(s), return to the pool */ smsg = ssn->toserver_smsg_head; while(smsg != NULL) { StreamMsg *smsg_next = smsg->next; SCLogDebug("returning smsg %p to pool", smsg); smsg->next = NULL; smsg->prev = NULL; FlowDeReference(&smsg->flow); StreamMsgReturnToPool(smsg); smsg = smsg_next; } ssn->toserver_smsg_head = NULL; smsg = ssn->toclient_smsg_head; while(smsg != NULL) { StreamMsg *smsg_next = smsg->next; SCLogDebug("returning smsg %p to pool", smsg); smsg->next = NULL; smsg->prev = NULL; FlowDeReference(&smsg->flow); StreamMsgReturnToPool(smsg); smsg = smsg_next; } ssn->toclient_smsg_head = NULL; memset(ssn, 0, sizeof(TcpSession)); SCMutexLock(&ssn_pool_mutex); PoolReturn(ssn_pool, ssn); #ifdef DEBUG ssn_pool_cnt--; #endif SCMutexUnlock(&ssn_pool_mutex); SCReturn; } /** * \brief Function to return the stream segments back to the pool. * * We don't clear out the app layer storage here as that is under protection * of the "use_cnt" reference counter in the flow. This function is called * when the use_cnt is always at least 1 (this pkt has incremented the flow * use_cnt itself), so we don't bother. * * \param p Packet used to identify the stream. */ void StreamTcpSessionPktFree (Packet *p) { SCEnter(); TcpSession *ssn = (TcpSession *)p->flow->protoctx; if (ssn == NULL) SCReturn; StreamTcpReturnStreamSegments(&ssn->client); StreamTcpReturnStreamSegments(&ssn->server); SCReturn; } /** \brief Stream alloc function for the Pool * \retval ptr void ptr to TcpSession structure with all vars set to 0/NULL */ void *StreamTcpSessionPoolAlloc() { void *ptr = NULL; if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpSession)) == 0) return NULL; ptr = SCMalloc(sizeof(TcpSession)); if (unlikely(ptr == NULL)) return NULL; return ptr; } int StreamTcpSessionPoolInit(void *data, void* initdata) { memset(data, 0, sizeof(TcpSession)); StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession)); return 1; } /** \brief Pool free function * \param s Void ptr to TcpSession memory */ void StreamTcpSessionPoolCleanup(void *s) { StreamMsg *smsg = NULL; if (s == NULL) return; TcpSession *ssn = (TcpSession *)s; StreamTcpReturnStreamSegments(&ssn->client); StreamTcpReturnStreamSegments(&ssn->server); /* if we have (a) smsg(s), return to the pool */ smsg = ssn->toserver_smsg_head; while(smsg != NULL) { StreamMsg *smsg_next = smsg->next; SCLogDebug("returning smsg %p to pool", smsg); smsg->next = NULL; smsg->prev = NULL; FlowDeReference(&smsg->flow); StreamMsgReturnToPool(smsg); smsg = smsg_next; } ssn->toserver_smsg_head = NULL; smsg = ssn->toclient_smsg_head; while(smsg != NULL) { StreamMsg *smsg_next = smsg->next; SCLogDebug("returning smsg %p to pool", smsg); smsg->next = NULL; smsg->prev = NULL; FlowDeReference(&smsg->flow); StreamMsgReturnToPool(smsg); smsg = smsg_next; } ssn->toclient_smsg_head = NULL; StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession)); } /** \brief To initialize the stream global configuration data * * \param quiet It tells the mode of operation, if it is TRUE nothing will * be get printed. */ void StreamTcpInitConfig(char quiet) { intmax_t value = 0; SCLogDebug("Initializing Stream"); memset(&stream_config, 0, sizeof(stream_config)); /** set config defaults */ if ((ConfGetInt("stream.max-sessions", &value)) == 1) { stream_config.max_sessions = (uint32_t)value; } else { if (RunmodeIsUnittests()) stream_config.max_sessions = 1024; else stream_config.max_sessions = STREAMTCP_DEFAULT_SESSIONS; } if (!quiet) { SCLogInfo("stream \"max-sessions\": %"PRIu32"", stream_config.max_sessions); } if ((ConfGetInt("stream.prealloc-sessions", &value)) == 1) { stream_config.prealloc_sessions = (uint32_t)value; } else { if (RunmodeIsUnittests()) stream_config.prealloc_sessions = 128; else stream_config.prealloc_sessions = STREAMTCP_DEFAULT_PREALLOC; } if (!quiet) { SCLogInfo("stream \"prealloc-sessions\": %"PRIu32"", stream_config.prealloc_sessions); } char *temp_stream_memcap_str; if (ConfGet("stream.memcap", &temp_stream_memcap_str) == 1) { if (ParseSizeStringU64(temp_stream_memcap_str, &stream_config.memcap) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing stream.memcap " "from conf file - %s. Killing engine", temp_stream_memcap_str); exit(EXIT_FAILURE); } } else { stream_config.memcap = STREAMTCP_DEFAULT_MEMCAP; } if (!quiet) { SCLogInfo("stream \"memcap\": %"PRIu64, stream_config.memcap); } ConfGetBool("stream.midstream", &stream_config.midstream); if (!quiet) { SCLogInfo("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled"); } ConfGetBool("stream.async-oneside", &stream_config.async_oneside); if (!quiet) { SCLogInfo("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled"); } int csum = 0; if ((ConfGetBool("stream.checksum-validation", &csum)) == 1) { if (csum == 1) { stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION; } /* Default is that we validate the checksum of all the packets */ } else { stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION; } if (!quiet) { SCLogInfo("stream \"checksum-validation\": %s", stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION ? "enabled" : "disabled"); } int inl = 0; char *temp_stream_inline_str; if (ConfGet("stream.inline", &temp_stream_inline_str) == 1) { /* checking for "auto" and falling back to boolean to provide * backward compatibility */ if (strcmp(temp_stream_inline_str, "auto") == 0) { if (IS_ENGINE_MODE_IPS(engine_mode)) { stream_inline = 1; } else { stream_inline = 0; } } else if (ConfGetBool("stream.inline", &inl) == 1) { stream_inline = inl; } } if (!quiet) { SCLogInfo("stream.\"inline\": %s", stream_inline ? "enabled" : "disabled"); } char *temp_stream_reassembly_memcap_str; if (ConfGet("stream.reassembly.memcap", &temp_stream_reassembly_memcap_str) == 1) { if (ParseSizeStringU64(temp_stream_reassembly_memcap_str, &stream_config.reassembly_memcap) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing " "stream.reassembly.memcap " "from conf file - %s. Killing engine", temp_stream_reassembly_memcap_str); exit(EXIT_FAILURE); } } else { stream_config.reassembly_memcap = STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP; } if (!quiet) { SCLogInfo("stream.reassembly \"memcap\": %"PRIu64"", stream_config.reassembly_memcap); } char *temp_stream_reassembly_depth_str; if (ConfGet("stream.reassembly.depth", &temp_stream_reassembly_depth_str) == 1) { if (ParseSizeStringU32(temp_stream_reassembly_depth_str, &stream_config.reassembly_depth) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing " "stream.reassembly.depth " "from conf file - %s. Killing engine", temp_stream_reassembly_depth_str); exit(EXIT_FAILURE); } } else { stream_config.reassembly_depth = 0; } if (!quiet) { SCLogInfo("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth); } char *temp_stream_reassembly_toserver_chunk_size_str; if (ConfGet("stream.reassembly.toserver-chunk-size", &temp_stream_reassembly_toserver_chunk_size_str) == 1) { if (ParseSizeStringU16(temp_stream_reassembly_toserver_chunk_size_str, &stream_config.reassembly_toserver_chunk_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing " "stream.reassembly.toserver-chunk-size " "from conf file - %s. Killing engine", temp_stream_reassembly_toserver_chunk_size_str); exit(EXIT_FAILURE); } } else { stream_config.reassembly_toserver_chunk_size = STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE; } StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, stream_config.reassembly_toserver_chunk_size); char *temp_stream_reassembly_toclient_chunk_size_str; if (ConfGet("stream.reassembly.toclient-chunk-size", &temp_stream_reassembly_toclient_chunk_size_str) == 1) { if (ParseSizeStringU16(temp_stream_reassembly_toclient_chunk_size_str, &stream_config.reassembly_toclient_chunk_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing " "stream.reassembly.toclient-chunk-size " "from conf file - %s. Killing engine", temp_stream_reassembly_toclient_chunk_size_str); exit(EXIT_FAILURE); } } else { stream_config.reassembly_toclient_chunk_size = STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE; } StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, stream_config.reassembly_toclient_chunk_size); if (!quiet) { SCLogInfo("stream.reassembly \"toserver-chunk-size\": %"PRIu16, stream_config.reassembly_toserver_chunk_size); SCLogInfo("stream.reassembly \"toclient-chunk-size\": %"PRIu16, stream_config.reassembly_toclient_chunk_size); } /* init the memcap/use tracking */ SC_ATOMIC_INIT(st_memuse); SCMutexInit(&ssn_pool_mutex, NULL); SCMutexLock(&ssn_pool_mutex); ssn_pool = PoolInit(stream_config.max_sessions, stream_config.prealloc_sessions, sizeof(TcpSession), StreamTcpSessionPoolAlloc, StreamTcpSessionPoolInit, NULL, StreamTcpSessionPoolCleanup, NULL); if (ssn_pool == NULL) { SCLogError(SC_ERR_POOL_INIT, "ssn_pool is not initialized"); SCMutexUnlock(&ssn_pool_mutex); exit(EXIT_FAILURE); } SCMutexUnlock(&ssn_pool_mutex); StreamTcpReassembleInit(quiet); /* set the default free function and flow state function * values. */ FlowSetProtoFreeFunc(IPPROTO_TCP, StreamTcpSessionClear); FlowSetFlowStateFunc(IPPROTO_TCP, StreamTcpGetFlowState); } void StreamTcpFreeConfig(char quiet) { StreamTcpReassembleFree(quiet); SCMutexLock(&ssn_pool_mutex); if (ssn_pool != NULL) { PoolFree(ssn_pool); ssn_pool = NULL; } SCMutexUnlock(&ssn_pool_mutex); SCMutexDestroy(&ssn_pool_mutex); SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt); } /** \brief The function is used to to fetch a TCP session from the * ssn_pool, when a TCP SYN is received. * * \param quiet Packet P, which has been recieved for the new TCP session. * * \retval TcpSession A new TCP session with field initilaized to 0/NULL. */ TcpSession *StreamTcpNewSession (Packet *p) { TcpSession *ssn = (TcpSession *)p->flow->protoctx; if (ssn == NULL) { SCMutexLock(&ssn_pool_mutex); p->flow->protoctx = PoolGet(ssn_pool); #ifdef DEBUG if (p->flow->protoctx != NULL) ssn_pool_cnt++; #endif SCMutexUnlock(&ssn_pool_mutex); ssn = (TcpSession *)p->flow->protoctx; if (ssn == NULL) { SCLogDebug("ssn_pool is empty"); return NULL; } ssn->state = TCP_NONE; } return ssn; } static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn, uint8_t state) { if (state == ssn->state || PKT_IS_PSEUDOPKT(p)) return; ssn->state = state; } /** * \brief Function to set the OS policy for the given stream based on the * destination of the received packet. * * \param stream TcpStream of which os_policy needs to set * \param p Packet which is used to set the os policy */ void StreamTcpSetOSPolicy(TcpStream *stream, Packet *p) { int ret = 0; if (PKT_IS_IPV4(p)) { /* Get the OS policy based on destination IP address, as destination OS will decide how to react on the anomalies of newly received packets */ ret = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p)); if (ret > 0) stream->os_policy = ret; else stream->os_policy = OS_POLICY_DEFAULT; } else if (PKT_IS_IPV6(p)) { /* Get the OS policy based on destination IP address, as destination OS will decide how to react on the anomalies of newly received packets */ ret = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p)); if (ret > 0) stream->os_policy = ret; else stream->os_policy = OS_POLICY_DEFAULT; } if (stream->os_policy == OS_POLICY_BSD_RIGHT) stream->os_policy = OS_POLICY_BSD; else if (stream->os_policy == OS_POLICY_OLD_SOLARIS) stream->os_policy = OS_POLICY_SOLARIS; SCLogDebug("Policy is %"PRIu8"", stream->os_policy); } /** * \brief macro to update last_ack only if the new value is higher * * \param ssn session * \param stream stream to update * \param ack ACK value to test and set */ #define StreamTcpUpdateLastAck(ssn, stream, ack) { \ if (SEQ_GT((ack), (stream)->last_ack)) { \ (stream)->last_ack = (ack); \ SCLogDebug("ssn %p: last_ack set to %"PRIu32, (ssn), (stream)->last_ack); \ StreamTcpSackPruneList((stream)); \ } \ } /** * \brief macro to update next_win only if the new value is higher * * \param ssn session * \param stream stream to update * \param win window value to test and set */ #define StreamTcpUpdateNextWin(ssn, stream, win) { \ uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \ if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \ (stream)->next_win = ((win) + sacked_size__); \ SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \ } \ } static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p) { if (p->payload_len == 0) SCReturnInt(0); /* retransmission of already ack'd data */ if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) { StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION); SCReturnInt(1); } /* retransmission of in flight data */ if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->next_seq)) { StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION); SCReturnInt(2); } SCLogDebug("seq %u payload_len %u => %u, last_ack %u", TCP_GET_SEQ(p), p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack); SCReturnInt(0); } /** * \internal * \brief Function to handle the TCP_CLOSED or NONE state. The function handles * packets while the session state is None which means a newly * initialized structure, or a fully closed session. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling * * \retval 0 ok * \retval -1 error */ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (p->tcph->th_flags & TH_RST) { StreamTcpSetEvent(p, STREAM_RST_BUT_NO_SESSION); SCLogDebug("RST packet received, no session setup"); return -1; } else if (p->tcph->th_flags & TH_FIN) { StreamTcpSetEvent(p, STREAM_FIN_BUT_NO_SESSION); SCLogDebug("FIN packet received, no session setup"); return -1; /* SYN/ACK */ } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { if (stream_config.midstream == FALSE && stream_config.async_oneside == FALSE) return 0; if (ssn == NULL) { ssn = StreamTcpNewSession(p); if (ssn == NULL) { SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); return -1; } SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); SCLogDebug("ssn %p: =~ midstream picked ssn state is now " "TCP_SYN_RECV", ssn); ssn->flags |= STREAMTCP_FLAG_MIDSTREAM; /* Flag used to change the direct in the later stage in the session */ ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_SYNACK; /* sequence number & window */ ssn->server.isn = TCP_GET_SEQ(p); STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn); ssn->server.next_seq = ssn->server.isn + 1; ssn->server.window = TCP_GET_WINDOW(p); SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window); ssn->client.isn = TCP_GET_ACK(p) - 1; STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn); ssn->client.next_seq = ssn->client.isn + 1; ssn->client.last_ack = TCP_GET_ACK(p); /** If the client has a wscale option the server had it too, * so set the wscale for the server to max. Otherwise none * will have the wscale opt just like it should. */ if (p->tcpvars.ws != NULL) { ssn->client.wscale = TCP_GET_WSCALE(p); ssn->server.wscale = TCP_WSCALE_MAX; } SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq" " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack); SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq" " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack); /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ if (p->tcpvars.ts != NULL) { ssn->server.last_ts = TCP_GET_TSVAL(p); ssn->client.last_ts = TCP_GET_TSECR(p); SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " "ssn->client.last_ts %" PRIu32"", ssn, ssn->server.last_ts, ssn->client.last_ts); ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; ssn->server.last_pkt_ts = p->ts.tv_sec; if (ssn->server.last_ts == 0) ssn->server.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP; if (ssn->client.last_ts == 0) ssn->client.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP; } else { ssn->server.last_ts = 0; ssn->client.last_ts = 0; } if (TCP_GET_SACKOK(p) == 1) { ssn->flags |= STREAMTCP_FLAG_SACKOK; SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming " "SACK permitted for both sides", ssn); } } else if (p->tcph->th_flags & TH_SYN) { if (ssn == NULL) { ssn = StreamTcpNewSession(p); if (ssn == NULL) { SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); return -1; } SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT); SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn); /* set the sequence numbers and window */ ssn->client.isn = TCP_GET_SEQ(p); STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn); ssn->client.next_seq = ssn->client.isn + 1; /* Set the stream timestamp value, if packet has timestamp option * enabled. */ if (p->tcpvars.ts != NULL) { ssn->client.last_ts = TCP_GET_TSVAL(p); SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, p->tcpvars.ts, ssn->client.last_ts); if (ssn->client.last_ts == 0) ssn->client.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP; ssn->client.last_pkt_ts = p->ts.tv_sec; ssn->client.flags |= STREAMTCP_FLAG_TIMESTAMP; } ssn->server.window = TCP_GET_WINDOW(p); if (p->tcpvars.ws != NULL) { ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE; ssn->server.wscale = TCP_GET_WSCALE(p); } if (TCP_GET_SACKOK(p) == 1) { ssn->flags |= STREAMTCP_FLAG_CLIENT_SACKOK; SCLogDebug("ssn %p: SACK permited on SYN packet", ssn); } SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", " "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack " "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack); } else if (p->tcph->th_flags & TH_ACK) { if (stream_config.midstream == FALSE) return 0; if (ssn == NULL) { ssn = StreamTcpNewSession(p); if (ssn == NULL) { SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); return -1; } SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); SCLogDebug("ssn %p: =~ midstream picked ssn state is now " "TCP_ESTABLISHED", ssn); ssn->flags = STREAMTCP_FLAG_MIDSTREAM; ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED; /* set the sequence numbers and window */ ssn->client.isn = TCP_GET_SEQ(p) - 1; STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn); ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; ssn->client.window = TCP_GET_WINDOW(p); ssn->client.last_ack = TCP_GET_SEQ(p); ssn->client.next_win = ssn->client.last_ack + ssn->client.window; SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", ssn, ssn->client.isn, ssn->client.next_seq); ssn->server.isn = TCP_GET_ACK(p) - 1; STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn); ssn->server.next_seq = ssn->server.isn + 1; ssn->server.last_ack = TCP_GET_ACK(p); ssn->server.next_win = ssn->server.last_ack; SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", " "ssn->server.next_win %"PRIu32"", ssn, ssn->client.next_win, ssn->server.next_win); SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", " "ssn->server.last_ack %"PRIu32"", ssn, ssn->client.last_ack, ssn->server.last_ack); /** window scaling for midstream pickups, we can't do much other * than assume that it's set to the max value: 14 */ ssn->client.wscale = TCP_WSCALE_MAX; ssn->server.wscale = TCP_WSCALE_MAX; /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ if (p->tcpvars.ts != NULL) { ssn->client.last_ts = TCP_GET_TSVAL(p); ssn->server.last_ts = TCP_GET_TSECR(p); SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " "ssn->client.last_ts %" PRIu32"", ssn, ssn->server.last_ts, ssn->client.last_ts); ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; ssn->client.last_pkt_ts = p->ts.tv_sec; if (ssn->server.last_ts == 0) ssn->server.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP; if (ssn->client.last_ts == 0) ssn->client.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP; } else { ssn->server.last_ts = 0; ssn->client.last_ts = 0; } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); ssn->flags |= STREAMTCP_FLAG_SACKOK; SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn); } else { SCLogDebug("default case"); } return 0; } /** * \brief Function to handle the TCP_SYN_SENT state. The function handles * SYN, SYN/ACK, RST packets and correspondingly changes the connection * state. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (ssn == NULL) return -1; SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ? "toclient":"toserver"); /* RST */ if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; if (PKT_IS_TOSERVER(p)) { if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) && SEQ_EQ(TCP_GET_WINDOW(p), 0) && SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); } } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); } /* FIN */ } else if (p->tcph->th_flags & TH_FIN) { /** \todo */ /* SYN/ACK */ } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn); /* Check if the SYN/ACK packet ack's the earlier * received SYN packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->server.isn + 1))) { StreamTcpSetEvent(p, STREAM_4WHS_SYNACK_WITH_WRONG_ACK); SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %"PRIu32"" " != %" PRIu32 " from stream", ssn, TCP_GET_ACK(p), ssn->server.isn + 1); return -1; } /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN * packet. */ if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) { StreamTcpSetEvent(p, STREAM_4WHS_SYNACK_WITH_WRONG_SYN); SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %"PRIu32"" " != %" PRIu32 " from *first* SYN pkt", ssn, TCP_GET_SEQ(p), ssn->client.isn); return -1; } /* update state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn); /* sequence number & window */ ssn->client.isn = TCP_GET_SEQ(p); STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn); ssn->client.next_seq = ssn->client.isn + 1; ssn->server.window = TCP_GET_WINDOW(p); SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn, ssn->client.window); /* Set the timestamp values used to validate the timestamp of * received packets. */ if ((p->tcpvars.ts != NULL) && (ssn->server.flags & STREAMTCP_FLAG_TIMESTAMP)) { ssn->client.last_ts = TCP_GET_TSVAL(p); SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32" " "ssn->server.last_ts %" PRIu32"", ssn, ssn->client.last_ts, ssn->server.last_ts); ssn->server.flags &= ~STREAMTCP_FLAG_TIMESTAMP; ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; ssn->client.last_pkt_ts = p->ts.tv_sec; if (ssn->client.last_ts == 0) ssn->client.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP; } else { ssn->server.last_ts = 0; ssn->client.last_ts = 0; ssn->server.flags &= ~STREAMTCP_FLAG_TIMESTAMP; ssn->server.flags &= ~STREAMTCP_FLAG_ZERO_TIMESTAMP; } ssn->server.last_ack = TCP_GET_ACK(p); ssn->client.last_ack = ssn->client.isn + 1; /** check for the presense of the ws ptr to determine if we * support wscale at all */ if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && (p->tcpvars.ws != NULL)) { ssn->server.wscale = TCP_GET_WSCALE(p); } else { ssn->server.wscale = 0; } if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) && TCP_GET_SACKOK(p) == 1) { ssn->flags |= STREAMTCP_FLAG_SACKOK; SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn); } ssn->client.next_win = ssn->client.last_ack + ssn->client.window; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win); SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win); SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", " "ssn->client.next_seq %" PRIu32 ", " "ssn->client.last_ack %" PRIu32 " " "(ssn->server.last_ack %" PRIu32 ")", ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack, ssn->server.last_ack); /* done here */ return 0; } if (PKT_IS_TOSERVER(p)) { StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION); SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn); return -1; } /* Check if the SYN/ACK packet ack's the earlier * received SYN packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) { StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK); SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), ssn->client.isn + 1); return -1; } /* update state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn); /* sequence number & window */ ssn->server.isn = TCP_GET_SEQ(p); STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn); ssn->server.next_seq = ssn->server.isn + 1; ssn->client.window = TCP_GET_WINDOW(p); SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window); /* Set the timestamp values used to validate the timestamp of * received packets.*/ if ((p->tcpvars.ts != NULL) && (ssn->client.flags & STREAMTCP_FLAG_TIMESTAMP)) { ssn->server.last_ts = TCP_GET_TSVAL(p); SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " "ssn->client.last_ts %" PRIu32"", ssn, ssn->server.last_ts, ssn->client.last_ts); ssn->client.flags &= ~STREAMTCP_FLAG_TIMESTAMP; ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; ssn->server.last_pkt_ts = p->ts.tv_sec; if (ssn->server.last_ts == 0) ssn->server.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP; } else { ssn->client.last_ts = 0; ssn->server.last_ts = 0; ssn->client.flags &= ~STREAMTCP_FLAG_TIMESTAMP; ssn->client.flags &= ~STREAMTCP_FLAG_ZERO_TIMESTAMP; } ssn->client.last_ack = TCP_GET_ACK(p); ssn->server.last_ack = ssn->server.isn + 1; /** check for the presense of the ws ptr to determine if we * support wscale at all */ if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && (p->tcpvars.ws != NULL)) { ssn->client.wscale = TCP_GET_WSCALE(p); } else { ssn->client.wscale = 0; } if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) && TCP_GET_SACKOK(p) == 1) { ssn->flags |= STREAMTCP_FLAG_SACKOK; SCLogDebug("ssn %p: SACK permitted for session", ssn); } ssn->server.next_win = ssn->server.last_ack + ssn->server.window; ssn->client.next_win = ssn->client.last_ack + ssn->client.window; SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win); SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win); SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", " "ssn->server.next_seq %" PRIu32 ", " "ssn->server.last_ack %" PRIu32 " " "(ssn->client.last_ack %" PRIu32 ")", ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack, ssn->client.last_ack); /* unset the 4WHS flag as we received this SYN/ACK as part of a * (so far) valid 3WHS */ if (ssn->flags & STREAMTCP_FLAG_4WHS) SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK" " so considering 3WHS", ssn); ssn->flags &=~ STREAMTCP_FLAG_4WHS; } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn); if (ssn->flags & STREAMTCP_FLAG_4WHS) { SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of " "4WHS SYN", ssn); } if (PKT_IS_TOCLIENT(p)) { /** a SYN only packet in the opposite direction could be: * http://www.breakingpointsystems.com/community/blog/tcp- * portals-the-three-way-handshake-is-a-lie * * \todo improve resetting the session */ /* indicate that we're dealing with 4WHS here */ ssn->flags |= STREAMTCP_FLAG_4WHS; SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn); /* set the sequence numbers and window for server * We leave the ssn->client.isn in place as we will * check the SYN/ACK pkt with that. */ ssn->server.isn = TCP_GET_SEQ(p); STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn); ssn->server.next_seq = ssn->server.isn + 1; /* Set the stream timestamp value, if packet has timestamp * option enabled. */ if (p->tcpvars.ts != NULL) { ssn->server.last_ts = TCP_GET_TSVAL(p); SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, p->tcpvars.ts, ssn->server.last_ts); if (ssn->server.last_ts == 0) ssn->server.flags |= STREAMTCP_FLAG_ZERO_TIMESTAMP; ssn->server.last_pkt_ts = p->ts.tv_sec; ssn->server.flags |= STREAMTCP_FLAG_TIMESTAMP; } ssn->server.window = TCP_GET_WINDOW(p); if (p->tcpvars.ws != NULL) { ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE; ssn->server.wscale = TCP_GET_WSCALE(p); } else { ssn->flags &= ~STREAMTCP_FLAG_SERVER_WSCALE; ssn->server.wscale = 0; } if (TCP_GET_SACKOK(p) == 1) { ssn->flags |= STREAMTCP_FLAG_CLIENT_SACKOK; } else { ssn->flags &= ~STREAMTCP_FLAG_CLIENT_SACKOK; } SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", " "ssn->server.next_seq %" PRIu32 ", " "ssn->server.last_ack %"PRIu32"", ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack); SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", " "ssn->client.next_seq %" PRIu32 ", " "ssn->client.last_ack %"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack); } /** \todo check if it's correct or set event */ } else if (p->tcph->th_flags & TH_ACK) { /* Handle the asynchronous stream, when we receive a SYN packet and now istead of receving a SYN/ACK we receive a ACK from the same host, which sent the SYN, this suggests the ASNYC streams.*/ if (stream_config.async_oneside == FALSE) return 0; /* we are in AYNC (one side) mode now. */ /* one side async means we won't see a SYN/ACK, so we can * only check the SYN. */ if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) { StreamTcpSetEvent(p, STREAM_3WHS_ASYNC_WRONG_SEQ); SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " "%" PRIu32 " from stream",ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } ssn->flags |= STREAMTCP_FLAG_ASYNC; StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn); ssn->client.window = TCP_GET_WINDOW(p); ssn->client.last_ack = TCP_GET_SEQ(p); ssn->client.next_win = ssn->client.last_ack + ssn->client.window; /* Set the server side parameters */ ssn->server.isn = TCP_GET_ACK(p) - 1; STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn); ssn->server.next_seq = ssn->server.isn + 1; ssn->server.last_ack = ssn->server.next_seq; ssn->server.next_win = ssn->server.last_ack; SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " "ssn->client.next_seq %" PRIu32 "" ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_seq); ssn->client.wscale = TCP_WSCALE_MAX; ssn->server.wscale = TCP_WSCALE_MAX; /* Set the timestamp values used to validate the timestamp of * received packets.*/ if (p->tcpvars.ts != NULL && (ssn->client.flags & STREAMTCP_FLAG_TIMESTAMP)) { ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; ssn->client.flags &= ~STREAMTCP_FLAG_TIMESTAMP; ssn->client.last_pkt_ts = p->ts.tv_sec; } else { ssn->client.last_ts = 0; ssn->client.flags &= ~STREAMTCP_FLAG_TIMESTAMP; ssn->client.flags &= ~STREAMTCP_FLAG_ZERO_TIMESTAMP; } if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) { ssn->flags |= STREAMTCP_FLAG_SACKOK; } } else { SCLogDebug("ssn %p: default case", ssn); } return 0; } /** * \brief Function to handle the TCP_SYN_RECV state. The function handles * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes * the connection state. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling * * \retval 0 ok * \retval -1 error */ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (ssn == NULL) return -1; if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; uint8_t reset = TRUE; /* After receiveing the RST in SYN_RECV state and if detection evasion flags has been set, then the following operating systems will not closed the connection. As they consider the packet as stray packet and not belonging to the current session, for more information check http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */ if (ssn->flags & STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT) { if (PKT_IS_TOSERVER(p)) { if ((ssn->server.os_policy == OS_POLICY_LINUX) || (ssn->server.os_policy == OS_POLICY_OLD_LINUX) || (ssn->server.os_policy == OS_POLICY_SOLARIS)) { reset = FALSE; SCLogDebug("Detection evasion has been attempted, so" " not resetting the connection !!"); } } else { if ((ssn->client.os_policy == OS_POLICY_LINUX) || (ssn->client.os_policy == OS_POLICY_OLD_LINUX) || (ssn->client.os_policy == OS_POLICY_SOLARIS)) { reset = FALSE; SCLogDebug("Detection evasion has been attempted, so" " not resetting the connection !!"); } } } if (reset == TRUE) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } } } else if (p->tcph->th_flags & TH_FIN) { /* FIN is handled in the same way as in TCP_ESTABLISHED case */; if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1) return -1; /* SYN/ACK */ } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn); if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn); StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV); return -1; } /* Check if the SYN/ACK packets ACK matches the earlier * received SYN/ACK packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) { SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), ssn->client.isn + 1); StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK); return -1; } /* Check if the SYN/ACK packet SEQ the earlier * received SYN packet. */ if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) { SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), ssn->client.isn + 1); StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ); return -1; } } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn); if (PKT_IS_TOCLIENT(p)) { SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn); StreamTcpSetEvent(p, STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV); return -1; } if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) { SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn); StreamTcpSetEvent(p, STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV); return -1; } } else if (p->tcph->th_flags & TH_ACK) { /* If the timestamp option is enabled for both the streams, then * validate the received packet timestamp value against the * stream->last_ts. If the timestamp is valid then process the * packet normally otherwise the drop the packet (RFC 1323)*/ if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!(StreamTcpValidateTimestamp(ssn, p))) { return -1; } } if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) { SCLogDebug("ssn %p: ACK received on 4WHS session",ssn); if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) { SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn); StreamTcpSetEvent(p, STREAM_4WHS_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn); StreamTcpSetEvent(p, STREAM_4WHS_INVALID_ACK); return -1; } SCLogDebug("4WHS normal pkt"); SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); ssn->server.next_seq += p->payload_len; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; ssn->client.next_win = ssn->client.last_ack + ssn->client.window; StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", " "ssn->client.last_ack %"PRIu32"", ssn, ssn->client.next_win, ssn->client.last_ack); return 0; } /* Check if the ACK received is in right direction. But when we have * picked up a mid stream session after missing the initial SYN pkt, * in this case the ACK packet can arrive from either client (normal * case) or from server itself (asynchronous streams). Therefore * the check has been avoided in this case */ if (PKT_IS_TOCLIENT(p)) { /* special case, handle 4WHS, so SYN/ACK in the opposite * direction */ if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK) { SCLogDebug("ssn %p: ACK received on midstream SYN/ACK " "pickup session",ssn); /* fall through */ } else { SCLogDebug("ssn %p: ACK received in the wrong direction", ssn); StreamTcpSetEvent(p, STREAM_3WHS_ACK_IN_WRONG_DIR); return -1; } } SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 "" ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); /* Check both seq and ack number before accepting the packet and changing to ESTABLISHED state */ if ((SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) && SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) { SCLogDebug("normal pkt"); /* process the packet normal, No Async streams :) */ if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); ssn->client.next_seq += p->payload_len; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) { ssn->client.window = TCP_GET_WINDOW(p); ssn->server.next_win = ssn->server.last_ack + ssn->server.window; /* window scaling for midstream pickups, we can't do much * other than assume that it's set to the max value: 14 */ ssn->server.wscale = TCP_WSCALE_MAX; ssn->client.wscale = TCP_WSCALE_MAX; ssn->flags |= STREAMTCP_FLAG_SACKOK; } StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); /* If asynchronous stream handling is allowed then set the session, if packet's seq number is equal the expected seq no.*/ } else if (stream_config.async_oneside == TRUE && (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) { /*set the ASYNC flag used to indicate the session as async stream and helps in relaxing the windows checks.*/ ssn->flags |= STREAMTCP_FLAG_ASYNC; ssn->server.next_seq += p->payload_len; ssn->server.last_ack = TCP_GET_SEQ(p); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; ssn->client.last_ack = TCP_GET_ACK(p); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) { ssn->server.window = TCP_GET_WINDOW(p); ssn->client.next_win = ssn->server.last_ack + ssn->server.window; /* window scaling for midstream pickups, we can't do much * other than assume that it's set to the max value: 14 */ ssn->server.wscale = TCP_WSCALE_MAX; ssn->client.wscale = TCP_WSCALE_MAX; ssn->flags |= STREAMTCP_FLAG_SACKOK; } SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " "ssn->server.next_seq %" PRIu32 "\n" , ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_seq); StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); /* Upon receiving the packet with correct seq number and wrong ACK number, it causes the other end to send RST. But some target system (Linux & solaris) does not RST the connection, so it is likely to avoid the detection */ } else if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)){ ssn->flags |= STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT; SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!", ssn); StreamTcpSetEvent(p, STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION); return -1; } else { SCLogDebug("ssn %p: wrong seq nr on packet", ssn); StreamTcpSetEvent(p, STREAM_3WHS_WRONG_SEQ_WRONG_ACK); return -1; } SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", " "ssn->server.last_ack %"PRIu32"", ssn, ssn->server.next_win, ssn->server.last_ack); } else { SCLogDebug("ssn %p: default case", ssn); } return 0; } /** * \brief Function to handle the TCP_ESTABLISHED state packets, which are * sent by the client to server. The function handles * ACK packets and call StreamTcpReassembleHandleSegment() to handle * the reassembly. * * Timestamp has already been checked at this point. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param ssn Pointer to the current TCP session * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt, PacketQueue *pq) { SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 "," "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p)); if (StreamTcpValidateAck(ssn, &(ssn->server), p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK); return -1; } /* check for Keep Alive */ if ((p->payload_len == 0 || p->payload_len == 1) && (TCP_GET_SEQ(p) == (ssn->client.next_seq - 1))) { SCLogDebug("ssn %p: pkt is keep alive", ssn); /* normal pkt */ } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack))) { if (ssn->flags & STREAMTCP_FLAG_ASYNC) { SCLogDebug("ssn %p: server => Asynchrouns stream, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win" "%" PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); /* update the last_ack to current seq number as the session is * async and other stream is not updating it anymore :( */ StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p)); } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p)) && (stream_config.async_oneside == TRUE) && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) { SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ." " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); /* it seems we missed SYN and SYN/ACK packets of this session. * Update the last_ack to current seq number as the session * is async and other stream is not updating it anymore :( */ StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p)); ssn->flags |= STREAMTCP_FLAG_ASYNC; } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) && (stream_config.async_oneside == TRUE) && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) { SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); /* it seems we missed SYN and SYN/ACK packets of this session. * Update the last_ack to current seq number as the session * is async and other stream is not updating it anymore :(*/ StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p)); ssn->flags |= STREAMTCP_FLAG_ASYNC; } else { SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn); StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK); return -1; } } int zerowindowprobe = 0; /* zero window probe */ if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->client.next_seq && ssn->client.window == 0) { SCLogDebug("ssn %p: zero window probe", ssn); zerowindowprobe = 1; /* expected packet */ } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) { ssn->client.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); } /* in window check */ if (zerowindowprobe) { SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn); } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) || (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) || (ssn->flags & STREAMTCP_FLAG_ASYNC)) { SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win " "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn, ssn->server.window); /* Check if the ACK value is sane and inside the window limit */ StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the server packet and client has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); StreamTcpSackUpdatePacket(&ssn->server, p); /* update next_win */ StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window)); /* handle data (if any) */ StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ " "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, (TCP_GET_SEQ(p) + p->payload_len) - ssn->client.next_win); SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window, StreamTcpSackedSize(&ssn->client)); StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW); return -1; } return 0; } /** * \brief Function to handle the TCP_ESTABLISHED state packets, which are * sent by the server to client. The function handles * ACK packets and call StreamTcpReassembleHandleSegment() to handle * the reassembly * * Timestamp has already been checked at this point. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param ssn Pointer to the current TCP session * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt, PacketQueue *pq) { SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 "," " ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p)); if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK); return -1; } /* To get the server window value from the servers packet, when connection is picked up as midstream */ if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED)) { ssn->server.window = TCP_GET_WINDOW(p); ssn->server.next_win = ssn->server.last_ack + ssn->server.window; ssn->flags &= ~STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED; SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to " "%" PRIu32 "", ssn, ssn->server.next_win); } /* check for Keep Alive */ if ((p->payload_len == 0 || p->payload_len == 1) && (TCP_GET_SEQ(p) == (ssn->server.next_seq - 1))) { SCLogDebug("ssn %p: pkt is keep alive", ssn); /* normal pkt */ } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->server.last_ack))) { if (ssn->flags & STREAMTCP_FLAG_ASYNC) { SCLogDebug("ssn %p: client => Asynchrouns stream, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win" " %"PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->server.last_ack, ssn->server.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win); ssn->server.last_ack = TCP_GET_SEQ(p); } else { SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 " before last_ack %"PRIu32, ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack); StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK); return -1; } } int zerowindowprobe = 0; /* zero window probe */ if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->server.next_seq && ssn->server.window == 0) { SCLogDebug("ssn %p: zero window probe", ssn); zerowindowprobe = 1; /* expected packet */ } else if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) { ssn->server.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); } if (zerowindowprobe) { SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn); } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) || (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) || (ssn->flags & STREAMTCP_FLAG_ASYNC)) { SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win " "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn, ssn->client.window); StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); StreamTcpSackUpdatePacket(&ssn->client, p); StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window)); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); } else { SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ" "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win " "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->server.last_ack, ssn->server.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win); StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW); return -1; } return 0; } /** * \internal * * \brief Find the highest sequence number needed to consider all segments as ACK'd * * Used to treat all segments as ACK'd upon receiving a valid RST. * * \param stream stream to inspect the segments from * \param seq sequence number to check against * * \retval ack highest ack we need to set */ static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq) { uint32_t ack = seq; if (stream->seg_list_tail != NULL) { if (SEQ_GT((stream->seg_list_tail->seq + stream->seg_list_tail->payload_len), ack)) { ack = stream->seg_list_tail->seq + stream->seg_list_tail->payload_len; } } SCReturnUInt(ack); } /** * \brief Function to handle the TCP_ESTABLISHED state. The function handles * ACK, FIN, RST packets and correspondingly changes the connection * state. The function handles the data inside packets and call * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (ssn == NULL) return -1; if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; /* force both streams to reassemble, if necessary */ StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); if (PKT_IS_TOSERVER(p)) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); ssn->server.next_seq = TCP_GET_ACK(p); ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); /* don't return packets to pools here just yet, the pseudo * packet will take care, otherwise the normal session * cleanup. */ } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1; ssn->client.next_seq = TCP_GET_ACK(p); SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); /* don't return packets to pools here just yet, the pseudo * packet will take care, otherwise the normal session * cleanup. */ } } else if (p->tcph->th_flags & TH_FIN) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } SCLogDebug("ssn (%p: FIN received SEQ" " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32"," " win %" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack, ssn->server.next_win, ssn->server.window); if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1) return -1; /* SYN/ACK */ } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent", ssn); if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn); StreamTcpSetEvent(p, STREAM_EST_SYNACK_TOSERVER); return -1; } /* Check if the SYN/ACK packets ACK matches the earlier * received SYN/ACK packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) { SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), ssn->client.isn + 1); StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK); return -1; } /* Check if the SYN/ACK packet SEQ the earlier * received SYN packet. */ if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) { SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), ssn->client.isn + 1); StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ); return -1; } if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) { /* a resend of a SYN while we are established already -- fishy */ StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND); return -1; } SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. " "Likely due server not receiving final ACK in 3whs", ssn); /* resetting state to TCP_SYN_RECV as we should get another ACK now */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); SCLogDebug("ssn %p: =~ ssn state is now reset to TCP_SYN_RECV", ssn); return 0; } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn %p: SYN packet on state ESTABLISED... resent", ssn); if (PKT_IS_TOCLIENT(p)) { SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn); StreamTcpSetEvent(p, STREAM_EST_SYN_TOCLIENT); return -1; } if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) { SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn); StreamTcpSetEvent(p, STREAM_EST_SYN_RESEND_DIFF_SEQ); return -1; } /* a resend of a SYN while we are established already -- fishy */ StreamTcpSetEvent(p, STREAM_EST_SYN_RESEND); return -1; } else if (p->tcph->th_flags & TH_ACK) { /* Urgent pointer size can be more than the payload size, as it tells * the future coming data from the sender will be handled urgently * until data of size equal to urgent offset has been processed * (RFC 2147) */ /* If the timestamp option is enabled for both the streams, then * validate the received packet timestamp value against the * stream->last_ts. If the timestamp is valid then process the * packet normally otherwise the drop the packet (RFC 1323) */ if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { /* Process the received packet to server */ HandleEstablishedPacketToServer(tv, ssn, p, stt, pq); SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 "," " next win %" PRIu32 ", win %" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack ,ssn->client.next_win, ssn->client.window); } else { /* implied to client */ if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) { ssn->flags |= STREAMTCP_FLAG_3WHS_CONFIRMED; SCLogDebug("3whs is now confirmed by server"); } /* Process the received packet to client */ HandleEstablishedPacketToClient(tv, ssn, p, stt, pq); SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 "," " next win %" PRIu32 ", win %" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack, ssn->server.next_win, ssn->server.window); } } else { SCLogDebug("ssn %p: default case", ssn); } return 0; } /** * \brief Function to handle the FIN packets for states TCP_SYN_RECV and * TCP_ESTABLISHED and changes to another TCP state as required. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling * * \retval 0 success * \retval -1 something wrong with the packet */ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession *ssn, Packet *p, PacketQueue *pq) { if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 "," " ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN_INVALID_ACK); return -1; } if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW); return -1; } StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT); ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn); if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", " "ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN_INVALID_ACK); return -1; } if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != " "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW); return -1; } StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn); if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } return 0; } /** * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles * ACK, FIN, RST packets and correspondingly changes the connection * state. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling * * \retval 0 success * \retval -1 something wrong with the packet */ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (ssn == NULL) return -1; if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; /* force both streams to reassemble, if necessary */ StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); } } else if ((p->tcph->th_flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK); return -1; } if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) { ssn->client.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK); return -1; } if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) { ssn->server.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } } else if (p->tcph->th_flags & TH_FIN) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK); return -1; } if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_CLOSING); ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) { ssn->client.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK); return -1; } if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_CLOSING); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) { ssn->server.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn); StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND); return -1; } else if (p->tcph->th_flags & TH_ACK) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK); return -1; } if (!retransmission) { if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) || (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) || ssn->flags & STREAMTCP_FLAG_ASYNC) { SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win " "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win); if (TCP_GET_SEQ(p) == ssn->client.next_seq) { StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2); SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn); } } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ); return -1; } ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) { ssn->client.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); } StreamTcpSackUpdatePacket(&ssn->server, p); /* update next_win */ StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window)); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK); return -1; } if (!retransmission) { if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) || (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) || (ssn->flags & STREAMTCP_FLAG_ASYNC)) { SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win " "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win); if (TCP_GET_SEQ(p) == ssn->server.next_seq) { StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2); SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn); } } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ); return -1; } ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) { ssn->server.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); } StreamTcpSackUpdatePacket(&ssn->client, p); /* update next_win */ StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window)); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { SCLogDebug("ssn (%p): default case", ssn); } return 0; } /** * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles * ACK, RST, FIN packets and correspondingly changes the connection * state. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (ssn == NULL) return -1; if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; /* force both streams to reassemble, if necessary */ StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); } } else if (p->tcph->th_flags & TH_FIN) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq - 1) && SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) { SCLogDebug("ssn %p: retransmission", ssn); retransmission = 1; } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ " "%" PRIu32 " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK); return -1; } if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq - 1) && SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) { SCLogDebug("ssn %p: retransmission", ssn); retransmission = 1; } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ " "%" PRIu32 " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK); return -1; } if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn); StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND); return -1; } else if (p->tcph->th_flags & TH_ACK) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK); return -1; } if (!retransmission) { if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) || (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) || (ssn->flags & STREAMTCP_FLAG_ASYNC)) { SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win " "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win); } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ); return -1; } ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) { ssn->client.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); } StreamTcpSackUpdatePacket(&ssn->server, p); /* update next_win */ StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window)); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK); return -1; } if (!retransmission) { if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) || (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) || (ssn->flags & STREAMTCP_FLAG_ASYNC)) { SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win " "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win); } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ); return -1; } ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; } StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) { ssn->server.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); } StreamTcpSackUpdatePacket(&ssn->client, p); /* update next_win */ StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window)); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { SCLogDebug("ssn %p: default case", ssn); } return 0; } /** * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK * the connection goes to TCP_TIME_WAIT state. The state has been * reached as both end application has been closed. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (ssn == NULL) return -1; if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; /* force both streams to reassemble, if necessary */ StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); } } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn (%p): SYN pkt on Closing", ssn); StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND); return -1; } else if (p->tcph->th_flags & TH_ACK) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (TCP_GET_SEQ(p) != ssn->client.next_seq) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_CLOSING_INVALID_ACK); return -1; } StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (TCP_GET_SEQ(p) != ssn->server.next_seq) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_CLOSING_INVALID_ACK); return -1; } StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ " "%" PRIu32 ", last ACK %" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { SCLogDebug("ssn %p: default case", ssn); } return 0; } /** * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN * packet from server the connection goes to TCP_LAST_ACK state. * The state is possible only for server host. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { SCEnter(); if (ssn == NULL) { SCReturnInt(-1); } if (PKT_IS_TOCLIENT(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); } else { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); } if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; /* force both streams to reassemble, if necessary */ StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); } } else if (p->tcph->th_flags & TH_FIN) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) SCReturnInt(-1); } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW); SCReturnInt(-1); } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK); SCReturnInt(-1); } /* don't update to LAST_ACK here as we want a toclient FIN for that */ ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW); SCReturnInt(-1); } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK); SCReturnInt(-1); } StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn); StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND); SCReturnInt(-1); } else if (p->tcph->th_flags & TH_ACK) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) SCReturnInt(-1); } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) { SCLogDebug("ssn %p: -> retransmission", ssn); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK); SCReturnInt(-1); } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW); SCReturnInt(-1); } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK); SCReturnInt(-1); } ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq)) ssn->client.next_seq += p->payload_len; StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) { SCLogDebug("ssn %p: -> retransmission", ssn); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK); SCReturnInt(-1); } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW); SCReturnInt(-1); } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK); SCReturnInt(-1); } ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq)) ssn->server.next_seq += p->payload_len; StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { SCLogDebug("ssn %p: default case", ssn); } SCReturnInt(0); } /** * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK * the connection goes to TCP_CLOSED state and stream memory is * returned back to pool. The state is possible only for server host. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPakcetStateLastAck(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (ssn == NULL) return -1; if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; /* force both streams to reassemble, if necessary */ StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); } } else if (p->tcph->th_flags & TH_FIN) { /** \todo */ } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn); StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND); return -1; } else if (p->tcph->th_flags & TH_ACK) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq + 1) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_LASTACK_ACK_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_LASTACK_INVALID_ACK); SCReturnInt(-1); } StreamTcpPacketSetState(p, ssn, TCP_CLOSED); SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); } } else { SCLogDebug("ssn %p: default case", ssn); } return 0; } /** * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK * the connection goes to TCP_CLOSED state and stream memory is * returned back to pool. * * \param tv Thread Variable containig input/output queue, cpu affinity * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq) { if (ssn == NULL) return -1; if (p->tcph->th_flags & TH_RST) { if (!StreamTcpValidateRst(ssn, p)) return -1; /* force both streams to reassemble, if necessary */ StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); } } else if (p->tcph->th_flags & TH_FIN) { /** \todo */ } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn); StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND); return -1; } else if (p->tcph->th_flags & TH_ACK) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; } if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq+1) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ); return -1; } if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_TIMEWAIT_INVALID_ACK); SCReturnInt(-1); } StreamTcpPacketSetState(p, ssn, TCP_CLOSED); SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->client.next_seq, ssn->server.last_ack); StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); } else { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); SCReturnInt(-1); } if (TCP_GET_SEQ(p) != ssn->server.next_seq && TCP_GET_SEQ(p) != ssn->server.next_seq+1) { if (p->payload_len > 0 && TCP_GET_SEQ(p) == ssn->server.last_ack) { SCLogDebug("ssn %p: -> retransmission", ssn); SCReturnInt(0); } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" " != %" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ); return -1; } } if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_TIMEWAIT_INVALID_ACK); SCReturnInt(-1); } StreamTcpPacketSetState(p, ssn, TCP_CLOSED); SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " "%" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack); StreamTcpPseudoPacketCreateStreamEndPacket(p, ssn, pq); } } else { SCLogDebug("ssn %p: default case", ssn); } return 0; } /* flow is and stays locked */ static int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueue *pq) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(p->flow); SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); TcpSession *ssn = (TcpSession *)p->flow->protoctx; /* update counters */ if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { SCPerfCounterIncr(stt->counter_tcp_synack, tv->sc_perf_pca); } else if (p->tcph->th_flags & (TH_SYN)) { SCPerfCounterIncr(stt->counter_tcp_syn, tv->sc_perf_pca); } if (p->tcph->th_flags & (TH_RST)) { SCPerfCounterIncr(stt->counter_tcp_rst, tv->sc_perf_pca); } /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */ if (!(p->tcph->th_flags & TH_ACK) && TCP_GET_ACK(p) != 0) { StreamTcpSetEvent(p, STREAM_PKT_BROKEN_ACK); } /* If we are on IPS mode, and got a drop action triggered from * the IP only module, or from a reassembled msg and/or from an * applayer detection, then drop the rest of the packets of the * same stream and avoid inspecting it any further */ if (StreamTcpCheckFlowDrops(p) == 1) { SCLogDebug("This flow/stream triggered a drop rule"); FlowSetNoPacketInspectionFlag(p->flow); DecodeSetNoPacketInspectionFlag(p); FlowSetSessionNoApplayerInspectionFlag(p->flow); UPDATE_PACKET_ACTION(p, ACTION_DROP); /* return the segments to the pool */ StreamTcpSessionPktFree(p); SCReturnInt(0); } if (ssn == NULL || ssn->state == TCP_NONE) { if (StreamTcpPacketStateNone(tv, p, stt, ssn, &stt->pseudo_queue) == -1) { goto error; } if (ssn != NULL) SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto); } else { /* check if the packet is in right direction, when we missed the SYN packet and picked up midstream session. */ if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK) StreamTcpPacketSwitchDir(ssn, p); switch (ssn->state) { case TCP_SYN_SENT: if(StreamTcpPacketStateSynSent(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_SYN_RECV: if(StreamTcpPacketStateSynRecv(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_ESTABLISHED: if(StreamTcpPacketStateEstablished(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_FIN_WAIT1: if(StreamTcpPacketStateFinWait1(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_FIN_WAIT2: if(StreamTcpPacketStateFinWait2(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_CLOSING: if(StreamTcpPacketStateClosing(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_CLOSE_WAIT: if(StreamTcpPacketStateCloseWait(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_LAST_ACK: if(StreamTcpPakcetStateLastAck(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_TIME_WAIT: if(StreamTcpPacketStateTimeWait(tv, p, stt, ssn, &stt->pseudo_queue)) { goto error; } break; case TCP_CLOSED: /* TCP session memory is not returned to pool until timeout. * If in the mean time we receive any other session from * the same client reusing same port then we switch back to * tcp state none, but only on a valid SYN that is not a * resend from our previous session. * * We also check it's not a SYN/ACK, all other SYN pkt * validation is done at StreamTcpPacketStateNone(); */ if (PKT_IS_TOSERVER(p) && (p->tcph->th_flags & TH_SYN) && !(p->tcph->th_flags & TH_ACK) && !(SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p)))) { SCLogDebug("reusing closed TCP session"); /* return segments */ StreamTcpReturnStreamSegments(&ssn->client); StreamTcpReturnStreamSegments(&ssn->server); /* free SACK list */ StreamTcpSackFreeList(&ssn->client); StreamTcpSackFreeList(&ssn->server); /* reset the app layer state */ AppLayerParserCleanupState(p->flow); ssn->state = 0; ssn->flags = 0; ssn->client.flags = 0; ssn->server.flags = 0; /* set state the NONE, also pulls flow out of closed queue */ StreamTcpPacketSetState(p, ssn, TCP_NONE); p->flow->alproto = ALPROTO_UNKNOWN; p->flow->flags &= ~FLOW_TS_PM_PP_ALPROTO_DETECT_DONE; p->flow->flags &= ~FLOW_TS_PM_PP_ALPROTO_DETECT_DONE; if (StreamTcpPacketStateNone(tv,p,stt,ssn, &stt->pseudo_queue)) { goto error; } SCPerfCounterIncr(stt->counter_tcp_reused_ssn, tv->sc_perf_pca); } else { SCLogDebug("packet received on closed state"); } break; default: SCLogDebug("packet received on default state"); break; } if (ssn->state >= TCP_ESTABLISHED) { p->flags |= PKT_STREAM_EST; } if (PKT_IS_TOSERVER(p)) { if (ssn->client.flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) p->flags |= PKT_STREAM_EOF; } else { if (ssn->server.flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) p->flags |= PKT_STREAM_EOF; } } /* deal with a pseudo packet that is created upon receiving a RST * segment. To be sure we process both sides of the connection, we * inject a fake packet into the system, forcing reassembly of the * opposing direction. * There should be only one, but to be sure we do a while loop. */ if (ssn != NULL) { while (stt->pseudo_queue.len > 0) { SCLogDebug("processing pseudo packet / stream end"); Packet *np = PacketDequeue(&stt->pseudo_queue); if (np != NULL) { /* process the opposing direction of the original packet */ if (PKT_IS_TOSERVER(np)) { SCLogDebug("pseudo packet is to server"); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, np, NULL); } else { SCLogDebug("pseudo packet is to client"); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, np, NULL); } /* enqueue this packet so we inspect it in detect etc */ PacketEnqueue(pq, np); } SCLogDebug("processing pseudo packet / stream end done"); } /* Process stream smsgs we may have in queue */ if (StreamTcpReassembleProcessAppLayer(stt->ra_ctx) < 0) { goto error; } /* recalc the csum on the packet if it was modified */ if (p->flags & PKT_STREAM_MODIFIED) { ReCalculateChecksum(p); } /* check for conditions that may make us not want to log this packet */ /* streams that hit depth */ if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) || (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) { p->flags |= PKT_STREAM_NOPCAPLOG; } /* encrypted packets */ if ((PKT_IS_TOSERVER(p) && (ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) || (PKT_IS_TOCLIENT(p) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY))) { p->flags |= PKT_STREAM_NOPCAPLOG; } } StreamTcpMemuseCounter(tv, stt); SCReturnInt(0); error: /* make sure we don't leave packets in our pseudo queue */ while (stt->pseudo_queue.len > 0) { Packet *np = PacketDequeue(&stt->pseudo_queue); if (np != NULL) { PacketEnqueue(pq, np); } } /* recalc the csum on the packet if it was modified */ if (p->flags & PKT_STREAM_MODIFIED) { ReCalculateChecksum(p); } if (StreamTcpInlineMode()) { UPDATE_PACKET_ACTION(p, ACTION_DROP); } SCReturnInt(-1); } /** * \brief Function to validate the checksum of the received packet. If the * checksum is invalid, packet will be dropped, as the end system will * also drop the packet. * * \param p Packet of which checksum has to be validated * \retval 1 if the checksum is valid, otherwise 0 */ static inline int StreamTcpValidateChecksum(Packet *p) { int ret = 1; if (p->flags & PKT_IGNORE_CHECKSUM) return ret; if (p->tcpvars.comp_csum == -1) { if (PKT_IS_IPV4(p)) { p->tcpvars.comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); } else if (PKT_IS_IPV6(p)) { p->tcpvars.comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); } } if (p->tcpvars.comp_csum != p->tcph->th_sum) { ret = 0; SCLogDebug("Checksum of received packet %p is invalid",p); if (p->livedev) { (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1); } } return ret; } TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { StreamTcpThread *stt = (StreamTcpThread *)data; TmEcode ret = TM_ECODE_OK; if (!(PKT_IS_TCP(p))) return TM_ECODE_OK; if (p->flow == NULL) { SCPerfCounterIncr(stt->counter_tcp_no_flow, tv->sc_perf_pca); return TM_ECODE_OK; } if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { if (StreamTcpValidateChecksum(p) == 0) { SCPerfCounterIncr(stt->counter_tcp_invalid_checksum, tv->sc_perf_pca); return TM_ECODE_OK; } } else { p->flags |= PKT_IGNORE_CHECKSUM; } PACKET_PROFILING_APP_RESET(&stt->ra_ctx->dp_ctx); FLOWLOCK_WRLOCK(p->flow); ret = StreamTcpPacket(tv, p, stt, pq); FLOWLOCK_UNLOCK(p->flow); //if (ret) // return TM_ECODE_FAILED; stt->pkts++; return ret; } TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); StreamTcpThread *stt = SCMalloc(sizeof(StreamTcpThread)); if (unlikely(stt == NULL)) SCReturnInt(TM_ECODE_FAILED); memset(stt, 0, sizeof(StreamTcpThread)); *data = (void *)stt; stt->counter_tcp_sessions = SCPerfTVRegisterCounter("tcp.sessions", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->counter_tcp_ssn_memcap = SCPerfTVRegisterCounter("tcp.ssn_memcap_drop", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->counter_tcp_pseudo = SCPerfTVRegisterCounter("tcp.pseudo", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->counter_tcp_invalid_checksum = SCPerfTVRegisterCounter("tcp.invalid_checksum", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->counter_tcp_no_flow = SCPerfTVRegisterCounter("tcp.no_flow", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->counter_tcp_reused_ssn = SCPerfTVRegisterCounter("tcp.reused_ssn", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->counter_tcp_memuse = SCPerfTVRegisterCounter("tcp.memuse", tv, SC_PERF_TYPE_Q_NORMAL, "NULL"); stt->counter_tcp_syn = SCPerfTVRegisterCounter("tcp.syn", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->counter_tcp_synack = SCPerfTVRegisterCounter("tcp.synack", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->counter_tcp_rst = SCPerfTVRegisterCounter("tcp.rst", tv, SC_PERF_TYPE_UINT64, "NULL"); /* init reassembly ctx */ stt->ra_ctx = StreamTcpReassembleInitThreadCtx(); if (stt->ra_ctx == NULL) SCReturnInt(TM_ECODE_FAILED); stt->ra_ctx->counter_tcp_segment_memcap = SCPerfTVRegisterCounter("tcp.segment_memcap_drop", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->ra_ctx->counter_tcp_stream_depth = SCPerfTVRegisterCounter("tcp.stream_depth_reached", tv, SC_PERF_TYPE_UINT64, "NULL"); stt->ra_ctx->counter_tcp_reass_memuse = SCPerfTVRegisterCounter("tcp.reassembly_memuse", tv, SC_PERF_TYPE_Q_NORMAL, "NULL"); stt->ra_ctx->counter_tcp_reass_gap = SCPerfTVRegisterCounter("tcp.reassembly_gap", tv, SC_PERF_TYPE_UINT64, "NULL"); tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); SCPerfAddToClubbedTMTable(tv->name, &tv->sc_perf_pctx); SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p", stt, stt->ra_ctx); SCReturnInt(TM_ECODE_OK); } TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); StreamTcpThread *stt = (StreamTcpThread *)data; if (stt == NULL) { return TM_ECODE_OK; } /* XXX */ /* free reassembly ctx */ StreamTcpReassembleFreeThreadCtx(stt->ra_ctx); /* clear memory */ memset(stt, 0, sizeof(StreamTcpThread)); SCFree(stt); SCReturnInt(TM_ECODE_OK); } void StreamTcpExitPrintStats(ThreadVars *tv, void *data) { StreamTcpThread *stt = (StreamTcpThread *)data; if (stt == NULL) { return; } SCLogInfo("Stream TCP processed %" PRIu64 " TCP packets", stt->pkts); } /** * \brief Function to check the validity of the RST packets based on the * target OS of the given packet. * * \param ssn TCP session to which the given packet belongs * \param p Packet which has to be checked for its validity * * \retval 0 unacceptable RST * \retval 1 acceptable RST * * WebSense sends RST packets that are: * - RST flag, win 0, ack 0, seq = nextseq * */ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) { uint8_t os_policy; if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) { SCReturnInt(0); } } /* Set up the os_policy to be used in validating the RST packets based on target system */ if (PKT_IS_TOSERVER(p)) { if (ssn->server.os_policy == 0) StreamTcpSetOSPolicy(&ssn->server, p); os_policy = ssn->server.os_policy; if (p->tcph->th_flags & TH_ACK && TCP_GET_ACK(p) && StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_RST_INVALID_ACK); SCReturnInt(0); } } else { if (ssn->client.os_policy == 0) StreamTcpSetOSPolicy(&ssn->client, p); os_policy = ssn->client.os_policy; if (p->tcph->th_flags & TH_ACK && TCP_GET_ACK(p) && StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_RST_INVALID_ACK); SCReturnInt(0); } } switch (os_policy) { case OS_POLICY_HPUX11: if(PKT_IS_TOSERVER(p)){ if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } else { SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " " "and server SEQ: %" PRIu32 "", TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " " "and client SEQ: %" PRIu32 "", TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } break; case OS_POLICY_OLD_LINUX: case OS_POLICY_LINUX: case OS_POLICY_SOLARIS: if(PKT_IS_TOSERVER(p)){ if(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack)) { /*window base is needed !!*/ if(SEQ_LT(TCP_GET_SEQ(p), (ssn->client.next_seq + ssn->client.window))) { SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and" " server SEQ: %" PRIu32 "", TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ if(SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack)) { /*window base is needed !!*/ if(SEQ_LT(TCP_GET_SEQ(p), (ssn->server.next_seq + ssn->server.window))) { SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and" " client SEQ: %" PRIu32 "", TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } break; default: case OS_POLICY_BSD: case OS_POLICY_FIRST: case OS_POLICY_HPUX10: case OS_POLICY_IRIX: case OS_POLICY_MACOS: case OS_POLICY_LAST: case OS_POLICY_WINDOWS: case OS_POLICY_WINDOWS2K3: case OS_POLICY_VISTA: if(PKT_IS_TOSERVER(p)) { if(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " " "and server SEQ: %" PRIu32 "", TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ if(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and" " client SEQ: %" PRIu32 "", TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } break; } return 0; } /** * \brief Function to return the FLOW state depending upon the TCP session state. * * \param s TCP session of which the state has to be returned * \retval state The FLOW_STATE_ depends upon the TCP sesison state, default is * FLOW_STATE_CLOSED */ int StreamTcpGetFlowState(void *s) { SCEnter(); TcpSession *ssn = (TcpSession *)s; if (ssn == NULL) { SCReturnInt(FLOW_STATE_CLOSED); } switch(ssn->state) { case TCP_NONE: case TCP_SYN_SENT: case TCP_SYN_RECV: case TCP_LISTEN: SCReturnInt(FLOW_STATE_NEW); case TCP_ESTABLISHED: case TCP_FIN_WAIT1: case TCP_FIN_WAIT2: case TCP_CLOSING: case TCP_CLOSE_WAIT: SCReturnInt(FLOW_STATE_ESTABLISHED); case TCP_LAST_ACK: case TCP_TIME_WAIT: case TCP_CLOSED: SCReturnInt(FLOW_STATE_CLOSED); } SCReturnInt(FLOW_STATE_CLOSED); } /** * \brief Function to check the validity of the received timestamp based on * the target OS of the given stream. * * It's passive except for: * 1. it sets the os policy on the stream if necessary * 2. it sets an event in the packet if necessary * * \param ssn TCP session to which the given packet belongs * \param p Packet which has to be checked for its validity * * \retval 1 if the timestamp is valid * \retval 0 if the timestamp is invalid */ static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p) { SCEnter(); TcpStream *sender_stream; TcpStream *receiver_stream; uint8_t ret = 1; uint8_t check_ts = 1; if (PKT_IS_TOSERVER(p)) { sender_stream = &ssn->client; receiver_stream = &ssn->server; } else { sender_stream = &ssn->server; receiver_stream = &ssn->client; } /* Set up the os_policy to be used in validating the timestamps based on the target system */ if (receiver_stream->os_policy == 0) { StreamTcpSetOSPolicy(receiver_stream, p); } if (p->tcpvars.ts != NULL) { uint32_t ts = TCP_GET_TSVAL(p); uint32_t last_pkt_ts = sender_stream->last_pkt_ts; uint32_t last_ts = sender_stream->last_ts; if (sender_stream->flags & STREAMTCP_FLAG_ZERO_TIMESTAMP) { /* The 3whs used the timestamp with 0 value. */ switch (receiver_stream->os_policy) { case OS_POLICY_LINUX: case OS_POLICY_WINDOWS2K3: /* Linux and windows 2003 does not allow the use of 0 as * timestamp in the 3whs. */ check_ts = 0; break; case OS_POLICY_OLD_LINUX: case OS_POLICY_WINDOWS: case OS_POLICY_VISTA: if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) { last_ts = ts; check_ts = 0; /*next packet will be checked for validity and stream TS has been updated with this one.*/ } break; } } if (receiver_stream->os_policy == OS_POLICY_HPUX11) { /* HPUX11 igoners the timestamp of out of order packets */ if (!SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) check_ts = 0; } if (ts == 0) { switch (receiver_stream->os_policy) { case OS_POLICY_OLD_LINUX: case OS_POLICY_WINDOWS: case OS_POLICY_WINDOWS2K3: case OS_POLICY_VISTA: case OS_POLICY_SOLARIS: /* Old Linux and windows allowed packet with 0 timestamp. */ break; default: /* other OS simply drop the pakcet with 0 timestamp, when * 3whs has valid timestamp*/ goto invalid; } } if (check_ts) { int32_t result = 0; SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts); if (receiver_stream->os_policy == OS_POLICY_LINUX) { /* Linux accepts TS which are off by one.*/ result = (int32_t) ((ts - last_ts) + 1); } else { result = (int32_t) (ts - last_ts); } SCLogDebug("result %"PRIi32", p->ts.tv_sec %"PRIuMAX"", result, (uintmax_t)p->ts.tv_sec); if (last_pkt_ts == 0 && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) { last_pkt_ts = p->ts.tv_sec; } if (result < 0) { SCLogDebug("timestamp is not valid last_ts " "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result " "%" PRId32 "", last_ts, ts, result); /* candidate for rejection */ ret = 0; } else if ((sender_stream->last_ts != 0) && (((uint32_t) p->ts.tv_sec) > last_pkt_ts + PAWS_24DAYS)) { SCLogDebug("packet is not valid last_pkt_ts " "%" PRIu32 " p->ts.tv_sec %" PRIu32 "", last_pkt_ts, (uint32_t) p->ts.tv_sec); /* candidate for rejection */ ret = 0; } if (ret == 0) { /* if the timestamp of packet is not valid then, check if the * current stream timestamp is not so old. if so then we need to * accept the packet and update the stream->last_ts (RFC 1323)*/ if ((SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) && (((uint32_t) p->ts.tv_sec > (last_pkt_ts + PAWS_24DAYS)))) { SCLogDebug("timestamp considered valid anyway"); } else { goto invalid; } } } } SCReturnInt(1); invalid: StreamTcpSetEvent(p, STREAM_PKT_INVALID_TIMESTAMP); SCReturnInt(0); } /** * \brief Function to check the validity of the received timestamp based on * the target OS of the given stream and update the session. * * \param ssn TCP session to which the given packet belongs * \param p Packet which has to be checked for its validity * * \retval 1 if the timestamp is valid * \retval 0 if the timestamp is invalid */ static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p) { SCEnter(); TcpStream *sender_stream; TcpStream *receiver_stream; uint8_t ret = 1; uint8_t check_ts = 1; if (PKT_IS_TOSERVER(p)) { sender_stream = &ssn->client; receiver_stream = &ssn->server; } else { sender_stream = &ssn->server; receiver_stream = &ssn->client; } /* Set up the os_policy to be used in validating the timestamps based on the target system */ if (receiver_stream->os_policy == 0) { StreamTcpSetOSPolicy(receiver_stream, p); } if (p->tcpvars.ts != NULL) { uint32_t ts = TCP_GET_TSVAL(p); if (sender_stream->flags & STREAMTCP_FLAG_ZERO_TIMESTAMP) { /* The 3whs used the timestamp with 0 value. */ switch (receiver_stream->os_policy) { case OS_POLICY_LINUX: case OS_POLICY_WINDOWS2K3: /* Linux and windows 2003 does not allow the use of 0 as * timestamp in the 3whs. */ ssn->flags &= ~STREAMTCP_FLAG_TIMESTAMP; check_ts = 0; break; case OS_POLICY_OLD_LINUX: case OS_POLICY_WINDOWS: case OS_POLICY_VISTA: sender_stream->flags &= ~STREAMTCP_FLAG_ZERO_TIMESTAMP; if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) { sender_stream->last_ts = ts; check_ts = 0; /*next packet will be checked for validity and stream TS has been updated with this one.*/ } break; default: break; } } if (receiver_stream->os_policy == OS_POLICY_HPUX11) { /*HPUX11 igoners the timestamp of out of order packets*/ if (!SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) check_ts = 0; } if (ts == 0) { switch (receiver_stream->os_policy) { case OS_POLICY_OLD_LINUX: case OS_POLICY_WINDOWS: case OS_POLICY_WINDOWS2K3: case OS_POLICY_VISTA: case OS_POLICY_SOLARIS: /* Old Linux and windows allowed packet with 0 timestamp. */ break; default: /* other OS simply drop the pakcet with 0 timestamp, when * 3whs has valid timestamp*/ goto invalid; } } if (check_ts) { int32_t result = 0; SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts); if (receiver_stream->os_policy == OS_POLICY_LINUX) { /* Linux accepts TS which are off by one.*/ result = (int32_t) ((ts - sender_stream->last_ts) + 1); } else { result = (int32_t) (ts - sender_stream->last_ts); } SCLogDebug("result %"PRIi32", p->ts.tv_sec %"PRIuMAX"", result, (uintmax_t)p->ts.tv_sec); if (sender_stream->last_pkt_ts == 0 && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) { sender_stream->last_pkt_ts = p->ts.tv_sec; } if (result < 0) { SCLogDebug("timestamp is not valid sender_stream->last_ts " "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result " "%" PRId32 "", sender_stream->last_ts, ts, result); /* candidate for rejection */ ret = 0; } else if ((sender_stream->last_ts != 0) && (((uint32_t) p->ts.tv_sec) > sender_stream->last_pkt_ts + PAWS_24DAYS)) { SCLogDebug("packet is not valid sender_stream->last_pkt_ts " "%" PRIu32 " p->ts.tv_sec %" PRIu32 "", sender_stream->last_pkt_ts, (uint32_t) p->ts.tv_sec); /* candidate for rejection */ ret = 0; } if (ret == 1) { /* Update the timestamp and last seen packet time for this * stream */ if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) sender_stream->last_ts = ts; sender_stream->last_pkt_ts = p->ts.tv_sec; } else if (ret == 0) { /* if the timestamp of packet is not valid then, check if the * current stream timestamp is not so old. if so then we need to * accept the packet and update the stream->last_ts (RFC 1323)*/ if ((SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) && (((uint32_t) p->ts.tv_sec > (sender_stream->last_pkt_ts + PAWS_24DAYS)))) { sender_stream->last_ts = ts; sender_stream->last_pkt_ts = p->ts.tv_sec; SCLogDebug("timestamp considered valid anyway"); } else { goto invalid; } } } } else { /* Solaris stops using timestamps if a packet is received without a timestamp and timestamps were used on that stream. */ if (receiver_stream->os_policy == OS_POLICY_SOLARIS) ssn->flags &= ~STREAMTCP_FLAG_TIMESTAMP; } SCReturnInt(1); invalid: StreamTcpSetEvent(p, STREAM_PKT_INVALID_TIMESTAMP); SCReturnInt(0); } /** * \brief Function to test the received ACK values against the stream window * and previous ack value. ACK values should be higher than previous * ACK value and less than the next_win value. * * \param ssn TcpSession for state access * \param stream TcpStream of which last_ack needs to be tested * \param p Packet which is used to test the last_ack * * \retval 0 ACK is valid, last_ack is updated if ACK was higher * \retval -1 ACK is invalid */ static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); uint32_t ack = TCP_GET_ACK(p); /* fast track */ if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win)) { SCLogDebug("ACK in bounds"); SCReturnInt(0); } /* fast track */ else if (SEQ_EQ(ack, stream->last_ack)) { SCLogDebug("pkt ACK %"PRIu32" == stream last ACK %"PRIu32, TCP_GET_ACK(p), stream->last_ack); SCReturnInt(0); } /* exception handling */ if (SEQ_LT(ack, stream->last_ack)) { SCLogDebug("pkt ACK %"PRIu32" < stream last ACK %"PRIu32, TCP_GET_ACK(p), stream->last_ack); /* This is an attempt to get a 'left edge' value that we can check against. * It doesn't work when the window is 0, need to think of a better way. */ if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) { SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window " "%"PRIu32" = %"PRIu32, ack, stream->last_ack, stream->window, stream->last_ack - stream->window); goto invalid; } SCReturnInt(0); } if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) { SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win); goto invalid; /* a toclient RST as a reponse to SYN, next_win is 0, ack will be isn+1, just like * the syn ack */ } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && p->tcph->th_flags & TH_RST && SEQ_EQ(ack, stream->isn + 1)) { SCReturnInt(0); } SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32 " next_win %"PRIu32, ack, stream->last_ack, stream->next_win); invalid: StreamTcpSetEvent(p, STREAM_PKT_INVALID_ACK); SCReturnInt(-1); } /** \brief Set the No reassembly flag for the given direction in given TCP * session. * * \param ssn TCP Session to set the flag in * \param direction direction to set the flag in: 0 toserver, 1 toclient */ void StreamTcpSetSessionNoReassemblyFlag (TcpSession *ssn, char direction) { direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY) : (ssn->client.flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY); } #define PSEUDO_PKT_SET_IPV4HDR(nipv4h,ipv4h) do { \ IPV4_SET_RAW_VER(nipv4h, IPV4_GET_RAW_VER(ipv4h)); \ IPV4_SET_RAW_HLEN(nipv4h, IPV4_GET_RAW_HLEN(ipv4h)); \ IPV4_SET_RAW_IPLEN(nipv4h, IPV4_GET_RAW_IPLEN(ipv4h)); \ IPV4_SET_RAW_IPTOS(nipv4h, IPV4_GET_RAW_IPTOS(ipv4h)); \ IPV4_SET_RAW_IPPROTO(nipv4h, IPV4_GET_RAW_IPPROTO(ipv4h)); \ (nipv4h)->s_ip_src = IPV4_GET_RAW_IPDST(ipv4h); \ (nipv4h)->s_ip_dst = IPV4_GET_RAW_IPSRC(ipv4h); \ } while (0) #define PSEUDO_PKT_SET_IPV6HDR(nipv6h,ipv6h) do { \ (nipv6h)->s_ip6_src[0] = (ipv6h)->s_ip6_dst[0]; \ (nipv6h)->s_ip6_src[1] = (ipv6h)->s_ip6_dst[1]; \ (nipv6h)->s_ip6_src[2] = (ipv6h)->s_ip6_dst[2]; \ (nipv6h)->s_ip6_src[3] = (ipv6h)->s_ip6_dst[3]; \ (nipv6h)->s_ip6_dst[0] = (ipv6h)->s_ip6_src[0]; \ (nipv6h)->s_ip6_dst[1] = (ipv6h)->s_ip6_src[1]; \ (nipv6h)->s_ip6_dst[2] = (ipv6h)->s_ip6_src[2]; \ (nipv6h)->s_ip6_dst[3] = (ipv6h)->s_ip6_src[3]; \ IPV6_SET_RAW_NH(nipv6h, IPV6_GET_RAW_NH(ipv6h)); \ } while (0) #define PSEUDO_PKT_SET_TCPHDR(ntcph,tcph) do { \ COPY_PORT((tcph)->th_dport, (ntcph)->th_sport); \ COPY_PORT((tcph)->th_sport, (ntcph)->th_dport); \ (ntcph)->th_seq = (tcph)->th_ack; \ (ntcph)->th_ack = (tcph)->th_seq; \ } while (0) /** * \brief Function to fetch a packet from the packet allocation queue for * creation of the pseudo packet from the reassembled stream. * * @param parent Pointer to the parent of the pseudo packet * @param pkt pointer to the raw packet of the parent * @param len length of the packet * @return upon success returns the pointer to the new pseudo packet * otherwise NULL */ Packet *StreamTcpPseudoSetup(Packet *parent, uint8_t *pkt, uint32_t len) { SCEnter(); Packet *p = PacketGetFromQueueOrAlloc(); if (p == NULL || len == 0) { SCReturnPtr(NULL, "Packet"); } /* set the root ptr to the lowest layer */ if (parent->root != NULL) p->root = parent->root; else p->root = parent; /* copy packet and set lenght, proto */ p->proto = parent->proto; p->datalink = parent->datalink; PacketCopyData(p, pkt, len); p->recursion_level = parent->recursion_level + 1; p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; FlowReference(&p->flow, parent->flow); /* set tunnel flags */ /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); /* tell parent packet it's part of a tunnel */ SET_TUNNEL_PKT(parent); /* increment tunnel packet refcnt in the root packet */ TUNNEL_INCR_PKT_TPR(p); return p; } /** * \brief Function to setup the IP and TCP header of the pseudo packet from * the newly copied raw packet contents of the parent. * * @param np pointer to the pseudo packet * @param p pointer to the original packet */ static void StreamTcpPseudoPacketSetupHeader(Packet *np, Packet *p) { /* Setup the IP header */ if (PKT_IS_IPV4(p)) { np->ip4h = (IPV4Hdr *)((uint8_t *)GET_PKT_DATA(np) + (GET_PKT_LEN(np) - IPV4_GET_IPLEN(p))); PSEUDO_PKT_SET_IPV4HDR(np->ip4h, p->ip4h); /* Similarly setup the TCP header with ports in opposite direction */ np->tcph = (TCPHdr *)((uint8_t *)np->ip4h + IPV4_GET_HLEN(np)); PSEUDO_PKT_SET_TCPHDR(np->tcph, p->tcph); /* Setup the adress and port details */ SET_IPV4_SRC_ADDR(p, &np->dst); SET_IPV4_DST_ADDR(p, &np->src); SET_TCP_SRC_PORT(p, &np->dp); SET_TCP_DST_PORT(p, &np->sp); } else if (PKT_IS_IPV6(p)) { np->ip6h = (IPV6Hdr *)((uint8_t *)GET_PKT_DATA(np) + (GET_PKT_LEN(np) - IPV6_GET_PLEN(p) - IPV6_HEADER_LEN)); PSEUDO_PKT_SET_IPV6HDR(np->ip6h, p->ip6h); /* Similarly setup the TCP header with ports in opposite direction */ np->tcph = (TCPHdr *)((uint8_t *)np->ip6h + IPV6_HEADER_LEN); PSEUDO_PKT_SET_TCPHDR(np->tcph, p->tcph); /* Setup the adress and port details */ SET_IPV6_SRC_ADDR(p, &np->dst); SET_IPV6_DST_ADDR(p, &np->src); SET_TCP_SRC_PORT(p, &np->dp); SET_TCP_DST_PORT(p, &np->sp); } /* we don't need a payload (if any) */ np->payload = NULL; np->payload_len = 0; } /** \brief Create a pseudo packet injected into the engine to signal the * opposing direction of this stream to wrap up stream reassembly. * * \param p real packet * \param pq packet queue to store the new pseudo packet in */ void StreamTcpPseudoPacketCreateStreamEndPacket(Packet *p, TcpSession *ssn, PacketQueue *pq) { SCEnter(); if (p->flags & PKT_PSEUDO_STREAM_END) { SCReturn; } /* no need for a pseudo packet if there is nothing left to reassemble */ if (ssn->server.seg_list == NULL && ssn->client.seg_list == NULL) { SCReturn; } Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p)); if (np == NULL) { SCLogDebug("The packet received from packet allocation is NULL"); SCReturn; } PKT_SET_SRC(np, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO); /* Setup the IP and TCP headers */ StreamTcpPseudoPacketSetupHeader(np,p); np->flowflags = p->flowflags; np->flags |= PKT_STREAM_EST; np->flags |= PKT_STREAM_EOF; np->flags |= PKT_HAS_FLOW; np->flags |= PKT_PSEUDO_STREAM_END; if (PKT_IS_TOSERVER(p)) { SCLogDebug("original is to_server, so pseudo is to_client"); np->flowflags &= ~FLOW_PKT_TOSERVER; np->flowflags |= FLOW_PKT_TOCLIENT; #ifdef DEBUG BUG_ON(!(PKT_IS_TOCLIENT(np))); BUG_ON((PKT_IS_TOSERVER(np))); #endif } else if (PKT_IS_TOCLIENT(p)) { SCLogDebug("original is to_client, so pseudo is to_server"); np->flowflags &= ~FLOW_PKT_TOCLIENT; np->flowflags |= FLOW_PKT_TOSERVER; #ifdef DEBUG BUG_ON(!(PKT_IS_TOSERVER(np))); BUG_ON((PKT_IS_TOCLIENT(np))); #endif } PacketEnqueue(pq, np); SCReturn; } /** * \brief Run callback function on each TCP segment * * This function is used by StreamMsgForEach() which * should be used directly. * * \return -1 in case of error, the number of segment in case of success * */ int StreamTcpSegmentForEach(Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data) { TcpSession *ssn = NULL; TcpStream *stream = NULL; int ret = 0; int cnt = 0; if (p->flow == NULL) return 0; FLOWLOCK_RDLOCK(p->flow); ssn = (TcpSession *)p->flow->protoctx; if (ssn == NULL) { FLOWLOCK_UNLOCK(p->flow); return 0; } if (flag & FLOW_PKT_TOSERVER) { stream = &(ssn->server); } else { stream = &(ssn->client); } TcpSegment *seg = stream->seg_list; for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) { ret = CallbackFunc(p, data, seg->payload, seg->payload_len); if (ret != 1) { SCLogDebug("Callback function has failed"); FLOWLOCK_UNLOCK(p->flow); return -1; } seg = seg->next; cnt++; } FLOWLOCK_UNLOCK(p->flow); return cnt; } #ifdef UNITTESTS /** * \test Test the allocation of TCP session for a given packet from the * ssn_pool. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest01 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); TcpSession *ssn = StreamTcpNewSession(p); if (ssn == NULL) { printf("Session can not be allocated: "); goto end; } f.protoctx = ssn; if (f.alparser != NULL) { printf("AppLayer field not set to NULL: "); goto end; } if (ssn->state != 0) { printf("TCP state field not set to 0: "); goto end; } StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the deallocation of TCP session for a given packet and return * the memory back to ssn_pool and corresponding segments to segment * pool. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest02 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx ra_ctx; StreamMsgQueue stream_q; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&stream_q, 0, sizeof(StreamMsgQueue)); memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; int ret = 0; ra_ctx.stream_q = &stream_q; stt.ra_ctx = &ra_ctx; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_SYN | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(6); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a TCP session when we missed the intial * SYN packet of the session. The session is setup only if midstream * sessions are allowed to setup. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest03 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_SYN|TH_ACK; p->tcph = &tcph; int ret = 0; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(19); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.midstream != TRUE) { ret = 1; goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) goto end; if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 20 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11) goto end; StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a TCP session when we missed the intial * SYN/ACK packet of the session. The session is setup only if * midstream sessions are allowed to setup. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest04 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK; p->tcph = &tcph; int ret = 0; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(9); p->tcph->th_ack = htonl(19); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.midstream != TRUE) { ret = 1; goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) goto end; if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 10 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 20) goto end; StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a TCP session when we missed the intial * 3WHS packet of the session. The session is setup only if * midstream sessions are allowed to setup. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest05 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(13); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(19); p->tcph->th_ack = htonl(16); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x44, 3, 4); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.midstream != TRUE) { ret = 1; goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) goto end; if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 16 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) goto end; StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a TCP session when we have seen only the * FIN, RST packets packet of the session. The session is setup only if * midstream sessions are allowed to setup. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest06 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; TcpSession ssn; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof (TcpSession)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); tcph.th_flags = TH_FIN; p->tcph = &tcph; /* StreamTcpPacket returns -1 on unsolicited FIN */ if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) { printf("StreamTcpPacket failed: "); goto end; } if (((TcpSession *)(p->flow->protoctx)) != NULL) { printf("we have a ssn while we shouldn't: "); goto end; } p->tcph->th_flags = TH_RST; /* StreamTcpPacket returns -1 on unsolicited RST */ if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) { printf("StreamTcpPacket failed (2): "); goto end; } if (((TcpSession *)(p->flow->protoctx)) != NULL) { printf("we have a ssn while we shouldn't (2): "); goto end; } ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the working on PAWS. The packet will be dropped by stream, as * its timestamp is old, although the segment is in the window. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest07 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; TCPVars tcpvars; TCPOpt ts; uint32_t data[2]; PacketQueue pq; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); memset(&tcpvars, 0, sizeof(TCPVars)); memset(&ts, 0, sizeof(TCPOpt)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); stream_config.midstream = TRUE; /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; data[0] = htonl(10); data[1] = htonl(11); ts.type = TCP_OPT_TS; ts.len = 10; ts.data = (uint8_t *)data; tcpvars.ts = &ts; p->tcpvars = tcpvars; p->payload = payload; p->payload_len = 1; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; data[0] = htonl(2); p->tcpvars.ts->data = (uint8_t *)data; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 11) { printf("the timestamp values are client %"PRIu32" server %" PRIu32"" " seq %" PRIu32 "\n", TCP_GET_TSVAL(p), TCP_GET_TSECR(p), ((TcpSession *) (p->flow->protoctx))->client.next_seq); goto end; } StreamTcpSessionClear(p->flow->protoctx); ret = 1; } end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the working on PAWS. The packet will be accpeted by engine as * the timestamp is valid and it is in window. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest08 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; TCPVars tcpvars; TCPOpt ts; uint32_t data[2]; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); memset(&tcpvars, 0, sizeof(TCPVars)); memset(&ts, 0, sizeof(TCPOpt)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); stream_config.midstream = TRUE; /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; data[0] = htonl(10); data[1] = htonl(11); ts.type = TCP_OPT_TS; ts.len = 10; ts.data = (uint8_t *)data; tcpvars.ts = &ts; p->tcpvars = tcpvars; p->payload = payload; p->payload_len = 1; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(20); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; data[0] = htonl(12); p->tcpvars.ts->data = (uint8_t *)data; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 12) { printf("the timestamp values are client %"PRIu32" server %" PRIu32 " " "seq %" PRIu32 "\n", TCP_GET_TSVAL(p), TCP_GET_TSECR(p), ((TcpSession *) (p->flow->protoctx))->client.next_seq); goto end; } StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the working of No stream reassembly flag. The stream will not * reassemble the segment if the flag is set. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest09 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); stream_config.midstream = TRUE; //prevent L7 from kicking in StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->payload = payload; p->payload_len = 1; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(12); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpSetSessionNoReassemblyFlag(((TcpSession *)(p->flow->protoctx)), 0); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (((TcpSession *) (p->flow->protoctx))->client.seg_list->next == NULL) ret = 1; StreamTcpSessionClear(p->flow->protoctx); end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a TCP session when we are seeing asynchronous * stream, while we see all the packets in that stream from start. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest10 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(11); tcph.th_flags = TH_SYN; p->tcph = &tcph; int ret = 0; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(6); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.async_oneside != TRUE) { ret = 1; goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) { printf("failed in setting state\n"); goto end; } if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) { printf("failed in setting asynchronous session\n"); goto end; } if (((TcpSession *)(p->flow->protoctx))->client.last_ack != 6 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11) { printf("failed in seq %"PRIu32" match\n", ((TcpSession *)(p->flow->protoctx))->client.last_ack); goto end; } StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a TCP session when we are seeing asynchronous * stream, while we missed the SYN packet of that stream. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest11 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(1); tcph.th_flags = TH_SYN|TH_ACK; p->tcph = &tcph; int ret = 0; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(2); p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.async_oneside != TRUE) { ret = 1; goto end; } if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) { printf("failed in setting asynchronous session\n"); goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) { printf("failed in setting state\n"); goto end; } if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 2 && ((TcpSession *)(p->flow->protoctx))->client.next_seq != 1) { printf("failed in seq %"PRIu32" match\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a TCP session when we are seeing asynchronous * stream, while we missed the SYN and SYN/ACK packets in that stream. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest12 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(11); tcph.th_flags = TH_ACK; p->tcph = &tcph; int ret = 0; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(10); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(6); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.async_oneside != TRUE) { ret = 1; goto end; } if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) { printf("failed in setting asynchronous session\n"); goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) { printf("failed in setting state\n"); goto end; } if (((TcpSession *)(p->flow->protoctx))->client.last_ack != 6 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11) { printf("failed in seq %"PRIu32" match\n", ((TcpSession *)(p->flow->protoctx))->client.last_ack); goto end; } StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a TCP session when we are seeing asynchronous * stream, while we missed the SYN and SYN/ACK packets in that stream. * Later, we start to receive the packet from other end stream too. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest13 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(11); tcph.th_flags = TH_ACK; p->tcph = &tcph; int ret = 0; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(10); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(6); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.async_oneside != TRUE) { ret = 1; goto end; } if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) { printf("failed in setting asynchronous session\n"); goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) { printf("failed in setting state\n"); goto end; } p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(9); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (((TcpSession *)(p->flow->protoctx))->client.last_ack != 9 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 14) { printf("failed in seq %"PRIu32" match\n", ((TcpSession *)(p->flow->protoctx))->client.last_ack); goto end; } StreamTcpSessionPktFree(p); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /* Dummy conf string to setup the OS policy for unit testing */ static const char *dummy_conf_string = "%YAML 1.1\n" "---\n" "\n" "default-log-dir: /var/log/eidps\n" "\n" "logging:\n" "\n" " default-log-level: debug\n" "\n" " default-format: \"<%t> - <%l>\"\n" "\n" " default-startup-message: Your IDS has started.\n" "\n" " default-output-filter:\n" "\n" "host-os-policy:\n" "\n" " windows: 192.168.0.1\n" "\n" " linux: 192.168.0.2\n" "\n"; /* Dummy conf string to setup the OS policy for unit testing */ static const char *dummy_conf_string1 = "%YAML 1.1\n" "---\n" "\n" "default-log-dir: /var/log/eidps\n" "\n" "logging:\n" "\n" " default-log-level: debug\n" "\n" " default-format: \"<%t> - <%l>\"\n" "\n" " default-startup-message: Your IDS has started.\n" "\n" " default-output-filter:\n" "\n" "host-os-policy:\n" "\n" " windows: 192.168.0.0/24," "192.168.1.1\n" "\n" " linux: 192.168.1.0/24," "192.168.0.1\n" "\n"; /** * \brief Function to parse the dummy conf string and get the value of IP * address for the corresponding OS policy type. * * \param conf_val_name Name of the OS policy type * \retval returns IP address as string on success and NULL on failure */ char *StreamTcpParseOSPolicy (char *conf_var_name) { SCEnter(); char conf_var_type_name[15] = "host-os-policy"; char *conf_var_full_name = NULL; char *conf_var_value = NULL; if (conf_var_name == NULL) goto end; /* the + 2 is for the '.' and the string termination character '\0' */ conf_var_full_name = (char *)SCMalloc(strlen(conf_var_type_name) + strlen(conf_var_name) + 2); if (conf_var_full_name == NULL) goto end; if (snprintf(conf_var_full_name, strlen(conf_var_type_name) + strlen(conf_var_name) + 2, "%s.%s", conf_var_type_name, conf_var_name) < 0) { SCLogError(SC_ERR_INVALID_VALUE, "Error in making the conf full name"); goto end; } if (ConfGet(conf_var_full_name, &conf_var_value) != 1) { SCLogError(SC_ERR_UNKNOWN_VALUE, "Error in getting conf value for conf name %s", conf_var_full_name); goto end; } SCLogDebug("Value obtained from the yaml conf file, for the var " "\"%s\" is \"%s\"", conf_var_name, conf_var_value); end: if (conf_var_full_name != NULL) SCFree(conf_var_full_name); SCReturnCharPtr(conf_var_value); } /** * \test Test the setting up a OS policy. Te OS policy values are defined in * the config string "dummy_conf_string" * * \retval On success it returns 1 and on failure 0 */ static int StreamTcpTest14 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; struct in_addr addr; IPV4Hdr ipv4h; char os_policy_name[10] = "windows"; char *ip_addr; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name)); ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); addr.s_addr = inet_addr("192.168.0.1"); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->dst.family = AF_INET; p->dst.address.address_un_data32[0] = addr.s_addr; p->ip4h = &ipv4h; StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(15); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(14); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; addr.s_addr = inet_addr("192.168.0.2"); p->tcph->th_seq = htonl(25); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(24); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.midstream != TRUE) { ret = 1; goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) goto end; if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) { printf("failed in next_seq match client.next_seq %"PRIu32"" " server.next_seq %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->client.next_seq, ((TcpSession *)(p->flow->protoctx))->server.next_seq); goto end; } if (((TcpSession *)(p->flow->protoctx))->client.os_policy != OS_POLICY_WINDOWS && ((TcpSession *) (p->flow->protoctx))->server.os_policy != OS_POLICY_LINUX) { printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) (p->flow->protoctx))->client.os_policy, OS_POLICY_WINDOWS, ((TcpSession *)(p->flow->protoctx))->server.os_policy, OS_POLICY_LINUX); goto end; } StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** * \test Test the setting up a TCP session using the 4WHS: * SYN, SYN, SYN/ACK, ACK * * \retval On success it returns 1 and on failure 0. */ static int StreamTcp4WHSTest01 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = 0; tcph.th_flags = TH_SYN; p->tcph = &tcph; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = 0; p->tcph->th_flags = TH_SYN; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) { printf("STREAMTCP_FLAG_4WHS flag not set: "); goto end; } p->tcph->th_seq = htonl(10); p->tcph->th_ack = htonl(21); /* the SYN/ACK uses the SEQ from the first SYN pkt */ p->tcph->th_flags = TH_SYN|TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(21); p->tcph->th_ack = htonl(10); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) { printf("state is not ESTABLISHED: "); goto end; } ret = 1; end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test set up a TCP session using the 4WHS: * SYN, SYN, SYN/ACK, ACK, but the SYN/ACK does * not have the right SEQ * * \retval On success it returns 1 and on failure 0. */ static int StreamTcp4WHSTest02 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = 0; tcph.th_flags = TH_SYN; p->tcph = &tcph; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = 0; p->tcph->th_flags = TH_SYN; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) { printf("STREAMTCP_FLAG_4WHS flag not set: "); goto end; } p->tcph->th_seq = htonl(30); p->tcph->th_ack = htonl(21); /* the SYN/ACK uses the SEQ from the first SYN pkt */ p->tcph->th_flags = TH_SYN|TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) { printf("SYN/ACK pkt not rejected but it should have: "); goto end; } ret = 1; end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test set up a TCP session using the 4WHS: * SYN, SYN, SYN/ACK, ACK: however the SYN/ACK and ACK * are part of a normal 3WHS * * \retval On success it returns 1 and on failure 0. */ static int StreamTcp4WHSTest03 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p->flow = &f; StreamTcpInitConfig(TRUE); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = 0; tcph.th_flags = TH_SYN; p->tcph = &tcph; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = 0; p->tcph->th_flags = TH_SYN; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) { printf("STREAMTCP_FLAG_4WHS flag not set: "); goto end; } p->tcph->th_seq = htonl(30); p->tcph->th_ack = htonl(11); p->tcph->th_flags = TH_SYN|TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(31); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) { printf("state is not ESTABLISHED: "); goto end; } ret = 1; end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the setting up a OS policy. Te OS policy values are defined in * the config string "dummy_conf_string1" * * \retval On success it returns 1 and on failure 0 */ static int StreamTcpTest15 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; struct in_addr addr; IPV4Hdr ipv4h; char os_policy_name[10] = "windows"; char *ip_addr; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name)); ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); addr.s_addr = inet_addr("192.168.0.20"); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->dst.family = AF_INET; p->dst.address.address_un_data32[0] = addr.s_addr; p->ip4h = &ipv4h; StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(15); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(14); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; addr.s_addr = inet_addr("192.168.1.20"); p->tcph->th_seq = htonl(25); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(24); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.midstream != TRUE) { ret = 1; goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) goto end; if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) { printf("failed in next_seq match client.next_seq %"PRIu32"" " server.next_seq %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->client.next_seq, ((TcpSession *)(p->flow->protoctx))->server.next_seq); goto end; } if (((TcpSession *)(p->flow->protoctx))->client.os_policy != OS_POLICY_WINDOWS && ((TcpSession *) (p->flow->protoctx))->server.os_policy != OS_POLICY_LINUX) { printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) (p->flow->protoctx))->client.os_policy, OS_POLICY_WINDOWS, ((TcpSession *)(p->flow->protoctx))->server.os_policy, OS_POLICY_LINUX); goto end; } StreamTcpSessionPktFree(p); ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** * \test Test the setting up a OS policy. Te OS policy values are defined in * the config string "dummy_conf_string1" * * \retval On success it returns 1 and on failure 0 */ static int StreamTcpTest16 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; struct in_addr addr; IPV4Hdr ipv4h; char os_policy_name[10] = "windows"; char *ip_addr; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name)); ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); addr.s_addr = inet_addr("192.168.0.1"); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->dst.family = AF_INET; p->dst.address.address_un_data32[0] = addr.s_addr; p->ip4h = &ipv4h; StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(15); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(14); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; addr.s_addr = inet_addr("192.168.1.1"); p->tcph->th_seq = htonl(25); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(24); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.midstream != TRUE) { ret = 1; goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) goto end; if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) { printf("failed in next_seq match client.next_seq %"PRIu32"" " server.next_seq %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->client.next_seq, ((TcpSession *)(p->flow->protoctx))->server.next_seq); goto end; } if (((TcpSession *)(p->flow->protoctx))->client.os_policy != OS_POLICY_LINUX && ((TcpSession *) (p->flow->protoctx))->server.os_policy != OS_POLICY_WINDOWS) { printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) (p->flow->protoctx))->client.os_policy, OS_POLICY_LINUX, ((TcpSession *)(p->flow->protoctx))->server.os_policy, OS_POLICY_WINDOWS); goto end; } StreamTcpSessionPktFree(p); ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** * \test Test the setting up a OS policy. Te OS policy values are defined in * the config string "dummy_conf_string1". To check the setting of * Default os policy * * \retval On success it returns 1 and on failure 0 */ static int StreamTcpTest17 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[4]; struct in_addr addr; IPV4Hdr ipv4h; char os_policy_name[10] = "windows"; char *ip_addr; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); p->flow = &f; int ret = 0; StreamTcpInitConfig(TRUE); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name)); ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); addr.s_addr = inet_addr("192.168.0.1"); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->dst.family = AF_INET; p->dst.address.address_un_data32[0] = addr.s_addr; p->ip4h = &ipv4h; StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(15); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(14); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; addr.s_addr = inet_addr("10.1.1.1"); p->tcph->th_seq = htonl(25); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_seq = htonl(24); p->tcph->th_ack = htonl(13); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; if (stream_config.midstream != TRUE) { ret = 1; goto end; } if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) goto end; if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 && ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) { printf("failed in next_seq match client.next_seq %"PRIu32"" " server.next_seq %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->client.next_seq, ((TcpSession *)(p->flow->protoctx))->server.next_seq); goto end; } if (((TcpSession *)(p->flow->protoctx))->client.os_policy != OS_POLICY_LINUX && ((TcpSession *) (p->flow->protoctx))->server.os_policy != OS_POLICY_DEFAULT) { printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) (p->flow->protoctx))->client.os_policy, OS_POLICY_LINUX, ((TcpSession *)(p->flow->protoctx))->server.os_policy, OS_POLICY_DEFAULT); goto end; } StreamTcpSessionPktFree(p); ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** \test Test the various OS policies based on different IP addresses from confuguration defined in 'dummy_conf_string1' */ static int StreamTcpTest18 (void) { struct in_addr addr; char os_policy_name[10] = "windows"; char *ip_addr; TcpStream stream; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ipv4h; int ret = 0; memset(&addr, 0, sizeof(addr)); memset(&stream, 0, sizeof(stream)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(ipv4h)); StreamTcpInitConfig(TRUE); SCHInfoCleanResources(); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); p->dst.family = AF_INET; p->ip4h = &ipv4h; addr.s_addr = inet_addr("192.168.1.1"); p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpSetOSPolicy(&stream, p); if (stream.os_policy != OS_POLICY_WINDOWS) goto end; ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** \test Test the various OS policies based on different IP addresses from confuguration defined in 'dummy_conf_string1' */ static int StreamTcpTest19 (void) { struct in_addr addr; char os_policy_name[10] = "windows"; char *ip_addr; TcpStream stream; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ipv4h; int ret = 0; memset(&addr, 0, sizeof(addr)); memset(&stream, 0, sizeof(stream)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(ipv4h)); StreamTcpInitConfig(TRUE); SCHInfoCleanResources(); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); p->dst.family = AF_INET; p->ip4h = &ipv4h; addr.s_addr = inet_addr("192.168.0.30"); p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpSetOSPolicy(&stream, p); if (stream.os_policy != OS_POLICY_WINDOWS) { printf("expected os_policy: %"PRIu8" but received %"PRIu8": ", OS_POLICY_WINDOWS, stream.os_policy); goto end; } ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** \test Test the various OS policies based on different IP addresses from confuguration defined in 'dummy_conf_string1' */ static int StreamTcpTest20 (void) { struct in_addr addr; char os_policy_name[10] = "linux"; char *ip_addr; TcpStream stream; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ipv4h; int ret = 0; memset(&addr, 0, sizeof(addr)); memset(&stream, 0, sizeof(stream)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(ipv4h)); StreamTcpInitConfig(TRUE); SCHInfoCleanResources(); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); p->dst.family = AF_INET; p->ip4h = &ipv4h; addr.s_addr = inet_addr("192.168.0.1"); p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpSetOSPolicy(&stream, p); if (stream.os_policy != OS_POLICY_LINUX) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", OS_POLICY_LINUX, stream.os_policy); goto end; } ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** \test Test the various OS policies based on different IP addresses from confuguration defined in 'dummy_conf_string1' */ static int StreamTcpTest21 (void) { struct in_addr addr; char os_policy_name[10] = "linux"; char *ip_addr; TcpStream stream; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ipv4h; int ret = 0; memset(&addr, 0, sizeof(addr)); memset(&stream, 0, sizeof(stream)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(ipv4h)); StreamTcpInitConfig(TRUE); SCHInfoCleanResources(); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); p->dst.family = AF_INET; p->ip4h = &ipv4h; addr.s_addr = inet_addr("192.168.1.30"); p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpSetOSPolicy(&stream, p); if (stream.os_policy != OS_POLICY_LINUX) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", OS_POLICY_LINUX, stream.os_policy); goto end; } ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** \test Test the various OS policies based on different IP addresses from confuguration defined in 'dummy_conf_string1' */ static int StreamTcpTest22 (void) { struct in_addr addr; char os_policy_name[10] = "windows"; char *ip_addr; TcpStream stream; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV4Hdr ipv4h; int ret = 0; memset(&addr, 0, sizeof(addr)); memset(&stream, 0, sizeof(stream)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(ipv4h)); StreamTcpInitConfig(TRUE); SCHInfoCleanResources(); /* Load the config string in to parser */ ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1)); /* Get the IP address as string and add it to Host info tree for lookups */ ip_addr = StreamTcpParseOSPolicy(os_policy_name); SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1); p->dst.family = AF_INET; p->ip4h = &ipv4h; addr.s_addr = inet_addr("123.231.2.1"); p->dst.address.address_un_data32[0] = addr.s_addr; StreamTcpSetOSPolicy(&stream, p); if (stream.os_policy != OS_POLICY_DEFAULT) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", OS_POLICY_DEFAULT, stream.os_policy); goto end; } ret = 1; end: StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return ret; } /** \test Test the stream mem leaks conditions. */ static int StreamTcpTest23(void) { TcpSession ssn; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); uint8_t packet[1460] = ""; ThreadVars tv; int result = 1; PacketQueue pq; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&tv, 0, sizeof (ThreadVars)); StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); ssn.client.os_policy = OS_POLICY_BSD; f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL; p->tcph->th_seq = htonl(3184324453UL); p->tcph->th_ack = htonl(3373419609UL); p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { printf("failed in segment reassmebling: "); result &= 0; goto end; } p->tcph->th_seq = htonl(3184324455UL); p->tcph->th_ack = htonl(3373419621UL); p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { printf("failed in segment reassmebling: "); result &= 0; goto end; } p->tcph->th_seq = htonl(3184324453UL); p->tcph->th_ack = htonl(3373419621UL); p->payload_len = 6; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { printf("failed in segment reassmebling: "); result &= 0; // goto end; } if(ssn.client.seg_list_tail != NULL && ssn.client.seg_list_tail->payload_len != 4) { printf("failed in segment reassmebling: "); result &= 0; } end: StreamTcpReturnStreamSegments(&ssn.client); StreamTcpFreeConfig(TRUE); if (SC_ATOMIC_GET(st_memuse) == 0) { result &= 1; } else { printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse)); } SCFree(p); return result; } /** \test Test the stream mem leaks conditions. */ static int StreamTcpTest24(void) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); uint8_t packet[1460] = ""; ThreadVars tv; int result = 1; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&tcph, 0, sizeof (TCPHdr)); ssn.client.os_policy = OS_POLICY_BSD; f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL; p->tcph->th_seq = htonl(3184324455UL); p->tcph->th_ack = htonl(3373419621UL); p->payload_len = 4; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } p->tcph->th_seq = htonl(3184324459UL); p->tcph->th_ack = htonl(3373419633UL); p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } p->tcph->th_seq = htonl(3184324459UL); p->tcph->th_ack = htonl(3373419657UL); p->payload_len = 4; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } if(ssn.client.seg_list_tail != NULL && ssn.client.seg_list_tail->payload_len != 2) { printf("failed in segment reassmebling\n"); result &= 0; } end: StreamTcpReturnStreamSegments(&ssn.client); StreamTcpFreeConfig(TRUE); if (SC_ATOMIC_GET(st_memuse) == 0) { result &= 1; } else { printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse)); } SCFree(p); return result; } /** * \test Test the initialization of tcp streams with congestion flags * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest25(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); int ret = 0; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN | TH_CWR; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_SYN | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(6); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the initialization of tcp streams with congestion flags * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest26(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); int ret = 0; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN | TH_ECN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_SYN | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(6); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the initialization of tcp streams with congestion flags * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest27(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); int ret = 0; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN | TH_CWR | TH_ECN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_SYN | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(6); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) goto end; StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** \test Test the memcap incrementing/decrementing and memcap check */ static int StreamTcpTest28(void) { uint8_t ret = 0; StreamTcpInitConfig(TRUE); uint32_t memuse = SC_ATOMIC_GET(st_memuse); StreamTcpIncrMemuse(500); if (SC_ATOMIC_GET(st_memuse) != (memuse+500)) { printf("failed in incrementing the memory"); goto end; } StreamTcpDecrMemuse(500); if (SC_ATOMIC_GET(st_memuse) != memuse) { printf("failed in decrementing the memory"); goto end; } if (StreamTcpCheckMemcap(500) != 1) { printf("failed in validating the memcap"); goto end; } if (StreamTcpCheckMemcap((memuse + stream_config.memcap)) != 0) { printf("failed in validating the overflowed memcap"); goto end; } StreamTcpFreeConfig(TRUE); if (SC_ATOMIC_GET(st_memuse) != 0) { printf("failed in clearing the memory"); goto end; } ret = 1; return ret; end: StreamTcpFreeConfig(TRUE); return ret; } #if 0 /** * \test Test the resetting of the sesison with bad checksum packet and later * send the malicious contents on the session. Engine should drop the * packet with the bad checksum. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest29(void) { Packet p; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; TcpSession ssn; IPV4Hdr ipv4h; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); struct in_addr addr; struct in_addr addr1; TCPCache tcpc; TCPVars tcpvars; TcpStream server; TcpStream client; memset (&p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset (&ipv4h, 0, sizeof(IPV4Hdr)); memset (&addr, 0, sizeof(addr)); memset (&addr1, 0, sizeof(addr1)); memset (&tcpc, 0, sizeof(tcpc)); memset (&tcpvars, 0, sizeof(tcpvars)); memset(&ssn, 0, sizeof (TcpSession)); memset(&server, 0, sizeof (TcpStream)); memset(&client, 0, sizeof (TcpStream)); uint8_t packet[1460] = ""; int result = 1; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ ssn.client.os_policy = OS_POLICY_BSD; p.src.family = AF_INET; p.dst.family = AF_INET; p.proto = IPPROTO_TCP; p.flow = &f; tcph.th_win = 5480; p.tcph = &tcph; p.payload = packet; p.ip4h = &ipv4h; p.tcpc = tcpc; p.tcpc.comp_csum = -1; tcpvars.hlen = 20; p.tcpvars = tcpvars; ssn.state = TCP_ESTABLISHED; addr.s_addr = inet_addr("10.1.3.53"); p.dst.address.address_un_data32[0] = addr.s_addr; addr1.s_addr = inet_addr("10.1.3.7"); p.src.address.address_un_data32[0] = addr1.s_addr; f.protoctx = &ssn; stt.ra_ctx = ra_ctx; ssn.server = server; ssn.client = client; ssn.client.isn = 10; ssn.client.window = 5184; ssn.client.last_ack = 10; ssn.client.ra_base_seq = 10; ssn.client.next_win = 5184; ssn.server.isn = 119197101; ssn.server.window = 5184; ssn.server.next_win = 5184; ssn.server.last_ack = 119197101; ssn.server.ra_base_seq = 119197101; tcph.th_flags = TH_PUSH | TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; p.tcph->th_seq = htonl(11); p.tcph->th_ack = htonl(119197102); p.payload_len = 4; p.ip4h->ip_src = addr1; p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src), (uint16_t *)p.tcph, (p.payload_len + p.tcpvars.hlen) ); if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } tcph.th_flags = TH_ACK; p.flowflags = FLOW_PKT_TOCLIENT; p.tcph->th_seq = htonl(119197102); p.tcph->th_ack = htonl(15); p.payload_len = 0; p.ip4h->ip_src = addr; p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src), (uint16_t *)p.tcph, (p.payload_len + p.tcpvars.hlen) ); if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } tcph.th_flags = TH_RST | TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; p.tcph->th_seq = htonl(15); p.tcph->th_ack = htonl(119197102); p.payload_len = 0; p.ip4h->ip_src = addr1; p.tcph->th_sum = 12345; if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } if (ssn.state != TCP_ESTABLISHED) { printf("the ssn.state should be TCP_ESTABLISHED(%"PRIu8"), not %"PRIu8"" "\n", TCP_ESTABLISHED, ssn.state); result &= 0; goto end; } end: StreamTcpReturnStreamSegments(&ssn.client); StreamTcpFreeConfig(TRUE); return result; } /** * \test Test the overlapping of the packet with bad checksum packet and later * send the malicious contents on the session. Engine should drop the * packet with the bad checksum. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest30(void) { Packet p; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; TcpSession ssn; IPV4Hdr ipv4h; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); struct in_addr addr; struct in_addr addr1; TCPCache tcpc; TCPVars tcpvars; TcpStream server; TcpStream client; memset (&p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset (&ipv4h, 0, sizeof(IPV4Hdr)); memset (&addr, 0, sizeof(addr)); memset (&addr1, 0, sizeof(addr1)); memset (&tcpc, 0, sizeof(tcpc)); memset (&tcpvars, 0, sizeof(tcpvars)); memset(&ssn, 0, sizeof (TcpSession)); memset(&server, 0, sizeof (TcpStream)); memset(&client, 0, sizeof (TcpStream)); uint8_t payload[9] = "AAAAAAAAA"; uint8_t payload1[9] = "GET /EVIL"; uint8_t expected_content[9] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x45, 0x56, 0x49, 0x4c }; int result = 1; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ ssn.client.os_policy = OS_POLICY_BSD; p.src.family = AF_INET; p.dst.family = AF_INET; p.proto = IPPROTO_TCP; p.flow = &f; tcph.th_win = 5480; p.tcph = &tcph; p.payload = payload; p.ip4h = &ipv4h; p.tcpc = tcpc; p.tcpc.comp_csum = -1; p.tcpvars = tcpvars; ssn.state = TCP_ESTABLISHED; addr.s_addr = inet_addr("10.1.3.53"); p.dst.address.address_un_data32[0] = addr.s_addr; addr1.s_addr = inet_addr("10.1.3.7"); p.src.address.address_un_data32[0] = addr1.s_addr; f.protoctx = &ssn; stt.ra_ctx = ra_ctx; ssn.server = server; ssn.client = client; ssn.client.isn = 10; ssn.client.window = 5184; ssn.client.last_ack = 10; ssn.client.ra_base_seq = 10; ssn.client.next_win = 5184; ssn.server.isn = 1351079940; ssn.server.window = 5184; ssn.server.next_win = 1351088132; ssn.server.last_ack = 1351079940; ssn.server.ra_base_seq = 1351079940; tcph.th_flags = TH_PUSH | TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; p.tcph->th_seq = htonl(11); p.tcph->th_ack = htonl(1351079940); p.payload_len = 9; p.ip4h->ip_src = addr1; p.tcph->th_sum = 12345; if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } tcph.th_flags = TH_PUSH | TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; p.tcph->th_seq = htonl(11); p.tcph->th_ack = htonl(1351079940); p.payload = payload1; p.payload_len = 9; p.ip4h->ip_src = addr1; p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src), (uint16_t *)p.tcph, (p.payload_len + p.tcpvars.hlen) ); if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } tcph.th_flags = TH_ACK; p.flowflags = FLOW_PKT_TOCLIENT; p.tcph->th_seq = htonl(1351079940); p.tcph->th_ack = htonl(20); p.payload_len = 0; p.ip4h->ip_src = addr; p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src), (uint16_t *)p.tcph, (p.payload_len + p.tcpvars.hlen) ); if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } if (StreamTcpCheckStreamContents(expected_content, 9, &ssn.client) != 1) { printf("the contents are not as expected(GET /EVIL), contents are: "); PrintRawDataFp(stdout, ssn.client.seg_list->payload, 9); result &= 0; goto end; } end: StreamTcpReturnStreamSegments(&ssn.client); StreamTcpFreeConfig(TRUE); return result; } /** * \test Test the multiple SYN packet handling with bad checksum and timestamp * value. Engine should drop the bad checksum packet and establish * TCP session correctly. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest31(void) { Packet p; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; TcpSession ssn; IPV4Hdr ipv4h; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); struct in_addr addr; struct in_addr addr1; TCPCache tcpc; TCPVars tcpvars; TcpStream server; TcpStream client; TCPOpt tcpopt; memset (&p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset (&ipv4h, 0, sizeof(IPV4Hdr)); memset (&addr, 0, sizeof(addr)); memset (&addr1, 0, sizeof(addr1)); memset (&tcpc, 0, sizeof(tcpc)); memset (&tcpvars, 0, sizeof(tcpvars)); memset(&ssn, 0, sizeof (TcpSession)); memset(&server, 0, sizeof (TcpStream)); memset(&client, 0, sizeof (TcpStream)); memset(&tcpopt, 0, sizeof (TCPOpt)); int result = 1; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ ssn.client.os_policy = OS_POLICY_LINUX; p.src.family = AF_INET; p.dst.family = AF_INET; p.proto = IPPROTO_TCP; p.flow = &f; tcph.th_win = 5480; p.tcph = &tcph; p.ip4h = &ipv4h; p.tcpc = tcpc; p.tcpc.comp_csum = -1; p.tcpvars = tcpvars; p.tcpvars.ts = &tcpopt; addr.s_addr = inet_addr("10.1.3.53"); p.dst.address.address_un_data32[0] = addr.s_addr; addr1.s_addr = inet_addr("10.1.3.7"); p.src.address.address_un_data32[0] = addr1.s_addr; f.protoctx = &ssn; stt.ra_ctx = ra_ctx; ssn.server = server; ssn.client = client; ssn.client.isn = 10; ssn.client.window = 5184; ssn.client.last_ack = 10; ssn.client.ra_base_seq = 10; ssn.client.next_win = 5184; ssn.server.isn = 1351079940; ssn.server.window = 5184; ssn.server.next_win = 1351088132; ssn.server.last_ack = 1351079940; ssn.server.ra_base_seq = 1351079940; tcph.th_flags = TH_SYN; p.flowflags = FLOW_PKT_TOSERVER; p.tcph->th_seq = htonl(10); p.payload_len = 0; p.ip4h->ip_src = addr1; p.tcpc.ts1 = 100; p.tcph->th_sum = 12345; if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } tcph.th_flags = TH_SYN; p.flowflags = FLOW_PKT_TOSERVER; p.tcph->th_seq = htonl(10); p.payload_len = 0; p.ip4h->ip_src = addr1; p.tcpc.ts1 = 10; p.tcpc.comp_csum = -1; p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src), (uint16_t *)p.tcph, (p.payload_len + p.tcpvars.hlen) ); if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } ssn.flags |= STREAMTCP_FLAG_TIMESTAMP; tcph.th_flags = TH_SYN | TH_ACK; p.flowflags = FLOW_PKT_TOCLIENT; p.tcph->th_seq = htonl(1351079940); p.tcph->th_ack = htonl(11); p.payload_len = 0; p.tcpc.ts1 = 10; p.ip4h->ip_src = addr; p.tcpc.comp_csum = -1; p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src), (uint16_t *)p.tcph, (p.payload_len + p.tcpvars.hlen) ); if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } tcph.th_flags = TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; p.tcph->th_seq = htonl(11); p.tcph->th_ack = htonl(1351079941); p.payload_len = 0; p.tcpc.ts1 = 10; p.ip4h->ip_src = addr1; p.tcpc.comp_csum = -1; p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src), (uint16_t *)p.tcph, (p.payload_len + p.tcpvars.hlen) ); if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) { printf("failed in segment reassmebling\n"); result &= 0; goto end; } if (ssn.state != TCP_ESTABLISHED) { printf("the should have been changed to TCP_ESTABLISHED!!\n "); result &= 0; goto end; } end: StreamTcpReturnStreamSegments(&ssn.client); StreamTcpFreeConfig(TRUE); return result; } /** * \test Test the initialization of tcp streams with ECN & CWR flags * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest32(void) { Packet p; Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); int ret = 0; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); stt.ra_ctx = ra_ctx; p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN | TH_CWR | TH_ECN; p.tcph = &tcph; p.flowflags = FLOW_PKT_TOSERVER; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(1); p.tcph->th_flags = TH_SYN | TH_ACK | TH_ECN; p.flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } p.tcph->th_ack = htonl(1); p.tcph->th_seq = htonl(1); p.tcph->th_flags = TH_ACK | TH_ECN | TH_CWR; p.flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } p.tcph->th_ack = htonl(1); p.tcph->th_seq = htonl(2); p.tcph->th_flags = TH_PUSH | TH_ACK | TH_ECN | TH_CWR; p.flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p.payload = payload; p.payload_len = 3; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } p.flowflags = FLOW_PKT_TOCLIENT; p.tcph->th_flags = TH_ACK; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) { printf("the TCP state should be TCP_ESTABLISEHD\n"); goto end; } StreamTcpSessionClear(p.flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the allocation of TCP session for a given packet when the same * ports have been used to start the new session after resetting the * previous session. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest33 (void) { Packet p; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; TcpReassemblyThreadCtx ra_ctx; StreamMsgQueue stream_q; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&stream_q, 0, sizeof(StreamMsgQueue)); memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); memset (&p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; p.tcph = &tcph; p.flowflags = FLOW_PKT_TOSERVER; int ret = 0; ra_ctx.stream_q = &stream_q; stt.ra_ctx = &ra_ctx; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(1); p.tcph->th_flags = TH_SYN | TH_ACK; p.flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(1); p.tcph->th_seq = htonl(1); p.tcph->th_flags = TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(1); p.tcph->th_seq = htonl(1); p.tcph->th_flags = TH_RST | TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; if (((TcpSession *)(p.flow->protoctx))->state != TCP_CLOSED) { printf("Tcp session should have been closed\n"); goto end; } p.tcph->th_seq = htonl(1); p.tcph->th_flags = TH_SYN; p.flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_seq = htonl(1); p.tcph->th_ack = htonl(2); p.tcph->th_flags = TH_SYN | TH_ACK; p.flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(2); p.tcph->th_seq = htonl(2); p.tcph->th_flags = TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) { printf("Tcp session should have been ESTABLISHED\n"); goto end; } ret = 1; end: StreamTcpSessionClear(p.flow->protoctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the allocation of TCP session for a given packet when the SYN * packet is sent with the PUSH flag set. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest34 (void) { Packet p; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; TcpReassemblyThreadCtx ra_ctx; StreamMsgQueue stream_q; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&stream_q, 0, sizeof(StreamMsgQueue)); memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); memset (&p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN|TH_PUSH; p.tcph = &tcph; p.flowflags = FLOW_PKT_TOSERVER; int ret = 0; ra_ctx.stream_q = &stream_q; stt.ra_ctx = &ra_ctx; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(1); p.tcph->th_flags = TH_SYN | TH_ACK; p.flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(1); p.tcph->th_seq = htonl(1); p.tcph->th_flags = TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) { printf("Tcp session should have been establisehd\n"); goto end; } ret = 1; end: StreamTcpSessionClear(p.flow->protoctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the allocation of TCP session for a given packet when the SYN * packet is sent with the URG flag set. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest35 (void) { Packet p; Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; TcpReassemblyThreadCtx ra_ctx; StreamMsgQueue stream_q; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&stream_q, 0, sizeof(StreamMsgQueue)); memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); memset (&p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN|TH_URG; p.tcph = &tcph; p.flowflags = FLOW_PKT_TOSERVER; int ret = 0; ra_ctx.stream_q = &stream_q; stt.ra_ctx = &ra_ctx; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(1); p.tcph->th_flags = TH_SYN | TH_ACK; p.flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; p.tcph->th_ack = htonl(1); p.tcph->th_seq = htonl(1); p.tcph->th_flags = TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) goto end; if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) { printf("Tcp session should have been establisehd\n"); goto end; } ret = 1; end: StreamTcpSessionClear(p.flow->protoctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the processing of PSH and URG flag in tcp session. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest36(void) { Packet p; Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); int ret = 0; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset (&p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); stt.ra_ctx = ra_ctx; p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; p.tcph = &tcph; p.flowflags = FLOW_PKT_TOSERVER; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) { printf("failed in processing packet\n"); goto end; } p.tcph->th_ack = htonl(1); p.tcph->th_flags = TH_SYN | TH_ACK; p.flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } p.tcph->th_ack = htonl(1); p.tcph->th_seq = htonl(1); p.tcph->th_flags = TH_ACK; p.flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) { printf("the TCP state should be TCP_ESTABLISEHD\n"); goto end; } p.tcph->th_ack = htonl(2); p.tcph->th_seq = htonl(1); p.tcph->th_flags = TH_PUSH | TH_ACK | TH_URG; p.flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p.payload = payload; p.payload_len = 3; if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } if (((TcpSession *)p.flow->protoctx)->client.next_seq != 4) { printf("the ssn->client.next_seq should be 4, but it is %"PRIu32"\n", ((TcpSession *)p.flow->protoctx)->client.next_seq); goto end; } StreamTcpSessionClear(p.flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); return ret; } #endif /** * \test Test the processing of out of order FIN packets in tcp session. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest37(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); int ret = 0; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet\n"); goto end; } p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_SYN | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } if (((TcpSession *)p->flow->protoctx)->state != TCP_ESTABLISHED) { printf("the TCP state should be TCP_ESTABLISEHD\n"); goto end; } p->tcph->th_ack = htonl(2); p->tcph->th_seq = htonl(4); p->tcph->th_flags = TH_ACK|TH_FIN; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } if (((TcpSession *)p->flow->protoctx)->state != TCP_CLOSE_WAIT) { printf("the TCP state should be TCP_CLOSE_WAIT\n"); goto end; } p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } p->tcph->th_ack = htonl(4); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_ACK; p->payload_len = 0; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) { printf("failed in processing packet\n"); goto end; } if (((TcpSession *)p->flow->protoctx)->client.ra_raw_base_seq != 3) { printf("the ssn->client.next_seq should be 3, but it is %"PRIu32"\n", ((TcpSession *)p->flow->protoctx)->client.ra_raw_base_seq); goto end; } StreamTcpSessionClear(p->flow->protoctx); ret = 1; end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test the validation of the ACK number before setting up the * stream.last_ack. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest38 (void) { int ret = 0; Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx ra_ctx; StreamMsgQueue stream_q; PacketQueue pq; memset(&stream_q, 0, sizeof(StreamMsgQueue)); memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&pq,0,sizeof(PacketQueue)); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; ra_ctx.stream_q = &stream_q; stt.ra_ctx = &ra_ctx; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_SYN | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } p->tcph->th_ack = htonl(29847); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } /* last_ack value should be 1 as the previous sent ACK value is out of window */ if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 1) { printf("the server.last_ack should be 1, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } p->tcph->th_ack = htonl(2984); p->tcph->th_seq = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } /* last_ack value should be 2984 as the previous sent ACK value is inside window */ if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 2984) { printf("the server.last_ack should be 2984, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } ret = 1; end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the validation of the ACK number before setting up the * stream.last_ack and update the next_seq after loosing the . * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpTest39 (void) { Flow f; ThreadVars tv; StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx ra_ctx; StreamMsgQueue stream_q; PacketQueue pq; memset(&stream_q, 0, sizeof(StreamMsgQueue)); memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&pq,0,sizeof(PacketQueue)); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; int ret = 0; ra_ctx.stream_q = &stream_q; stt.ra_ctx = &ra_ctx; StreamTcpInitConfig(TRUE); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } p->tcph->th_ack = htonl(1); p->tcph->th_flags = TH_SYN | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } p->tcph->th_ack = htonl(2984); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } /* last_ack value should be 2984 as the previous sent ACK value is inside window */ if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 2984) { printf("the server.last_ack should be 2984, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } p->tcph->th_seq = htonl(2984); p->tcph->th_ack = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->payload = payload; p->payload_len = 3; if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; } /* next_seq value should be 2987 as the previous sent ACK value is inside window */ if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 2987) { printf("the server.next_seq should be 2987, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.next_seq); goto end; } ret = 1; end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); return ret; } static int StreamTcpTest40(void) { uint8_t raw_vlan[] = { 0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, 0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15, 0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55, 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); PACKET_INITIALIZE(p); SET_PKT_LEN(p, sizeof(raw_vlan)); memcpy(GET_PKT_DATA(p), raw_vlan, sizeof(raw_vlan)); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); DecodeVLAN(&tv, &dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), NULL); if(p->vlanh == NULL) { SCFree(p); return 0; } if(p->tcph == NULL) { SCFree(p); return 0; } Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p)); if (np == NULL) { printf("the packet received from packet allocation is NULL: "); return 0; } StreamTcpPseudoPacketSetupHeader(np,p); if (((uint8_t *)p->tcph - (uint8_t *)p->ip4h) != ((uint8_t *)np->tcph - (uint8_t *)np->ip4h)) { return 0; } FlowShutdown(); PACKET_CLEANUP(p); return 1; } static int StreamTcpTest41(void) { /* IPV6/TCP/no eth header */ uint8_t raw_ip[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x28, 0x06, 0x40, 0x20, 0x01, 0x06, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x99, 0xcc, 0x70, 0x20, 0x01, 0x06, 0x18, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x8c, 0x9b, 0x00, 0x50, 0x6a, 0xe7, 0x07, 0x36, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0x30, 0x29, 0x9c, 0x00, 0x00, 0x02, 0x04, 0x05, 0x8c, 0x04, 0x02, 0x08, 0x0a, 0x00, 0xdd, 0x1a, 0x39, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); PACKET_INITIALIZE(p); if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { PACKET_CLEANUP(p); SCFree(p); return 1; } FlowInitConfig(FLOW_QUIET); DecodeRaw(&tv, &dtv, p, raw_ip, GET_PKT_LEN(p), NULL); if (p->ip6h == NULL) { printf("expected a valid ipv6 header but it was NULL: "); FlowShutdown(); SCFree(p); return 1; } if(p->tcph == NULL) { SCFree(p); return 0; } Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p)); if (np == NULL) { printf("the packet received from packet allocation is NULL: "); return 0; } StreamTcpPseudoPacketSetupHeader(np,p); if (((uint8_t *)p->tcph - (uint8_t *)p->ip6h) != ((uint8_t *)np->tcph - (uint8_t *)np->ip6h)) { return 0; } FlowShutdown(); PACKET_CLEANUP(p); SCFree(p); return 1; } #endif /* UNITTESTS */ void StreamTcpRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("StreamTcpTest01 -- TCP session allocation", StreamTcpTest01, 1); UtRegisterTest("StreamTcpTest02 -- TCP session deallocation", StreamTcpTest02, 1); UtRegisterTest("StreamTcpTest03 -- SYN missed MidStream session", StreamTcpTest03, 1); UtRegisterTest("StreamTcpTest04 -- SYN/ACK missed MidStream session", StreamTcpTest04, 1); UtRegisterTest("StreamTcpTest05 -- 3WHS missed MidStream session", StreamTcpTest05, 1); UtRegisterTest("StreamTcpTest06 -- FIN, RST message MidStream session", StreamTcpTest06, 1); UtRegisterTest("StreamTcpTest07 -- PAWS invalid timestamp", StreamTcpTest07, 1); UtRegisterTest("StreamTcpTest08 -- PAWS valid timestamp", StreamTcpTest08, 1); UtRegisterTest("StreamTcpTest09 -- No Client Reassembly", StreamTcpTest09, 1); UtRegisterTest("StreamTcpTest10 -- No missed packet Async stream", StreamTcpTest10, 1); UtRegisterTest("StreamTcpTest11 -- SYN missed Async stream", StreamTcpTest11, 1); UtRegisterTest("StreamTcpTest12 -- SYN/ACK missed Async stream", StreamTcpTest12, 1); UtRegisterTest("StreamTcpTest13 -- opposite stream packets for Async " "stream", StreamTcpTest13, 1); UtRegisterTest("StreamTcp4WHSTest01", StreamTcp4WHSTest01, 1); UtRegisterTest("StreamTcp4WHSTest02", StreamTcp4WHSTest02, 1); UtRegisterTest("StreamTcp4WHSTest03", StreamTcp4WHSTest03, 1); UtRegisterTest("StreamTcpTest14 -- setup OS policy", StreamTcpTest14, 1); UtRegisterTest("StreamTcpTest15 -- setup OS policy", StreamTcpTest15, 1); UtRegisterTest("StreamTcpTest16 -- setup OS policy", StreamTcpTest16, 1); UtRegisterTest("StreamTcpTest17 -- setup OS policy", StreamTcpTest17, 1); UtRegisterTest("StreamTcpTest18 -- setup OS policy", StreamTcpTest18, 1); UtRegisterTest("StreamTcpTest19 -- setup OS policy", StreamTcpTest19, 1); UtRegisterTest("StreamTcpTest20 -- setup OS policy", StreamTcpTest20, 1); UtRegisterTest("StreamTcpTest21 -- setup OS policy", StreamTcpTest21, 1); UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22, 1); UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23, 1); UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24, 1); UtRegisterTest("StreamTcpTest25 -- test ecn/cwr sessions", StreamTcpTest25, 1); UtRegisterTest("StreamTcpTest26 -- test ecn/cwr sessions", StreamTcpTest26, 1); UtRegisterTest("StreamTcpTest27 -- test ecn/cwr sessions", StreamTcpTest27, 1); UtRegisterTest("StreamTcpTest28 -- Memcap Test", StreamTcpTest28, 1); #if 0 /* VJ 2010/09/01 disabled since they blow up on Fedora and Fedora is * right about blowing up. The checksum functions are not used properly * in the tests. */ UtRegisterTest("StreamTcpTest29 -- Badchecksum Reset Test", StreamTcpTest29, 1); UtRegisterTest("StreamTcpTest30 -- Badchecksum Overlap Test", StreamTcpTest30, 1); UtRegisterTest("StreamTcpTest31 -- MultipleSyns Test", StreamTcpTest31, 1); UtRegisterTest("StreamTcpTest32 -- Bogus CWR Test", StreamTcpTest32, 1); UtRegisterTest("StreamTcpTest33 -- RST-SYN Again Test", StreamTcpTest33, 1); UtRegisterTest("StreamTcpTest34 -- SYN-PUSH Test", StreamTcpTest34, 1); UtRegisterTest("StreamTcpTest35 -- SYN-URG Test", StreamTcpTest35, 1); UtRegisterTest("StreamTcpTest36 -- PUSH-URG Test", StreamTcpTest36, 1); #endif UtRegisterTest("StreamTcpTest37 -- Out of order FIN Test", StreamTcpTest37, 1); UtRegisterTest("StreamTcpTest38 -- validate ACK", StreamTcpTest38, 1); UtRegisterTest("StreamTcpTest39 -- update next_seq", StreamTcpTest39, 1); UtRegisterTest("StreamTcpTest40 -- pseudo setup", StreamTcpTest40, 1); UtRegisterTest("StreamTcpTest41 -- pseudo setup", StreamTcpTest41, 1); /* set up the reassembly tests as well */ StreamTcpReassembleRegisterTests(); StreamTcpSackRegisterTests (); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-print.c0000644000000000000000000001733112253546156013305 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Print utility functions */ #include "suricata-common.h" #include "util-print.h" #include "util-error.h" #include "util-debug.h" /** * \brief print a buffer as hex on a single line * * Prints in the format "00 AA BB" * * \param fp FILE pointer to print to * \param buf buffer to print from * \param buflen length of the input buffer */ void PrintRawLineHexFp(FILE *fp, uint8_t *buf, uint32_t buflen) { #define BUFFER_LENGTH 2048 char nbuf[BUFFER_LENGTH] = ""; uint32_t offset = 0; uint32_t u = 0; for (u = 0; u < buflen; u++) { PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "%02X ", buf[u]); } fprintf(fp, "%s", nbuf); } /** * \brief print a buffer as hex on a single line in to retbuf buffer * * Prints in the format "00 AA BB" * * \param retbuf pointer to the buffer which will have the result * \param rebuflen lenght of the buffer * \param buf buffer to print from * \param buflen length of the input buffer */ void PrintRawLineHexBuf(char *retbuf, uint32_t retbuflen, uint8_t *buf, uint32_t buflen) { uint32_t offset = 0; uint32_t u = 0; for (u = 0; u < buflen; u++) { PrintBufferData(retbuf, &offset, retbuflen, "%02X ", buf[u]); } } void PrintRawJsonFp(FILE *fp, uint8_t *buf, uint32_t buflen) { #define BUFFER_LENGTH 2048 char nbuf[BUFFER_LENGTH] = ""; uint32_t offset = 0; uint32_t u = 0; for (u = 0; u < buflen; u++) { if (buf[u] == '\\' || buf[u] == '/' || buf[u] == '\"') { PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "\\%c", buf[u]); } else if (isprint(buf[u])) { PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "%c", buf[u]); } else { PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "\\\\x%02X", buf[u]); } } fprintf(fp, "%s", nbuf); } void PrintRawUriFp(FILE *fp, uint8_t *buf, uint32_t buflen) { #define BUFFER_LENGTH 2048 char nbuf[BUFFER_LENGTH] = ""; uint32_t offset = 0; uint32_t u = 0; for (u = 0; u < buflen; u++) { if (isprint(buf[u]) && buf[u] != '\"') { PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "%c", buf[u]); } else { PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "\\x%02X", buf[u]); } } fprintf(fp, "%s", nbuf); } void PrintRawUriBuf(char *retbuf, uint32_t *offset, uint32_t retbuflen, uint8_t *buf, uint32_t buflen) { uint32_t u = 0; for (u = 0; u < buflen; u++) { if (isprint(buf[u]) && buf[u] != '\"') { if (buf[u] == '\\') { PrintBufferData(retbuf, offset, retbuflen, "\\\\"); } else { PrintBufferData(retbuf, offset, retbuflen, "%c", buf[u]); } } else { PrintBufferData(retbuf, offset, retbuflen, "\\x%02X", buf[u]); } } return; } void PrintRawDataFp(FILE *fp, uint8_t *buf, uint32_t buflen) { int ch = 0; uint32_t u = 0; for (u = 0; u < buflen; u+=16) { fprintf(fp ," %04X ", u); for (ch = 0; (u+ch) < buflen && ch < 16; ch++) { fprintf(fp, "%02X ", (uint8_t)buf[u+ch]); if (ch == 7) fprintf(fp, " "); } if (ch == 16) fprintf(fp, " "); else if (ch < 8) { int spaces = (16 - ch) * 3 + 2 + 1; int s = 0; for ( ; s < spaces; s++) fprintf(fp, " "); } else if(ch < 16) { int spaces = (16 - ch) * 3 + 2; int s = 0; for ( ; s < spaces; s++) fprintf(fp, " "); } for (ch = 0; (u+ch) < buflen && ch < 16; ch++) { fprintf(fp, "%c", isprint((uint8_t)buf[u+ch]) ? (uint8_t)buf[u+ch] : '.'); if (ch == 7) fprintf(fp, " "); if (ch == 15) fprintf(fp, "\n"); } } if (ch != 16) fprintf(fp, "\n"); } void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, uint8_t *src_buf, uint32_t src_buf_len) { int ch = 0; uint32_t u = 0; for (u = 0; u < src_buf_len; u+=16) { PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " %04X ", u); for (ch = 0; (u + ch) < src_buf_len && ch < 16; ch++) { PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "%02X ", (uint8_t)src_buf[u + ch]); if (ch == 7) { PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); } } if (ch == 16) { PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); } else if (ch < 8) { int spaces = (16 - ch) * 3 + 2 + 1; int s = 0; for ( ; s < spaces; s++) PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); } else if(ch < 16) { int spaces = (16 - ch) * 3 + 2; int s = 0; for ( ; s < spaces; s++) PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); } for (ch = 0; (u+ch) < src_buf_len && ch < 16; ch++) { PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "%c", isprint((uint8_t)src_buf[u + ch]) ? (uint8_t)src_buf[u + ch] : '.'); if (ch == 7) PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); if (ch == 15) PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "\n"); } } if (ch != 16) PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "\n"); return; } #ifndef s6_addr16 # define s6_addr16 __u6_addr.__u6_addr16 #endif static const char *PrintInetIPv6(const void *src, char *dst, socklen_t size) { struct in6_addr * insrc = (struct in6_addr *) src; int i; char s_part[6]; /* current IPv6 format is fixed size */ if (size < 8 * 5) { SCLogWarning(SC_ERR_ARG_LEN_LONG, "Too small buffer to write IPv6 address"); return NULL; } memset(dst, 0, size); for(i = 0; i < 8; i++) { snprintf(s_part, 6, "%04x:", htons(insrc->s6_addr16[i])); strlcat(dst, s_part, size); } /* suppress last ':' */ dst[strlen(dst) - 1] = 0; return dst; } const char *PrintInet(int af, const void *src, char *dst, socklen_t size) { switch (af) { case AF_INET: return inet_ntop(af, src, dst, size); case AF_INET6: /* Format IPv6 without deleting zeroes */ return PrintInetIPv6(src, dst, size); default: SCLogError(SC_ERR_INVALID_VALUE, "Unsupported protocol: %d", af); } return NULL; } suricata-1.4.7/src/util-decode-der-get.c0000644000000000000000000001776612253546156014735 00000000000000/* * Copyright (C) 2011-2012 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * \author Pierre Chifflier * */ #include "suricata-common.h" #include "util-decode-der.h" #include "util-decode-der-get.h" static const uint8_t SEQ_IDX_ISSUER[] = { 0, 2 }; static const uint8_t SEQ_IDX_SUBJECT[] = { 0, 4 }; static const char *Oid2ShortStr(const char *oid) { if (strcmp(oid, "1.2.840.113549.1.9.1")==0) return "emailAddress"; if (strcmp(oid, "2.5.4.3")==0) return "CN"; if (strcmp(oid, "2.5.4.5")==0) return "serialNumber"; if (strcmp(oid, "2.5.4.6")==0) return "C"; if (strcmp(oid, "2.5.4.7")==0) return "L"; if (strcmp(oid, "2.5.4.8")==0) return "ST"; if (strcmp(oid, "2.5.4.10")==0) return "O"; if (strcmp(oid, "2.5.4.11")==0) return "OU"; return "unknown"; } /** * \brief Iterate through an ASN.1 structure, following the index sequence. * Context specific elements are skipped. * * \retval The matching node, or NULL */ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, const uint32_t seqsz, uint32_t *errcode) { const Asn1Generic * node; uint8_t idx, i; uint8_t offset = 0; if (errcode) *errcode = ERR_DER_MISSING_ELEMENT; node = top; if (node == NULL || seq_index == NULL) return NULL; for (offset=0; offsetdata == NULL) return NULL; /* skip context-specific elements */ while (node->data->header.cls == ASN1_CLASS_CONTEXTSPEC) { node = node->next; if (node == NULL || node->data == NULL) return NULL; } node = node->next; if (node == NULL || node->data == NULL) return NULL; } /* skip context-specific elements */ if (node == NULL || node->data == NULL) return NULL; while (node->data->header.cls == ASN1_CLASS_CONTEXTSPEC) { node = node->next; if (node == NULL || node->data == NULL) return NULL; } node = node->data; } if (errcode) *errcode = 0; return node; } int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode) { const Asn1Generic *node_oid; const Asn1Generic *node, *it; const Asn1Generic *node_set; const Asn1Generic *node_str; const char *shortname; int rc = -1; const char *separator = ", "; if (errcode) *errcode = ERR_DER_MISSING_ELEMENT; if (length < 10) goto issuer_dn_error; buffer[0] = '\0'; node = Asn1DerGet(cert, SEQ_IDX_ISSUER, sizeof(SEQ_IDX_ISSUER), errcode); if ((node == NULL) || node->type != ASN1_SEQUENCE) goto issuer_dn_error; it = node; while (it != NULL) { if (it->data == NULL) goto issuer_dn_error; node_set = it->data; if (node_set->type != ASN1_SET || node_set->data == NULL) goto issuer_dn_error; node = node_set->data; if (node->type != ASN1_SEQUENCE || node->data == NULL) goto issuer_dn_error; node_oid = node->data; if (node_oid->str == NULL || node_oid->type != ASN1_OID) goto issuer_dn_error; shortname = Oid2ShortStr(node_oid->str); if (node->next == NULL) goto issuer_dn_error; node = node->next; node_str = node->data; if (node_str == NULL || node_str->str == NULL) goto issuer_dn_error; switch (node_str->type) { case ASN1_PRINTSTRING: case ASN1_IA5STRING: case ASN1_T61STRING: case ASN1_UTF8STRING: case ASN1_OCTETSTRING: strlcat(buffer, shortname, length); strlcat(buffer, "=", length); strlcat(buffer, node_str->str, length); break; default: if (errcode) *errcode = ERR_DER_UNSUPPORTED_STRING; goto issuer_dn_error; } if (strcmp(shortname,"CN")==0) separator = "/"; if (it->next != NULL) strlcat(buffer, separator, length); it = it->next; } if (errcode) *errcode = 0; rc = 0; issuer_dn_error: return rc; } int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode) { const Asn1Generic *node_oid; const Asn1Generic *node, *it; const Asn1Generic *node_set; const Asn1Generic *node_str; const char *shortname; int rc = -1; const char *separator = ", "; if (errcode) *errcode = ERR_DER_MISSING_ELEMENT; if (length < 10) goto subject_dn_error; buffer[0] = '\0'; node = Asn1DerGet(cert, SEQ_IDX_SUBJECT, sizeof(SEQ_IDX_SUBJECT), errcode); if ((node == NULL) || node->type != ASN1_SEQUENCE) goto subject_dn_error; it = node; while (it != NULL) { if (it == NULL || it->data == NULL) goto subject_dn_error; node_set = it->data; if (node_set->type != ASN1_SET || node_set->data == NULL) goto subject_dn_error; node = node_set->data; if (node->type != ASN1_SEQUENCE || node->data == NULL) goto subject_dn_error; node_oid = node->data; if (node_oid->str == NULL || node_oid->type != ASN1_OID) goto subject_dn_error; shortname = Oid2ShortStr(node_oid->str); if (node->next == NULL) goto subject_dn_error; node = node->next; node_str = node->data; if (node_str == NULL || node_str->str == NULL) goto subject_dn_error; switch (node_str->type) { case ASN1_PRINTSTRING: case ASN1_IA5STRING: case ASN1_T61STRING: case ASN1_UTF8STRING: case ASN1_OCTETSTRING: strlcat(buffer, shortname, length); strlcat(buffer, "=", length); strlcat(buffer, node_str->str, length); break; default: if (errcode) *errcode = ERR_DER_UNSUPPORTED_STRING; goto subject_dn_error; } if (strcmp(shortname,"CN")==0) separator = "/"; if (it->next != NULL) strlcat(buffer, separator, length); it = it->next; } if (errcode) *errcode = 0; rc = 0; subject_dn_error: return rc; } /* vim: set et ts=4 sw=4: */ suricata-1.4.7/src/decode-sctp.c0000644000000000000000000000365712253546156013376 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Eric Leblond * * Decode SCTP */ #include "suricata-common.h" #include "decode.h" #include "decode-sctp.h" #include "decode-events.h" #include "util-unittest.h" #include "util-debug.h" #include "util-optimize.h" #include "flow.h" static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len) { if (unlikely(len < SCTP_HEADER_LEN)) { ENGINE_SET_EVENT(p, SCTP_PKT_TOO_SMALL); return -1; } p->sctph = (SCTPHdr *)pkt; SET_SCTP_SRC_PORT(p,&p->sp); SET_SCTP_DST_PORT(p,&p->dp); p->payload = pkt + sizeof(SCTPHdr); p->payload_len = len - sizeof(SCTPHdr); p->proto = IPPROTO_SCTP; return 0; } void DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_sctp, tv->sc_perf_pca); if (unlikely(DecodeSCTPPacket(tv, p,pkt,len) < 0)) { p->sctph = NULL; return; } #ifdef DEBUG SCLogDebug("SCTP sp: %" PRIu32 " -> dp: %" PRIu32, SCTP_GET_SRC_PORT(p), SCTP_GET_DST_PORT(p)); #endif /* Flow is an integral part of us */ FlowHandlePacket(tv, p); return; } /** * @} */ suricata-1.4.7/src/runmode-pfring.h0000644000000000000000000000225612253546156014137 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien */ #ifndef __RUNMODE_PFRING_H__ #define __RUNMODE_PFRING_H__ #include "suricata-common.h" int RunModeIdsPfringAuto(DetectEngineCtx *); int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx); int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx); int RunModeIdsPfringWorkers(DetectEngineCtx *de_ctx); void RunModeIdsPfringRegister(void); const char *RunModeIdsPfringGetDefaultMode(void); #endif /* __RUNMODE_PFRING_H__ */ suricata-1.4.7/src/flow-manager.c0000644000000000000000000006034312253546156013556 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * \author Victor Julien */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "conf.h" #include "threadvars.h" #include "tm-threads.h" #include "runmodes.h" #include "util-random.h" #include "util-time.h" #include "flow.h" #include "flow-queue.h" #include "flow-hash.h" #include "flow-util.h" #include "flow-var.h" #include "flow-private.h" #include "flow-timeout.h" #include "flow-manager.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-byte.h" #include "util-debug.h" #include "util-privs.h" #include "util-signal.h" #include "threads.h" #include "detect.h" #include "detect-engine-state.h" #include "stream.h" #include "app-layer-parser.h" #include "host-timeout.h" #include "defrag-timeout.h" /* Run mode selected at suricata.c */ extern int run_mode; SC_ATOMIC_EXTERN(unsigned char, flow_flags); /* 1 seconds */ #define FLOW_NORMAL_MODE_UPDATE_DELAY_SEC 1 #define FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC 0 /* 0.1 seconds */ #define FLOW_EMERG_MODE_UPDATE_DELAY_SEC 0 #define FLOW_EMERG_MODE_UPDATE_DELAY_NSEC 100000 #define NEW_FLOW_COUNT_COND 10 typedef struct FlowTimeoutCounters_ { uint32_t new; uint32_t est; uint32_t clo; } FlowTimeoutCounters; /** * \brief Used to kill flow manager thread(s). * * \todo Kinda hackish since it uses the tv name to identify flow manager * thread. We need an all weather identification scheme. */ void FlowKillFlowManagerThread(void) { ThreadVars *tv = NULL; int cnt = 0; SCCondSignal(&flow_manager_cond); SCMutexLock(&tv_root_lock); /* flow manager thread(s) is/are a part of mgmt threads */ tv = tv_root[TVT_MGMT]; while (tv != NULL) { if (strcasecmp(tv->name, "FlowManagerThread") == 0) { TmThreadsSetFlag(tv, THV_KILL); TmThreadsSetFlag(tv, THV_DEINIT); /* be sure it has shut down */ while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { usleep(100); } cnt++; } tv = tv->next; } /* not possible, unless someone decides to rename FlowManagerThread */ if (cnt == 0) { SCMutexUnlock(&tv_root_lock); abort(); } SCMutexUnlock(&tv_root_lock); return; } /** \internal * \brief Get the flow's state * * \param f flow * * \retval state either FLOW_STATE_NEW, FLOW_STATE_ESTABLISHED or FLOW_STATE_CLOSED */ static inline int FlowGetFlowState(Flow *f) { if (flow_proto[f->protomap].GetProtoState != NULL) { return flow_proto[f->protomap].GetProtoState(f->protoctx); } else { if ((f->flags & FLOW_TO_SRC_SEEN) && (f->flags & FLOW_TO_DST_SEEN)) return FLOW_STATE_ESTABLISHED; else return FLOW_STATE_NEW; } } /** \internal * \brief get timeout for flow * * \param f flow * \param state flow state * \param emergency bool indicating emergency mode 1 yes, 0 no * * \retval timeout timeout in seconds */ static inline uint32_t FlowGetFlowTimeout(Flow *f, int state, int emergency) { uint32_t timeout; if (emergency) { switch(state) { default: case FLOW_STATE_NEW: timeout = flow_proto[f->protomap].emerg_new_timeout; break; case FLOW_STATE_ESTABLISHED: timeout = flow_proto[f->protomap].emerg_est_timeout; break; case FLOW_STATE_CLOSED: timeout = flow_proto[f->protomap].emerg_closed_timeout; break; } } else { /* implies no emergency */ switch(state) { default: case FLOW_STATE_NEW: timeout = flow_proto[f->protomap].new_timeout; break; case FLOW_STATE_ESTABLISHED: timeout = flow_proto[f->protomap].est_timeout; break; case FLOW_STATE_CLOSED: timeout = flow_proto[f->protomap].closed_timeout; break; } } return timeout; } /** \internal * \brief check if a flow is timed out * * \param f flow * \param ts timestamp * \param emergency bool indicating emergency mode * * \retval 0 not timed out * \retval 1 timed out */ static int FlowManagerFlowTimeout(Flow *f, int state, struct timeval *ts, int emergency) { /* set the timeout value according to the flow operating mode, * flow's state and protocol.*/ uint32_t timeout = FlowGetFlowTimeout(f, state, emergency); /* do the timeout check */ if ((int32_t)(f->lastts_sec + timeout) >= ts->tv_sec) { return 0; } return 1; } /** \internal * \brief See if we can really discard this flow. Check use_cnt reference * counter and force reassembly if necessary. * * \param f flow * \param ts timestamp * \param emergency bool indicating emergency mode * * \retval 0 not timed out just yet * \retval 1 fully timed out, lets kill it */ static int FlowManagerFlowTimedOut(Flow *f, struct timeval *ts) { /** never prune a flow that is used by a packet or stream msg * we are currently processing in one of the threads */ if (SC_ATOMIC_GET(f->use_cnt) > 0) { return 0; } int server = 0, client = 0; if (FlowForceReassemblyNeedReassmbly(f, &server, &client) == 1) { FlowForceReassemblyForFlowV2(f, server, client); return 0; } #ifdef DEBUG /* this should not be possible */ BUG_ON(SC_ATOMIC_GET(f->use_cnt) > 0); #endif return 1; } /** * \internal * * \brief check all flows in a hash row for timing out * * \param f last flow in the hash row * \param ts timestamp * \param emergency bool indicating emergency mode * \param counters ptr to FlowTimeoutCounters structure * * \retval cnt timed out flows */ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, int emergency, FlowTimeoutCounters *counters) { uint32_t cnt = 0; do { if (FLOWLOCK_TRYWRLOCK(f) != 0) { f = f->hprev; continue; } Flow *next_flow = f->hprev; int state = FlowGetFlowState(f); /* timeout logic goes here */ if (FlowManagerFlowTimeout(f, state, ts, emergency) == 0) { FLOWLOCK_UNLOCK(f); f = f->hprev; continue; } /* check if the flow is fully timed out and * ready to be discarded. */ if (FlowManagerFlowTimedOut(f, ts) == 1) { /* remove from the hash */ if (f->hprev != NULL) f->hprev->hnext = f->hnext; if (f->hnext != NULL) f->hnext->hprev = f->hprev; if (f->fb->head == f) f->fb->head = f->hnext; if (f->fb->tail == f) f->fb->tail = f->hprev; f->hnext = NULL; f->hprev = NULL; FlowClearMemory (f, f->protomap); /* no one is referring to this flow, use_cnt 0, removed from hash * so we can unlock it and move it back to the spare queue. */ FLOWLOCK_UNLOCK(f); /* move to spare list */ FlowMoveToSpare(f); cnt++; switch (state) { case FLOW_STATE_NEW: default: counters->new++; break; case FLOW_STATE_ESTABLISHED: counters->est++; break; case FLOW_STATE_CLOSED: counters->clo++; break; } } else { FLOWLOCK_UNLOCK(f); } f = next_flow; } while (f != NULL); return cnt; } /** * \brief time out flows from the hash * * \param ts timestamp * \param try_cnt number of flows to time out max (0 is unlimited) * \param counters ptr to FlowTimeoutCounters structure * * \retval cnt number of timed out flow */ uint32_t FlowTimeoutHash(struct timeval *ts, uint32_t try_cnt, FlowTimeoutCounters *counters) { uint32_t idx = 0; uint32_t cnt = 0; int emergency = 0; if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) emergency = 1; for (idx = 0; idx < flow_config.hash_size; idx++) { FlowBucket *fb = &flow_hash[idx]; if (FBLOCK_TRYLOCK(fb) != 0) continue; /* flow hash bucket is now locked */ if (fb->tail == NULL) goto next; /* we have a flow, or more than one */ cnt += FlowManagerHashRowTimeout(fb->tail, ts, emergency, counters); next: FBLOCK_UNLOCK(fb); if (try_cnt > 0 && cnt >= try_cnt) break; } return cnt; } /** \brief Thread that manages the flow table and times out flows. * * \param td ThreadVars casted to void ptr * * Keeps an eye on the spare list, alloc flows if needed... */ void *FlowManagerThread(void *td) { /* block usr1. usr1 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *th_v = (ThreadVars *)td; struct timeval ts; uint32_t established_cnt = 0, new_cnt = 0, closing_cnt = 0; int emerg = FALSE; int prev_emerg = FALSE; uint32_t last_sec = 0; struct timespec cond_time; int flow_update_delay_sec = FLOW_NORMAL_MODE_UPDATE_DELAY_SEC; int flow_update_delay_nsec = FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC; /* VJ leaving disabled for now, as hosts are only used by tags and the numbers * are really low. Might confuse ppl uint16_t flow_mgr_host_prune = SCPerfTVRegisterCounter("hosts.pruned", th_v, SC_PERF_TYPE_UINT64, "NULL"); uint16_t flow_mgr_host_active = SCPerfTVRegisterCounter("hosts.active", th_v, SC_PERF_TYPE_Q_NORMAL, "NULL"); uint16_t flow_mgr_host_spare = SCPerfTVRegisterCounter("hosts.spare", th_v, SC_PERF_TYPE_Q_NORMAL, "NULL"); */ uint16_t flow_mgr_cnt_clo = SCPerfTVRegisterCounter("flow_mgr.closed_pruned", th_v, SC_PERF_TYPE_UINT64, "NULL"); uint16_t flow_mgr_cnt_new = SCPerfTVRegisterCounter("flow_mgr.new_pruned", th_v, SC_PERF_TYPE_UINT64, "NULL"); uint16_t flow_mgr_cnt_est = SCPerfTVRegisterCounter("flow_mgr.est_pruned", th_v, SC_PERF_TYPE_UINT64, "NULL"); uint16_t flow_mgr_memuse = SCPerfTVRegisterCounter("flow.memuse", th_v, SC_PERF_TYPE_Q_NORMAL, "NULL"); uint16_t flow_mgr_spare = SCPerfTVRegisterCounter("flow.spare", th_v, SC_PERF_TYPE_Q_NORMAL, "NULL"); uint16_t flow_emerg_mode_enter = SCPerfTVRegisterCounter("flow.emerg_mode_entered", th_v, SC_PERF_TYPE_UINT64, "NULL"); uint16_t flow_emerg_mode_over = SCPerfTVRegisterCounter("flow.emerg_mode_over", th_v, SC_PERF_TYPE_UINT64, "NULL"); if (th_v->thread_setup_flags != 0) TmThreadSetupOptions(th_v); memset(&ts, 0, sizeof(ts)); FlowForceReassemblySetup(); /* set the thread name */ if (SCSetThreadName(th_v->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } else { SCLogDebug("%s started...", th_v->name); } th_v->sc_perf_pca = SCPerfGetAllCountersArray(&th_v->sc_perf_pctx); SCPerfAddToClubbedTMTable(th_v->name, &th_v->sc_perf_pctx); /* Set the threads capability */ th_v->cap_flags = 0; SCDropCaps(th_v); FlowHashDebugInit(); TmThreadsSetFlag(th_v, THV_INIT_DONE); while (1) { if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { TmThreadsSetFlag(th_v, THV_PAUSED); TmThreadTestThreadUnPaused(th_v); TmThreadsUnsetFlag(th_v, THV_PAUSED); } if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) { emerg = TRUE; if (emerg == TRUE && prev_emerg == FALSE) { prev_emerg = TRUE; SCLogDebug("Flow emergency mode entered..."); SCPerfCounterIncr(flow_emerg_mode_enter, th_v->sc_perf_pca); } } /* Get the time */ memset(&ts, 0, sizeof(ts)); TimeGet(&ts); SCLogDebug("ts %" PRIdMAX "", (intmax_t)ts.tv_sec); if (((uint32_t)ts.tv_sec - last_sec) > 600) { FlowHashDebugPrint((uint32_t)ts.tv_sec); last_sec = (uint32_t)ts.tv_sec; } /* see if we still have enough spare flows */ FlowUpdateSpareFlows(); /* try to time out flows */ FlowTimeoutCounters counters = { 0, 0, 0, }; FlowTimeoutHash(&ts, 0 /* check all */, &counters); DefragTimeoutHash(&ts); //uint32_t hosts_pruned = HostTimeoutHash(&ts); /* SCPerfCounterAddUI64(flow_mgr_host_prune, th_v->sc_perf_pca, (uint64_t)hosts_pruned); uint32_t hosts_active = HostGetActiveCount(); SCPerfCounterSetUI64(flow_mgr_host_active, th_v->sc_perf_pca, (uint64_t)hosts_active); uint32_t hosts_spare = HostGetSpareCount(); SCPerfCounterSetUI64(flow_mgr_host_spare, th_v->sc_perf_pca, (uint64_t)hosts_spare); */ SCPerfCounterAddUI64(flow_mgr_cnt_clo, th_v->sc_perf_pca, (uint64_t)counters.clo); SCPerfCounterAddUI64(flow_mgr_cnt_new, th_v->sc_perf_pca, (uint64_t)counters.new); SCPerfCounterAddUI64(flow_mgr_cnt_est, th_v->sc_perf_pca, (uint64_t)counters.est); long long unsigned int flow_memuse = SC_ATOMIC_GET(flow_memuse); SCPerfCounterSetUI64(flow_mgr_memuse, th_v->sc_perf_pca, (uint64_t)flow_memuse); uint32_t len = 0; FQLOCK_LOCK(&flow_spare_q); len = flow_spare_q.len; FQLOCK_UNLOCK(&flow_spare_q); SCPerfCounterSetUI64(flow_mgr_spare, th_v->sc_perf_pca, (uint64_t)len); /* Don't fear, FlowManagerThread is here... * clear emergency bit if we have at least xx flows pruned. */ if (emerg == TRUE) { SCLogDebug("flow_sparse_q.len = %"PRIu32" prealloc: %"PRIu32 "flow_spare_q status: %"PRIu32"%% flows at the queue", len, flow_config.prealloc, len * 100 / flow_config.prealloc); /* only if we have pruned this "emergency_recovery" percentage * of flows, we will unset the emergency bit */ if (len * 100 / flow_config.prealloc > flow_config.emergency_recovery) { SC_ATOMIC_AND(flow_flags, ~FLOW_EMERGENCY); emerg = FALSE; prev_emerg = FALSE; flow_update_delay_sec = FLOW_NORMAL_MODE_UPDATE_DELAY_SEC; flow_update_delay_nsec = FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC; SCLogInfo("Flow emergency mode over, back to normal... unsetting" " FLOW_EMERGENCY bit (ts.tv_sec: %"PRIuMAX", " "ts.tv_usec:%"PRIuMAX") flow_spare_q status(): %"PRIu32 "%% flows at the queue", (uintmax_t)ts.tv_sec, (uintmax_t)ts.tv_usec, len * 100 / flow_config.prealloc); SCPerfCounterIncr(flow_emerg_mode_over, th_v->sc_perf_pca); } else { flow_update_delay_sec = FLOW_EMERG_MODE_UPDATE_DELAY_SEC; flow_update_delay_nsec = FLOW_EMERG_MODE_UPDATE_DELAY_NSEC; } } if (TmThreadsCheckFlag(th_v, THV_KILL)) { SCPerfSyncCounters(th_v, 0); break; } cond_time.tv_sec = time(NULL) + flow_update_delay_sec; cond_time.tv_nsec = flow_update_delay_nsec; SCMutexLock(&flow_manager_mutex); SCCondTimedwait(&flow_manager_cond, &flow_manager_mutex, &cond_time); SCMutexUnlock(&flow_manager_mutex); SCLogDebug("woke up... %s", SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY ? "emergency":""); SCPerfSyncCountersIfSignalled(th_v, 0); } TmThreadsSetFlag(th_v, THV_RUNNING_DONE); TmThreadWaitForFlag(th_v, THV_DEINIT); FlowHashDebugDeinit(); SCLogInfo("%" PRIu32 " new flows, %" PRIu32 " established flows were " "timed out, %"PRIu32" flows in closed state", new_cnt, established_cnt, closing_cnt); TmThreadsSetFlag(th_v, THV_CLOSED); pthread_exit((void *) 0); return NULL; } /** \brief spawn the flow manager thread */ void FlowManagerThreadSpawn() { ThreadVars *tv_flowmgr = NULL; SCCondInit(&flow_manager_cond, NULL); SCMutexInit(&flow_manager_mutex, NULL); tv_flowmgr = TmThreadCreateMgmtThread("FlowManagerThread", FlowManagerThread, 0); TmThreadSetCPU(tv_flowmgr, MANAGEMENT_CPU_SET); if (tv_flowmgr == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(1); } if (TmThreadSpawn(tv_flowmgr) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(1); } return; } #ifdef UNITTESTS /** * \test Test the timing out of a flow with a fresh TcpSession * (just initialized, no data segments) in normal mode. * * \retval On success it returns 1 and on failure 0. */ static int FlowMgrTest01 (void) { TcpSession ssn; Flow f; FlowBucket fb; struct timeval ts; FlowQueueInit(&flow_spare_q); memset(&ssn, 0, sizeof(TcpSession)); memset(&f, 0, sizeof(Flow)); memset(&ts, 0, sizeof(ts)); memset(&fb, 0, sizeof(FlowBucket)); FBLOCK_INIT(&fb); FLOW_INITIALIZE(&f); f.flags |= FLOW_TIMEOUT_REASSEMBLY_DONE; TimeGet(&ts); f.lastts_sec = ts.tv_sec - 5000; f.protoctx = &ssn; f.fb = &fb; f.proto = IPPROTO_TCP; int state = FlowGetFlowState(&f); if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); return 0; } FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); return 1; } /** * \test Test the timing out of a flow with a TcpSession * (with data segments) in normal mode. * * \retval On success it returns 1 and on failure 0. */ static int FlowMgrTest02 (void) { TcpSession ssn; Flow f; FlowBucket fb; struct timeval ts; TcpSegment seg; TcpStream client; uint8_t payload[3] = {0x41, 0x41, 0x41}; FlowQueueInit(&flow_spare_q); memset(&ssn, 0, sizeof(TcpSession)); memset(&f, 0, sizeof(Flow)); memset(&fb, 0, sizeof(FlowBucket)); memset(&ts, 0, sizeof(ts)); memset(&seg, 0, sizeof(TcpSegment)); memset(&client, 0, sizeof(TcpSegment)); FBLOCK_INIT(&fb); FLOW_INITIALIZE(&f); f.flags |= FLOW_TIMEOUT_REASSEMBLY_DONE; TimeGet(&ts); seg.payload = payload; seg.payload_len = 3; seg.next = NULL; seg.prev = NULL; client.seg_list = &seg; ssn.client = client; ssn.server = client; ssn.state = TCP_ESTABLISHED; f.lastts_sec = ts.tv_sec - 5000; f.protoctx = &ssn; f.fb = &fb; f.proto = IPPROTO_TCP; int state = FlowGetFlowState(&f); if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); return 0; } FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); return 1; } /** * \test Test the timing out of a flow with a fresh TcpSession * (just initialized, no data segments) in emergency mode. * * \retval On success it returns 1 and on failure 0. */ static int FlowMgrTest03 (void) { TcpSession ssn; Flow f; FlowBucket fb; struct timeval ts; FlowQueueInit(&flow_spare_q); memset(&ssn, 0, sizeof(TcpSession)); memset(&f, 0, sizeof(Flow)); memset(&ts, 0, sizeof(ts)); memset(&fb, 0, sizeof(FlowBucket)); FBLOCK_INIT(&fb); FLOW_INITIALIZE(&f); f.flags |= FLOW_TIMEOUT_REASSEMBLY_DONE; TimeGet(&ts); ssn.state = TCP_SYN_SENT; f.lastts_sec = ts.tv_sec - 300; f.protoctx = &ssn; f.fb = &fb; f.proto = IPPROTO_TCP; f.flags |= FLOW_EMERGENCY; int state = FlowGetFlowState(&f); if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); return 0; } FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); return 1; } /** * \test Test the timing out of a flow with a TcpSession * (with data segments) in emergency mode. * * \retval On success it returns 1 and on failure 0. */ static int FlowMgrTest04 (void) { TcpSession ssn; Flow f; FlowBucket fb; struct timeval ts; TcpSegment seg; TcpStream client; uint8_t payload[3] = {0x41, 0x41, 0x41}; FlowQueueInit(&flow_spare_q); memset(&ssn, 0, sizeof(TcpSession)); memset(&f, 0, sizeof(Flow)); memset(&fb, 0, sizeof(FlowBucket)); memset(&ts, 0, sizeof(ts)); memset(&seg, 0, sizeof(TcpSegment)); memset(&client, 0, sizeof(TcpSegment)); FBLOCK_INIT(&fb); FLOW_INITIALIZE(&f); f.flags |= FLOW_TIMEOUT_REASSEMBLY_DONE; TimeGet(&ts); seg.payload = payload; seg.payload_len = 3; seg.next = NULL; seg.prev = NULL; client.seg_list = &seg; ssn.client = client; ssn.server = client; ssn.state = TCP_ESTABLISHED; f.lastts_sec = ts.tv_sec - 5000; f.protoctx = &ssn; f.fb = &fb; f.proto = IPPROTO_TCP; f.flags |= FLOW_EMERGENCY; int state = FlowGetFlowState(&f); if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); return 0; } FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); return 1; } /** * \test Test flow allocations when it reach memcap * * * \retval On success it returns 1 and on failure 0. */ static int FlowMgrTest05 (void) { int result = 0; FlowInitConfig(FLOW_QUIET); FlowConfig backup; memcpy(&backup, &flow_config, sizeof(FlowConfig)); uint32_t ini = 0; uint32_t end = flow_spare_q.len; flow_config.memcap = 10000; flow_config.prealloc = 100; /* Let's get the flow_spare_q empty */ UTHBuildPacketOfFlows(ini, end, 0); /* And now let's try to reach the memcap val */ while (FLOW_CHECK_MEMCAP(sizeof(Flow))) { ini = end + 1; end = end + 2; UTHBuildPacketOfFlows(ini, end, 0); } /* should time out normal */ TimeSetIncrementTime(2000); ini = end + 1; end = end + 2;; UTHBuildPacketOfFlows(ini, end, 0); struct timeval ts; TimeGet(&ts); /* try to time out flows */ FlowTimeoutCounters counters = { 0, 0, 0, }; FlowTimeoutHash(&ts, 0 /* check all */, &counters); if (flow_spare_q.len > 0) { result = 1; } memcpy(&flow_config, &backup, sizeof(FlowConfig)); FlowShutdown(); return result; } #endif /* UNITTESTS */ /** * \brief Function to register the Flow Unitests. */ void FlowMgrRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("FlowMgrTest01 -- Timeout a flow having fresh TcpSession", FlowMgrTest01, 1); UtRegisterTest("FlowMgrTest02 -- Timeout a flow having TcpSession with segments", FlowMgrTest02, 1); UtRegisterTest("FlowMgrTest03 -- Timeout a flow in emergency having fresh TcpSession", FlowMgrTest03, 1); UtRegisterTest("FlowMgrTest04 -- Timeout a flow in emergency having TcpSession with segments", FlowMgrTest04, 1); UtRegisterTest("FlowMgrTest05 -- Test flow Allocations when it reach memcap", FlowMgrTest05, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-flowvar.h0000644000000000000000000000242312253546156014125 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_FLOWVAR_H__ #define __DETECT_FLOWVAR_H__ typedef struct DetectFlowvarData_ { char *name; uint16_t idx; uint8_t *content; uint8_t content_len; uint8_t flags; } DetectFlowvarData; /* prototypes */ void DetectFlowvarRegister (void); int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx); int DetectFlowvarStoreMatch(DetectEngineThreadCtx *, uint16_t, uint8_t *, uint16_t); void DetectFlowvarCleanupList(DetectEngineThreadCtx *det_ctx); #endif /* __DETECT_FLOWVAR_H__ */ suricata-1.4.7/src/app-layer-htp-body.c0000644000000000000000000001360312253546156014612 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Gurvinder Singh * \author Pablo Rincon * \author Brian Rectanus * * This file provides a HTTP protocol support for the engine using HTP library. */ #include "suricata.h" #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "util-radix-tree.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-htp.h" #include "util-spm.h" #include "util-debug.h" #include "app-layer-htp.h" #include "app-layer-htp-file.h" #include "util-time.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "flow-util.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "detect-parse.h" #include "conf.h" #include "util-memcmp.h" /** * \brief Append a chunk of body to the HtpBody struct * * \param body pointer to the HtpBody holding the list * \param data pointer to the data of the chunk * \param len length of the chunk pointed by data * * \retval 0 ok * \retval -1 error */ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32_t len) { SCEnter(); HtpBodyChunk *bd = NULL; if (len == 0 || data == NULL) { SCReturnInt(0); } if (body->first == NULL) { /* New chunk */ bd = (HtpBodyChunk *)SCMalloc(sizeof(HtpBodyChunk)); if (bd == NULL) goto error; bd->len = len; bd->stream_offset = 0; bd->next = NULL; bd->data = SCMalloc(len); if (bd->data == NULL) { goto error; } memcpy(bd->data, data, len); body->first = body->last = bd; body->content_len_so_far = len; } else { bd = (HtpBodyChunk *)SCMalloc(sizeof(HtpBodyChunk)); if (bd == NULL) goto error; bd->len = len; bd->stream_offset = body->content_len_so_far; bd->next = NULL; bd->data = SCMalloc(len); if (bd->data == NULL) { goto error; } memcpy(bd->data, data, len); body->last->next = bd; body->last = bd; body->content_len_so_far += len; } SCLogDebug("Body %p; data %p, len %"PRIu32, body, bd->data, (uint32_t)bd->len); SCReturnInt(0); error: if (bd != NULL) { if (bd->data != NULL) { SCFree(bd->data); } SCFree(bd); } SCReturnInt(-1); } /** * \brief Print the information and chunks of a Body * \param body pointer to the HtpBody holding the list * \retval none */ void HtpBodyPrint(HtpBody *body) { if (SCLogDebugEnabled()||1) { SCEnter(); if (body->first == NULL) return; HtpBodyChunk *cur = NULL; SCLogDebug("--- Start body chunks at %p ---", body); printf("--- Start body chunks at %p ---\n", body); for (cur = body->first; cur != NULL; cur = cur->next) { SCLogDebug("Body %p; data %p, len %"PRIu32, body, cur->data, (uint32_t)cur->len); printf("Body %p; data %p, len %"PRIu32"\n", body, cur->data, (uint32_t)cur->len); PrintRawDataFp(stdout, (uint8_t*)cur->data, cur->len); } SCLogDebug("--- End body chunks at %p ---", body); } } /** * \brief Free the information held in the request body * \param body pointer to the HtpBody holding the list * \retval none */ void HtpBodyFree(HtpBody *body) { SCEnter(); if (body->first == NULL) return; SCLogDebug("Removing chunks of Body %p; data %p, len %"PRIu32, body, body->last->data, (uint32_t)body->last->len); HtpBodyChunk *cur = NULL; HtpBodyChunk *prev = NULL; prev = body->first; while (prev != NULL) { cur = prev->next; if (prev->data != NULL) SCFree(prev->data); SCFree(prev); prev = cur; } body->first = body->last = NULL; } /** * \brief Free request body chunks that are already fully parsed. * * \param htud pointer to the HtpTxUserData holding the body * * \retval none */ void HtpBodyPrune(HtpBody *body) { SCEnter(); if (body == NULL || body->first == NULL) { SCReturn; } if (body->body_parsed == 0) { SCReturn; } SCLogDebug("Pruning chunks of Body %p; data %p, len %"PRIu32, body, body->last->data, (uint32_t)body->last->len); HtpBodyChunk *cur = body->first; while (cur != NULL) { HtpBodyChunk *next = cur->next; SCLogDebug("cur->stream_offset %"PRIu64" + cur->len %u = %"PRIu64", " "body->body_parsed %"PRIu64, cur->stream_offset, cur->len, cur->stream_offset + cur->len, body->body_parsed); if (cur->stream_offset >= body->body_inspected) { break; } body->first = next; if (body->last == cur) { body->last = next; } if (cur->data != NULL) { SCFree(cur->data); } SCFree(cur); cur = next; } SCReturn; } suricata-1.4.7/src/alert-fastlog.h0000644000000000000000000000203612253546156013743 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __ALERT_FASTLOG_H__ #define __ALERT_FASTLOG_H__ void TmModuleAlertFastLogRegister (void); void TmModuleAlertFastLogIPv4Register (void); void TmModuleAlertFastLogIPv6Register (void); OutputCtx *AlertFastLogInitCtx(ConfNode *); #endif /* __ALERT_FASTLOG_H__ */ suricata-1.4.7/src/detect-http-raw-header.h0000644000000000000000000000166712253546156015452 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_HTTP_RAW_HEADER_H__ #define __DETECT_HTTP_RAW_HEADER_H__ void DetectHttpRawHeaderRegister(void); #endif /* __DETECT_HTTP_RAW_HEADER_H__ */ suricata-1.4.7/src/flow-bit.h0000644000000000000000000000265112253546156012725 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __FLOW_BIT_H__ #define __FLOW_BIT_H__ #include "flow.h" #include "util-var.h" typedef struct FlowBit_ { uint8_t type; /* type, DETECT_FLOWBITS in this case */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ uint16_t idx; /* name idx */ } FlowBit; void FlowBitFree(FlowBit *); void FlowBitRegisterTests(void); void FlowBitSet(Flow *, uint16_t); void FlowBitUnset(Flow *, uint16_t); void FlowBitToggle(Flow *, uint16_t); int FlowBitIsset(Flow *, uint16_t); int FlowBitIsnotset(Flow *, uint16_t); #endif /* __FLOW_BIT_H__ */ suricata-1.4.7/src/util-cuda.c0000644000000000000000000047123012253546156013067 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * NVIDIA CUDA utility functions */ /* compile in, only if we have a CUDA enabled device on the machine, with the * toolkit and the driver installed */ #ifdef __SC_CUDA_SUPPORT__ #include #include "util-cuda.h" #include "suricata-common.h" #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" #define CASE_CODE(E) case E: return #E typedef enum SCCudaAPIS_ { /* init api */ SC_CUDA_CU_INIT, /* device management api */ SC_CUDA_CU_DEVICE_GET_COUNT, SC_CUDA_CU_DEVICE_GET, SC_CUDA_CU_DEVICE_GET_NAME, SC_CUDA_CU_DEVICE_TOTAL_MEM, SC_CUDA_CU_DEVICE_COMPUTE_CAPABILITY, SC_CUDA_CU_DEVICE_GET_PROPERTIES, SC_CUDA_CU_DEVICE_GET_ATTRIBUTE, /* version management api */ SC_CUDA_CU_DRIVER_GET_VERSION, /* context management api */ SC_CUDA_CU_CTX_ATTACH, SC_CUDA_CU_CTX_CREATE, SC_CUDA_CU_CTX_DESTROY, SC_CUDA_CU_CTX_DETACH, SC_CUDA_CU_CTX_GET_DEVICE, SC_CUDA_CU_CTX_POP_CURRENT, SC_CUDA_CU_CTX_PUSH_CURRENT, SC_CUDA_CU_CTX_SYNCHRONIZE, /* module management api */ SC_CUDA_CU_MODULE_GET_FUNCTION, SC_CUDA_CU_MODULE_GET_GLOBAL, SC_CUDA_CU_MODULE_GET_TEX_REF, SC_CUDA_CU_MODULE_LOAD, SC_CUDA_CU_MODULE_LOAD_DATA, SC_CUDA_CU_MODULE_LOAD_DATA_EX, SC_CUDA_CU_MODULE_LOAD_FAT_BINARY, SC_CUDA_CU_MODULE_UNLOAD, /* stream management api */ SC_CUDA_CU_STREAM_CREATE, SC_CUDA_CU_STREAM_DESTROY, SC_CUDA_CU_STREAM_QUERY, SC_CUDA_CU_STREAM_SYNCHRONIZE, /* event management api */ SC_CUDA_CU_EVENT_CREATE, SC_CUDA_CU_EVENT_DESTROY, SC_CUDA_CU_EVENT_ELAPSED_TIME, SC_CUDA_CU_EVENT_QUERY, SC_CUDA_CU_EVENT_RECORD, SC_CUDA_CU_EVENT_SYNCHRONIZE, /* execution control api */ SC_CUDA_CU_FUNC_GET_ATTRIBUTE, SC_CUDA_CU_FUNC_SET_BLOCK_SHAPE, SC_CUDA_CU_FUNC_SET_SHARED_SIZE, SC_CUDA_CU_LAUNCH, SC_CUDA_CU_LAUNCH_GRID, SC_CUDA_CU_LAUNCH_GRID_ASYNC, SC_CUDA_CU_PARAM_SETF, SC_CUDA_CU_PARAM_SETI, SC_CUDA_CU_PARAM_SET_SIZE, SC_CUDA_CU_PARAM_SET_TEX_REF, SC_CUDA_CU_PARAM_SETV, /* memory management api */ SC_CUDA_CU_ARRAY_3D_CREATE, SC_CUDA_CU_ARRAY_3D_GET_DESCRIPTOR, SC_CUDA_CU_ARRAY_CREATE, SC_CUDA_CU_ARRAY_DESTROY, SC_CUDA_CU_ARRAY_GET_DESCRIPTOR, SC_CUDA_CU_MEM_ALLOC, SC_CUDA_CU_MEM_ALLOC_HOST, SC_CUDA_CU_MEM_ALLOC_PITCH, SC_CUDA_CU_MEMCPY_2D, SC_CUDA_CU_MEMCPY_2D_ASYNC, SC_CUDA_CU_MEMCPY_2D_UNALIGNED, SC_CUDA_CU_MEMCPY_3D, SC_CUDA_CU_MEMCPY_3D_ASYNC, SC_CUDA_CU_MEMCPY_A_TO_A, SC_CUDA_CU_MEMCPY_A_TO_D, SC_CUDA_CU_MEMCPY_A_TO_H, SC_CUDA_CU_MEMCPY_A_TO_H_ASYNC, SC_CUDA_CU_MEMCPY_D_TO_A, SC_CUDA_CU_MEMCPY_D_TO_D, SC_CUDA_CU_MEMCPY_D_TO_H, SC_CUDA_CU_MEMCPY_D_TO_H_ASYNC, SC_CUDA_CU_MEMCPY_H_TO_A, SC_CUDA_CU_MEMCPY_H_TO_A_ASYNC, SC_CUDA_CU_MEMCPY_H_TO_D, SC_CUDA_CU_MEMCPY_H_TO_D_ASYNC, SC_CUDA_CU_MEM_FREE, SC_CUDA_CU_MEM_FREE_HOST, SC_CUDA_CU_MEM_GET_ADDRESS_RANGE, SC_CUDA_CU_MEM_GET_INFO, SC_CUDA_CU_MEM_HOST_ALLOC, SC_CUDA_CU_MEM_HOST_GET_DEVICE_POINTER, SC_CUDA_CU_MEM_HOST_GET_FLAGS, SC_CUDA_CU_MEMSET_D16, SC_CUDA_CU_MEMSET_D2_D16, SC_CUDA_CU_MEMSET_D2_D32, SC_CUDA_CU_MEMSET_D2_D8, SC_CUDA_CU_MEMSET_D32, SC_CUDA_CU_MEMSET_D8, /* texture reference api */ SC_CUDA_CU_TEX_REF_CREATE, SC_CUDA_CU_TEX_REF_DESTROY, SC_CUDA_CU_TEX_REF_GET_ADDRESS, SC_CUDA_CU_TEX_REF_GET_ADDRESS_MODE, SC_CUDA_CU_TEX_REF_GET_ARRAY, SC_CUDA_CU_TEX_REF_GET_FILTER_MODE, SC_CUDA_CU_TEX_REF_GET_FLAGS, SC_CUDA_CU_TEX_REF_GET_FORMAT, SC_CUDA_CU_TEX_REF_SET_ADDRESS, SC_CUDA_CU_TEX_REF_SET_ADDRESS_2D, SC_CUDA_CU_TEX_REF_SET_ADDRESS_MODE, SC_CUDA_CU_TEX_REF_SET_ARRAY, SC_CUDA_CU_TEX_REF_SET_FILTER_MODE, SC_CUDA_CU_TEX_REF_SET_FLAGS, SC_CUDA_CU_TEX_REF_SET_FORMAT, } SCCudaAPIS; SCEnumCharMap sc_cuda_api_names_string_map[] = { /* init api */ { "cuInit", SC_CUDA_CU_INIT }, /* device management api */ { "cuDeviceGetCount", SC_CUDA_CU_DEVICE_GET_COUNT }, { "cuDeviceGet", SC_CUDA_CU_DEVICE_GET }, { "cuDeviceGetName", SC_CUDA_CU_DEVICE_GET_NAME }, { "cuDeviceTotalMem", SC_CUDA_CU_DEVICE_TOTAL_MEM }, { "cuDeviceGetProperties", SC_CUDA_CU_DEVICE_GET_PROPERTIES }, { "cuDeviceGetAttributes", SC_CUDA_CU_DEVICE_GET_ATTRIBUTE }, /* version management api */ { "cuDriverGetVersion", SC_CUDA_CU_DRIVER_GET_VERSION, }, /* context management api */ { "cuCtxAttach", SC_CUDA_CU_CTX_ATTACH }, { "cuCtxCreate", SC_CUDA_CU_CTX_CREATE }, { "cuCtxDestroy", SC_CUDA_CU_CTX_DESTROY }, { "cuCtxDetach", SC_CUDA_CU_CTX_DETACH }, { "cuCtxGetDevice", SC_CUDA_CU_CTX_GET_DEVICE }, { "cuCtxPopCurrent", SC_CUDA_CU_CTX_POP_CURRENT }, { "cuCtxPushCurrent", SC_CUDA_CU_CTX_PUSH_CURRENT }, { "cuCtxSynchronize", SC_CUDA_CU_CTX_SYNCHRONIZE }, /* module management api */ { "cuModuleGetFunction", SC_CUDA_CU_MODULE_GET_FUNCTION }, { "cuModuleGetGlobal", SC_CUDA_CU_MODULE_GET_GLOBAL }, { "cuModuleGetTexRef", SC_CUDA_CU_MODULE_GET_TEX_REF }, { "cuModuleLoad", SC_CUDA_CU_MODULE_LOAD }, { "cuModuleLoadData", SC_CUDA_CU_MODULE_LOAD_DATA }, { "cuModuleLoadDataEx", SC_CUDA_CU_MODULE_LOAD_DATA_EX }, { "cuModuleLoadFatBinary", SC_CUDA_CU_MODULE_LOAD_FAT_BINARY }, { "cuModuleUnload", SC_CUDA_CU_MODULE_UNLOAD }, /* stream management api */ { "cuStreamCreate", SC_CUDA_CU_STREAM_CREATE }, { "cuStreamDestroy", SC_CUDA_CU_STREAM_DESTROY }, { "cuStreamQuery", SC_CUDA_CU_STREAM_QUERY }, { "cuStreamSynchronize", SC_CUDA_CU_STREAM_SYNCHRONIZE }, /* event management api */ { "cuEventCreate", SC_CUDA_CU_EVENT_CREATE }, { "cuEventDestroy", SC_CUDA_CU_EVENT_DESTROY }, { "cuEventElapseTime", SC_CUDA_CU_EVENT_ELAPSED_TIME }, { "cuEventQuery", SC_CUDA_CU_EVENT_QUERY }, { "cuEventRecord", SC_CUDA_CU_EVENT_RECORD }, { "cuEventSynchronize", SC_CUDA_CU_EVENT_SYNCHRONIZE }, /* execution control api */ { "cuFuncGetAttribute", SC_CUDA_CU_FUNC_GET_ATTRIBUTE }, { "cuFuncSetShape", SC_CUDA_CU_FUNC_SET_BLOCK_SHAPE }, { "cuFuncSetSharedSize", SC_CUDA_CU_FUNC_SET_SHARED_SIZE }, { "cuLaunch", SC_CUDA_CU_LAUNCH }, { "cuLaunchGrid", SC_CUDA_CU_LAUNCH_GRID }, { "cuLaunchGridAsync", SC_CUDA_CU_LAUNCH_GRID_ASYNC }, { "cuParamSetf", SC_CUDA_CU_PARAM_SETF }, { "cuParamSeti", SC_CUDA_CU_PARAM_SETI }, { "cuParamSetSize", SC_CUDA_CU_PARAM_SET_SIZE }, { "cuSetTexRef", SC_CUDA_CU_PARAM_SET_TEX_REF }, { "cuSetv", SC_CUDA_CU_PARAM_SETV }, /* memory management api */ { "cuArray3DCreate", SC_CUDA_CU_ARRAY_3D_CREATE }, { "cuArray3DGetDescriptor", SC_CUDA_CU_ARRAY_3D_GET_DESCRIPTOR }, { "cuArrayCreate", SC_CUDA_CU_ARRAY_CREATE }, { "cuArrayDestroy", SC_CUDA_CU_ARRAY_DESTROY }, { "cuArrayGetDescriptor", SC_CUDA_CU_ARRAY_GET_DESCRIPTOR }, { "cuMemAlloc", SC_CUDA_CU_MEM_ALLOC }, { "cuMemAllocHost", SC_CUDA_CU_MEM_ALLOC_HOST }, { "cuMemAllocPitch", SC_CUDA_CU_MEM_ALLOC_PITCH }, { "cuMemcpy2D", SC_CUDA_CU_MEMCPY_2D }, { "cuMemcpy2DAsync", SC_CUDA_CU_MEMCPY_2D_ASYNC }, { "cuMemcpy2DUnaligned", SC_CUDA_CU_MEMCPY_2D_UNALIGNED }, { "cuMemcpy3D", SC_CUDA_CU_MEMCPY_3D }, { "cuMemcpy3DAsync", SC_CUDA_CU_MEMCPY_3D_ASYNC }, { "cuMemcpyAtoA", SC_CUDA_CU_MEMCPY_A_TO_A }, { "cuMemcpyAtoD", SC_CUDA_CU_MEMCPY_A_TO_D }, { "cuMemcpyAtoH", SC_CUDA_CU_MEMCPY_A_TO_H }, { "cuMemcpyAtoHAsyn", SC_CUDA_CU_MEMCPY_A_TO_H_ASYNC }, { "cuMemcpyDtoA", SC_CUDA_CU_MEMCPY_D_TO_A }, { "cuMemcpyDtoD", SC_CUDA_CU_MEMCPY_D_TO_D }, { "cuMemcpyDtoH", SC_CUDA_CU_MEMCPY_D_TO_H }, { "cuMemcpyDtoHAsyn", SC_CUDA_CU_MEMCPY_D_TO_H_ASYNC }, { "cuMemcpyHtoA", SC_CUDA_CU_MEMCPY_H_TO_A }, { "cuMemcpyHtoAAsync", SC_CUDA_CU_MEMCPY_H_TO_A_ASYNC }, { "cuMemcpyHtoD", SC_CUDA_CU_MEMCPY_H_TO_D }, { "cuMemcpyHtoDAsync", SC_CUDA_CU_MEMCPY_H_TO_D_ASYNC }, { "cuMemFree", SC_CUDA_CU_MEM_FREE }, { "cuMemFreeHost", SC_CUDA_CU_MEM_FREE_HOST }, { "cuMemGetAddressRange", SC_CUDA_CU_MEM_GET_ADDRESS_RANGE }, { "cuMemGetInfo", SC_CUDA_CU_MEM_GET_INFO }, { "cuMemHostAlloc", SC_CUDA_CU_MEM_HOST_ALLOC }, { "cuMemHostGetDevicePointer", SC_CUDA_CU_MEM_HOST_GET_DEVICE_POINTER }, { "cuMemHostGetFlags", SC_CUDA_CU_MEM_HOST_GET_FLAGS }, { "cuMemsetD16", SC_CUDA_CU_MEMSET_D16 }, { "cuMemsetD2D16", SC_CUDA_CU_MEMSET_D2_D16 }, { "cuMemsetD2D32", SC_CUDA_CU_MEMSET_D2_D32 }, { "cuMemsetD2D8", SC_CUDA_CU_MEMSET_D2_D8 }, { "cuMemsetD32", SC_CUDA_CU_MEMSET_D32 }, { "cuMemsetD8", SC_CUDA_CU_MEMSET_D8 }, /* texture reference api */ { "cuTexRefCreate", SC_CUDA_CU_TEX_REF_CREATE}, { "cuTexRefDestroy", SC_CUDA_CU_TEX_REF_DESTROY}, { "cuTexRefGetAddress", SC_CUDA_CU_TEX_REF_GET_ADDRESS}, { "cuTexRefGetAddressMode", SC_CUDA_CU_TEX_REF_GET_ADDRESS_MODE}, { "cuTexRefGetArray", SC_CUDA_CU_TEX_REF_GET_ARRAY}, { "cuTexRefGetFilterMode", SC_CUDA_CU_TEX_REF_GET_FILTER_MODE}, { "cuTexRefGetFlags", SC_CUDA_CU_TEX_REF_GET_FLAGS}, { "cuTexRefGetFormat", SC_CUDA_CU_TEX_REF_GET_FORMAT}, { "cuTexRefSetAddress", SC_CUDA_CU_TEX_REF_SET_ADDRESS}, { "cuTexRefSetAddress2D", SC_CUDA_CU_TEX_REF_SET_ADDRESS_2D}, { "cuTexRefSetAddressMode", SC_CUDA_CU_TEX_REF_SET_ADDRESS_MODE}, { "cuTexRefSetArray", SC_CUDA_CU_TEX_REF_SET_ARRAY}, { "cuTexRefSetFilterMode", SC_CUDA_CU_TEX_REF_SET_FILTER_MODE}, { "cuTexRefSetFlags", SC_CUDA_CU_TEX_REF_SET_FLAGS}, { "cuTexRefSetFormat", SC_CUDA_CU_TEX_REF_SET_FORMAT}, }; static SCCudaDevices *devices = NULL; /*****************************Error_Handling_API*******************************/ /** * \internal * \brief Maps the error enums from SCCudaAPIS to strings using the preprocessor * #ENUM_VALUE. This is mainly needed for logging purposes to log the * error codes. * * \param err The error_code for which the string has to be returned. * * \retval The string equivalent of the error code. */ static const char *SCCudaGetErrorCodeInString(int err) { switch (err) { CASE_CODE(CUDA_SUCCESS); CASE_CODE(CUDA_ERROR_INVALID_VALUE); CASE_CODE(CUDA_ERROR_OUT_OF_MEMORY); CASE_CODE(CUDA_ERROR_NOT_INITIALIZED); CASE_CODE(CUDA_ERROR_DEINITIALIZED); CASE_CODE(CUDA_ERROR_NO_DEVICE); CASE_CODE(CUDA_ERROR_INVALID_DEVICE); CASE_CODE(CUDA_ERROR_INVALID_IMAGE); CASE_CODE(CUDA_ERROR_INVALID_CONTEXT); CASE_CODE(CUDA_ERROR_CONTEXT_ALREADY_CURRENT); CASE_CODE(CUDA_ERROR_MAP_FAILED); CASE_CODE(CUDA_ERROR_UNMAP_FAILED); CASE_CODE(CUDA_ERROR_ARRAY_IS_MAPPED); CASE_CODE(CUDA_ERROR_ALREADY_MAPPED); CASE_CODE(CUDA_ERROR_NO_BINARY_FOR_GPU); CASE_CODE(CUDA_ERROR_ALREADY_ACQUIRED); CASE_CODE(CUDA_ERROR_NOT_MAPPED); CASE_CODE(CUDA_ERROR_INVALID_SOURCE); CASE_CODE(CUDA_ERROR_FILE_NOT_FOUND); CASE_CODE(CUDA_ERROR_INVALID_HANDLE); CASE_CODE(CUDA_ERROR_NOT_FOUND); CASE_CODE(CUDA_ERROR_NOT_READY); CASE_CODE(CUDA_ERROR_LAUNCH_FAILED); CASE_CODE(CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES); CASE_CODE(CUDA_ERROR_LAUNCH_TIMEOUT); CASE_CODE(CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING); CASE_CODE(CUDA_ERROR_UNKNOWN); default: return "CUDA_UNKNOWN_ERROR_CODE"; } } /** * \internal * \brief A generic function that handles the return values from the CUDA driver * API. * * \param result The result from the CUDA driver API call. * \param api_type An enum value SCCudaAPIS corresponing to the API for which the * result was returned. The enum is needed to map the api type to * a string for logging purposes. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaHandleRetValue(CUresult result, SCCudaAPIS api_type) { if (result == CUDA_SUCCESS) { SCLogDebug("%s executed successfully", SCMapEnumValueToName(api_type, sc_cuda_api_names_string_map)); return 0; } else { SCLogError(SC_ERR_CUDA_ERROR, "%s failed. Returned errocode - %s", SCMapEnumValueToName(api_type, sc_cuda_api_names_string_map), SCCudaGetErrorCodeInString(result)); return -1; } } /****************************Memory_Management_API*****************************/ /** * \brief Creates a CUDA array according to the CUDA_ARRAY3D_DESCRIPTOR * structure pAllocateArray and returns a handle to the new CUDA * array in *p_handle. The CUDA_ARRAY3D_DESCRIPTOR is defined as: * * typedef struct { * unsigned int Width; * unsigned int Height; * unsigned int Depth; * CUarray_format Format; * unsigned int NumChannels; * unsigned int Flags; * } CUDA_ARRAY3D_DESCRIPTOR; * * where: * * - Width, Height, and Depth are the width, height, and depth of the * CUDA array (in elements); the CUDA array is one-dimensional if * height and depth are 0, two-dimensional if depth is 0, and * three-dimensional otherwise; * - Format speci?es the format of the elements; CUarray_format is * defined as: * * typedef enum CUarray_format_enum { * CU_AD_FORMAT_UNSIGNED_INT8 = 0x01, * CU_AD_FORMAT_UNSIGNED_INT16 = 0x02, * CU_AD_FORMAT_UNSIGNED_INT32 = 0x03, * CU_AD_FORMAT_SIGNED_INT8 = 0x08, * CU_AD_FORMAT_SIGNED_INT16 = 0x09, * CU_AD_FORMAT_SIGNED_INT32 = 0x0a, * CU_AD_FORMAT_HALF = 0x10, * CU_AD_FORMAT_FLOAT = 0x20 * } CUarray_format; * * - NumChannels speci?es the number of packed components per CUDA array * element; it may be 1, 2, or 4; * - Flags provides for future features. For now, it must be set to 0. * * Here are examples of CUDA array descriptions: * * Description for a CUDA array of 2048 floats: * * CUDA_ARRAY3D_DESCRIPTOR desc; * desc.Format = CU_AD_FORMAT_FLOAT; * desc.NumChannels = 1; * desc.Width = 2048; * desc.Height = 0; * desc.Depth = 0; * * Description for a 64 x 64 CUDA array of floats: * * CUDA_ARRAY3D_DESCRIPTOR desc; * desc.Format = CU_AD_FORMAT_FLOAT; * desc.NumChannels = 1; * desc.Width = 64; * desc.Height = 64; * desc.Depth = 0; * * Description for a width x height x depth CUDA array of 64-bit, * 4x16-bit float16's: * * CUDA_ARRAY3D_DESCRIPTOR desc; * desc.FormatFlags = CU_AD_FORMAT_HALF; * desc.NumChannels = 4; * desc.Width = width; * desc.Height = height; * desc.Depth = depth; * * \param p_handle Returned Handle. * \param p_allocate_array 3D array descriptor. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaArray3DCreate(CUarray *p_handle, const CUDA_ARRAY3D_DESCRIPTOR *p_allocate_array) { CUresult result = 0; if (p_handle == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_handle is NULL"); goto error; } result = cuArray3DCreate(p_handle, p_allocate_array); if (SCCudaHandleRetValue(result, SC_CUDA_CU_ARRAY_3D_CREATE) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *p_rray_descriptor a descriptor containing information on * the format and dimensions of the CUDA array h_array. It is useful for * subroutines that have been passed a CUDA array, but need to know the * CUDA array parameters for validation or other purposes. * * This function may be called on 1D and 2D arrays, in which case the * Height and/or Depth members of the descriptor struct will be set to 0. * * \param p_array_descriptor Returned 3D array descriptor. * \param h_array 3D array to get descriptor of. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaArray3DGetDescriptor(CUDA_ARRAY3D_DESCRIPTOR *p_array_descriptor, CUarray h_array) { CUresult result = 0; if (p_array_descriptor == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_array_descriptor is NULL"); goto error; } result = cuArray3DGetDescriptor(p_array_descriptor, h_array); if (SCCudaHandleRetValue(result, SC_CUDA_CU_ARRAY_3D_GET_DESCRIPTOR) == -1) goto error; return 0; error: return -1; } /** * \brief Creates a CUDA array according to the CUDA_ARRAY_DESCRIPTOR structure * p_allocate_array and returns a handle to the new CUDA array in * p_handle. The CUDA_ARRAY_DESCRIPTOR is defined as: * * typedef struct { * unsigned int Width; * unsigned int Height; * CUarray_format Format; * unsigned int NumChannels; * } CUDA_ARRAY_DESCRIPTOR; * * where: * * - Width, and Height are the width, and height of the CUDA array * (in elements); the CUDA array is one-dimensional if height is 0, * two-dimensional otherwise; * - Format speci?es the format of the elements; CUarray_format is * defined as: * * typedef enum CUarray_format_enum { * CU_AD_FORMAT_UNSIGNED_INT8 = 0x01, * CU_AD_FORMAT_UNSIGNED_INT16 = 0x02, * CU_AD_FORMAT_UNSIGNED_INT32 = 0x03, * CU_AD_FORMAT_SIGNED_INT8 = 0x08, * CU_AD_FORMAT_SIGNED_INT16 = 0x09, * CU_AD_FORMAT_SIGNED_INT32 = 0x0a, * CU_AD_FORMAT_HALF = 0x10, * CU_AD_FORMAT_FLOAT = 0x20 * } CUarray_format; * * - NumChannels specifies the number of packed components per CUDA * array element; it may be 1, 2, or 4; * * Here are examples of CUDA array descriptions: * * Description for a CUDA array of 2048 floats: * * CUDA_ARRAY_DESCRIPTOR desc; * desc.Format = CU_AD_FORMAT_FLOAT; * desc.NumChannels = 1; * desc.Width = 2048; * desc.Height = 1; * * Description for a 64 x 64 CUDA array of floats: * * CUDA_ARRAY_DESCRIPTOR desc; * desc.Format = CU_AD_FORMAT_FLOAT; * desc.NumChannels = 1; * desc.Width = 64; * desc.Height = 64; * * Description for a width x height CUDA array of 64-bit, 4x16-bit * float16's: * * CUDA_ARRAY_DESCRIPTOR desc; * desc.FormatFlags = CU_AD_FORMAT_HALF; * desc.NumChannels = 4; * desc.Width = width; * desc.Height = height; * * Description for a width x height CUDA array of 16-bit elements, each * of which is two 8-bit unsigned chars: * * CUDA_ARRAY_DESCRIPTOR arrayDesc; * desc.FormatFlags = CU_AD_FORMAT_UNSIGNED_INT8; * desc.NumChannels = 2; * desc.Width = width; * desc.Height = height; * * \param p_handle Returned array. * \param p_allocate_array Array descriptor. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaArrayCreate(CUarray *p_handle, const CUDA_ARRAY_DESCRIPTOR *p_allocate_array) { CUresult result = 0; if (p_handle == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_handle is NULL"); goto error; } result = cuArrayCreate(p_handle, p_allocate_array); if (SCCudaHandleRetValue(result, SC_CUDA_CU_ARRAY_CREATE) == -1) goto error; return 0; error: return -1; } /** * \brief Destroys the CUDA array h_array. * * \param h_array Array to destroy. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaArrayDestroy(CUarray h_array) { int result = cuArrayDestroy(h_array); if (SCCudaHandleRetValue(result, SC_CUDA_CU_ARRAY_DESTROY) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *p_array_descriptor a descriptor containing information on * the format and dimensions of the CUDA array h_array. It is useful for * subroutines that have been passed a CUDA array, but need to know the * CUDA array parameters for validation or other purposes. * * \param p_array_descriptor Returned array descriptor. * \param h_array Array to get descriptor of. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaArrayGetDescriptor(CUDA_ARRAY_DESCRIPTOR *p_array_descriptor, CUarray h_array) { CUresult result = 0; if (p_array_descriptor == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_array_descriptor is NULL"); goto error; } result = cuArrayGetDescriptor(p_array_descriptor, h_array); if (SCCudaHandleRetValue(result, SC_CUDA_CU_ARRAY_GET_DESCRIPTOR) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *p_array_descriptor a descriptor containing information on * the format and dimensions of the CUDA array h_array. It is useful for * subroutines that have been passed a CUDA array, but need to know the * CUDA array parameters for validation or other purposes. * * \param p_array_descriptor Returned array descriptor. * \param h_array Array to get descriptor of. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemAlloc(CUdeviceptr *dptr, unsigned int byte_size) { CUresult result = 0; if (dptr == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "dptr is NULL"); goto error; } result = cuMemAlloc(dptr, byte_size); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_ALLOC) == -1) goto error; return 0; error: return -1; } /** * \brief Allocates bytesize bytes of host memory that is page-locked and * accessible to the device. The driver tracks the vir-tual memory * ranges allocated with this function and automatically accelerates * calls to functions such as cuMemcpy(). Since the memory can be * accessed directly by the device, it can be read or written with * much higher bandwidth than pageable memory obtained with functions * such as SCMalloc(). Allocating excessive amounts of memory with * cuMemAllocHost() may degrade system performance, since it reduces * the amount of memory available to the system for paging. As a result, * this function is best used sparingly to allocate staging areas for * data exchange between host and device. * * \param pp Returned host pointer to page-locked memory. * \param byte_size Requested allocation size in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemAllocHost(void **pp, unsigned int byte_size) { CUresult result = 0; if (pp == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "pp is NULL"); goto error; } result = cuMemAllocHost(pp, byte_size); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_ALLOC) == -1) goto error; return 0; error: return -1; } /** * \brief Allocates at least width_in_bytes * height bytes of linear memory on the * device and returns in *dptr a pointer to the allocated memory. The * function may pad the allocation to ensure that corresponding pointers in * any given row will continue to meet the alignment requirements for * coalescing as the address is updated from row to row. ElementSizeBytes * specifies the size of the largest reads and writes that will be * performed on the memory range. * * element_size_bytes may be 4, 8 or 16 (since coalesced memory * transactions are not possible on other data sizes). If element_size_bytes * is smaller than the actual read/write size of a kernel, the kernel will * run correctly, but possibly at reduced speed. The pitch returned in * *p_itch by cuMemAllocPitch() is the width in bytes of the allocation. * The intended usage of pitch is as a separate parameter of the allocation, * used to compute addresses within the 2D array. Given the row and column * of an array element of type T, the address is computed as: * * T * p_element = (T*)((char*)base_address + row * pitch) + column; * * The pitch returned by cuMemAllocPitch() is guaranteed to work with * cuMemcpy2D() under all circumstances. For allocations of 2D arrays, it * is recommended that programmers consider performing pitch allocations * using cuMemAllocPitch(). Due to alignment restrictions in the hardware, * this is especially true if the application will be performing 2D memory * copies between different regions of device memory (whether linear memory * or CUDA arrays). * * \param dptr Returned device pointer. * \param p_pitch Returned pitch of allocation in bytes. * \param width_in_bytes Requested allocation width in bytes. * \param height Requested allocation width in rows. * \param element_size_bytes Size of largest reads/writes for range. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemAllocPitch(CUdeviceptr *dptr, unsigned int *p_pitch, unsigned int width_in_bytes, unsigned int height, unsigned int element_size_bytes) { CUresult result = 0; if (dptr == NULL || p_pitch == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "dptr is NULL or p_pitch is NULL"); goto error; } result = cuMemAllocPitch(dptr, p_pitch, width_in_bytes, height, element_size_bytes); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_ALLOC_PITCH) == -1) goto error; return 0; error: return -1; } /** * \brief Perform a 2D memory copy according to the parameters specified in * p_copy. The CUDA_MEMCPY2D structure is defined as: * * typedef struct CUDA_MEMCPY2D_st { * unsigned int srcXInBytes, srcY; * CUmemorytype srcMemoryType; * const void *srcHost; * CUdeviceptr srcDevice; * CUarray srcArray; * unsigned int srcPitch; * unsigned int dstXInBytes, dstY; * CUmemorytype dstMemoryType; * void *dstHost; * CUdeviceptr dstDevice; * CUarray dstArray; * unsigned int dstPitch; * unsigned int WidthInBytes; * unsigned int Height; * } CUDA_MEMCPY2D; * * where: * * - srcMemoryType and dstMemoryType specify the type of memory of the * source and destination, respectively; * * CUmemorytype_enum is de?ned as: * * typedef enum CUmemorytype_enum { * CU_MEMORYTYPE_HOST = 0x01, * CU_MEMORYTYPE_DEVICE = 0x02, * CU_MEMORYTYPE_ARRAY = 0x03 * } CUmemorytype; * * If srcMemoryType is CU_MEMORYTYPE_HOST, srcHost and srcPitch specify * the (host) base address of the source data and the bytes per row to * apply. srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_DEVICE, srcDevice and srcPitch * specify the (device) base address of the source data and the bytes per * row to apply. srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_ARRAY, srcArray speci?es the handle * of the source data. srcHost, srcDevice and srcPitch are ignored. * * If dstMemoryType is CU_MEMORYTYPE_HOST, dstHost and dstPitch specify * the (host) base address of the destination data and the bytes per row * to apply. dstArray is ignored. * * If dstMemoryType is CU_MEMORYTYPE_DEVICE, dstDevice and dstPitch * specify the (device) base address of the destination data and the * bytes per row to apply. dstArray is ignored. * * If dstMemoryType is CU_MEMORYTYPE_ARRAY, dstArray specifies the handle * of the destination data dstHost, dstDevice and dstPitch are ignored. * * - srcXInBytes and srcY specify the base address of the source data for * the copy. * * For host pointers, the starting address is * * void* Start = (void*)((char*)srcHost+srcY*srcPitch + srcXInBytes); * * For device pointers, the starting address is * * CUdeviceptr Start = srcDevice+srcY*srcPitch+srcXInBytes; * * For CUDA arrays, srcXInBytes must be evenly divisible by the array * element size. * * - dstXInBytes and dstY specify the base address of the destination data * for the copy. * * For host pointers, the base address is * * void* dstStart = (void*)((char*)dstHost+dstY*dstPitch + dstXInBytes); * * For device pointers, the starting address is * * CUdeviceptr dstStart = dstDevice+dstY*dstPitch+dstXInBytes; * * For CUDA arrays, dstXInBytes must be evenly divisible by the array * element size. * * - WidthInBytes and Height specify the width (in bytes) and height of * the 2D copy being performed. Any pitches must be greater than or * equal to WidthInBytes. * * cuMemcpy2D() returns an error if any pitch is greater than the * maximum allowed (CU_DEVICE_ATTRIBUTE_MAX_PITCH). cuMemAllocPitch() * passes back pitches that always work with cuMemcpy2D(). On intra-device * memory copies (device ? device, CUDA array ? device, CUDA array ? * CUDA array), cuMemcpy2D() may fail for pitches not computed by * cuMemAllocPitch(). cuMemcpy2DUnaligned() does not have this restriction, * but may run signi?cantly slower in the cases where cuMemcpy2D() would * have returned an error code. * * \param p_copy Parameters for the memory copy. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpy2D(const CUDA_MEMCPY2D *p_copy) { CUresult result = 0; if (p_copy == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_copy is NULL"); goto error; } result = cuMemcpy2D(p_copy); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_2D) == -1) goto error; return 0; error: return -1; } /** * \brief Perform a 2D memory copy according to the parameters specified in * p_copy. The CUDA_MEMCPY2D structure is defined as: * * typedef struct CUDA_MEMCPY2D_st { * unsigned int srcXInBytes, srcY; * CUmemorytype srcMemoryType; * const void *srcHost; * CUdeviceptr srcDevice; * CUarray srcArray; * unsigned int srcPitch; * unsigned int dstXInBytes, dstY; * CUmemorytype dstMemoryType; * void *dstHost; * CUdeviceptr dstDevice; * CUarray dstArray; * unsigned int dstPitch; * unsigned int WidthInBytes; * unsigned int Height; * } CUDA_MEMCPY2D; * * where: * * - srcMemoryType and dstMemoryType specify the type of memory of the * source and destination, respectively; * * CUmemorytype_enum is de?ned as: * * typedef enum CUmemorytype_enum { * CU_MEMORYTYPE_HOST = 0x01, * CU_MEMORYTYPE_DEVICE = 0x02, * CU_MEMORYTYPE_ARRAY = 0x03 * } CUmemorytype; * * If srcMemoryType is CU_MEMORYTYPE_HOST, srcHost and srcPitch specify * the (host) base address of the source data and the bytes per row to * apply. srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_DEVICE, srcDevice and srcPitch * specify the (device) base address of the source data and the bytes per * row to apply. srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_ARRAY, srcArray speci?es the handle * of the source data. srcHost, srcDevice and srcPitch are ignored. * * If dstMemoryType is CU_MEMORYTYPE_HOST, dstHost and dstPitch specify * the (host) base address of the destination data and the bytes per row * to apply. dstArray is ignored. * * If dstMemoryType is CU_MEMORYTYPE_DEVICE, dstDevice and dstPitch * specify the (device) base address of the destination data and the * bytes per row to apply. dstArray is ignored. * * If dstMemoryType is CU_MEMORYTYPE_ARRAY, dstArray specifies the handle * of the destination data dstHost, dstDevice and dstPitch are ignored. * * - srcXInBytes and srcY specify the base address of the source data for * the copy. * * For host pointers, the starting address is * * void* Start = (void*)((char*)srcHost+srcY*srcPitch + srcXInBytes); * * For device pointers, the starting address is * * CUdeviceptr Start = srcDevice+srcY*srcPitch+srcXInBytes; * * For CUDA arrays, srcXInBytes must be evenly divisible by the array * element size. * * - dstXInBytes and dstY specify the base address of the destination data * for the copy. * * For host pointers, the base address is * * void* dstStart = (void*)((char*)dstHost+dstY*dstPitch + dstXInBytes); * * For device pointers, the starting address is * * CUdeviceptr dstStart = dstDevice+dstY*dstPitch+dstXInBytes; * * For CUDA arrays, dstXInBytes must be evenly divisible by the array * element size. * * - WidthInBytes and Height specify the width (in bytes) and height of * the 2D copy being performed. Any pitches must be greater than or * equal to WidthInBytes. * * cuMemcpy2D() returns an error if any pitch is greater than the * maximum allowed (CU_DEVICE_ATTRIBUTE_MAX_PITCH). cuMemAllocPitch() * passes back pitches that always work with cuMemcpy2D(). On intra-device * memory copies (device ? device, CUDA array ? device, CUDA array ? * CUDA array), cuMemcpy2D() may fail for pitches not computed by * cuMemAllocPitch(). cuMemcpy2DUnaligned() does not have this restriction, * but may run signi?cantly slower in the cases where cuMemcpy2D() would * have returned an error code. * * cuMemcpy2DAsync() is asynchronous and can optionally be associated to a * stream by passing a non-zero hStream argument. It only works on * page-locked host memory and returns an error if a pointer to pageable * memory is passed as input. * * \param p_copy Parameters for the memory copy. * \param h_stream Stream identifier. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpy2DAsync(const CUDA_MEMCPY2D *p_copy, CUstream h_stream) { CUresult result = 0; if (p_copy == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_copy is NULL"); goto error; } result = cuMemcpy2DAsync(p_copy, h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_2D_ASYNC) == -1) goto error; return 0; error: return -1; } /** * \brief Perform a 2D memory copy according to the parameters specified in * p_copy. The CUDA_MEMCPY2D structure is defined as: * * typedef struct CUDA_MEMCPY2D_st { * unsigned int srcXInBytes, srcY; * CUmemorytype srcMemoryType; * const void *srcHost; * CUdeviceptr srcDevice; * CUarray srcArray; * unsigned int srcPitch; * unsigned int dstXInBytes, dstY; * CUmemorytype dstMemoryType; * void *dstHost; * CUdeviceptr dstDevice; * CUarray dstArray; * unsigned int dstPitch; * unsigned int WidthInBytes; * unsigned int Height; * } CUDA_MEMCPY2D; * * where: * * - srcMemoryType and dstMemoryType specify the type of memory of the * source and destination, respectively; * * CUmemorytype_enum is de?ned as: * * typedef enum CUmemorytype_enum { * CU_MEMORYTYPE_HOST = 0x01, * CU_MEMORYTYPE_DEVICE = 0x02, * CU_MEMORYTYPE_ARRAY = 0x03 * } CUmemorytype; * * If srcMemoryType is CU_MEMORYTYPE_HOST, srcHost and srcPitch specify * the (host) base address of the source data and the bytes per row to * apply. srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_DEVICE, srcDevice and srcPitch * specify the (device) base address of the source data and the bytes per * row to apply. srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_ARRAY, srcArray speci?es the handle * of the source data. srcHost, srcDevice and srcPitch are ignored. * * If dstMemoryType is CU_MEMORYTYPE_HOST, dstHost and dstPitch specify * the (host) base address of the destination data and the bytes per row * to apply. dstArray is ignored. * * If dstMemoryType is CU_MEMORYTYPE_DEVICE, dstDevice and dstPitch * specify the (device) base address of the destination data and the * bytes per row to apply. dstArray is ignored. * * If dstMemoryType is CU_MEMORYTYPE_ARRAY, dstArray specifies the handle * of the destination data dstHost, dstDevice and dstPitch are ignored. * * - srcXInBytes and srcY specify the base address of the source data for * the copy. * * For host pointers, the starting address is * * void* Start = (void*)((char*)srcHost+srcY*srcPitch + srcXInBytes); * * For device pointers, the starting address is * * CUdeviceptr Start = srcDevice+srcY*srcPitch+srcXInBytes; * * For CUDA arrays, srcXInBytes must be evenly divisible by the array * element size. * * - dstXInBytes and dstY specify the base address of the destination data * for the copy. * * For host pointers, the base address is * * void* dstStart = (void*)((char*)dstHost+dstY*dstPitch + dstXInBytes); * * For device pointers, the starting address is * * CUdeviceptr dstStart = dstDevice+dstY*dstPitch+dstXInBytes; * * For CUDA arrays, dstXInBytes must be evenly divisible by the array * element size. * * - WidthInBytes and Height specify the width (in bytes) and height of * the 2D copy being performed. Any pitches must be greater than or * equal to WidthInBytes. * * cuMemcpy2D() returns an error if any pitch is greater than the * maximum allowed (CU_DEVICE_ATTRIBUTE_MAX_PITCH). cuMemAllocPitch() * passes back pitches that always work with cuMemcpy2D(). On intra-device * memory copies (device ? device, CUDA array ? device, CUDA array ? * CUDA array), cuMemcpy2D() may fail for pitches not computed by * cuMemAllocPitch(). cuMemcpy2DUnaligned() does not have this restriction, * but may run signi?cantly slower in the cases where cuMemcpy2D() would * have returned an error code. * * cuMemcpy2DAsync() is asynchronous and can optionally be associated to a * stream by passing a non-zero hStream argument. It only works on * page-locked host memory and returns an error if a pointer to pageable * memory is passed as input. * * \param p_copy Parameters for the memory copy. * \param h_stream Stream identifier. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpy2DUnaligned(const CUDA_MEMCPY2D *p_copy) { CUresult result = 0; if (p_copy == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_copy is NULL"); goto error; } result = cuMemcpy2DUnaligned(p_copy); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_2D_UNALIGNED) == -1) goto error; return 0; error: return -1; } /** * \brief Perform a 3D memory copy according to the parameters specified in * p_copy. The CUDA_MEMCPY3D structure is defined as: * * typedef struct CUDA_MEMCPY3D_st { * unsigned int srcXInBytes, srcY, srcZ; * unsigned int srcLOD; * CUmemorytype srcMemoryType; * const void *srcHost; * CUdeviceptr srcDevice; * CUarray srcArray; * unsigned int srcPitch; // ignored when src is array * unsigned int srcHeight; // ignored when src is array; may be 0 if Depth==1 * unsigned int dstXInBytes, dstY, dstZ; * unsigned int dstLOD; * CUmemorytype dstMemoryType; * void *dstHost; * CUdeviceptr dstDevice; * CUarray dstArray; * unsigned int dstPitch; // ignored when dst is array * unsigned int dstHeight; // ignored when dst is array; may be 0 if Depth==1 * unsigned int WidthInBytes; * unsigned int Height; * unsigned int Depth; * } CUDA_MEMCPY3D; * * where: * * - srcMemoryType and dstMemoryType specify the type of memory of the * source and destination, respectively; * CUmemorytype_enum is defined as: * * typedef enum CUmemorytype_enum { * CU_MEMORYTYPE_HOST = 0x01, * CU_MEMORYTYPE_DEVICE = 0x02, * CU_MEMORYTYPE_ARRAY = 0x03 * } CUmemorytype; * * If srcMemoryType is CU_MEMORYTYPE_HOST, srcHost, srcPitch and srcHeight * specify the (host) base address of the source data, the bytes per row, * and the height of each 2D slice of the 3D array. srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_DEVICE, srcDevice, srcPitch and * srcHeight specify the (device) base address of the source data, the * bytes per row, and the height of each 2D slice of the 3D array. * srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_ARRAY, srcArray specifies the handle * of the source data. srcHost, srcDevice, srcPitch and srcHeight are * ignored. If dstMemoryType is CU_MEMORYTYPE_HOST, dstHost and dstPitch * specify the (host) base address of the destination data, the bytes per * row, and the height of each 2D slice of the 3D array. dstArray is * ignored. * * If dstMemoryType is CU_MEMORYTYPE_DEVICE, dstDevice and dstPitch * specify the (device) base address of the destination data, the bytes * per row, and the height of each 2D slice of the 3D array. dstArray is * ignored. * * If dstMemoryType is CU_MEMORYTYPE_ARRAY, dstArray specifies the * handle of the destination data. dstHost, dstDevice, dstPitch and * dstHeight are ignored. * * - srcXInBytes, srcY and srcZ specify the base address of the source * data for the copy. * * For host pointers, the starting address is * * void* Start = (void*)((char*)srcHost+(srcZ*srcHeight+srcY)*srcPitch + srcXInBytes); * * For device pointers, the starting address is * * CUdeviceptr Start = srcDevice+(srcZ*srcHeight+srcY)*srcPitch+srcXInBytes; * * For CUDA arrays, srcXInBytes must be evenly divisible by the array * element size. * * - dstXInBytes, dstY and dstZ specify the base address of the destination * data for the copy. * * For host pointers, the base address is * * void* dstStart = (void*)((char*)dstHost+(dstZ*dstHeight+dstY)*dstPitch + dstXInBytes); * * For device pointers, the starting address is * * CUdeviceptr dstStart = dstDevice+(dstZ*dstHeight+dstY)*dstPitch+dstXInBytes; * * For CUDA arrays, dstXInBytes must be evenly divisible by the array * element size. * * - WidthInBytes, Height and Depth specify the width (in bytes), height * and depth of the 3D copy being performed. Any pitches must be greater * than or equal to WidthInBytes. * * cuMemcpy3D() returns an error if any pitch is greater than the maximum * allowed (CU_DEVICE_ATTRIBUTE_MAX_PITCH). * * The srcLOD and dstLOD members of the CUDA_MEMCPY3D structure must be * set to 0. * * \param p_copy Parameters for the memory copy. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpy3D(const CUDA_MEMCPY3D *p_copy) { CUresult result = 0; if (p_copy == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_copy is NULL"); goto error; } result = cuMemcpy3D(p_copy); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_3D) == -1) goto error; return 0; error: return -1; } /** * \brief Perform a 3D memory copy according to the parameters specified in * p_copy. The CUDA_MEMCPY3D structure is defined as: * * typedef struct CUDA_MEMCPY3D_st { * unsigned int srcXInBytes, srcY, srcZ; * unsigned int srcLOD; * CUmemorytype srcMemoryType; * const void *srcHost; * CUdeviceptr srcDevice; * CUarray srcArray; * unsigned int srcPitch; // ignored when src is array * unsigned int srcHeight; // ignored when src is array; may be 0 if Depth==1 * unsigned int dstXInBytes, dstY, dstZ; * unsigned int dstLOD; * CUmemorytype dstMemoryType; * void *dstHost; * CUdeviceptr dstDevice; * CUarray dstArray; * unsigned int dstPitch; // ignored when dst is array * unsigned int dstHeight; // ignored when dst is array; may be 0 if Depth==1 * unsigned int WidthInBytes; * unsigned int Height; * unsigned int Depth; * } CUDA_MEMCPY3D; * * where: * * - srcMemoryType and dstMemoryType specify the type of memory of the * source and destination, respectively; * CUmemorytype_enum is defined as: * * typedef enum CUmemorytype_enum { * CU_MEMORYTYPE_HOST = 0x01, * CU_MEMORYTYPE_DEVICE = 0x02, * CU_MEMORYTYPE_ARRAY = 0x03 * } CUmemorytype; * * If srcMemoryType is CU_MEMORYTYPE_HOST, srcHost, srcPitch and srcHeight * specify the (host) base address of the source data, the bytes per row, * and the height of each 2D slice of the 3D array. srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_DEVICE, srcDevice, srcPitch and * srcHeight specify the (device) base address of the source data, the * bytes per row, and the height of each 2D slice of the 3D array. * srcArray is ignored. * * If srcMemoryType is CU_MEMORYTYPE_ARRAY, srcArray specifies the handle * of the source data. srcHost, srcDevice, srcPitch and srcHeight are * ignored. If dstMemoryType is CU_MEMORYTYPE_HOST, dstHost and dstPitch * specify the (host) base address of the destination data, the bytes per * row, and the height of each 2D slice of the 3D array. dstArray is * ignored. * * If dstMemoryType is CU_MEMORYTYPE_DEVICE, dstDevice and dstPitch * specify the (device) base address of the destination data, the bytes * per row, and the height of each 2D slice of the 3D array. dstArray is * ignored. * * If dstMemoryType is CU_MEMORYTYPE_ARRAY, dstArray specifies the * handle of the destination data. dstHost, dstDevice, dstPitch and * dstHeight are ignored. * * - srcXInBytes, srcY and srcZ specify the base address of the source * data for the copy. * * For host pointers, the starting address is * * void* Start = (void*)((char*)srcHost+(srcZ*srcHeight+srcY)*srcPitch + srcXInBytes); * * For device pointers, the starting address is * * CUdeviceptr Start = srcDevice+(srcZ*srcHeight+srcY)*srcPitch+srcXInBytes; * * For CUDA arrays, srcXInBytes must be evenly divisible by the array * element size. * * - dstXInBytes, dstY and dstZ specify the base address of the destination * data for the copy. * * For host pointers, the base address is * * void* dstStart = (void*)((char*)dstHost+(dstZ*dstHeight+dstY)*dstPitch + dstXInBytes); * * For device pointers, the starting address is * * CUdeviceptr dstStart = dstDevice+(dstZ*dstHeight+dstY)*dstPitch+dstXInBytes; * * For CUDA arrays, dstXInBytes must be evenly divisible by the array * element size. * * - WidthInBytes, Height and Depth specify the width (in bytes), height * and depth of the 3D copy being performed. Any pitches must be greater * than or equal to WidthInBytes. * * cuMemcpy3D() returns an error if any pitch is greater than the maximum * allowed (CU_DEVICE_ATTRIBUTE_MAX_PITCH). * * cuMemcpy3DAsync() is asynchronous and can optionally be associated * to a stream by passing a non-zero hStream argument. It only works on * page-locked host memory and returns an error if a pointer to pageable * memory is passed as input. * * The srcLOD and dstLOD members of the CUDA_MEMCPY3D structure must be * set to 0. * * \param p_copy Parameters for the memory copy. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpy3DAsync(const CUDA_MEMCPY3D *p_copy, CUstream h_stream) { CUresult result = 0; if (p_copy == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_copy is NULL"); goto error; } result = cuMemcpy3DAsync(p_copy, h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_3D_ASYNC) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from one 1D CUDA array to another. dstArray and srcArray * specify the handles of the destination and source CUDA arrays for the * copy, respectively. dstIndex and srcIndex specify the destination and * source indices into the CUDA array. These values are in the range * [0, Width-1] for the CUDA array; they are not byte offsets. ByteCount * is the number of bytes to be copied. The size of the elements in the * CUDA arrays need not be the same format, but the elements must be the * same size; and count must be evenly divisible by that size. * * \param dst_array Destination array. * \param dst_index Offset of destination array. * \param src_array Source array. * \param src_index Offset of source array. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyAtoA(CUarray dst_array, unsigned int dst_index, CUarray src_array, unsigned int src_index, unsigned int byte_count) { CUresult result = 0; result = cuMemcpyAtoA(dst_array, dst_index, src_array, src_index, byte_count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_A_TO_A) == -1) goto error; return 0; error: return -1; } /** * \param Copies from one 1D CUDA array to device memory. dstDevice specifies the * base pointer of the destination and must be naturally aligned with the * CUDA array elements. hSrc and SrcIndex specify the CUDA array handle and * the index (in array elements) of the array element where the copy is * to begin. ByteCount speci?es the number of bytes to copy and must be * evenly divisible by the array element size. * * \param dst_device Destination device pointer. * \param h_src Source array. * \param src_index Offset of source array. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyAtoD(CUdeviceptr dst_device, CUarray h_src, unsigned int src_index, unsigned int byte_count) { CUresult result = 0; result = cuMemcpyAtoD(dst_device, h_src, src_index, byte_count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_A_TO_D) == -1) goto error; return 0; error: return -1; } /** * \param Copies from one 1D CUDA array to host memory. dstHost specifies the * base pointer of the destination. srcArray and srcIndex specify the * CUDA array handle and starting index of the source data. ByteCount * specifies the number of bytes to copy. * * \param dst_device Destination device pointer. * \param h_src Source array. * \param src_index Offset of source array. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyAtoH(void *dst_host, CUarray src_array,unsigned int src_index, unsigned int byte_count) { CUresult result = 0; result = cuMemcpyAtoH(dst_host, src_array, src_index, byte_count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_A_TO_H) == -1) goto error; return 0; error: return -1; } /** * \param Copies from one 1D CUDA array to host memory. dstHost specifies the * base pointer of the destination. srcArray and srcIndex specify the * CUDA array handle and starting index of the source data. ByteCount * specifies the number of bytes to copy. * * cuMemcpyAtoHAsync() is asynchronous and can optionally be associated * to a stream by passing a non-zero stream argument. It only works on * page-locked host memory and returns an error if a pointer to pageable * memory is passed as input. * * \param dst_device Destination device pointer. * \param src_array Source array. * \param src_index Offset of source array. * \param byte_count Size of memory copy in bytes. * \param h_stream Stream identifier. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyAtoHAsync(void *dst_host, CUarray src_array, unsigned int src_index, unsigned int byte_count, CUstream h_stream) { CUresult result = 0; result = cuMemcpyAtoHAsync(dst_host, src_array, src_index, byte_count, h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_A_TO_H_ASYNC) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from device memory to a 1D CUDA array. dstArray and dstIndex * specify the CUDA array handle and starting index of the destination * data. srcDevice speci?es the base pointer of the source. ByteCount * specifies the number of bytes to copy. * * \param dst_array Destination array. * \param dst_index Offset of destination array. * \param src_device Source device pointer. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyDtoA(CUarray dst_array, unsigned int dst_index, CUdeviceptr src_device, unsigned int byte_count) { CUresult result = 0; result = cuMemcpyDtoA(dst_array, dst_index, src_device, byte_count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_D_TO_A) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from device memory to device memory. dstDevice and srcDevice are * the base pointers of the destination and source, respectively. * byte_count specifies the number of bytes to copy. Note that this * function is asynchronous. * * \param dst_device Destination device pointer. * \param src_device Source device pointer. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyDtoD(CUdeviceptr dst_device, CUdeviceptr src_device, unsigned int byte_count) { CUresult result = 0; result = cuMemcpyDtoD(dst_device, src_device, byte_count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_D_TO_D) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from device to host memory. dst_host and src_device specify * the base pointers of the destination and source, respectively. * byte_count specifies the number of bytes to copy. Note that this * function is synchronous. * * \param dst_host Destination device pointer. * \param src_device Source device pointer. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyDtoH(void *dst_host, CUdeviceptr src_device, unsigned int byte_count) { CUresult result = 0; result = cuMemcpyDtoH(dst_host, src_device, byte_count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_D_TO_H) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from device to host memory. dst_host and src_device specify * the base pointers of the destination and source, respectively. * byte_count specifies the number of bytes to copy. * * cuMemcpyDtoHAsync() is asynchronous and can optionally be associated * to a stream by passing a non-zero h_stream argument. It only works * on page-locked memory and returns an error if a pointer to pageable * memory is passed as input. * * \param dst_host Destination device pointer. * \param src_device Source device pointer. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyDtoHAsync(void *dst_host, CUdeviceptr src_device, unsigned int byte_count, CUstream h_stream) { CUresult result = 0; result = cuMemcpyDtoHAsync(dst_host, src_device, byte_count, h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_D_TO_H_ASYNC) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from host memory to a 1D CUDA array. dst_array and dst_index * specify the CUDA array handle and starting index of the destination * data. p_src specifies the base address of the source. byte_count * specifies the number of bytes to copy. * * \param dst_array Destination array. * \param dst_index Offset of destination array. * \param p_src Source host pointer. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyHtoA(CUarray dst_array, unsigned int dst_index, const void *p_src, unsigned int byte_count) { CUresult result = 0; result = cuMemcpyHtoA(dst_array, dst_index, p_src, byte_count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_H_TO_A) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from host memory to a 1D CUDA array. dst_array and dst_index * specify the CUDA array handle and starting index of the destination * data. p_src specifies the base address of the source. byte_count * specfies the number of bytes to copy. * * cuMemcpyHtoAAsync() is asynchronous and can optionally be associated * to a stream by passing a non-zero h_stream argument. It only works on * page-locked memory and returns an error if a pointer to pageable * memory is passed as input. * * \param dst_array Destination array. * \param dst_index Offset of destination array. * \param p_src Source host pointer. * \param byte_count Size of memory copy in bytes. * \param h_stream Stream identifier. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyHtoAAsync(CUarray dst_array, unsigned int dst_index, const void *p_src, unsigned int byte_count, CUstream h_stream) { CUresult result = 0; result = cuMemcpyHtoAAsync(dst_array, dst_index, p_src, byte_count, h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_H_TO_A_ASYNC) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from host memory to device memory. dst_device and src_host * are the base addresses of the destination and source, respectively. * byte_count specifies the number of bytes to copy. Note that this * function is synchronous. * * \param dst_device Destination device pointer. * \param src_host Source host pointer. * \param byte_count Size of memory copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyHtoD(CUdeviceptr dst_device, const void *src_host, unsigned int byte_count) { CUresult result = 0; result = cuMemcpyHtoD(dst_device, src_host,byte_count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_H_TO_D) == -1) goto error; return 0; error: return -1; } /** * \brief Copies from host memory to device memory. dst_device and src_host are * the base addresses of the destination and source, respectively. * byte_count specifies the number of bytes to copy. * * cuMemcpyHtoDAsync() is asynchronous and can optionally be associated * to a stream by passing a non-zero h_stream argument. It only works on * page-locked memory and returns an error if a pointer to pageable * memory is passed as input. * * * \param dst_device Destination device pointer. * \param src_host Source host pointer. * \param byte_count Size of memory copy in bytes. * \param h_stream Stream identifier. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemcpyHtoDAsync(CUdeviceptr dst_device, const void *src_host, unsigned int byte_count, CUstream h_stream) { CUresult result = 0; result = cuMemcpyHtoDAsync(dst_device, src_host, byte_count, h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMCPY_H_TO_D_ASYNC) == -1) goto error; return 0; error: return -1; } /** * \brief Frees the memory space pointed to by dptr, which must have been * returned by a previous call to cuMemAlloc() or cuMemAllocPitch(). * * \param dptr Pointer to the memory to free. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemFree(CUdeviceptr dptr) { CUresult result = 0; result = cuMemFree(dptr); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_FREE) == -1) goto error; return 0; error: return -1; } /** * \brief Frees the memory space pointed to by p, which must have been returned * by a previous call to cuMemAllocHost(). * * \param p Pointer to the memory to free. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemFreeHost(void *p) { CUresult result = 0; if (p == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p is NULL"); goto error; } result = cuMemFreeHost(p); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_FREE_HOST) == -1) goto error; return 0; error: return -1; } /** * \brief Returns the base address in *pbase and size in *psize of the allocation * by cuMemAlloc() or cuMemAllocPitch() that contains the input pointer * dptr. Both parameters pbase and psize are optional. If one of them is * NULL, it is ignored. * * \param pbase Returned base address. * \param psize Returned size of device memory allocation. * \param dptr Device pointer to query * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemGetAddressRange(CUdeviceptr *pbase, unsigned int *psize, CUdeviceptr dptr) { CUresult result = 0; result = cuMemGetAddressRange(pbase, psize, dptr); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_GET_ADDRESS_RANGE) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *free and *total respectively, the free and total amount * of memory available for allocation by the CUDA context, in bytes. * * \param free Returned free memory in bytes. * \param total Returned total memory in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemGetInfo(unsigned int *free, unsigned int *total) { CUresult result = 0; if (free == NULL || total == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "free is NULL || total is NULL"); goto error; } result = cuMemGetInfo(free, total); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_GET_INFO) == -1) goto error; return 0; error: return -1; } /** * \brief Allocates bytesize bytes of host memory that is page-locked and * accessible to the device. The driver tracks the virtual memory ranges * allocated with this function and automatically accelerates calls to * functions such as cuMemcpyHtoD(). Since the memory can be accessed * directly by the device, it can be read or written with much higher * bandwidth than pageable memory obtained with functions such as * SCMalloc(). Allocating excessive amounts of pinned memory may degrade * system performance, since it reduces the amount of memory available * to the system for paging. As a result, this function is best used * sparingly to allocate staging areas for data exchange between host * and device. * * The Flags parameter enables different options to be specified that * affect the allocation, as follows. * * - CU_MEMHOSTALLOC_PORTABLE: The memory returned by this call will be * considered as pinned memory by all CUDA contexts, not just the one * that performed the allocation. * - CU_MEMHOSTALLOC_DEVICEMAP: Maps the allocation into the CUDA * address space. The device pointer to the memory may be obtained by * calling cuMemHostGetDevicePointer(). This feature is available only * on GPUs with compute capability greater than or equal to 1.1. * - CU_MEMHOSTALLOC_WRITECOMBINED: Allocates the memory as write-combined * (WC). WC memory can be transferred across the PCI Express bus more * quickly on some system con?gurations, but cannot be read efficiently * by most CPUs. WC memory is a good option for buffers that will be * written by the CPU and read by the GPU via mapped pinned memory or * host->device transfers. All of these fags are orthogonal to one * another: a developer may allocate memory that is portable, mapped * and/or write-combined with no restrictions. * * The CUDA context must have been created with the CU_CTX_MAP_HOST flag * in order for the CU_MEMHOSTALLOC_MAPPED flag to have any effect. * * The CU_MEMHOSTALLOC_MAPPED flag may be specified on CUDA contexts for * devices that do not support mapped pinned memory. The failure is * deferred to cuMemHostGetDevicePointer() because the memory may be * mapped into other CUDA contexts via the CU_MEMHOSTALLOC_PORTABLE flag. * * The memory allocated by this function must be freed with cuMemFreeHost(). * * \param pp Returned host pointer to page-locked memory. * \param byte_size Requested allocation size in bytes. * \param flags Flags for allocation request. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemHostAlloc(void **pp, size_t byte_size, unsigned int flags) { CUresult result = 0; result = cuMemHostAlloc(pp, byte_size, flags); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_HOST_ALLOC) == -1) goto error; return 0; error: return -1; } /** * \brief Passes back the device pointer pdptr corresponding to the mapped, * pinned host buffer p allocated by cuMemHostAlloc. * * cuMemHostGetDevicePointer() will fail if the CU_MEMALLOCHOST_DEVICEMAP * flag was not speci?ed at the time the memory was allocated, or if the * function is called on a GPU that does not support mapped pinned memory. * * Flags provides for future releases. For now, it must be set to 0. * * \param pdptr Returned device pointer. * \param p Host pointer. * \param flags Options(must be 0). * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemHostGetDevicePointer(CUdeviceptr *pdptr, void *p, unsigned int flags) { CUresult result = 0; result = cuMemHostGetDevicePointer(pdptr, p, flags); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_HOST_GET_DEVICE_POINTER) == -1) goto error; return 0; error: return -1; } /** * \brief Passes back the flags p_flags that were specified when allocating the * pinned host buffer p allocated by cuMemHostAlloc. * * cuMemHostGetFlags() will fail if the pointer does not reside in an * allocation performed by cuMemAllocHost() or cuMemHostAlloc(). * * \param p_flags Returned flags word. * \param p Host pointer. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemHostGetFlags(unsigned int *p_flags, void *p) { CUresult result = 0; result = cuMemHostGetFlags(p_flags, p); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEM_HOST_GET_FLAGS) == -1) goto error; return 0; error: return -1; } /** * \brief Sets the memory range of N 16-bit values to the speci?ed value us. * * \param dst_device Destination device pointer. * \param us Value to set. * \param n Number of elements. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemsetD16(CUdeviceptr dst_device, unsigned short us, unsigned int n) { CUresult result = 0; result = cuMemsetD16(dst_device, us, n); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMSET_D16) == -1) goto error; return 0; error: return -1; } /** * \brief Sets the 2D memory range of Width 16-bit values to the specified * value us. Height specifies the number of rows to set, and dst_pitch * specifies the number of bytes between each row. This function * performs fastest when the pitch is one that has been passed back * by cuMemAllocPitch(). * * \param dst_device Destination device pointer. * \param dst_pitch Pitch of destination device pointer. * \param us Value to set * \param width Width of row. * \param height Number of rows * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemsetD2D16(CUdeviceptr dst_device, unsigned int dst_pitch, unsigned short us, unsigned int width, unsigned int height) { CUresult result = 0; result = cuMemsetD2D16(dst_device, dst_pitch, us, width, height); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMSET_D2_D16) == -1) goto error; return 0; error: return -1; } /** * \brief Sets the 2D memory range of Width 32-bit values to the specified value * ui. Height speci?es the number of rows to set, and dstPitch specifies * the number of bytes between each row. This function performs fastest * when the pitch is one that has been passed back by cuMemAllocPitch(). * * \param dst_device Destination device pointer. * \param dst_pitch Pitch of destination device pointer. * \param ui Value to set * \param width Width of row. * \param height Number of rows * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemsetD2D32(CUdeviceptr dst_device, unsigned int dst_pitch, unsigned int ui, unsigned int width, unsigned int height) { CUresult result = 0; result = cuMemsetD2D32(dst_device, dst_pitch, ui, width, height); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMSET_D2_D32) == -1) goto error; return 0; error: return -1; } /** * \brief Sets the 2D memory range of Width 8-bit values to the specified value * uc. Height speci?es the number of rows to set, and dstPitch specifies * the number of bytes between each row. This function performs fastest * when the pitch is one that has been passed back by cuMemAllocPitch(). * * \param dst_device Destination device pointer. * \param dst_pitch Pitch of destination device pointer. * \param uc Value to set * \param width Width of row. * \param height Number of rows * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemsetD2D8(CUdeviceptr dst_device, unsigned int dst_pitch, unsigned char uc, unsigned int width, unsigned int height) { CUresult result = 0; result = cuMemsetD2D8(dst_device, dst_pitch, uc, width, height); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMSET_D2_D8) == -1) goto error; return 0; error: return -1; } /** * \brief Sets the memory range of N 32-bit values to the specified value ui. * * \param dst_device Destination device pointer. * \param ui Value to set. * \param n Number of elements. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemsetD32(CUdeviceptr dst_device, unsigned int ui, unsigned int n) { CUresult result = 0; result = cuMemsetD32(dst_device, ui, n); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMSET_D32) == -1) goto error; return 0; error: return -1; } /** * \brief Sets the memory range of N 8-bit values to the specified value ui. * * \param dst_device Destination device pointer. * \param uc Value to set. * \param n Number of elements. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaMemsetD8(CUdeviceptr dst_device, unsigned char uc, unsigned int n) { CUresult result = 0; result = cuMemsetD8(dst_device, uc, n); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MEMSET_D8) == -1) goto error; return 0; error: return -1; } /***********************Texture_Reference_Management_API***********************/ /** * \brief Creates a texture reference and returns its handle in *pTexRef. Once * created, the application must call cuTexRefSetArray() or cuTexRefSetAddress() * to associate the reference with allocated memory. Other texture reference * functions are used to specify the format and interpretation (addressing, * filtering, etc.) to be used when the memory is read through this texture * reference. To associate the texture reference with a texture ordinal for * a given function, the application should call cuParamSetTexRef(). * * \param p_tex_ref Returned texture reference * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefCreate(CUtexref *p_tex_ref) { CUresult result = 0; if (p_tex_ref == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_tex_ref is NULL"); goto error; } result = cuTexRefCreate(p_tex_ref); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_CREATE) == -1) goto error; return 0; error: return -1; } /** * \brief Destroys the texture reference specified by hTexRef. * * \param h_tex_ref Texture reference to destroy * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefDestroy(CUtexref h_tex_ref) { CUresult result = 0; result = cuTexRefDestroy(h_tex_ref); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_DESTROY) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *pdptr the base address bound to the texture reference * hTexRef, or returns CUDA_ERROR_INVALID_VALUE if the texture reference * is not bound to any device memory range. * * \param pdptr Returned device address * \param h_tex_ref Texture reference * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefGetAddress(CUdeviceptr *pdptr, CUtexref h_tex_ref) { CUresult result = 0; if (pdptr == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "pdptr is NULL"); goto error; } result = cuTexRefGetAddress(pdptr, h_tex_ref); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_GET_ADDRESS) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *pam the addressing mode corresponding to the dimension * dim of the texture reference hTexRef. Currently, the only valid value * for dim are 0 and 1. * * \param pam Returned addressing mode * \param h_tex_ref Texture reference * \param dim Dimension * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefGetAddressMode(CUaddress_mode *pam, CUtexref h_tex_ref, int dim) { CUresult result = 0; if (pam == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "pam is NULL"); goto error; } result = cuTexRefGetAddressMode(pam, h_tex_ref, dim); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_GET_ADDRESS_MODE) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *phArray the CUDA array bound to the texture reference * hTexRef, or returns CUDA_ERROR_INVALID_VALUE if the texture reference * is not bound to any CUDA array. * * \param ph_array Returned array * \param h_tex_ref Texture reference * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefGetArray(CUarray *ph_array, CUtexref h_tex_ref) { CUresult result = 0; if (ph_array == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "ph_array is NULL"); goto error; } result = cuTexRefGetArray(ph_array, h_tex_ref); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_GET_ARRAY) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *pfm the filtering mode of the texture reference hTexRef. * * \param pfm Returned filtering mode * \param h_tex_ref Texture reference * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefGetFilterMode(CUfilter_mode *pfm, CUtexref h_tex_ref) { CUresult result = 0; if (pfm == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "pfm is NULL"); goto error; } result = cuTexRefGetFilterMode(pfm, h_tex_ref); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_GET_FILTER_MODE) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *pFlags the flags of the texture reference hTexRef. * * \param p_flags Returned flags * \param h_tex_ref Texture reference * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefGetFlags(unsigned int *p_flags, CUtexref h_tex_ref) { CUresult result = 0; if (p_flags == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_flags is NULL"); goto error; } result = cuTexRefGetFlags(p_flags, h_tex_ref); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_GET_FLAGS) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *pFormat and *pNumChannels the format and number of * components of the CUDA array bound to the texture reference hTexRef. * If pFormat or pNumChannels is NULL, it will be ignored. * * \param p_format Returned format * \param p_num_channels Returned number of components * \param h_tex_ref Texture reference * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefGetFormat(CUarray_format *p_format, int *p_num_channels, CUtexref h_tex_ref) { CUresult result = 0; if (p_format == NULL || p_num_channels == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_format == NULL || p_num_channels == NULL"); goto error; } result = cuTexRefGetFormat(p_format, p_num_channels, h_tex_ref); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_GET_FORMAT) == -1) goto error; return 0; error: return -1; } /** * \brief Binds a linear address range to the texture reference hTexRef. Any * previous address or CUDA array state associated with the texture * reference is superseded by this function. Any memory previously * bound to hTexRef is unbound. * * Since the hardware enforces an alignment requirement on texture * base addresses, cuTexRefSetAddress() passes back a byte offset in * *ByteOffset that must be applied to texture fetches in order to read * from the desired memory. This offset must be divided by the texel * size and passed to kernels that read from the texture so they can be * applied to the tex1Dfetch() function. * * If the device memory pointer was returned from cuMemAlloc(), the * offset is guaranteed to be 0 and NULL may be passed as the * ByteOffset parameter. * * \param byte_offset Returned byte offset * \param h_tex_ref Texture reference to bind * \param dptr Device pointer to bind * \param bytes Size of memory to bind in bytes * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefSetAddress(unsigned int *byte_offset, CUtexref h_tex_ref, CUdeviceptr dptr, unsigned int bytes) { CUresult result = 0; if (byte_offset == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "byte_offset is NULL"); goto error; } result = cuTexRefSetAddress(byte_offset, h_tex_ref, dptr, bytes); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_SET_ADDRESS) == -1) goto error; return 0; error: return -1; } /** * \brief Binds a linear address range to the texture reference hTexRef. Any * previous address or CUDA array state associated with the texture * reference is superseded by this function. Any memory previously bound * to hTexRef is unbound. * * Using a tex2D() function inside a kernel requires a call to either * cuTexRefSetArray() to bind the corresponding texture reference to an * array, or cuTexRefSetAddress2D() to bind the texture reference to * linear memory. * * Function calls to cuTexRefSetFormat() cannot follow calls to * cuTexRefSetAddress2D() for the same texture reference. * * It is required that dptr be aligned to the appropriate hardware- * specific texture alignment. You can query this value using the device * attribute CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT. If an unaligned dptr * is supplied, CUDA_ERROR_INVALID_VALUE is returned. * * \param h_tex_ref Texture reference to bind * \param desc Descriptor of CUDA array * \param dptr Device pointer to bind * \param pitch Line pitch in bytes * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefSetAddress2D(CUtexref h_tex_ref, const CUDA_ARRAY_DESCRIPTOR *desc, CUdeviceptr dptr, unsigned int pitch) { CUresult result = 0; result = cuTexRefSetAddress2D(h_tex_ref, desc, dptr, pitch); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_SET_ADDRESS_2D) == -1) goto error; return 0; error: return -1; } /** * \brief Specifies the addressing mode am for the given dimension dim of the * texture reference hTexRef. If dim is zero, the addressing mode is * applied to the first parameter of the functions used to fetch from * the texture; if dim is 1, the second, and so on. CUaddress_mode is * defined as: * * typedef enum CUaddress_mode_enum { * CU_TR_ADDRESS_MODE_WRAP = 0, * CU_TR_ADDRESS_MODE_CLAMP = 1, * CU_TR_ADDRESS_MODE_MIRROR = 2, * } CUaddress_mode; * * \param h_tex_ref Texture reference * \param dim Dimension * \param am Addressing mode to set * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefSetAddressMode(CUtexref h_tex_ref, int dim, CUaddress_mode am) { CUresult result = 0; result = cuTexRefSetAddressMode(h_tex_ref, dim, am); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_SET_ADDRESS_MODE) == -1) goto error; return 0; error: return -1; } /** * \brief Binds the CUDA array hArray to the texture reference hTexRef. Any * previous address or CUDA array state associated with the texture * reference is superseded by this function. Flags must be set to * CU_TRSA_OVERRIDE_FORMAT. Any CUDA array previously bound to hTexRef * is unbound. * * \param h_tex_ref Texture reference to bind * \param h_array Array to bind * \param flags Options (must be CU_TRSA_OVERRIDE_FORMAT) * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefSetArray(CUtexref h_tex_ref, CUarray h_array, unsigned int flags) { CUresult result = 0; result = cuTexRefSetArray(h_tex_ref, h_array, flags); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_SET_ARRAY) == -1) goto error; return 0; error: return -1; } /** * \brief Specifies the filtering mode fm to be used when reading memory through * the texture reference hTexRef. CUfilter_mode_enum is defined as: * * typedef enum CUfilter_mode_enum { * CU_TR_FILTER_MODE_POINT = 0, * CU_TR_FILTER_MODE_LINEAR = 1 * } CUfilter_mode; * * \param h_tex_ref Texture reference * \param fm Filtering mode to set * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefSetFilterMode(CUtexref h_tex_ref, CUfilter_mode fm) { CUresult result = 0; result = cuTexRefSetFilterMode(h_tex_ref, fm); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_SET_FILTER_MODE) == -1) goto error; return 0; error: return -1; } /** * \brief Specifies optional flags via Flags to specify the behavior of data * returned through the texture reference hTexRef. The valid flags are: * * * CU_TRSF_READ_AS_INTEGER, which suppresses the default behavior of * having the texture promote integer data to floating point data in * the range [0, 1]; * * CU_TRSF_NORMALIZED_COORDINATES, which suppresses the default * behavior of having the texture coordinates range from [0, Dim) where * Dim is the width or height of the CUDA array. Instead, the texture * coordinates [0, 1.0) reference the entire breadth of the array * dimension; * * \param h_tex_ref Texture reference * \param flags Optional flags to set * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefSetFlags(CUtexref h_tex_ref, unsigned int flags) { CUresult result = 0; result = cuTexRefSetFlags(h_tex_ref, flags); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_SET_FLAGS) == -1) goto error; return 0; error: return -1; } /** * \brief Specifies the format of the data to be read by the texture reference * hTexRef. fmt and NumPackedComponents are exactly analogous to the * Format and NumChannels members of the CUDA_ARRAY_DESCRIPTOR structure: * They specify the format of each component and the number of components * per array element. * * \param h_tex_ref Texture reference * \param fmt Format to set * \param num_packed_components Number of components per array element * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaTexRefSetFormat(CUtexref h_tex_ref, CUarray_format fmt, int num_packed_components) { CUresult result = 0; result = cuTexRefSetFormat(h_tex_ref, fmt, num_packed_components); if (SCCudaHandleRetValue(result, SC_CUDA_CU_TEX_REF_SET_FORMAT) == -1) goto error; return 0; error: return -1; } /***********************Execution_Control_Management_API***********************/ /** * \brief Returns in *pi the integer value of the attribute attrib on the * kernel given by hfunc. The supported attributes are: * * - CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK: The number of threads * beyond which a launch of the function would fail. This number * depends on both the function and the device on which the * function is currently loaded. * - CU_FUNC_ATTRIBUTE_SHARED_SIZE_BYTES: The size in bytes of * statically-allocated shared memory required by this function. * This does not include dynamically-allocated shared memory * requested by the user at runtime. * - CU_FUNC_ATTRIBUTE_CONST_SIZE_BYTES: The size in bytes of * user-allocated constant memory required by this function. * - CU_FUNC_ATTRIBUTE_LOCAL_SIZE_BYTES: The size in bytes of thread * local memory used by this function. * - CU_FUNC_ATTRIBUTE_NUM_REGS: The number of registers used by each * thread of this function. * * \param pi Pointer to an integer which would be updated with the returned * attribute value. * \param attrib Attribute requested. * \param hfunc Function to query attribute of. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaFuncGetAttribute(int *pi, CUfunction_attribute attrib, CUfunction hfunc) { CUresult result = 0; if (pi == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "pi is NULL"); goto error; } result = cuFuncGetAttribute(pi, attrib, hfunc); if (SCCudaHandleRetValue(result, SC_CUDA_CU_FUNC_GET_ATTRIBUTE) == -1) goto error; return 0; error: return -1; } /** * \brief Specifies the x, y, and z dimensions of the thread blocks that are * created when the kernel given by hfunc is launched. * * \param hfunc Kernel to specify dimensions of. * \param x X dimension. * \param y Y dimension. * \param z Z dimension. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaFuncSetBlockShape(CUfunction hfunc, int x, int y, int z) { CUresult result = 0; result = cuFuncSetBlockShape(hfunc, x, y, z); if (SCCudaHandleRetValue(result, SC_CUDA_CU_FUNC_SET_BLOCK_SHAPE) == -1) goto error; return 0; error: return -1; } /** * \brief Sets through bytes the amount of dynamic shared memory that will be * available to each thread block when the kernel given by hfunc is * launched. * * \param hfunc Kernel to specify dynamic shared memory for. * \param bytes Dynamic shared memory size per thread in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaFuncSetSharedSize(CUfunction hfunc, unsigned int bytes) { CUresult result = 0; result = cuFuncSetSharedSize(hfunc, bytes); if (SCCudaHandleRetValue(result, SC_CUDA_CU_FUNC_SET_SHARED_SIZE) == -1) goto error; return 0; error: return -1; } /** * \brief Invokes the kernel f on a 1 x 1 x 1 grid of blocks. The block contains * the number of threads specified by a previous call to * cuFuncSetBlockShape(). * * \param f Kernel to launch. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaLaunch(CUfunction f) { CUresult result = 0; result = cuLaunch(f); if (SCCudaHandleRetValue(result, SC_CUDA_CU_LAUNCH) == -1) goto error; return 0; error: return -1; } /** * \brief Invokes the kernel f on a grid_width x grid_height grid of blocks. * Each block contains the number of threads specified by a previous call * to cuFuncSetBlockShape(). * * \param f Kernel to launch. * \param grid_width Width of grid in blocks. * \param grib_height Height of grid in blocks. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaLaunchGrid(CUfunction f, int grid_width, int grid_height) { CUresult result = 0; result = cuLaunchGrid(f, grid_width, grid_height); if (SCCudaHandleRetValue(result, SC_CUDA_CU_LAUNCH_GRID) == -1) goto error; return 0; error: return -1; } /** * \brief Invokes the kernel f on a grid_width x grid_height grid of blocks. * Each block contains the number of threads specified by a previous call * to cuFuncSetBlockShape(). cuLaunchGridAsync() can optionally be * associated to a stream by passing a non-zero hStream argument. * * \param f Kernel to launch. * \param grid_width Width of grid in blocks. * \param grib_height Height of grid in blocks. * \param h_stream Stream identifier. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaLaunchGridAsync(CUfunction f, int grid_width, int grid_height, CUstream h_stream) { CUresult result = 0; result = cuLaunchGridAsync(f, grid_width, grid_height, h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_LAUNCH_GRID_ASYNC) == -1) goto error; return 0; error: return -1; } /** * \brief Sets a foating-point parameter that will be specified the next time * the kernel corresponding to hfunc will be invoked. offset is a byte * offset. * * \param h_func Kernel to add parameter to. * \param offset Offset to add parameter to argument list. * \param value Value of parameter. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaParamSetf(CUfunction h_func, int offset, float value) { CUresult result = 0; result = cuParamSetf(h_func, offset, value); if (SCCudaHandleRetValue(result, SC_CUDA_CU_PARAM_SETF) == -1) goto error; return 0; error: return -1; } /** * \brief Sets an integer parameter that will be specified the next time * the kernel corresponding to hfunc will be invoked. offset is a byte * offset. * * \param h_func Kernel to add parameter to. * \param offset Offset to add parameter to argument list. * \param value Value of parameter. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaParamSeti(CUfunction h_func, int offset, unsigned int value) { CUresult result = 0; result = cuParamSeti(h_func, offset, value); if (SCCudaHandleRetValue(result, SC_CUDA_CU_PARAM_SETI) == -1) goto error; return 0; error: return -1; } /** * \brief Sets through numbytes the total size in bytes needed by the function * parameters of the kernel corresponding to hfunc. * * \param h_func Kernel to set parameter size for. * \param num_bytes Size of paramter list in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaParamSetSize(CUfunction h_func, unsigned int num_bytes) { CUresult result = 0; result = cuParamSetSize(h_func, num_bytes); if (SCCudaHandleRetValue(result, SC_CUDA_CU_PARAM_SET_SIZE) == -1) goto error; return 0; error: return -1; } /** * \brief Makes the CUDA array or linear memory bound to the texture reference * h_tex_ref available to a device program as a texture. In this version * of CUDA, the texture-reference must be obtained via cuModuleGetTexRef() * and the tex_unit parameter must be set to CU_PARAM_TR_DEFAULT. * * \param h_func Kernel to add texture-reference to. * \param tex_unit Texture unit (must be CU_PARAM_TR_DEFAULT). * \param h_tex_ref Texture-reference to add to argument list. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaParamSetTexRef(CUfunction h_func, int tex_unit, CUtexref h_tex_ref) { CUresult result = 0; result = cuParamSetTexRef(h_func, tex_unit, h_tex_ref); if (SCCudaHandleRetValue(result, SC_CUDA_CU_PARAM_SET_TEX_REF) == -1) goto error; return 0; error: return -1; } /** * \brief Copies an arbitrary amount of data (specified in numbytes) from ptr * into the parameter space of the kernel corresponding to hfunc. * offset is a byte offset. * * \param h_func Kernel to add data to. * \param offset Offset to add data to argument list. * \param ptr Pointer to arbitrary data. * \param num_bytes Size of data to copy in bytes. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaParamSetv(CUfunction h_func, int offset, void *ptr, unsigned int num_bytes) { CUresult result = 0; if (ptr == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "ptr is NULL"); goto error; } result = cuParamSetv(h_func, offset, ptr, num_bytes); if (SCCudaHandleRetValue(result, SC_CUDA_CU_PARAM_SETV) == -1) goto error; return 0; error: return -1; } /*****************************Event_Management_API*****************************/ /** * \brief Creates an event *ph_event with the flags specified via flags. Valid * flags include: * * CU_EVENT_DEFAULT: Default event creation flag. * CU_EVENT_BLOCKING_SYNC: Specifies that event should use blocking * synchronization. * * \param ph_event Returns newly created event. * \param flags Event creation flags. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaEventCreate(CUevent *ph_event, unsigned int flags) { CUresult result = 0; if (ph_event == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "ph_event is NULL"); goto error; } result = cuEventCreate(ph_event, flags); if (SCCudaHandleRetValue(result, SC_CUDA_CU_EVENT_CREATE) == -1) goto error; return 0; error: return -1; } /** * \brief Destroys the event specified by h_event. * * \param h_event Event to destroy. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaEventDestroy(CUevent h_event) { CUresult result = 0; result = cuEventDestroy(h_event); if (SCCudaHandleRetValue(result, SC_CUDA_CU_EVENT_DESTROY) == -1) goto error; return 0; error: return -1; } /** * \brief Computes the elapsed time between two events (in milliseconds with * a resolution of around 0.5 microseconds). If either event has not * been recorded yet, this function returns CUDA_ERROR_NOT_READY. If * either event has been recorded with a non-zero stream, the result * is undefined. * * \param p_milli_seconds Returned elapsed time in milliseconds. * \param h_start Starting event. * \param h_end Ending event. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaEventElapsedTime(float *p_milli_seconds, CUevent h_start, CUevent h_end) { CUresult result = 0; if (p_milli_seconds == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_milli_seconds is NULL"); goto error; } result = cuEventElapsedTime(p_milli_seconds, h_start, h_end); if (SCCudaHandleRetValue(result, SC_CUDA_CU_EVENT_ELAPSED_TIME) == -1) goto error; return 0; error: return -1; } /** * \brief Returns CUDA_SUCCESS if the event has actually been recorded, or * CUDA_ERROR_NOT_READY if not. If cuEventRecord() has not been called * on this event, the function returns CUDA_ERROR_INVALID_VALUE. * * \param h_event Event to query. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaEventQuery(CUevent h_event) { CUresult result = 0; result = cuEventQuery(h_event); if (SCCudaHandleRetValue(result, SC_CUDA_CU_EVENT_QUERY) == -1) goto error; return 0; error: return -1; } /** * \brief Records an event. If stream is non-zero, the event is recorded after * all preceding operations in the stream have been completed; otherwise, * it is recorded after all preceding operations in the CUDA context have * been completed. Since operation is asynchronous, cuEventQuery() and/or * cuEventSynchronize() must be used to determine when the event has * actually been recorded. * * If cuEventRecord() has previously been called and the event has not * been recorded yet, this function returns CUDA_ERROR_INVALID_VALUE. * * \param h_event Event to record. * \param h_stream Stream to record event for. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaEventRecord(CUevent h_event, CUstream h_stream) { CUresult result = 0; result = cuEventRecord(h_event, h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_EVENT_RECORD) == -1) goto error; return 0; error: return -1; } /** * \brief Waits until the event has actually been recorded. If cuEventRecord() * has been called on this event, the function returns * CUDA_ERROR_INVALID_VALUE. * * If cuEventRecord() has previously been called and the event has not * been recorded yet, this function returns CUDA_ERROR_INVALID_VALUE. * * \param h_event Event to wait for. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaEventSynchronize(CUevent h_event) { CUresult result = 0; result = cuEventSynchronize(h_event); if (SCCudaHandleRetValue(result, SC_CUDA_CU_EVENT_SYNCHRONIZE) == -1) goto error; return 0; error: return -1; } /*****************************Stream_Management_API****************************/ /** * \brief Creates a stream and returns a handle in ph_stream. Flags is * required to be 0. * * \param ph_stream Returned newly created stream. * \param flags Parameters for stream creation(must be 0). * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaStreamCreate(CUstream *ph_stream, unsigned int flags) { CUresult result = 0; if (ph_stream == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "phStream is NULL"); goto error; } result = cuStreamCreate(ph_stream, flags); if (SCCudaHandleRetValue(result, SC_CUDA_CU_STREAM_CREATE) == -1) goto error; return 0; error: return -1; } /** * \brief Destroys the stream specified by h_stream. * * \param h_stream Stream to destroy. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaStreamDestroy(CUstream h_stream) { CUresult result = 0; result = cuStreamDestroy(h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_STREAM_DESTROY) == -1) goto error; return 0; error: return -1; } /** * \brief Returns CUDA_SUCCESS if all operations in the stream specifed by * h_stream have completed, or CUDA_ERROR_NOT_READY if not. * * \param h_stream Stream to query status of. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaStreamQuery(CUstream h_stream) { CUresult result = 0; result = cuStreamQuery(h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_STREAM_QUERY) == -1) goto error; return 0; error: return -1; } /** * \brief Waits until the device has completed all operations in the stream * specified by h_stream. * * \param h_stream Stream to wait for. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaStreamSynchronize(CUstream h_stream) { CUresult result = 0; result = cuStreamSynchronize(h_stream); if (SCCudaHandleRetValue(result, SC_CUDA_CU_STREAM_SYNCHRONIZE) == -1) goto error; return 0; error: return -1; } /*****************************Module_Management_API****************************/ /** * \brief Returns in *hfunc the handle of the function of name \"name\" located * in module hmod. If no function of that name exists, * cuModuleGetFunction() returns CUDA_ERROR_NOT_FOUND. * * \param hfunc Returned function handle. * \param hmod Module to return function from. * \param name Name of function to retrieve. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaModuleGetFunction(CUfunction *hfunc, CUmodule hmod, const char *name) { CUresult result = 0; if (hfunc == NULL || name == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "hfunc is NULL or name is NULL"); goto error; } result = cuModuleGetFunction(hfunc, hmod, name); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MODULE_GET_FUNCTION) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *dptr and *bytes the base pointer and size of the global * name \"name\" located in module hmod. If no variable of that name * exists, cuModuleGetGlobal() returns CUDA_ERROR_NOT_FOUND. Both * parameters dptr and bytes are optional. If one of them is NULL, * it is ignored. * * \param dptr Returned global device pointer. * \param bytes Returned global size in bytes. * \param hmod Module to return function from. * \param name Name of global to retrieve. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaModuleGetGlobal(CUdeviceptr *dptr, unsigned int *bytes, CUmodule hmod, const char *name) { CUresult result = 0; if (name == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "name is NULL"); goto error; } result = cuModuleGetGlobal(dptr, bytes, hmod, name); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MODULE_GET_GLOBAL) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *p_tex_ref the handle of the texture reference of name * \"name\" in the module hmod. If no texture reference of that name * exists, cuModuleGetTexRef() returns CUDA_ERROR_NOT_FOUND. This texture * reference handle should not be destroyed, since it will be destroyed * when the module is unloaded. * * \param p_tex_ref Returned global device pointer. * \param hmod Module to retrieve texture reference from. * \param name Name of the texture reference to retrieve. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaModuleGetTexRef(CUtexref *p_tex_ref, CUmodule hmod, const char *name) { CUresult result = 0; if (p_tex_ref == NULL || name == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "p_tex_ref is NULL or name is NULL"); goto error; } result = cuModuleGetTexRef(p_tex_ref, hmod, name); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MODULE_GET_TEX_REF) == -1) goto error; return 0; error: return -1; } /** * \brief Takes a filename fname and loads the corresponding module \"module\" * into the current context. The CUDA driver API does not attempt to * lazily allocate the resources needed by a module; if the memory for * functions and data (constant and global) needed by the module cannot * be allocated, cuModuleLoad() fails. The file should be a cubin file * as output by nvcc or a PTX file, either as output by nvcc or handwrtten. * * \param module Returned module. * \param fname Filename of module to load. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaModuleLoad(CUmodule *module, const char *fname) { CUresult result = 0; if (module == NULL || fname == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "module is NULL or fname is NULL"); goto error; } result = cuModuleLoad(module, fname); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MODULE_LOAD) == -1) goto error; return 0; error: return -1; } /** * \brief Takes a pointer image and loads the corresponding module \"module\" * into the current context. The pointer may be obtained by mapping a * cubin or PTX file, passing a cubin or PTX ?le as a NULL-terminated * text string, or incorporating a cubin object into the executable * resources and using operating system calls such as Windows * FindResource() to obtain the pointer. * * \param module Returned module. * \param image Module data to load * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaModuleLoadData(CUmodule *module, const char *image) { CUresult result = 0; if (module == NULL || image == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "module is NULL or image is NULL"); goto error; } result = cuModuleLoadData(module, image); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MODULE_LOAD_DATA) == -1) goto error; return 0; error: return -1; } /** * \brief Takes a pointer image and loads the corresponding module module into * the current context. The pointer may be obtained by mapping a cubin or * PTX file, passing a cubin or PTX file as a NULL-terminated text * string, or incorporating a cubin object into the executable resources * and using operating system calls such as Windows FindResource() to * obtain the pointer. Options are passed as an array via options and any * corresponding parameters are passed in optionValues. The number of * total options is supplied via numOptions. Any outputs will be returned * via optionValues. Supported options are: * * - CU_JIT_MAX_REGISTERS: input specifies the maximum number of registers * per thread; * - CU_JIT_THREADS_PER_BLOCK: input specifies number of threads per block * to target compilation for; output returns the number of threads * the compiler actually targeted; * - CU_JIT_WALL_TIME: output returns the float value of wall clock time, * in milliseconds, spent compiling the PTX code; * - CU_JIT_INFO_LOG_BUFFER: input is a pointer to a buffer in which to * print any informational log messages from PTX assembly; * - CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES: input is the size in bytes of the * buffer; output is the number of bytes filled with messages; * - CU_JIT_ERROR_LOG_BUFFER: input is a pointer to a buffer in which to * print any error log messages from PTX assembly; * - CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES: input is the size in bytes of the * buffer; output is the number of bytes filled with messages; * - CU_JIT_OPTIMIZATION_LEVEL: input is the level of optimization to apply * to generated code (0 - 4), with 4 being the default and highest * level; * - CU_JIT_TARGET_FROM_CUCONTEXT: causes compilation target to be * determined based on current attached context (default); * - CU_JIT_TARGET: input is the compilation target based on supplied * CUjit_target_enum; possible values are: * -- CU_TARGET_COMPUTE_10 * -- CU_TARGET_COMPUTE_11 * -- CU_TARGET_COMPUTE_12 * -- CU_TARGET_COMPUTE_13 * * \param module Returned module. * \param image Module data to load. * \param numOptions Number of options. * \param options Options for JIT. * \param optionValues Option values for JIT. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaModuleLoadDataEx(CUmodule *module, const char *image, unsigned int num_options, CUjit_option *options, void **option_values) { CUresult result = 0; if (module == NULL || image == NULL || options == NULL || option_values == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "module is NULL or image is NULL or options is NULL or " "option_values is NULL"); goto error; } result = cuModuleLoadDataEx(module, image, num_options, options, option_values); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MODULE_LOAD_DATA_EX) == -1) goto error; return 0; error: return -1; } /** * \brief Takes a pointer fat_cubin and loads the corresponding module \"module\" * into the current context. The pointer represents a fat binary object, * which is a collection of different cubin files, all representing the * same device code, but compiled and optimized for different * architectures. There is currently no documented API for constructing * and using fat binary objects by programmers, and therefore this * function is an internal function in this version of CUDA. More * information can be found in the nvcc document. * * \param module Returned module. * \param fatCubin Fat binary to load. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaModuleLoadFatBinary(CUmodule *module, const void *fat_cubin) { CUresult result = 0; if (module == NULL || fat_cubin == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "module is NULL or fatCubin is NULL"); goto error; } result = cuModuleLoadFatBinary(module, fat_cubin); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MODULE_LOAD_FAT_BINARY) == -1) goto error; return 0; error: return -1; } /** * \brief Unloads a module hmod from the current context. * * \param module Module to unload * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaModuleUnload(CUmodule hmod) { CUresult result = 0; result = cuModuleUnload(hmod); if (SCCudaHandleRetValue(result, SC_CUDA_CU_MODULE_UNLOAD) == -1) goto error; return 0; error: return -1; } /*****************************Context_Management_API***************************/ /** * \brief Increments the usage count of the context and passes back a context * handle in *pctx that must be passed to cuCtxDetach() when the * application is done with the context. cuCtxAttach() fails if there is * no context current to the thread. Currently, the flags parameter must * be 0. * * \param pctx Returned context handle of the current context. * \param flags Context attach flags (must be 0). * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaCtxAttach(CUcontext *pctx, unsigned int flags) { CUresult result = 0; if (pctx == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "pctx NULL"); goto error; } result = cuCtxAttach(pctx, flags); if (SCCudaHandleRetValue(result, SC_CUDA_CU_CTX_ATTACH) == -1) goto error; return 0; error: return -1; } /** * \brief Creates a new CUDA context and associates it with the calling thread. * The flags parameter is described below. The context is created with * a usage count of 1 and the caller of cuCtxCreate() must call * cuCtxDestroy() or cuCtxDetach() when done using the context. If a * context is already current to the thread, it is supplanted by the * newly created context and may be restored by a subsequent call to * cuCtxPopCurrent(). The two LSBs of the flags parameter can be used * to control how the OS thread, which owns the CUDA context at the * time of an API call, interacts with the OS scheduler when waiting for * results from the GPU. * * - CU_CTX_SCHED_AUTO: The default value if the flags parameter is zero, * uses a heuristic based on the number of active CUDA contexts in * the process C and the number of logical processors in the system * P. If C > P, then CUDA will yield to other OS threads when * waiting for the GPU, otherwise CUDA will not yield while waiting * for results and actively spin on the processor. * - CU_CTX_SCHED_SPIN: Instruct CUDA to actively spin when waiting for * results from the GPU. This can de-crease latency when waiting for * the GPU, but may lower the performance of CPU threads if they are * performing work in parallel with the CUDA thread. * - CU_CTX_SCHED_YIELD: Instruct CUDA to yield its thread when waiting * for results from the GPU. This can increase latency when waiting * for the GPU, but can increase the performance of CPU threads * performing work in parallel with the GPU. * - CU_CTX_BLOCKING_SYNC: Instruct CUDA to block the CPU thread on a * synchronization primitive when waiting for the GPU to finish work. * - CU_CTX_MAP_HOST: Instruct CUDA to support mapped pinned allocations. * This flag must be set in order to allocate pinned host memory * that is accessible to the GPU. * * Note to Linux users: * Context creation will fail with CUDA_ERROR_UNKNOWN if the compute mode * of the device is CU_COMPUTEMODE_PROHIBITED. Similarly, context creation * will also fail with CUDA_ERROR_UNKNOWN if the compute mode for the * device is set to CU_COMPUTEMODE_EXCLUSIVE and there is already an * active context on the device. The function cuDeviceGetAttribute() can * be used with CU_DEVICE_ATTRIBUTE_COMPUTE_MODE to determine the compute * mode of the device. The nvidia-smi tool can be used to set the compute * mode for devices. Documentation for nvidia-smi can be obtained by * passing a -h option to it. * * \param pctx Returned context handle of the current context. * \param flags Context creation flags. * \param dev Device to create context on. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaCtxCreate(CUcontext *pctx, unsigned int flags, CUdevice dev) { CUresult result = 0; if (pctx == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "pctx NULL"); goto error; } result = cuCtxCreate(pctx, flags, dev); if (SCCudaHandleRetValue(result, SC_CUDA_CU_CTX_CREATE) == -1) goto error; return 0; error: return -1; } /** * \brief Destroys the CUDA context specified by ctx. If the context usage count * is not equal to 1, or the context is current to any CPU thread other * than the current one, this function fails. Floating contexts (detached * from a CPU thread via cuCtxPopCurrent()) may be destroyed by this * function. * * \param ctx Context to destroy. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaCtxDestroy(CUcontext ctx) { CUresult result = 0; result = cuCtxDestroy(ctx); if (SCCudaHandleRetValue(result, SC_CUDA_CU_CTX_DESTROY) == -1) goto error; return 0; error: return -1; } /** * \brief Decrements the usage count of the context ctx, and destroys the * context if the usage count goes to 0. The context must be a handle * that was passed back by cuCtxCreate() or cuCtxAttach(), and must be * current to the calling thread. * * \param ctx Context to destroy. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaCtxDetach(CUcontext ctx) { CUresult result = 0; result = cuCtxDetach(ctx); if (SCCudaHandleRetValue(result, SC_CUDA_CU_CTX_DETACH) == -1) goto error; return 0; error: return -1; } /** * \brief Returns in *device the ordinal of the current context's device. * * \param device Returned device id for the current context. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaCtxGetDevice(CUdevice *device) { CUresult result = 0; if (device == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "device NULL"); goto error; } result = cuCtxGetDevice(device); if (SCCudaHandleRetValue(result, SC_CUDA_CU_CTX_GET_DEVICE) == -1) goto error; return 0; error: return -1; } /** * \brief Pops the current CUDA context from the CPU thread. The CUDA context * must have a usage count of 1. CUDA contexts have a usage count of 1 * upon creation; the usage count may be incremented with cuCtxAttach() * and decremented with cuCtxDetach(). * * If successful, cuCtxPopCurrent() passes back the new context handle * in *pctx. The old context may then be made current to a different CPU * thread by calling cuCtxPushCurrent(). * * Floating contexts may be destroyed by calling cuCtxDestroy(). * * If a context was current to the CPU thread before cuCtxCreate() or * cuCtxPushCurrent() was called, this function makes that context * current to the CPU thread again. * * \param pctx Returned new context handle. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaCtxPopCurrent(CUcontext *pctx) { CUresult result = 0; result = cuCtxPopCurrent(pctx); if (SCCudaHandleRetValue(result, SC_CUDA_CU_CTX_POP_CURRENT) == -1) goto error; return 0; error: return -1; } /** * \brief Pushes the given context ctx onto the CPU thread's stack of current * contexts. The speci?ed context becomes the CPU thread's current * context, so all CUDA functions that operate on the current context * are affected. * * The previous current context may be made current again by calling * cuCtxDestroy() or cuCtxPopCurrent(). * * The context must be "floating," i.e. not attached to any thread. * Contexts are made to float by calling cuCtxPopCurrent(). * * \param ctx Floating context to attach. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaCtxPushCurrent(CUcontext ctx) { CUresult result = 0; result = cuCtxPushCurrent(ctx); if (SCCudaHandleRetValue(result, SC_CUDA_CU_CTX_PUSH_CURRENT) == -1) goto error; return 0; error: return -1; } /** * \brief Blocks until the device has completed all preceding requested tasks. * cuCtxSynchronize() returns an error if one of the preceding tasks failed. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaCtxSynchronize(void) { CUresult result = 0; result = cuCtxSynchronize(); if (SCCudaHandleRetValue(result, SC_CUDA_CU_CTX_SYNCHRONIZE) == -1) goto error; return 0; error: return -1; } /*****************************Version_Management_API***************************/ /** * \brief Returns in *driver_version the version number of the installed CUDA * driver. This function automatically returns CUDA_ERROR_INVALID_VALUE * if the driverVersion argument is NULL. * * \param driver_version Returns the CUDA driver version. * * \retval 0 On success. * \retval -1 On failure. */ int SCCudaDriverGetVersion(int *driver_version) { CUresult result = 0; if (driver_version == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "driver_version NULL"); goto error; } result = cuDriverGetVersion(driver_version); if (SCCudaHandleRetValue(result, SC_CUDA_CU_DRIVER_GET_VERSION) == -1) goto error; return 0; error: return -1; } /*****************************Device_Management_API****************************/ /** * \internal * \brief Gets the total no of devices with compute capability greater than or * equal to 1.0 that are available for execution. * * \param count Pointer to an integer that will be updated with the device count. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaDeviceGetCount(int *count) { CUresult result = 0; if (count == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "count NULL"); goto error; } result = cuDeviceGetCount(count); if (SCCudaHandleRetValue(result, SC_CUDA_CU_DEVICE_GET_COUNT) == -1) goto error; return 0; error: return -1; } /** * \internal * \brief Returns a device handle given an ordinal in the range * [0, cuDeviceGetCount() - 1]. * * \param device Pointer to a CUDevice instance that will be updated with the * device handle. * \param ordinal An index in the range [0, cuDeviceGetCount() - 1]. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaDeviceGet(CUdevice *device, int ordinal) { CUresult result = 0; if (device == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "device NULL"); goto error; } result = cuDeviceGet(device, ordinal); if (SCCudaHandleRetValue(result, SC_CUDA_CU_DEVICE_GET) == -1) goto error; return 0; error: return -1; } /** * \internal * \brief Returns the device name, given the device handle. * * \param name Pointer to a char buffer which will be updated with the device name. * \param len Length of the above buffer. * \param dev The device handle. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaDeviceGetName(char *name, int len, CUdevice dev) { CUresult result = 0; if (name == NULL || len == 0) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "name is NULL or len is 0"); goto error; } result = cuDeviceGetName(name, len, dev); if (SCCudaHandleRetValue(result, SC_CUDA_CU_DEVICE_GET_NAME) == -1) goto error; return 0; error: return -1; } /** * \internal * \brief Returns the total amount of memory availabe on the device which * is sent as the argument. * * \param bytes Pointer to an unsigned int instance, that will be updated with * total memory for the device. * \param dev The device handle. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaDeviceTotalMem(unsigned int *bytes, CUdevice dev) { CUresult result = 0; if (bytes == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "bytes is NULL"); goto error; } result = cuDeviceTotalMem(bytes, dev); if (SCCudaHandleRetValue(result, SC_CUDA_CU_DEVICE_TOTAL_MEM) == -1) goto error; return 0; error: return -1; } /** * \internal * \brief Returns the major and the minor revision numbers that define the * compute capability for the device that is sent as the argument. * * \param major Pointer to an integer, that will be updated with the major revision. * \param minor Pointer to an integer, that will be updated with the minor revision. * \param dev The device handle. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaDeviceComputeCapability(int *major, int *minor, CUdevice dev) { CUresult result = 0; if (major == NULL || minor == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "major is NULL or minor is NULL"); goto error; } result = cuDeviceComputeCapability(major, minor, dev); if (SCCudaHandleRetValue(result, SC_CUDA_CU_DEVICE_COMPUTE_CAPABILITY) == -1) goto error; return 0; error: return -1; } /** * \internal * \brief Returns the properties of the device. The CUdevprop structure is * defined as * * typedef struct CUdevprop_st { * int maxThreadsPerBlock; * int maxThreadsDim[3]; * int maxGridSize[3]; * int sharedMemPerBlock; * int totalConstantMemory; * int SIMDWidth; * int memPitch; * int regsPerBlock; * int clockRate; * int textureAlign * } CUdevprop; * * \param prop Pointer to a CUdevprop instance that holds the device properties. * \param dev The device handle. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaDeviceGetProperties(CUdevprop *prop, CUdevice dev) { CUresult result = 0; if (prop == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "prop is NULL"); goto error; } result = cuDeviceGetProperties(prop, dev); if (SCCudaHandleRetValue(result, SC_CUDA_CU_DEVICE_GET_PROPERTIES) == -1) goto error; return 0; error: return -1; } /** * \internal * \brief Returns the various attributes for the device that is sent as the arg. * * The supported attributes are: * * CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK: Maximum number of threads * per block; * CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X: Maximum x-dimension of a block; * CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y: Maximum y-dimension of a block; * CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z: Maximum z-dimension of a block; * CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X: Maximum x-dimension of a grid; * CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y: Maximum y-dimension of a grid; * CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z: Maximum z-dimension of a grid; * CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK: Maximum amount of * shared mem-ory available to a thread block in bytes; this amount * is shared by all thread blocks simultaneously resident on a * multiprocessor; * CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY: Memory available on device * for __constant_-_ variables in a CUDA C kernel in bytes; * CU_DEVICE_ATTRIBUTE_WARP_SIZE: Warp size in threads; * CU_DEVICE_ATTRIBUTE_MAX_PITCH: Maximum pitch in bytes allowed by the * memory copy functions that involve memory regions allocated * through cuMemAllocPitch(); * CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK: Maximum number of 32-bit * registers avail-able to a thread block; this number is shared by * all thread blocks simultaneously resident on a multiprocessor; * CU_DEVICE_ATTRIBUTE_CLOCK_RATE: Peak clock frequency in kilohertz; * CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT: Alignment requirement; texture * base addresses aligned to textureAlign bytes do not need an offset * applied to texture fetches; * CU_DEVICE_ATTRIBUTE_GPU_OVERLAP: 1 if the device can concurrently copy * memory between host and device while executing a kernel, or 0 if not; * CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT: Number of multiprocessors on * the device; * CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT: 1 if there is a run time limit * for kernels executed on the device, or 0 if not; * CU_DEVICE_ATTRIBUTE_INTEGRATED: 1 if the device is integrated with the * memory subsystem, or 0 if not; * CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY: 1 if the device can map host * memory into the CUDA address space, or 0 if not; * CU_DEVICE_ATTRIBUTE_COMPUTE_MODE: Compute mode that device is currently * in. Available modes are as follows: * - CU_COMPUTEMODE_DEFAULT: Default mode - Device is not restricted * and can have multiple CUDA contexts present at a single time. * - CU_COMPUTEMODE_EXCLUSIVE: Compute-exclusive mode - Device can have * only one CUDA con-text present on it at a time. * - CU_COMPUTEMODE_PROHIBITED: Compute-prohibited mode - Device is * prohibited from creating new CUDA contexts. * * \param pi Pointer to an interger instance that will be updated with the * attribute value. * \param attrib Device attribute to query. * \param dev The device handle. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaDeviceGetAttribute(int *pi, CUdevice_attribute attrib, CUdevice dev) { CUresult result = 0; if (pi == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument supplied. " "prop is NULL"); goto error; } result = cuDeviceGetAttribute(pi, attrib, dev); if (SCCudaHandleRetValue(result, SC_CUDA_CU_DEVICE_GET_ATTRIBUTE) == -1) goto error; return 0; error: return -1; } /** * \internal * \brief Creates and returns a new instance of SCCudaDevice. * * \retval device Pointer to the new instance of SCCudaDevice. */ static SCCudaDevice *SCCudaAllocSCCudaDevice(void) { SCCudaDevice *device = SCMalloc(sizeof(SCCudaDevice)); if (unlikely(device == NULL)) return NULL; memset(device, 0 , sizeof(SCCudaDevice)); return device; } /** * \internal * \brief Frees an instance of SCCudaDevice. * * \param device Pointer to the an instance of SCCudaDevice to be freed. */ static void SCCudaDeAllocSCCudaDevice(SCCudaDevice *device) { SCFree(device); return; } /** * \internal * \brief Creates and returns a new instance of SCCudaDevices. * * \retval devices Pointer to the new instance of SCCudaDevices. */ static SCCudaDevices *SCCudaAllocSCCudaDevices(void) { SCCudaDevices *devices = SCMalloc(sizeof(SCCudaDevices)); if (unlikely(devices == NULL)) return NULL; memset(devices, 0 , sizeof(SCCudaDevices)); return devices; } /** * \internal * \brief Frees an instance of SCCudaDevices. * * \param device Pointer to the an instance of SCCudaDevices to be freed. */ static void SCCudaDeAllocSCCudaDevices(SCCudaDevices *devices) { int i = 0; if (devices == NULL) return; if (devices->devices != NULL) { for (i = 0; i < devices->count; i++) SCCudaDeAllocSCCudaDevice(devices->devices[i]); SCFree(devices->devices); } SCFree(devices); return; } /** * \brief Retrieves all the devices and all the information corresponding to * the devices on the CUDA device available on this system and returns * a SCCudaDevices instances which holds all this information. * * \retval devices Pointer to a SCCudaDevices instance that holds information * for all the CUDA devices on the system. */ static SCCudaDevices *SCCudaGetDevices(void) { SCCudaDevices *devices = SCCudaAllocSCCudaDevices(); int i = 0; if (SCCudaDeviceGetCount(&devices->count) == -1) goto error; devices->devices = SCMalloc(devices->count * sizeof(SCCudaDevice *)); if (devices->devices == NULL) goto error; /* update the device properties */ for (i = 0; i < devices->count; i++) { devices->devices[i] = SCCudaAllocSCCudaDevice(); if (SCCudaDeviceGet(&devices->devices[i]->device, i) == -1) goto error; if (SCCudaDeviceComputeCapability(&devices->devices[i]->major_rev, &devices->devices[i]->minor_rev, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetName(devices->devices[i]->name, SC_CUDA_DEVICE_NAME_MAX_LEN, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceTotalMem(&devices->devices[i]->bytes, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetProperties(&devices->devices[i]->prop, devices->devices[i]->device) == -1) { goto error; } /* retrieve the attributes */ if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_threads_per_block, CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_block_dim_x, CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_block_dim_y, CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_block_dim_z, CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_grid_dim_x, CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_grid_dim_y, CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_grid_dim_z, CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_shared_memory_per_block, CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_total_constant_memory, CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_warp_size, CU_DEVICE_ATTRIBUTE_WARP_SIZE, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_pitch, CU_DEVICE_ATTRIBUTE_MAX_PITCH, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_max_registers_per_block, CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_clock_rate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_texture_alignment, CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_gpu_overlap, CU_DEVICE_ATTRIBUTE_GPU_OVERLAP, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_multiprocessor_count, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_kernel_exec_timeout, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_integrated, CU_DEVICE_ATTRIBUTE_INTEGRATED, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_can_map_host_memory, CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY, devices->devices[i]->device) == -1) { goto error; } if (SCCudaDeviceGetAttribute(&devices->devices[i]->attr_compute_mode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, devices->devices[i]->device) == -1) { goto error; } } #ifdef DEBUG SCCudaPrintDeviceList(devices); #endif return devices; error: SCCudaDeAllocSCCudaDevices(devices); return NULL; } /** * \brief Prints the information for all the devices for this CUDA platform, * supplied inside the argument. * * \param devices Pointer to a SCCudaDevices instance that holds information on * the devices. */ void SCCudaPrintDeviceList(SCCudaDevices *devices) { int i = 0; if (devices == NULL) { SCLogError(SC_ERR_CUDA_ERROR, "CUDA environment not initialized. " "Please initialized the CUDA environment by calling " "SCCudaInitCudaEnvironment() before making any calls " "to the CUDA API."); return; } SCLogDebug("Printing device info for this CUDA context"); SCLogDebug("No of devices: %d", devices->count); for (i = 0; i < devices->count; i++) { SCLogDebug("Device ID: %d", devices->devices[i]->device); SCLogDebug("Device Name: %s", devices->devices[i]->name); SCLogDebug("Device Major Revision: %d", devices->devices[i]->major_rev); SCLogDebug("Device Minor Revision: %d", devices->devices[i]->minor_rev); /* Cudevprop */ SCLogDebug("Device Max Threads Per Block: %d", devices->devices[i]->prop.maxThreadsPerBlock); SCLogDebug("Device Max Threads Dim: [%d, %d, %d]", devices->devices[i]->prop.maxThreadsDim[0], devices->devices[i]->prop.maxThreadsDim[1], devices->devices[i]->prop.maxThreadsDim[2]); SCLogDebug("Device Max Grid Size: [%d, %d, %d]", devices->devices[i]->prop.maxGridSize[0], devices->devices[i]->prop.maxGridSize[1], devices->devices[i]->prop.maxGridSize[2]); SCLogDebug("Device Shared Memory Per Block: %d", devices->devices[i]->prop.sharedMemPerBlock); SCLogDebug("Device Total Constant Memory: %d", devices->devices[i]->prop.totalConstantMemory); SCLogDebug("Device SIMD Width(Warp Size): %d", devices->devices[i]->prop.SIMDWidth); SCLogDebug("Device Maximum Mem Pitch: %d", devices->devices[i]->prop.memPitch); SCLogDebug("Device Total Registers Available Per Block: %d", devices->devices[i]->prop.regsPerBlock); SCLogDebug("Device Clock Frequency: %d", devices->devices[i]->prop.clockRate); SCLogDebug("Device Texture Alignment Requirement: %d", devices->devices[i]->prop.textureAlign); /* device attributes */ SCLogDebug("Device Max Threads Per Block: %d", devices->devices[i]->attr_max_threads_per_block); SCLogDebug("Device Max Block Dim X: %d", devices->devices[i]->attr_max_block_dim_x); SCLogDebug("Device Max Block Dim Y: %d", devices->devices[i]->attr_max_block_dim_y); SCLogDebug("Device Max Block Dim Z: %d", devices->devices[i]->attr_max_block_dim_z); SCLogDebug("Device Max Grid Dim X: %d", devices->devices[i]->attr_max_grid_dim_x); SCLogDebug("Device Max Grid Dim Y: %d", devices->devices[i]->attr_max_grid_dim_y); SCLogDebug("Device Max Grid Dim Z: %d", devices->devices[i]->attr_max_grid_dim_z); SCLogDebug("Device Max Shared Memory Per Block: %d", devices->devices[i]->attr_max_shared_memory_per_block); SCLogDebug("Device Total Constant Memory: %d", devices->devices[i]->attr_total_constant_memory); SCLogDebug("Device Warp Size: %d", devices->devices[i]->attr_warp_size); SCLogDebug("Device Max Pitch: %d", devices->devices[i]->attr_max_pitch); SCLogDebug("Device Max Registers Per Block: %d", devices->devices[i]->attr_max_registers_per_block); SCLogDebug("Device Clock Rate: %d", devices->devices[i]->attr_clock_rate); SCLogDebug("Device Texture Alignement: %d", devices->devices[i]->attr_texture_alignment); SCLogDebug("Device GPU Overlap: %s", (devices->devices[i]->attr_gpu_overlap == 1) ? "Yes": "No"); SCLogDebug("Device Multiprocessor Count: %d", devices->devices[i]->attr_multiprocessor_count); SCLogDebug("Device Kernel Exec Timeout: %s", (devices->devices[i]->attr_kernel_exec_timeout) ? "Yes": "No"); SCLogDebug("Device Integrated With Memory Subsystem: %s", (devices->devices[i]->attr_integrated) ? "Yes": "No"); SCLogDebug("Device Can Map Host Memory: %s", (devices->devices[i]->attr_can_map_host_memory) ? "Yes": "No"); if (devices->devices[i]->attr_compute_mode == CU_COMPUTEMODE_DEFAULT) SCLogDebug("Device Compute Mode: CU_COMPUTEMODE_DEFAULT"); else if (devices->devices[i]->attr_compute_mode == CU_COMPUTEMODE_EXCLUSIVE) SCLogDebug("Device Compute Mode: CU_COMPUTEMODE_EXCLUSIVE"); else if (devices->devices[i]->attr_compute_mode == CU_COMPUTEMODE_PROHIBITED) SCLogDebug("Device Compute Mode: CU_COMPUTEMODE_PROHIBITED"); } return; } /** * \brief Prints some basic information for the default device(the first devie) * we will be using on this cuda platform for use by our engine. This * function is basically to be used to print some minimal information to * the user at engine startup. * * \param devices Pointer to a SCCudaDevices instance that holds information on * the devices. */ void SCCudaPrintBasicDeviceInfo(SCCudaDevices *devices) { int i = 0; if (devices == NULL) { SCLogError(SC_ERR_CUDA_ERROR, "CUDA environment not initialized. " "Please initialized the CUDA environment by calling " "SCCudaInitCudaEnvironment() before making any calls " "to the CUDA API."); return; } for (i = 0; i < devices->count; i++) { SCLogInfo("GPU Device %d: %s, %d Multiprocessors, %dMHz, CUDA Compute " "Capability %d.%d", i + 1, devices->devices[i]->name, devices->devices[i]->attr_multiprocessor_count, devices->devices[i]->attr_clock_rate/1000, devices->devices[i]->major_rev, devices->devices[i]->minor_rev); } return; } /** * \brief Gets the device list, for the CUDA platform environment initialized by * the engine. * * \retval devices Pointer to the CUDA device list on success; NULL on failure. */ SCCudaDevices *SCCudaGetDeviceList(void) { if (devices == NULL) { SCLogError(SC_ERR_CUDA_ERROR, "CUDA environment not initialized. " "Please initialized the CUDA environment by calling " "SCCudaInitCudaEnvironment() before making any calls " "to the CUDA API."); return NULL; } return devices; } /*****************************Cuda_Initialization_API**************************/ /** * \internal * \brief Inits the cuda driver API. * * \param flags Currently should be 0. * * \retval 0 On success. * \retval -1 On failure. */ static int SCCudaInit(unsigned int flags) { CUresult result = cuInit(flags); if (SCCudaHandleRetValue(result, SC_CUDA_CU_INIT) == -1) goto error; return 0; error: return -1; } /**************************Cuda_Env_Initialization_API*************************/ /** * \brief Initialize the CUDA Environment for the engine. * * \retval 0 On successfully initializing the CUDA environment for the engine. * \retval -1 On failure. */ int SCCudaInitCudaEnvironment(void) { if (devices != NULL) { SCLogWarning(SC_ERR_CUDA_ERROR, "CUDA engine already initalized!!!!"); return 0; } if (SCCudaInit(0) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error initializing CUDA API. SCCudaInit() " "returned -1"); goto error; } if ( (devices = SCCudaGetDevices()) == NULL) { SCLogError(SC_ERR_CUDA_ERROR, "Error getting CUDA device list. " "SCCudaGetDevices() returned NULL"); goto error; } SCCudaPrintBasicDeviceInfo(devices); return 0; error: SCCudaDeAllocSCCudaDevices(devices); return -1; } /**********************************Cuda_Utility********************************/ /** * \brief List the cuda cards on the system. * */ void SCCudaListCards(void) { int i = 0; if (devices == NULL) { SCLogWarning(SC_ERR_CUDA_ERROR, "CUDA engine not initalized! Please " "initialize the cuda environment using " "SCCudaInitCudaEnvironment()."); return; } printf("CUDA Cards recognized by the suricata CUDA module - \n"); printf("|-----------------------------------------------------------------------------|\n"); printf("| %-10s | %-20s | %-10s | %-10s | %-13s |\n", "Device Id", " Device Name", " Multi-", "Clock Rate", "Cuda Compute"); printf("| %-10s | %-20s | %-10s | %-10s | %-13s |\n", "", "", "Processors", " (MHz)", "Capability"); printf("|-----------------------------------------------------------------------------|\n"); for (i = 0; i < devices->count; i++) { printf("| %-10d | %-20s | %-10d | %-10d | %d.%-11d |\n", i, devices->devices[i]->name, devices->devices[i]->attr_multiprocessor_count, devices->devices[i]->attr_clock_rate/1000, devices->devices[i]->major_rev, devices->devices[i]->minor_rev); } printf("|-----------------------------------------------------------------------------|\n"); return; } int SCCudaIsCudaDeviceIdValid(int cuda_device_id) { if (devices == NULL) { SCLogWarning(SC_ERR_CUDA_ERROR, "CUDA engine not initalized! Please " "initialize the cuda environment using " "SCCudaInitCudaEnvironment()."); return 0; } return (cuda_device_id < devices->count); } /**********************************Unittests***********************************/ int SCCudaTest01(void) { SCCudaDevices *devices = SCCudaGetDeviceList(); if (devices == NULL) return 0; return (devices->count != 0); } #if defined(__x86_64__) || defined(__ia64__) /** * extern "C" __global__ void SCCudaSuricataTest(int *input, int *output) * { * output[threadIdx.x] = input[threadIdx.x] * 2; * } */ static const char *sc_cuda_test_kernel_64_bit = " .version 1.4\n" " .target sm_10, map_f64_to_f32\n" " .entry SCCudaSuricataTest (\n" " .param .u64 __cudaparm_SCCudaSuricataTest_input,\n" " .param .u64 __cudaparm_SCCudaSuricataTest_output)\n" "{\n" " .reg .u32 %r<5>;\n" " .reg .u64 %rd<8>;\n" " .loc 15 1 0\n" " $LBB1_SCCudaSuricataTest:\n" " .loc 15 3 0\n" " cvt.u32.u16 %r1, %tid.x;\n" " cvt.u64.u32 %rd1, %r1;\n" " mul.lo.u64 %rd2, %rd1, 4;\n" " ld.param.u64 %rd3, [__cudaparm_SCCudaSuricataTest_input];\n" " add.u64 %rd4, %rd3, %rd2;\n" " ld.global.s32 %r2, [%rd4+0];\n" " mul.lo.s32 %r3, %r2, 2;\n" " ld.param.u64 %rd5, [__cudaparm_SCCudaSuricataTest_output];\n" " add.u64 %rd6, %rd5, %rd2;\n" " st.global.s32 [%rd6+0], %r3;\n" " .loc 15 4 0\n" " exit;\n" " $LDWend_SCCudaSuricataTest:\n" "} // SCCudaSuricataTest\n" "\n"; #else /** * extern "C" __global__ void SCCudaSuricataTest(int *input, int *output) * { * output[threadIdx.x] = input[threadIdx.x] * 2; * } */ static const char *sc_cuda_test_kernel_32_bit = " .version 1.4\n" " .target sm_10, map_f64_to_f32\n" " .entry SCCudaSuricataTest (\n" " .param .u32 __cudaparm_SCCudaSuricataTest_input,\n" " .param .u32 __cudaparm_SCCudaSuricataTest_output)\n" " {\n" " .reg .u16 %rh<3>;\n" " .reg .u32 %r<9>;\n" " .loc 15 2 0\n" "$LBB1_SCCudaSuricataTest:\n" " .loc 15 4 0\n" " mov.u16 %rh1, %tid.x;\n" " mul.wide.u16 %r1, %rh1, 4;\n" " ld.param.u32 %r2, [__cudaparm_SCCudaSuricataTest_input];\n" " add.u32 %r3, %r2, %r1;\n" " ld.global.s32 %r4, [%r3+0];\n" " mul.lo.s32 %r5, %r4, 2;\n" " ld.param.u32 %r6, [__cudaparm_SCCudaSuricataTest_output];\n" " add.u32 %r7, %r6, %r1;\n" " st.global.s32 [%r7+0], %r5;\n" " .loc 15 5 0\n" " exit;\n" "$LDWend_SCCudaSuricataTest:\n" " } // SCCudaSuricataTest\n" ""; #endif int SCCudaTest02(void) { #define ALIGN_UP(offset, alignment) do { \ (offset) = ((offset) + (alignment) - 1) & ~((alignment) - 1); \ } while (0) #define N 256 CUcontext context; CUmodule module; CUfunction kernel; CUdeviceptr d_input, d_output; int h_input[N]; int h_result[N]; SCCudaDevices *devices = SCCudaGetDeviceList(); int result = 0; int offset = 0; int i = 0; if (devices == NULL) goto end; if (devices->count == 0) goto end; if (SCCudaCtxCreate(&context, 0, devices->devices[0]->device) == -1) goto end; #if defined(__x86_64__) || defined(__ia64__) if (SCCudaModuleLoadData(&module, (void *)sc_cuda_test_kernel_64_bit) == -1) goto end; #else if (SCCudaModuleLoadData(&module, (void *)sc_cuda_test_kernel_32_bit) == -1) goto end; #endif if (SCCudaModuleGetFunction(&kernel, module, "SCCudaSuricataTest") == -1) goto end; for (i = 0; i < N; i++) h_input[i] = i * 2; if (SCCudaMemAlloc(&d_input, N * sizeof(int)) == -1) goto end; if (SCCudaMemcpyHtoD(d_input, h_input, N * sizeof(int)) == -1) goto end; if (SCCudaMemAlloc(&d_output, N * sizeof(int)) == -1) goto end; offset = 0; ALIGN_UP(offset, __alignof(void *)); if (SCCudaParamSetv(kernel, offset, (void *)&d_input, sizeof(void *)) == -1) goto end; offset += sizeof(void *); ALIGN_UP(offset, __alignof(void *)); if (SCCudaParamSetv(kernel, offset, (void *)&d_output, sizeof(void *)) == -1) goto end; offset += sizeof(void *); if (SCCudaParamSetSize(kernel, offset) == -1) goto end; if (SCCudaFuncSetBlockShape(kernel, N, 1, 1) == -1) goto end; if (SCCudaLaunchGrid(kernel, 1, 1) == -1) goto end; if (SCCudaMemcpyDtoH(h_result, d_output, N * sizeof(int)) == -1) goto end; for (i = 0; i < N; i++) h_input[i] = i * 4; for (i = 0; i < N; i++) { if (h_result[i] != h_input[i]) goto end; } if (SCCudaMemFree(d_input) == -1) goto end; if (SCCudaMemFree(d_output) == -1) goto end; if (SCCudaModuleUnload(module) == -1) goto end; if (SCCudaCtxDestroy(context) == -1) goto end; result = 1; end: return result; } void SCCudaRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCCudaTest01", SCCudaTest01, 1); UtRegisterTest("SCCudaTest02", SCCudaTest02, 1); #endif return; } #endif /* __SC_CUDA_SUPPORT__ */ suricata-1.4.7/src/detect-byte-extract.h0000644000000000000000000000454612253546156015070 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_BYTEEXTRACT_H__ #define __DETECT_BYTEEXTRACT_H__ /* flags */ #define DETECT_BYTE_EXTRACT_FLAG_RELATIVE 0x01 #define DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER 0x02 #define DETECT_BYTE_EXTRACT_FLAG_STRING 0x04 #define DETECT_BYTE_EXTRACT_FLAG_ALIGN 0x08 #define DETECT_BYTE_EXTRACT_FLAG_ENDIAN 0x10 /* endian value to be used. Would be stored in DetectByteParseData->endian */ #define DETECT_BYTE_EXTRACT_ENDIAN_NONE 0 #define DETECT_BYTE_EXTRACT_ENDIAN_BIG 1 #define DETECT_BYTE_EXTRACT_ENDIAN_LITTLE 2 #define DETECT_BYTE_EXTRACT_ENDIAN_DCE 3 /** * \brief Holds data related to byte_extract keyword. */ typedef struct DetectByteExtractData_ { /* local id used by other keywords in the sig to reference this */ uint8_t local_id; uint8_t nbytes; int16_t pad; int32_t offset; const char *name; uint8_t flags; uint8_t endian; uint8_t base; uint8_t align_value; uint16_t multiplier_value; /* unique id used to reference this byte_extract keyword */ uint16_t id; } DetectByteExtractData; void DetectByteExtractRegister(void); int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); void DetectByteExtractFree(void *); int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); SigMatch *DetectByteExtractRetrieveSMVar(const char *, Signature *, int); int DetectByteExtractDoMatch(DetectEngineThreadCtx *, SigMatch *, Signature *, uint8_t *, uint16_t, uint64_t *, uint8_t); #endif /* __DETECT_BYTEEXTRACT_H__ */ suricata-1.4.7/src/detect-dce-stub-data.h0000644000000000000000000000172612253546156015067 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_DCE_STUB_DATA_H__ #define __DETECT_DCE_STUB_DATA_H__ void DetectDceStubDataRegister(void); void DetectDceStubDataRegisterTests(void); #endif /* __DETECT_DCE_STUB_DATA_H__ */ suricata-1.4.7/src/util-hash-lookup3.h0000644000000000000000000000560612253546156014475 00000000000000/* ------------------------------------------------------------------------------- lookup3.c, by Bob Jenkins, May 2006, Public Domain. These are functions for producing 32-bit hashes for hash table lookup. hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() are externally useful functions. Routines to test the hash are included if SELF_TEST is defined. You can use this free for any purpose. It's in the public domain. It has no warranty. You probably want to use hashlittle(). hashlittle() and hashbig() hash byte arrays. hashlittle() is is faster than hashbig() on little-endian machines. Intel and AMD are little-endian machines. On second thought, you probably want hashlittle2(), which is identical to hashlittle() except it returns two 32-bit hashes for the price of one. You could implement hashbig2() if you wanted but I haven't bothered here. If you want to find a hash of, say, exactly 7 integers, do a = i1; b = i2; c = i3; mix(a,b,c); a += i4; b += i5; c += i6; mix(a,b,c); a += i7; final(a,b,c); then use c as the hash value. If you have a variable length array of 4-byte integers to hash, use hashword(). If you have a byte array (like a character string), use hashlittle(). If you have several byte arrays, or a mix of things, see the comments above hashlittle(). Why is this so big? I read 12 bytes at a time into 3 4-byte integers, then mix those integers. This is fast (you can do a lot more thorough mixing with 12*3 instructions on 3 integers than you can with 3 instructions on 1 byte), but shoehorning those bytes into integers efficiently is messy. ------------------------------------------------------------------------------- */ #ifndef __UTIL_HASH_LOOKUP3_H__ #define __UTIL_HASH_LOOKUP3_H__ #define hashsize(n) ((uint32_t)1<<(n)) #define hashmask(n) (hashsize(n)-1) uint32_t hashword(const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t initval); /* the previous hash, or an arbitrary value */ void hashword2 (const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t *pc, /* IN: seed OUT: primary hash value */ uint32_t *pb); /* IN: more seed OUT: secondary hash value */ uint32_t hashlittle( const void *key, size_t length, uint32_t initval); void hashlittle2(const void *key, /* the key to hash */ size_t length, /* length of the key */ uint32_t *pc, /* IN: primary initval, OUT: primary hash */ uint32_t *pb); /* IN: secondary initval, OUT: secondary hash */ uint32_t hashbig( const void *key, size_t length, uint32_t initval); #endif /* __UTIL_HASH_LOOKUP3_H__ */ suricata-1.4.7/src/util-rule-vars.h0000644000000000000000000000216612253546156014076 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_RULE_VARS_H__ #define __UTIL_RULE_VARS_H__ /** Enum indicating the various vars type in the yaml conf file */ typedef enum { SC_RULE_VARS_ADDRESS_GROUPS, SC_RULE_VARS_PORT_GROUPS, } SCRuleVarsType; char *SCRuleVarsGetConfVar(const char *, SCRuleVarsType); void SCRuleVarsRegisterTests(void); #endif /* __UTIL_RULE_VARS_H__ */ suricata-1.4.7/src/detect-engine-dcepayload.c0000644000000000000000000137544412253546156016031 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "detect-pcre.h" #include "detect-isdataat.h" #include "detect-bytetest.h" #include "detect-bytejump.h" #include "detect-byte-extract.h" #include "detect-engine-content-inspection.h" #include "app-layer.h" #include "app-layer-dcerpc.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" /** * \brief Do the content inspection & validation for a signature against dce stub. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param sm SigMatch to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate) { SCEnter(); DCERPCState *dcerpc_state = (DCERPCState *)alstate; uint8_t *dce_stub_data = NULL; uint16_t dce_stub_data_len; int r = 0; if (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL || dcerpc_state == NULL) { SCReturnInt(0); } if (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh != 0) { /* the request stub and stub_len */ dce_stub_data = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer; dce_stub_data_len = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, dce_stub_data, dce_stub_data_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, dcerpc_state); //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); if (r == 1) { SCReturnInt(1); } } if (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) { /* the response stub and stub_len */ dce_stub_data = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer; dce_stub_data_len = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer_len; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, dce_stub_data, dce_stub_data_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, dcerpc_state); //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, //dce_stub_data, dce_stub_data_len, dcerpc_state); if (r == 1) { SCReturnInt(1); } } SCReturnInt(0); } /**************************************Unittests*******************************/ #ifdef UNITTESTS /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest01(void) { #if 0 int result = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); uint8_t request3[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x26, 0x65, 0x3c, 0x6e, 0x6d, 0x64, 0x24, 0x39, 0x56, 0x43, 0x3e, 0x61, 0x5c, 0x54, 0x42, 0x23, 0x75, 0x6b, 0x71, 0x27, 0x66, 0x2e, 0x6e, 0x3d, 0x58, 0x23, 0x54, 0x77, 0x3b, 0x52, 0x6b, 0x50, 0x3b, 0x74, 0x2c, 0x54, 0x25, 0x5c, 0x51, 0x7c, 0x29, 0x7c, 0x5f, 0x4a, 0x35, 0x5c, 0x3d, 0x3f, 0x33, 0x55, 0x3b, 0x5a, 0x57, 0x31, 0x59, 0x4f, 0x6d, 0x6d, 0x7b, 0x3e, 0x38, 0x4d, 0x68, 0x75, 0x64, 0x21, 0x50, 0x63, 0x47, 0x42, 0x56, 0x39, 0x6c, 0x6f, 0x61, 0x53, 0x32, 0x56, 0x43, 0x52, 0x43, 0x67, 0x26, 0x45, 0x28, 0x6b, 0x77, 0x28, 0x7c, 0x64, 0x61, 0x24, 0x38, 0x6b, 0x59, 0x2a, 0x4f, 0x6e, 0x5b, 0x57, 0x24, 0x54, 0x33, 0x37, 0x47, 0x58, 0x4b, 0x58, 0x3d, 0x21, 0x38, 0x7c, 0x2c, 0x24, 0x5f, 0x67, 0x3a, 0x41, 0x3e, 0x2a, 0x72, 0x66, 0x2d, 0x6b, 0x66, 0x7b, 0x2b, 0x75, 0x78, 0x2f, 0x4d, 0x4c, 0x51, 0x70, 0x5d, 0x55, 0x54, 0x3c, 0x63, 0x46, 0x6b, 0x64, 0x4d, 0x25, 0x45, 0x21, 0x34, 0x65, 0x48, 0x32, 0x58, 0x4c, 0x70, 0x4c, 0x4c, 0x75, 0x5c, 0x77, 0x68, 0x78, 0x34, 0x5c, 0x2d, 0x39, 0x58, 0x3b, 0x40, 0x71, 0x77, 0x47, 0x32, 0x2e, 0x3c, 0x61, 0x6f, 0x6d, 0x5f, 0x43, 0x74, 0x36, 0x4f, 0x21, 0x44, 0x66, 0x36, 0x62, 0x30, 0x29, 0x5a, 0x34, 0x66, 0x4e, 0x51, 0x23, 0x4e, 0x38, 0x51, 0x78, 0x74, 0x58, 0x2e, 0x6d, 0x51, 0x49, 0x55, 0x73, 0x2a, 0x71, 0x3c, 0x74, 0x38, 0x6f, 0x5d, 0x4b, 0x74, 0x68, 0x65, 0x4a, 0x58, 0x41, 0x55, 0x29, 0x42, 0x69, 0x55, 0x3b, 0x2b, 0x47, 0x64, 0x3b, 0x77, 0x72, 0x74, 0x38, 0x53, 0x5c, 0x69, 0x49, 0x49, 0x5b, 0x31, 0x41, 0x6a, 0x4e, 0x2c, 0x6a, 0x63, 0x3f, 0x58, 0x4e, 0x25, 0x3e, 0x57, 0x41, 0x61, 0x26, 0x5e, 0x24, 0x69, 0x7a, 0x38, 0x60, 0x73, 0x70, 0x7d, 0x63, 0x34, 0x78, 0x4d, 0x50, 0x35, 0x69, 0x49, 0x22, 0x45, 0x44, 0x3f, 0x6e, 0x75, 0x64, 0x57, 0x3a, 0x61, 0x60, 0x34, 0x21, 0x61, 0x21, 0x2a, 0x78, 0x7b, 0x52, 0x43, 0x50, 0x5b, 0x76, 0x5f, 0x4b, 0x6a, 0x5d, 0x23, 0x5b, 0x57, 0x40, 0x53, 0x51, 0x33, 0x21, 0x35, 0x7d, 0x31, 0x46, 0x65, 0x52, 0x28, 0x25, 0x30, 0x5a, 0x37, 0x7c, 0x2c, 0x3d, 0x2a, 0x48, 0x24, 0x5a, 0x2f, 0x47, 0x64, 0x73, 0x64, 0x3d, 0x7a, 0x5b, 0x34, 0x5e, 0x42, 0x22, 0x32, 0x47, 0x6e, 0x58, 0x3b, 0x3e, 0x25, 0x2f, 0x58, 0x78, 0x42, 0x66, 0x71, 0x56, 0x2a, 0x66, 0x66, 0x5b, 0x55, 0x35, 0x7a, 0x41, 0x7c, 0x7c, 0x6a, 0x2d, 0x59, 0x25, 0x22, 0x34, 0x5a, 0x61, 0x37, 0x48, 0x39, 0x31, 0x4a, 0x55, 0x6a, 0x68, 0x40, 0x2f, 0x45, 0x69, 0x46, 0x25, 0x51, 0x7d, 0x4f, 0x71, 0x21, 0x33, 0x55, 0x50, 0x56, 0x5f, 0x75, 0x27, 0x64, 0x36, 0x7a, 0x39, 0x40, 0x6a, 0x77, 0x38, 0x5d, 0x39, 0x30, 0x5e, 0x74, 0x54, 0x24, 0x3f, 0x3d, 0x79, 0x3b, 0x27, 0x7d, 0x68, 0x7d, 0x40, 0x71, 0x7a, 0x65, 0x54, 0x50, 0x66, 0x33, 0x3c, 0x42, 0x69, 0x6e, 0x3c, 0x63, 0x63, 0x69, 0x7a, 0x5e, 0x7b, 0x76, 0x26, 0x71, 0x6f, 0x4a, 0x6d, 0x70, 0x73, 0x66, 0x3b, 0x26, 0x70, 0x43, 0x5b, 0x52, 0x4c, 0x6d, 0x51, 0x2a, 0x66, 0x6c, 0x3e, 0x68, 0x6a, 0x31, 0x41, 0x79, 0x72, 0x37, 0x47, 0x7d, 0x2b, 0x3c, 0x40, 0x6b, 0x75, 0x56, 0x70, 0x7b, 0x2d, 0x5f, 0x33, 0x30, 0x30, 0x21, 0x35, 0x7a, 0x7a, 0x67, 0x48, 0x5e, 0x3b, 0x73, 0x50, 0x54, 0x47, 0x23, 0x2b, 0x4c, 0x4e, 0x2f, 0x24, 0x44, 0x34, 0x23, 0x5d, 0x76, 0x51, 0x5a, 0x73, 0x72, 0x3e, 0x47, 0x77, 0x40, 0x28, 0x65, 0x2e, 0x2a, 0x75, 0x3c, 0x2a, 0x27, 0x4a, 0x3f, 0x3c, 0x66, 0x2d, 0x21, 0x79, 0x2d, 0x2b, 0x78, 0x7c, 0x5a, 0x73, 0x46, 0x6b, 0x39, 0x65, 0x5e, 0x3d, 0x38, 0x40, 0x32, 0x3e, 0x21, 0x62, 0x34, 0x41, 0x58, 0x53, 0x67, 0x34, 0x58, 0x56, 0x61, 0x5b, 0x3e, 0x4e, 0x2c, 0x5b, 0x73, 0x35, 0x34, 0x35, 0x21, 0x3a, 0x61, 0x5f, 0x6e, 0x45, 0x78, 0x44, 0x28, 0x23, 0x48, 0x65, 0x53, 0x47, 0x6e, 0x2c, 0x38, 0x5e, 0x2c, 0x57, 0x58, 0x30, 0x7a, 0x3b, 0x4b, 0x4a, 0x74, 0x7d, 0x3e, 0x4d, 0x30, 0x24, 0x76, 0x66, 0x6d, 0x2e, 0x74, 0x75, 0x28, 0x48, 0x5c, 0x23, 0x6c, 0x46, 0x27, 0x46, 0x6e, 0x34, 0x63, 0x21, 0x58, 0x54, 0x50, 0x2f, 0x40, 0x47, 0x40, 0x32, 0x36, 0x48, 0x5f, 0x7d, 0x4a, 0x41, 0x6e, 0x60, 0x2c, 0x4a, 0x6a, 0x67, 0x6c, 0x41, 0x27, 0x23, 0x30, 0x48, 0x6a, 0x49, 0x73, 0x26, 0x77, 0x75, 0x4d, 0x65, 0x5b, 0x34, 0x79, 0x67, 0x61, 0x5b, 0x5c, 0x2b, 0x71, 0x3f, 0x62, 0x51, 0x3a, 0x53, 0x42, 0x26, 0x6f, 0x36, 0x57, 0x3f, 0x2b, 0x34, 0x24, 0x30, 0x60, 0x55, 0x70, 0x65, 0x70, 0x57, 0x5d, 0x68, 0x36, 0x52, 0x5d, 0x3f, 0x6a, 0x3a, 0x33, 0x31, 0x6c, 0x4e, 0x57, 0x79, 0x49, 0x79, 0x69, 0x71, 0x6f, 0x70, 0x6a, 0x76, 0x4b, 0x2f, 0x33, 0x51, 0x68, 0x30, 0x2e, 0x77, 0x78, 0x55, 0x2f, 0x53, 0x52, 0x5e, 0x57, 0x60, 0x3b, 0x6f, 0x69, 0x61, 0x6c, 0x60, 0x5a, 0x34, 0x5a, 0x35, 0x4b, 0x28, 0x54, 0x32, 0x6a, 0x35, 0x36, 0x6d, 0x68, 0x47, 0x5c, 0x74, 0x2e, 0x5f, 0x6c, 0x6d, 0x55, 0x42, 0x77, 0x64, 0x7d, 0x53, 0x4d, 0x39, 0x2c, 0x41, 0x42, 0x23, 0x3a, 0x73, 0x40, 0x60, 0x5d, 0x38, 0x6d, 0x36, 0x56, 0x57, 0x2a, 0x28, 0x3d, 0x3b, 0x5c, 0x75, 0x35, 0x2d, 0x69, 0x2d, 0x44, 0x51, 0x27, 0x63, 0x66, 0x33, 0x46, 0x42, 0x2e, 0x36, 0x6b, 0x7b, 0x2c, 0x23, 0x3b, 0x5a, 0x50, 0x2a, 0x65, 0x28, 0x3b, 0x3c, 0x51, 0x3f, 0x4d, 0x63, 0x38, 0x25, 0x74, 0x2e, 0x51, 0x22, 0x31, 0x74, 0x35, 0x33, 0x23, 0x2d, 0x3f, 0x77, 0x26, 0x2c, 0x55, 0x6d, 0x27, 0x39, 0x79, 0x76, 0x63, 0x4b, 0x43, 0x4a, 0x3a, 0x6b, 0x59, 0x55, 0x65, 0x26, 0x2f, 0x3f, 0x56, 0x67, 0x5a, 0x77, 0x71, 0x22, 0x51, 0x2b, 0x6d, 0x4c, 0x2c, 0x57, 0x66, 0x76, 0x37, 0x70, 0x5f, 0x52, 0x29, 0x44, 0x52, 0x22, 0x57, 0x37, 0x27, 0x79, 0x29, 0x5c, 0x57, 0x3b, 0x54, 0x3c, 0x3f, 0x53, 0x35, 0x27, 0x5e, 0x7c, 0x49, 0x77, 0x57, 0x5a, 0x22, 0x76, 0x7c, 0x5b, 0x2f, 0x53, 0x5e, 0x55, 0x6d, 0x64, 0x67, 0x34, 0x41, 0x23, 0x76, 0x67, 0x23, 0x78, 0x6a, 0x63, 0x27, 0x68, 0x43, 0x7d, 0x58, 0x49, 0x2d, 0x79, 0x2e, 0x75, 0x60, 0x6b, 0x34, 0x48, 0x6f, 0x4a, 0x6c, 0x48, 0x40, 0x68, 0x5f, 0x35, 0x25, 0x6c, 0x38, 0x5c, 0x30, 0x32, 0x4c, 0x36, 0x31, 0x29, 0x74, 0x4a, 0x55, 0x56, 0x6d, 0x4e, 0x23, 0x54, 0x2e, 0x69, 0x78, 0x61, 0x76, 0x66, 0x22, 0x44, 0x73, 0x25, 0x44, 0x29, 0x2a, 0x28, 0x3b, 0x67, 0x48, 0x58, 0x37, 0x4a, 0x76, 0x76, 0x51, 0x4a, 0x61, 0x70, 0x51, 0x74, 0x40, 0x23, 0x29, 0x63, 0x69, 0x4a, 0x29, 0x23, 0x34, 0x6a, 0x3b, 0x25, 0x28, 0x54, 0x45, 0x33, 0x28, 0x44, 0x30, 0x61, 0x5b, 0x60, 0x51, 0x3f, 0x68, 0x50, 0x70, 0x3d, 0x58, 0x2e, 0x6e, 0x59, 0x5a, 0x62, 0x66, 0x4d, 0x7a, 0x2e, 0x37, 0x37, 0x3d, 0x7b, 0x74, 0x79, 0x48, 0x45, 0x77, 0x56, 0x33, 0x76, 0x71, 0x60, 0x74, 0x3f, 0x61, 0x22, 0x52, 0x51, 0x71, 0x69 }; uint32_t request3_len = sizeof(request3); uint8_t request4[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x75, 0x3e, 0x76, 0x3e, 0x66, 0x6b, 0x6b, 0x3e, 0x6d, 0x59, 0x38, 0x2b, 0x63, 0x4d, 0x2c, 0x73, 0x54, 0x57, 0x34, 0x25, 0x5b, 0x42, 0x7d, 0x5d, 0x37, 0x34, 0x2c, 0x79, 0x24, 0x4b, 0x74, 0x73, 0x25, 0x36, 0x73, 0x3a, 0x2c, 0x55, 0x69, 0x3c, 0x58, 0x67, 0x33, 0x53, 0x67, 0x5c, 0x61, 0x7b, 0x44, 0x2e, 0x42, 0x2d, 0x6b, 0x50, 0x55, 0x24, 0x70, 0x58, 0x60, 0x38, 0x42, 0x45, 0x70, 0x6d, 0x2f, 0x27, 0x27, 0x2c, 0x21, 0x6d, 0x57, 0x6e, 0x43, 0x3c, 0x5b, 0x27, 0x7a, 0x34, 0x49, 0x5a, 0x69, 0x30, 0x3f, 0x6f, 0x77, 0x70, 0x39, 0x2d, 0x51, 0x74, 0x4b, 0x25, 0x70, 0x51, 0x64, 0x4d, 0x75, 0x52, 0x5e, 0x3e, 0x37, 0x30, 0x5d, 0x3b, 0x2c, 0x72, 0x25, 0x6c, 0x6f, 0x79, 0x69, 0x3c, 0x5b, 0x73, 0x3d, 0x41, 0x28, 0x28, 0x64, 0x60, 0x4b, 0x7a, 0x2c, 0x4a, 0x6b, 0x3d, 0x2e, 0x6c, 0x7a, 0x54, 0x70, 0x61, 0x6f, 0x4b, 0x40, 0x28, 0x59, 0x31, 0x25, 0x21, 0x57, 0x79, 0x4b, 0x31, 0x6f, 0x4e, 0x71, 0x2b, 0x3c, 0x24, 0x30, 0x28, 0x3c, 0x61, 0x28, 0x4b, 0x35, 0x61, 0x4d, 0x55, 0x5e, 0x66, 0x34, 0x5f, 0x61, 0x70, 0x7b, 0x67, 0x51, 0x55, 0x68, 0x78, 0x26, 0x3a, 0x27, 0x4e, 0x71, 0x79, 0x4f, 0x67, 0x2c, 0x5a, 0x79, 0x75, 0x59, 0x3a, 0x33, 0x4a, 0x36, 0x71, 0x72, 0x6d, 0x49, 0x3e, 0x53, 0x59, 0x2b, 0x2b, 0x27, 0x4e, 0x50, 0x5d, 0x21, 0x55, 0x64, 0x4b, 0x72, 0x73, 0x25, 0x55, 0x26, 0x4f, 0x3a, 0x21, 0x54, 0x29, 0x4f, 0x64, 0x51, 0x59, 0x60, 0x7b, 0x7c, 0x6f, 0x3e, 0x65, 0x74, 0x6a, 0x5b, 0x52, 0x2c, 0x56, 0x4e, 0x45, 0x53, 0x4b, 0x7c, 0x38, 0x49, 0x4b, 0x4e, 0x4f, 0x4a, 0x47, 0x5e, 0x7c, 0x46, 0x3b, 0x67, 0x2e, 0x43, 0x79, 0x35, 0x55, 0x59, 0x6d, 0x38, 0x70, 0x2f, 0x59, 0x4f, 0x27, 0x63, 0x40, 0x66, 0x2d, 0x39, 0x4f, 0x3d, 0x2e, 0x4c, 0x67, 0x71, 0x7d, 0x34, 0x22, 0x52, 0x4e, 0x36, 0x7b, 0x2c, 0x39, 0x4d, 0x42, 0x60, 0x75, 0x74, 0x72, 0x4f, 0x72, 0x68, 0x3a, 0x51, 0x31, 0x2d, 0x21, 0x4a, 0x35, 0x47, 0x6d, 0x69, 0x3c, 0x50, 0x4c, 0x59, 0x66, 0x4c, 0x71, 0x24, 0x3a, 0x36, 0x67, 0x24, 0x5a, 0x59, 0x28, 0x7c, 0x21, 0x5e, 0x77, 0x68, 0x5e, 0x7b, 0x6e, 0x56, 0x62, 0x36, 0x29, 0x6f, 0x4f, 0x5d, 0x57, 0x56, 0x2b, 0x75, 0x2a, 0x2c, 0x69, 0x63, 0x51, 0x74, 0x6e, 0x5e, 0x46, 0x50, 0x28, 0x2c, 0x3b, 0x32, 0x53, 0x28, 0x78, 0x59, 0x72, 0x39, 0x5e, 0x44, 0x5c, 0x77, 0x60, 0x72, 0x44, 0x3b, 0x75, 0x68, 0x39, 0x55, 0x3e, 0x44, 0x50, 0x76, 0x3c, 0x48, 0x46, 0x43, 0x22, 0x56, 0x27, 0x21, 0x31, 0x33, 0x4a, 0x5a, 0x74, 0x41, 0x58, 0x3f, 0x39, 0x29, 0x71, 0x73, 0x30, 0x57, 0x70, 0x33, 0x62, 0x7b, 0x4a, 0x75, 0x3e, 0x4d, 0x4c, 0x4e, 0x55, 0x63, 0x38, 0x66, 0x7d, 0x68, 0x7d, 0x6f, 0x23, 0x55, 0x50, 0x3d, 0x34, 0x46, 0x5e, 0x2f, 0x55, 0x27, 0x62, 0x68, 0x7c, 0x6c, 0x21, 0x2b, 0x63, 0x4b, 0x47, 0x6b, 0x6a, 0x5b, 0x7b, 0x5c, 0x71, 0x37, 0x7c, 0x52, 0x2b, 0x2f, 0x4a, 0x47, 0x70, 0x78, 0x50, 0x2f, 0x75, 0x28, 0x4c, 0x60, 0x4c, 0x4c, 0x54, 0x6b, 0x68, 0x63, 0x4f, 0x47, 0x39, 0x2a, 0x70, 0x51, 0x7d, 0x28, 0x59, 0x52, 0x46, 0x4b, 0x38, 0x27, 0x49, 0x50, 0x5d, 0x25, 0x22, 0x5f, 0x48, 0x2c, 0x2f, 0x67, 0x59, 0x5d, 0x7d, 0x21, 0x3d, 0x72, 0x4f, 0x5c, 0x5b, 0x41, 0x47, 0x5f, 0x56, 0x69, 0x42, 0x55, 0x60, 0x68, 0x4b, 0x77, 0x44, 0x4c, 0x3b, 0x7d, 0x5a, 0x58, 0x43, 0x7a, 0x33, 0x22, 0x58, 0x58, 0x6f, 0x74, 0x53, 0x57, 0x6d, 0x6e, 0x29, 0x6b, 0x33, 0x71, 0x68, 0x29, 0x48, 0x67, 0x35, 0x52, 0x41, 0x6b, 0x36, 0x4f, 0x46, 0x31, 0x24, 0x73, 0x56, 0x40, 0x48, 0x37, 0x51, 0x24, 0x2a, 0x59, 0x21, 0x74, 0x76, 0x25, 0x2e, 0x4a, 0x74, 0x32, 0x29, 0x5f, 0x57, 0x7c, 0x58, 0x30, 0x2c, 0x7b, 0x70, 0x5b, 0x51, 0x73, 0x27, 0x4a, 0x28, 0x77, 0x2a, 0x43, 0x28, 0x2e, 0x32, 0x3d, 0x38, 0x36, 0x2e, 0x6b, 0x40, 0x6c, 0x76, 0x54, 0x66, 0x4a, 0x5c, 0x25, 0x62, 0x2e, 0x61, 0x48, 0x30, 0x28, 0x41, 0x40, 0x69, 0x3c, 0x39, 0x36, 0x4b, 0x64, 0x50, 0x76, 0x3d, 0x52, 0x50, 0x77, 0x33, 0x3b, 0x65, 0x59, 0x31, 0x5c, 0x48, 0x6a, 0x74, 0x78, 0x5b, 0x74, 0x60, 0x47, 0x27, 0x60, 0x22, 0x4a, 0x72, 0x25, 0x34, 0x5d, 0x3a, 0x21, 0x66, 0x61, 0x7b, 0x34, 0x41, 0x3b, 0x3a, 0x27, 0x44, 0x48, 0x7c, 0x7a, 0x74, 0x3a, 0x68, 0x59, 0x48, 0x61, 0x32, 0x49, 0x61, 0x40, 0x22, 0x33, 0x75, 0x29, 0x76, 0x5b, 0x24, 0x5b, 0x5c, 0x76, 0x5c, 0x28, 0x75, 0x36, 0x26, 0x2c, 0x65, 0x5e, 0x51, 0x7b, 0x3a, 0x7d, 0x4f, 0x35, 0x73, 0x6b, 0x5b, 0x5c, 0x37, 0x35, 0x6b, 0x41, 0x35, 0x40, 0x3a, 0x22, 0x28, 0x6c, 0x71, 0x46, 0x68, 0x7b, 0x66, 0x56, 0x24, 0x7c, 0x54, 0x28, 0x30, 0x22, 0x4e, 0x3c, 0x65, 0x69, 0x36, 0x44, 0x53, 0x3d, 0x6c, 0x5f, 0x73, 0x6c, 0x6f, 0x5e, 0x27, 0x23, 0x4e, 0x60, 0x45, 0x2f, 0x3d, 0x37, 0x28, 0x51, 0x29, 0x77, 0x6a, 0x6b, 0x2a, 0x2a, 0x51, 0x26, 0x4c, 0x4e, 0x71, 0x77, 0x73, 0x71, 0x2d, 0x5a, 0x2c, 0x23, 0x3d, 0x5f, 0x62, 0x63, 0x2e, 0x72, 0x2a, 0x75, 0x66, 0x43, 0x56, 0x5f, 0x21, 0x64, 0x66, 0x35, 0x3b, 0x7a, 0x45, 0x3f, 0x4f, 0x57, 0x22, 0x5a, 0x45, 0x65, 0x37, 0x58, 0x5b, 0x43, 0x66, 0x4f, 0x5d, 0x6e, 0x41, 0x41, 0x62, 0x5e, 0x39, 0x65, 0x6f, 0x43, 0x4b, 0x5e, 0x51, 0x42, 0x3f, 0x2d, 0x68, 0x4b, 0x6e, 0x46, 0x6f, 0x21, 0x44, 0x3c, 0x22, 0x46, 0x31, 0x31, 0x2e, 0x56, 0x2e, 0x77, 0x48, 0x68, 0x23, 0x4a, 0x36, 0x52, 0x5d, 0x61, 0x47, 0x71, 0x2e, 0x3a, 0x4a, 0x5b, 0x56, 0x6b, 0x52, 0x2a, 0x4c, 0x4f, 0x24, 0x34, 0x60, 0x70, 0x58, 0x7a, 0x76, 0x4b, 0x68, 0x24, 0x5f, 0x51, 0x6d, 0x75, 0x45, 0x48, 0x21, 0x53, 0x4d, 0x27, 0x75, 0x5f, 0x50, 0x3e, 0x40, 0x3f, 0x5e, 0x64, 0x41, 0x5f, 0x68, 0x48, 0x30, 0x71, 0x4b, 0x66, 0x2c, 0x2f, 0x76, 0x4b, 0x23, 0x46, 0x34, 0x50, 0x58, 0x52, 0x69, 0x2b, 0x6e, 0x7a, 0x33, 0x53, 0x43, 0x43, 0x35, 0x54, 0x30, 0x73, 0x63, 0x3b, 0x43, 0x52, 0x29, 0x45, 0x37, 0x71, 0x79, 0x5a, 0x26, 0x24, 0x72, 0x73, 0x4e, 0x44, 0x38, 0x5b, 0x71, 0x36, 0x3a, 0x4f, 0x5b, 0x71, 0x28, 0x71, 0x79, 0x72, 0x40, 0x6e, 0x51, 0x72, 0x29, 0x3d, 0x4f, 0x33, 0x22, 0x73, 0x5a, 0x30, 0x71, 0x58, 0x54, 0x59, 0x48, 0x29, 0x2b, 0x5c, 0x73, 0x6f, 0x4e, 0x60, 0x2a, 0x72, 0x39, 0x50, 0x59, 0x6f, 0x48, 0x3e, 0x62, 0x6c, 0x62, 0x49, 0x6c, 0x2c, 0x3f, 0x43, 0x3f, 0x32, 0x7c, 0x6f, 0x6c, 0x39, 0x26, 0x26, 0x7b, 0x5d, 0x65, 0x6f, 0x41, 0x7c, 0x42, 0x2b, 0x65, 0x6f, 0x3e, 0x7b, 0x69, 0x46, 0x4d, 0x68, 0x68, 0x5a, 0x33, 0x25, 0x5d, 0x6f, 0x48, 0x7c, 0x77, 0x7d, 0x3f, 0x4e, 0x30, 0x69, 0x65, 0x28, 0x2e, 0x34, 0x34, 0x41, 0x43, 0x5e, 0x30, 0x23, 0x3b, 0x60, 0x79, 0x5b, 0x26, 0x7c, 0x77, 0x3e, 0x43, 0x24, 0x31, 0x3a, 0x56, 0x24, 0x3c, 0x60, 0x3f, 0x60, 0x55, 0x6a, 0x68 }; uint32_t request4_len = sizeof(request4); uint8_t request5[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x69, 0x3e, 0x72, 0x44, 0x31, 0x6b, 0x28, 0x2f, 0x79, 0x37, 0x58, 0x5d, 0x5f, 0x68, 0x71, 0x47, 0x7a, 0x68, 0x7c, 0x6c, 0x65, 0x3c, 0x74, 0x67, 0x59, 0x5c, 0x3d, 0x28, 0x65, 0x28, 0x58, 0x74, 0x44, 0x62, 0x2e, 0x36, 0x54, 0x2f, 0x24, 0x34, 0x4b, 0x6d, 0x3a, 0x7b, 0x60, 0x71, 0x5a, 0x77, 0x4a, 0x27, 0x25, 0x70, 0x75, 0x56, 0x78, 0x73, 0x2e, 0x38, 0x6c, 0x70, 0x66, 0x7b, 0x7b, 0x2d, 0x78, 0x27, 0x65, 0x63, 0x58, 0x4f, 0x7d, 0x5c, 0x31, 0x3e, 0x36, 0x6e, 0x65, 0x61, 0x2e, 0x4e, 0x26, 0x68, 0x2b, 0x33, 0x7d, 0x54, 0x2c, 0x28, 0x47, 0x3a, 0x31, 0x47, 0x56, 0x32, 0x74, 0x51, 0x79, 0x65, 0x42, 0x45, 0x60, 0x55, 0x6f, 0x48, 0x61, 0x23, 0x72, 0x62, 0x74, 0x3a, 0x5a, 0x26, 0x2d, 0x41, 0x58, 0x62, 0x75, 0x4b, 0x37, 0x2e, 0x3f, 0x2a, 0x6e, 0x2e, 0x2c, 0x43, 0x6f, 0x53, 0x5f, 0x48, 0x7a, 0x53, 0x7b, 0x54, 0x28, 0x30, 0x2b, 0x7a, 0x34, 0x33, 0x28, 0x2b, 0x23, 0x23, 0x72, 0x38, 0x25, 0x30, 0x35, 0x66, 0x76, 0x46, 0x2a, 0x57, 0x7a, 0x60, 0x38, 0x5a, 0x26, 0x4f, 0x78, 0x43, 0x2c, 0x7d, 0x3d, 0x76, 0x7d, 0x66, 0x48, 0x7d, 0x3e, 0x59, 0x31, 0x58, 0x6b, 0x30, 0x76, 0x45, 0x6e, 0x70, 0x72, 0x5f, 0x3c, 0x70, 0x6d, 0x77, 0x42, 0x75, 0x42, 0x73, 0x68, 0x5e, 0x5f, 0x72, 0x2b, 0x2a, 0x70, 0x38, 0x7a, 0x4c, 0x58, 0x2e, 0x5e, 0x2d, 0x2d, 0x78, 0x67, 0x5a, 0x77, 0x34, 0x5a, 0x50, 0x76, 0x2d, 0x2b, 0x77, 0x37, 0x6e, 0x38, 0x2d, 0x7b, 0x44, 0x78, 0x67, 0x52, 0x57, 0x79, 0x43, 0x7d, 0x6d, 0x4d, 0x32, 0x23, 0x37, 0x51, 0x4b, 0x41, 0x60, 0x6e, 0x53, 0x4e, 0x78, 0x37, 0x37, 0x60, 0x56, 0x64, 0x52, 0x25, 0x46, 0x53, 0x5f, 0x2b, 0x56, 0x2b, 0x3b, 0x40, 0x37, 0x33, 0x37, 0x23, 0x43, 0x36, 0x6b, 0x6b, 0x5d, 0x35, 0x28, 0x7d, 0x6a, 0x2c, 0x68, 0x28, 0x4b, 0x4a, 0x6c, 0x27, 0x35, 0x51, 0x66, 0x30, 0x39, 0x28, 0x4d, 0x61, 0x2f, 0x64, 0x36, 0x59, 0x39, 0x68, 0x4b, 0x24, 0x51, 0x7b, 0x6e, 0x38, 0x49, 0x55, 0x72, 0x5f, 0x33, 0x5c, 0x26, 0x45, 0x2f, 0x71, 0x66, 0x33, 0x3d, 0x36, 0x68, 0x65, 0x48, 0x42, 0x40, 0x58, 0x61, 0x4f, 0x50, 0x70, 0x5e, 0x3c, 0x5d, 0x56, 0x43, 0x4c, 0x41, 0x45, 0x54, 0x76, 0x4b, 0x21, 0x25, 0x45, 0x4c, 0x5e, 0x58, 0x23, 0x7d, 0x34, 0x61, 0x5c, 0x53, 0x2a, 0x47, 0x37, 0x22, 0x6d, 0x31, 0x42, 0x6e, 0x22, 0x72, 0x62, 0x55, 0x59, 0x66, 0x28, 0x73, 0x55, 0x50, 0x5c, 0x6f, 0x52, 0x40, 0x3e, 0x3b, 0x44, 0x2a, 0x51, 0x3d, 0x4d, 0x47, 0x3a, 0x57, 0x3e, 0x29, 0x29, 0x7d, 0x40, 0x36, 0x41, 0x3f, 0x58, 0x77, 0x3b, 0x41, 0x2d, 0x64, 0x5a, 0x72, 0x7c, 0x7d, 0x30, 0x68, 0x54, 0x34, 0x40, 0x21, 0x7d, 0x2b, 0x2d, 0x2b, 0x6d, 0x5f, 0x49, 0x57, 0x68, 0x65, 0x79, 0x2c, 0x21, 0x41, 0x31, 0x55, 0x27, 0x4d, 0x78, 0x55, 0x2f, 0x61, 0x62, 0x78, 0x58, 0x25, 0x3a, 0x4b, 0x3e, 0x67, 0x44, 0x7c, 0x7d, 0x52, 0x3d, 0x3e, 0x3b, 0x62, 0x2d, 0x28, 0x48, 0x70, 0x2c, 0x79, 0x31, 0x5a, 0x5e, 0x3f, 0x6a, 0x30, 0x78, 0x41, 0x44, 0x60, 0x4e, 0x63, 0x63, 0x2e, 0x31, 0x79, 0x2b, 0x47, 0x57, 0x26, 0x22, 0x6a, 0x46, 0x43, 0x70, 0x30, 0x51, 0x7d, 0x21, 0x3c, 0x68, 0x74, 0x40, 0x5a, 0x6e, 0x71, 0x3f, 0x76, 0x73, 0x2e, 0x29, 0x3f, 0x6a, 0x55, 0x21, 0x72, 0x65, 0x75, 0x5e, 0x6b, 0x39, 0x6e, 0x3e, 0x76, 0x42, 0x41, 0x65, 0x3f, 0x2b, 0x37, 0x70, 0x7a, 0x7a, 0x29, 0x50, 0x66, 0x21, 0x67, 0x3f, 0x54, 0x32, 0x5f, 0x73, 0x27, 0x59, 0x6f, 0x39, 0x4b, 0x4e, 0x23, 0x54, 0x3b, 0x39, 0x21, 0x38, 0x41, 0x33, 0x44, 0x57, 0x6b, 0x51, 0x30, 0x6a, 0x76, 0x62, 0x2c, 0x5c, 0x5e, 0x49, 0x3e, 0x59, 0x38, 0x5e, 0x4a, 0x59, 0x77, 0x34, 0x25, 0x4f, 0x76, 0x6a, 0x68, 0x6f, 0x73, 0x7c, 0x3d, 0x2d, 0x64, 0x6c, 0x7a, 0x3d, 0x2c, 0x26, 0x28, 0x58, 0x2b, 0x4b, 0x45, 0x68, 0x38, 0x74, 0x63, 0x7b, 0x4a, 0x63, 0x52, 0x26, 0x54, 0x3c, 0x46, 0x77, 0x2d, 0x6b, 0x78, 0x63, 0x7b, 0x6a, 0x50, 0x26, 0x42, 0x62, 0x63, 0x65, 0x6b, 0x63, 0x54, 0x4d, 0x47, 0x59, 0x48, 0x2e, 0x60, 0x7c, 0x4d, 0x33, 0x4d, 0x61, 0x72, 0x76, 0x72, 0x21, 0x4d, 0x2b, 0x43, 0x58, 0x47, 0x4a, 0x36, 0x2d, 0x7b, 0x32, 0x72, 0x21, 0x78, 0x22, 0x38, 0x2c, 0x7a, 0x34, 0x44, 0x45, 0x66, 0x31, 0x7b, 0x37, 0x68, 0x62, 0x65, 0x62, 0x6d, 0x4e, 0x7c, 0x75, 0x38, 0x2a, 0x73, 0x27, 0x64, 0x33, 0x4f, 0x21, 0x41, 0x7c, 0x41, 0x3f, 0x60, 0x68, 0x34, 0x72, 0x5b, 0x38, 0x33, 0x6f, 0x65, 0x3e, 0x5a, 0x7d, 0x25, 0x49, 0x50, 0x60, 0x36, 0x59, 0x5e, 0x6b, 0x25, 0x66, 0x7a, 0x7d, 0x71, 0x40, 0x6c, 0x2c, 0x6e, 0x6a, 0x5a, 0x24, 0x5a, 0x76, 0x21, 0x67, 0x39, 0x4b, 0x4a, 0x31, 0x24, 0x66, 0x66, 0x2e, 0x58, 0x43, 0x46, 0x75, 0x6c, 0x47, 0x28, 0x4f, 0x21, 0x75, 0x77, 0x6f, 0x71, 0x48, 0x3f, 0x4d, 0x4c, 0x51, 0x37, 0x3b, 0x41, 0x4d, 0x41, 0x48, 0x28, 0x71, 0x24, 0x2f, 0x7a, 0x22, 0x49, 0x4a, 0x39, 0x44, 0x43, 0x68, 0x21, 0x3a, 0x34, 0x4e, 0x52, 0x7a, 0x60, 0x71, 0x61, 0x6d, 0x51, 0x58, 0x2a, 0x59, 0x4c, 0x4a, 0x59, 0x6b, 0x77, 0x78, 0x2e, 0x27, 0x78, 0x76, 0x48, 0x4f, 0x46, 0x79, 0x2c, 0x54, 0x42, 0x7b, 0x2c, 0x52, 0x41, 0x54, 0x2b, 0x2c, 0x33, 0x6b, 0x70, 0x77, 0x2e, 0x2e, 0x41, 0x25, 0x7a, 0x48, 0x6e, 0x71, 0x55, 0x6a, 0x43, 0x5a, 0x2c, 0x6c, 0x76, 0x6d, 0x71, 0x72, 0x4d, 0x76, 0x5b, 0x7b, 0x22, 0x4b, 0x45, 0x31, 0x30, 0x26, 0x53, 0x75, 0x3f, 0x26, 0x59, 0x36, 0x2f, 0x68, 0x4f, 0x34, 0x5e, 0x2b, 0x30, 0x63, 0x68, 0x7b, 0x32, 0x5e, 0x77, 0x7d, 0x7b, 0x53, 0x5f, 0x63, 0x53, 0x77, 0x7a, 0x7d, 0x35, 0x28, 0x3e, 0x41, 0x6f, 0x5b, 0x31, 0x78, 0x7b, 0x2b, 0x51, 0x23, 0x43, 0x46, 0x6a, 0x32, 0x32, 0x25, 0x45, 0x57, 0x43, 0x22, 0x50, 0x60, 0x32, 0x70, 0x2e, 0x79, 0x2e, 0x6b, 0x33, 0x67, 0x6c, 0x43, 0x5b, 0x3b, 0x68, 0x53, 0x53, 0x6a, 0x48, 0x59, 0x5f, 0x30, 0x72, 0x7d, 0x6b, 0x37, 0x24, 0x75, 0x52, 0x50, 0x2b, 0x75, 0x35, 0x24, 0x3b, 0x6e, 0x53, 0x56, 0x34, 0x23, 0x54, 0x65, 0x4f, 0x78, 0x3e, 0x46, 0x7d, 0x25, 0x3f, 0x2f, 0x49, 0x6b, 0x49, 0x47, 0x45, 0x24, 0x38, 0x3b, 0x68, 0x6c, 0x4f, 0x29, 0x21, 0x50, 0x32, 0x67, 0x47, 0x5a, 0x72, 0x76, 0x21, 0x39, 0x67, 0x3c, 0x72, 0x47, 0x43, 0x4a, 0x2e, 0x31, 0x32, 0x34, 0x3c, 0x53, 0x2d, 0x22, 0x5b, 0x5b, 0x6a, 0x77, 0x75, 0x31, 0x68, 0x30, 0x45, 0x43, 0x5f, 0x60, 0x5d, 0x56, 0x67, 0x66, 0x55, 0x6a, 0x72, 0x77, 0x7b, 0x44, 0x61, 0x22, 0x64, 0x36, 0x39, 0x6e, 0x44, 0x37, 0x54, 0x45, 0x46, 0x6f, 0x58, 0x35, 0x51, 0x3c, 0x62, 0x49, 0x3a, 0x50, 0x58, 0x56, 0x5d, 0x77, 0x6f, 0x56, 0x64, 0x7b, 0x49, 0x39, 0x21, 0x31, 0x2d, 0x5f, 0x56, 0x56, 0x33, 0x31, 0x69, 0x4a, 0x52, 0x62, 0x5b, 0x6e, 0x65, 0x7c, 0x3d, 0x31, 0x55, 0x3d, 0x75, 0x25, 0x61, 0x50, 0x71, 0x45, 0x29 }; uint32_t request5_len = sizeof(request5); uint8_t request6[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x5b, 0x56, 0x3d, 0x5a, 0x6b, 0x43, 0x73, 0x26, 0x65, 0x3b, 0x38, 0x79, 0x26, 0x5e, 0x60, 0x59, 0x40, 0x71, 0x7c, 0x72, 0x28, 0x29, 0x69, 0x32, 0x72, 0x5a, 0x6c, 0x55, 0x43, 0x65, 0x3f, 0x4a, 0x21, 0x66, 0x59, 0x30, 0x76, 0x39, 0x21, 0x69, 0x4b, 0x25, 0x5d, 0x6e, 0x5f, 0x24, 0x2b, 0x38, 0x70, 0x78, 0x35, 0x7d, 0x39, 0x36, 0x31, 0x72, 0x44, 0x49, 0x45, 0x3d, 0x25, 0x50, 0x24, 0x3b, 0x52, 0x27, 0x66, 0x46, 0x5d, 0x4f, 0x34, 0x50, 0x26, 0x5a, 0x25, 0x3e, 0x3f, 0x34, 0x4b, 0x35, 0x77, 0x3a, 0x3f, 0x3e, 0x23, 0x4e, 0x30, 0x23, 0x70, 0x72, 0x33, 0x34, 0x60, 0x2a, 0x4a, 0x32, 0x6e, 0x29, 0x54, 0x73, 0x5f, 0x26, 0x71, 0x3a, 0x78, 0x5d, 0x3f, 0x31, 0x48, 0x59, 0x61, 0x44, 0x5c, 0x38, 0x4f, 0x41, 0x73, 0x67, 0x62, 0x73, 0x33, 0x52, 0x77, 0x73, 0x57, 0x49, 0x7a, 0x59, 0x26, 0x21, 0x34, 0x38, 0x2b, 0x5f, 0x5f, 0x37, 0x74, 0x28, 0x46, 0x3d, 0x43, 0x42, 0x26, 0x66, 0x63, 0x37, 0x6d, 0x2a, 0x65, 0x3f, 0x71, 0x2d, 0x4c, 0x72, 0x29, 0x4b, 0x3a, 0x77, 0x64, 0x6a, 0x6b, 0x42, 0x70, 0x5c, 0x51, 0x38, 0x71, 0x25, 0x4c, 0x7c, 0x6f, 0x74, 0x71, 0x39, 0x71, 0x25, 0x3f, 0x62, 0x23, 0x45, 0x5f, 0x77, 0x59, 0x56, 0x56, 0x67, 0x78, 0x3a, 0x2e, 0x4e, 0x27, 0x59, 0x65, 0x2f, 0x64, 0x3c, 0x62, 0x40, 0x69, 0x52, 0x36, 0x49, 0x3e, 0x3b, 0x2c, 0x47, 0x4f, 0x3e, 0x61, 0x78, 0x2d, 0x45, 0x71, 0x3f, 0x7b, 0x55, 0x34, 0x36, 0x47, 0x5e, 0x36, 0x51, 0x3d, 0x5a, 0x4b, 0x75, 0x44, 0x72, 0x61, 0x44, 0x71, 0x4e, 0x42, 0x6a, 0x2c, 0x34, 0x40, 0x3b, 0x40, 0x31, 0x31, 0x75, 0x4b, 0x32, 0x71, 0x69, 0x3a, 0x5d, 0x31, 0x25, 0x53, 0x2a, 0x61, 0x54, 0x68, 0x2a, 0x76, 0x71, 0x57, 0x67, 0x56, 0x23, 0x7d, 0x70, 0x7d, 0x28, 0x57, 0x5f, 0x2f, 0x4c, 0x71, 0x2e, 0x40, 0x63, 0x49, 0x5b, 0x7c, 0x7b, 0x56, 0x76, 0x77, 0x46, 0x69, 0x56, 0x3d, 0x75, 0x31, 0x3b, 0x35, 0x40, 0x37, 0x2c, 0x51, 0x37, 0x49, 0x6a, 0x79, 0x68, 0x53, 0x31, 0x4c, 0x6f, 0x57, 0x4c, 0x48, 0x31, 0x6a, 0x30, 0x2b, 0x69, 0x30, 0x56, 0x58, 0x4b, 0x76, 0x3b, 0x60, 0x6d, 0x35, 0x4d, 0x74, 0x2f, 0x74, 0x2c, 0x54, 0x4f, 0x6e, 0x3f, 0x38, 0x56, 0x5c, 0x67, 0x2b, 0x4a, 0x35, 0x30, 0x67, 0x7d, 0x58, 0x24, 0x59, 0x54, 0x48, 0x2e, 0x28, 0x7d, 0x6e, 0x51, 0x55, 0x68, 0x56, 0x54, 0x59, 0x31, 0x4a, 0x65, 0x5a, 0x5e, 0x27, 0x76, 0x76, 0x65, 0x6d, 0x2f, 0x75, 0x63, 0x67, 0x52, 0x5e, 0x29, 0x58, 0x3d, 0x5c, 0x3f, 0x54, 0x7c, 0x67, 0x21, 0x6e, 0x75, 0x67, 0x35, 0x77, 0x31, 0x3d, 0x26, 0x3f, 0x60, 0x45, 0x2d, 0x2b, 0x45, 0x5d, 0x3f, 0x55, 0x73, 0x59, 0x4c, 0x5e, 0x6c, 0x30, 0x4a, 0x4e, 0x47, 0x55, 0x42, 0x6a, 0x4b, 0x32, 0x3c, 0x75, 0x6e, 0x36, 0x51, 0x5f, 0x4c, 0x68, 0x72, 0x72, 0x27, 0x3b, 0x51, 0x59, 0x7b, 0x68, 0x7b, 0x3b, 0x54, 0x35, 0x37, 0x7c, 0x44, 0x43, 0x36, 0x4c, 0x4f, 0x67, 0x62, 0x4e, 0x39, 0x4b, 0x7a, 0x49, 0x36, 0x68, 0x38, 0x4c, 0x4a, 0x64, 0x33, 0x35, 0x2f, 0x3e, 0x5c, 0x58, 0x61, 0x23, 0x5b, 0x50, 0x6e, 0x34, 0x44, 0x60, 0x28, 0x54, 0x41, 0x5c, 0x31, 0x53, 0x2d, 0x58, 0x58, 0x54, 0x28, 0x77, 0x51, 0x6f, 0x64, 0x4c, 0x68, 0x34, 0x79, 0x45, 0x66, 0x2c, 0x26, 0x77, 0x64, 0x5f, 0x6c, 0x3b, 0x71, 0x28, 0x4d, 0x68, 0x2a, 0x6b, 0x37, 0x6a, 0x34, 0x51, 0x27, 0x2a, 0x46, 0x3a, 0x2e, 0x35, 0x21, 0x21, 0x79, 0x51, 0x44, 0x58, 0x5d, 0x6f, 0x65, 0x6b, 0x76, 0x68, 0x3a, 0x43, 0x70, 0x36, 0x41, 0x6b, 0x56, 0x64, 0x75, 0x5b, 0x37, 0x24, 0x56, 0x7c, 0x6e, 0x6c, 0x41, 0x3a, 0x60, 0x56, 0x38, 0x55, 0x63, 0x77, 0x4d, 0x6e, 0x50, 0x3c, 0x3d, 0x7a, 0x44, 0x71, 0x42, 0x4b, 0x55, 0x75, 0x72, 0x61, 0x60, 0x65, 0x6f, 0x7a, 0x26, 0x64, 0x46, 0x67, 0x74, 0x29, 0x2a, 0x5b, 0x62, 0x41, 0x28, 0x62, 0x30, 0x34, 0x33, 0x40, 0x79, 0x7a, 0x38, 0x56, 0x38, 0x73, 0x22, 0x7a, 0x7d, 0x73, 0x2a, 0x2a, 0x28, 0x2b, 0x63, 0x27, 0x6f, 0x3d, 0x3e, 0x2c, 0x56, 0x23, 0x32, 0x4b, 0x3b, 0x58, 0x4d, 0x72, 0x4c, 0x49, 0x6f, 0x30, 0x76, 0x23, 0x21, 0x21, 0x3c, 0x49, 0x56, 0x7a, 0x56, 0x79, 0x2f, 0x50, 0x7a, 0x5b, 0x21, 0x21, 0x4a, 0x48, 0x61, 0x33, 0x52, 0x49, 0x2e, 0x30, 0x7d, 0x2c, 0x2d, 0x67, 0x23, 0x55, 0x62, 0x66, 0x52, 0x5a, 0x61, 0x75, 0x63, 0x3c, 0x39, 0x69, 0x41, 0x31, 0x6b, 0x4e, 0x6f, 0x25, 0x34, 0x74, 0x30, 0x21, 0x3a, 0x40, 0x72, 0x44, 0x40, 0x60, 0x4c, 0x53, 0x74, 0x42, 0x64, 0x44, 0x49, 0x76, 0x67, 0x21, 0x79, 0x36, 0x3c, 0x37, 0x70, 0x4f, 0x58, 0x29, 0x71, 0x2a, 0x3a, 0x4d, 0x5d, 0x67, 0x68, 0x52, 0x63, 0x23, 0x24, 0x4b, 0x21, 0x3f, 0x68, 0x69, 0x6c, 0x66, 0x66, 0x42, 0x28, 0x59, 0x35, 0x34, 0x6f, 0x2d, 0x6a, 0x25, 0x66, 0x34, 0x54, 0x5d, 0x50, 0x26, 0x41, 0x22, 0x4f, 0x34, 0x79, 0x3c, 0x50, 0x68, 0x2d, 0x5f, 0x7b, 0x63, 0x7d, 0x58, 0x2e, 0x73, 0x46, 0x2f, 0x54, 0x61, 0x27, 0x74, 0x45, 0x23, 0x72, 0x31, 0x7d, 0x63, 0x4b, 0x43, 0x5e, 0x44, 0x54, 0x2c, 0x38, 0x58, 0x24, 0x75, 0x6c, 0x50, 0x3c, 0x23, 0x5f, 0x35, 0x57, 0x4f, 0x7b, 0x2f, 0x57, 0x29, 0x73, 0x58, 0x2a, 0x66, 0x3e, 0x49, 0x42, 0x5a, 0x6b, 0x75, 0x6a, 0x38, 0x3f, 0x73, 0x44, 0x42, 0x46, 0x2d, 0x39, 0x66, 0x5b, 0x28, 0x3e, 0x63, 0x62, 0x53, 0x75, 0x65, 0x64, 0x79, 0x32, 0x35, 0x71, 0x22, 0x6a, 0x7b, 0x41, 0x2b, 0x26, 0x43, 0x79, 0x58, 0x6f, 0x71, 0x25, 0x24, 0x34, 0x72, 0x5b, 0x4a, 0x2c, 0x5c, 0x77, 0x23, 0x42, 0x27, 0x6a, 0x67, 0x51, 0x5f, 0x3c, 0x75, 0x2c, 0x3f, 0x43, 0x45, 0x5b, 0x48, 0x65, 0x6f, 0x6c, 0x27, 0x65, 0x21, 0x3e, 0x33, 0x37, 0x5f, 0x2b, 0x2e, 0x24, 0x22, 0x47, 0x4e, 0x33, 0x5b, 0x7b, 0x21, 0x3c, 0x53, 0x69, 0x2e, 0x31, 0x3d, 0x48, 0x57, 0x3a, 0x56, 0x48, 0x6b, 0x47, 0x5d, 0x33, 0x41, 0x6c, 0x66, 0x4c, 0x61, 0x67, 0x32, 0x69, 0x53, 0x2c, 0x2f, 0x3e, 0x36, 0x68, 0x37, 0x28, 0x40, 0x21, 0x76, 0x27, 0x44, 0x26, 0x24, 0x6a, 0x30, 0x75, 0x2a, 0x73, 0x48, 0x36, 0x52, 0x4a, 0x3b, 0x51, 0x4e, 0x2f, 0x23, 0x36, 0x4b, 0x49, 0x33, 0x5a, 0x70, 0x2c, 0x54, 0x5b, 0x67, 0x48, 0x53, 0x5d, 0x21, 0x3e, 0x6b, 0x52, 0x6a, 0x3c, 0x48, 0x29, 0x68, 0x27, 0x32, 0x75, 0x61, 0x7c, 0x51, 0x2e, 0x7b, 0x49, 0x2f, 0x5b, 0x3d, 0x74, 0x5a, 0x28, 0x26, 0x29, 0x2c, 0x30, 0x54, 0x74, 0x45, 0x55, 0x4a, 0x3d, 0x39, 0x35, 0x66, 0x56, 0x28, 0x6d, 0x6e, 0x38, 0x7b, 0x2b, 0x40, 0x31, 0x56, 0x61, 0x74, 0x2b, 0x79, 0x5f, 0x63, 0x51, 0x53, 0x52, 0x7d, 0x73, 0x4e, 0x2e, 0x45, 0x3b, 0x22, 0x28, 0x6c, 0x2b, 0x47, 0x21, 0x50, 0x2a, 0x7c, 0x45, 0x48, 0x57, 0x3e, 0x2f, 0x6d, 0x66, 0x6c, 0x51, 0x23, 0x6c, 0x37, 0x4d, 0x4b, 0x4b, 0x66, 0x55, 0x69, 0x2e, 0x4a, 0x69, 0x71, 0x7c, 0x71, 0x30, 0x5c, 0x43, 0x46, 0x63, 0x5a, 0x23, 0x75, 0x40 }; uint32_t request6_len = sizeof(request6); uint8_t request7[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x5d, 0x32, 0x55, 0x71, 0x51, 0x45, 0x4e, 0x54, 0x34, 0x21, 0x46, 0x77, 0x5e, 0x5b, 0x75, 0x62, 0x2b, 0x5c, 0x34, 0x26, 0x72, 0x2b, 0x2c, 0x64, 0x4b, 0x65, 0x56, 0x72, 0x31, 0x7d, 0x6a, 0x5f, 0x70, 0x26, 0x32, 0x29, 0x7d, 0x21, 0x5b, 0x3e, 0x5e, 0x53, 0x3d, 0x48, 0x5e, 0x2a, 0x4c, 0x37, 0x3d, 0x59, 0x79, 0x21, 0x4f, 0x56, 0x79, 0x2a, 0x4e, 0x28, 0x61, 0x7d, 0x2c, 0x58, 0x2f, 0x78, 0x5c, 0x3f, 0x5c, 0x42, 0x6d, 0x2f, 0x71, 0x54, 0x25, 0x31, 0x73, 0x38, 0x6c, 0x31, 0x5a, 0x2e, 0x42, 0x5b, 0x2d, 0x41, 0x24, 0x4c, 0x37, 0x40, 0x39, 0x7d, 0x2a, 0x67, 0x60, 0x6a, 0x7a, 0x62, 0x24, 0x4e, 0x3f, 0x2e, 0x69, 0x35, 0x28, 0x65, 0x77, 0x53, 0x23, 0x44, 0x59, 0x71, 0x31, 0x5c, 0x40, 0x5d, 0x3a, 0x27, 0x46, 0x55, 0x30, 0x56, 0x21, 0x74, 0x3e, 0x73, 0x41, 0x22, 0x52, 0x68, 0x40, 0x6c, 0x37, 0x3e, 0x62, 0x5a, 0x2e, 0x21, 0x23, 0x33, 0x27, 0x73, 0x68, 0x26, 0x60, 0x67, 0x70, 0x58, 0x50, 0x42, 0x58, 0x27, 0x3a, 0x35, 0x6f, 0x51, 0x62, 0x78, 0x25, 0x2c, 0x7b, 0x66, 0x34, 0x6a, 0x5a, 0x39, 0x60, 0x70, 0x41, 0x2d, 0x65, 0x26, 0x5a, 0x67, 0x58, 0x2d, 0x3e, 0x56, 0x6d, 0x30, 0x4b, 0x4d, 0x5d, 0x45, 0x41, 0x3d, 0x6e, 0x27, 0x4e, 0x5a, 0x7d, 0x2e, 0x62, 0x4d, 0x42, 0x70, 0x31, 0x24, 0x73, 0x5c, 0x78, 0x77, 0x50, 0x73, 0x27, 0x48, 0x3d, 0x35, 0x2c, 0x4b, 0x40, 0x2d, 0x25, 0x77, 0x5d, 0x3d, 0x6b, 0x50, 0x6f, 0x57, 0x73, 0x2f, 0x4f, 0x6e, 0x4c, 0x6e, 0x56, 0x7b, 0x55, 0x3c, 0x6d, 0x60, 0x47, 0x53, 0x56, 0x39, 0x3b, 0x51, 0x61, 0x71, 0x75, 0x73, 0x6b, 0x70, 0x58, 0x5f, 0x2c, 0x27, 0x74, 0x49, 0x2c, 0x2b, 0x53, 0x2d, 0x5b, 0x79, 0x43, 0x34, 0x39, 0x5a, 0x38, 0x3e, 0x2d, 0x66, 0x70, 0x3d, 0x49, 0x51, 0x29, 0x4d, 0x5d, 0x4c, 0x57, 0x4a, 0x2f, 0x41, 0x69, 0x56, 0x57, 0x77, 0x49, 0x58, 0x75, 0x28, 0x29, 0x4a, 0x6d, 0x54, 0x4f, 0x4f, 0x3f, 0x58, 0x5f, 0x58, 0x6f, 0x39, 0x22, 0x4d, 0x5d, 0x31, 0x75, 0x43, 0x2f, 0x7d, 0x31, 0x3d, 0x4c, 0x4d, 0x76, 0x74, 0x4d, 0x57, 0x3b, 0x56, 0x57, 0x48, 0x2b, 0x5d, 0x32, 0x67, 0x51, 0x6e, 0x60, 0x39, 0x6f, 0x64, 0x38, 0x37, 0x52, 0x4b, 0x52, 0x42, 0x32, 0x4f, 0x24, 0x53, 0x31, 0x6e, 0x4a, 0x68, 0x2f, 0x28, 0x2e, 0x27, 0x49, 0x75, 0x77, 0x75, 0x26, 0x47, 0x7c, 0x5d, 0x72, 0x5a, 0x77, 0x50, 0x2e, 0x6c, 0x27, 0x68, 0x6b, 0x7b, 0x27, 0x63, 0x21, 0x3d, 0x30, 0x2d, 0x5c, 0x67, 0x4d, 0x41, 0x79, 0x47, 0x42, 0x50, 0x6d, 0x32, 0x74, 0x39, 0x62, 0x4d, 0x5f, 0x65, 0x78, 0x4f, 0x67, 0x3a, 0x60, 0x26, 0x45, 0x61, 0x7c, 0x61, 0x63, 0x40, 0x46, 0x79, 0x52, 0x47, 0x57, 0x49, 0x53, 0x4c, 0x48, 0x36, 0x67, 0x47, 0x5c, 0x71, 0x50, 0x4d, 0x4f, 0x58, 0x26, 0x40, 0x6d, 0x54, 0x55, 0x67, 0x66, 0x23, 0x70, 0x23, 0x68, 0x70, 0x4d, 0x2c, 0x7a, 0x3d, 0x60, 0x51, 0x35, 0x64, 0x56, 0x2f, 0x26, 0x6d, 0x72, 0x6a, 0x59, 0x34, 0x3a, 0x73, 0x4b, 0x27, 0x33, 0x61, 0x26, 0x45, 0x61, 0x28, 0x74, 0x22, 0x54, 0x50, 0x2e, 0x39, 0x6a, 0x2c, 0x27, 0x59, 0x26, 0x73, 0x44, 0x71, 0x67, 0x4c, 0x37, 0x74, 0x2c, 0x63, 0x52, 0x2a, 0x60, 0x4f, 0x7b, 0x32, 0x39, 0x21, 0x79, 0x54, 0x79, 0x6d, 0x28, 0x27, 0x3a, 0x6a, 0x7d, 0x40, 0x6a, 0x4f, 0x4b, 0x46, 0x61, 0x36, 0x6a, 0x22, 0x3f, 0x77, 0x2d, 0x6a, 0x3b, 0x73, 0x71, 0x72, 0x3c, 0x21, 0x2e, 0x3f, 0x33, 0x25, 0x76, 0x64, 0x64, 0x70, 0x43, 0x32, 0x44, 0x73, 0x61, 0x51, 0x3c, 0x3b, 0x45, 0x3a, 0x68, 0x46, 0x5b, 0x6e, 0x36, 0x47, 0x4d, 0x38, 0x26, 0x4f, 0x5c, 0x7d, 0x73, 0x29, 0x24, 0x78, 0x44, 0x75, 0x40, 0x42, 0x41, 0x2a, 0x73, 0x2b, 0x24, 0x38, 0x51, 0x67, 0x36, 0x67, 0x2f, 0x70, 0x58, 0x54, 0x6e, 0x5d, 0x3b, 0x41, 0x59, 0x76, 0x7d, 0x2d, 0x40, 0x70, 0x29, 0x4a, 0x4a, 0x31, 0x79, 0x2c, 0x4e, 0x22, 0x31, 0x59, 0x31, 0x3c, 0x2f, 0x21, 0x29, 0x3f, 0x65, 0x6c, 0x38, 0x55, 0x4f, 0x27, 0x66, 0x66, 0x34, 0x45, 0x49, 0x41, 0x56, 0x24, 0x2e, 0x40, 0x36, 0x23, 0x5a, 0x46, 0x40, 0x23, 0x7b, 0x2d, 0x69, 0x54, 0x6c, 0x51, 0x58, 0x73, 0x56, 0x60, 0x5f, 0x60, 0x63, 0x5f, 0x77, 0x6a, 0x4c, 0x2c, 0x35, 0x39, 0x60, 0x73, 0x63, 0x3e, 0x2d, 0x55, 0x5a, 0x26, 0x4b, 0x43, 0x3b, 0x56, 0x33, 0x58, 0x74, 0x51, 0x4f, 0x5c, 0x2a, 0x44, 0x78, 0x66, 0x78, 0x71, 0x40, 0x29, 0x5e, 0x26, 0x57, 0x51, 0x49, 0x30, 0x29, 0x73, 0x38, 0x56, 0x6c, 0x41, 0x78, 0x3d, 0x61, 0x3d, 0x2c, 0x33, 0x46, 0x57, 0x54, 0x63, 0x3e, 0x79, 0x55, 0x4a, 0x7d, 0x2e, 0x2a, 0x3c, 0x77, 0x47, 0x35, 0x29, 0x5a, 0x6d, 0x69, 0x48, 0x6b, 0x73, 0x7d, 0x4f, 0x5f, 0x6f, 0x3a, 0x7a, 0x4e, 0x54, 0x59, 0x38, 0x62, 0x44, 0x72, 0x51, 0x57, 0x6a, 0x74, 0x54, 0x4f, 0x77, 0x6b, 0x66, 0x4a, 0x6b, 0x39, 0x29, 0x69, 0x60, 0x71, 0x52, 0x6a, 0x32, 0x66, 0x6c, 0x25, 0x76, 0x27, 0x7a, 0x2c, 0x38, 0x72, 0x4e, 0x5f, 0x40, 0x26, 0x74, 0x6a, 0x5e, 0x42, 0x38, 0x78, 0x34, 0x4f, 0x4f, 0x35, 0x27, 0x39, 0x62, 0x52, 0x61, 0x37, 0x54, 0x47, 0x38, 0x70, 0x31, 0x7a, 0x66, 0x69, 0x72, 0x24, 0x52, 0x2a, 0x2a, 0x78, 0x72, 0x2b, 0x2e, 0x2a, 0x57, 0x4a, 0x21, 0x52, 0x3c, 0x2a, 0x2f, 0x24, 0x58, 0x34, 0x3c, 0x42, 0x5c, 0x5b, 0x78, 0x27, 0x55, 0x63, 0x58, 0x3e, 0x26, 0x50, 0x2c, 0x72, 0x60, 0x36, 0x6c, 0x46, 0x58, 0x63, 0x59, 0x23, 0x2a, 0x2d, 0x63, 0x6a, 0x68, 0x69, 0x74, 0x3f, 0x49, 0x4f, 0x48, 0x4a, 0x3b, 0x59, 0x56, 0x77, 0x43, 0x6d, 0x57, 0x28, 0x5f, 0x39, 0x73, 0x28, 0x74, 0x3c, 0x4f, 0x43, 0x48, 0x6a, 0x57, 0x5d, 0x41, 0x73, 0x3f, 0x41, 0x7c, 0x65, 0x5e, 0x2d, 0x38, 0x72, 0x3a, 0x53, 0x3e, 0x33, 0x47, 0x69, 0x6a, 0x6e, 0x78, 0x67, 0x5d, 0x35, 0x3b, 0x3f, 0x23, 0x7c, 0x71, 0x3d, 0x7c, 0x3a, 0x3c, 0x75, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x80, 0x23, 0x00, 0xdf, 0xaf, 0xff, 0x33, 0x9b, 0x78, 0x70, 0x43, 0xc5, 0x0a, 0x4d, 0x98, 0x96, 0x02, 0x64, 0x92, 0xc1, 0xee, 0x70, 0x32 }; uint32_t request7_len = sizeof(request7); uint8_t request8[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x65, 0xc1, 0xef, 0x7b, 0xd6, 0xaa, 0xd6, 0x09, 0x21, 0xf6, 0xe7, 0xd1, 0x4c, 0xdf, 0x6a, 0x2d, 0x0a, 0xfb, 0x43, 0xea, 0xda, 0x07, 0x24, 0x84, 0x88, 0x52, 0x9e, 0xa8, 0xa1, 0x7f, 0x4b, 0x60, 0xec, 0x94, 0x57, 0x33, 0x06, 0x93, 0x92, 0x25, 0xd6, 0xac, 0xdc, 0x89, 0x68, 0x5e, 0xbb, 0x32, 0x2b, 0x17, 0x68, 0xf2, 0x06, 0xb7, 0x86, 0xac, 0x81, 0xfe, 0x52, 0x27, 0xf5, 0x80, 0x11, 0x0d, 0x4e, 0x2e, 0x1b, 0xa3, 0x44, 0x8a, 0x58, 0xed, 0xf3, 0x9c, 0xe9, 0x31, 0x01, 0x72, 0xa6, 0xab, 0xfa, 0xa8, 0x05, 0x00, 0x37, 0x60, 0x6b, 0x81, 0xef, 0xf4, 0x96, 0x9a, 0xf7, 0x67, 0x95, 0x27, 0x7a, 0x25, 0xef, 0x6f, 0x0e, 0xff, 0x2d, 0x15, 0x7f, 0x23, 0x1c, 0xa7, 0x56, 0x94, 0x4a, 0x18, 0x98, 0xc6, 0xd8, 0xd2, 0x29, 0x5b, 0x57, 0xb8, 0x5d, 0x3a, 0x93, 0x58, 0x45, 0x77, 0x36, 0xe3, 0xd1, 0x36, 0x87, 0xff, 0xe3, 0x94, 0x0f, 0x00, 0xe6, 0x7c, 0x1a, 0x92, 0xc1, 0x5f, 0x40, 0xc3, 0xa3, 0x25, 0xce, 0xd4, 0xaf, 0x39, 0xeb, 0x17, 0xcf, 0x22, 0x43, 0xd9, 0x0c, 0xce, 0x37, 0x86, 0x46, 0x54, 0xd6, 0xce, 0x00, 0x30, 0x36, 0xae, 0xf9, 0xb5, 0x2b, 0x11, 0xa0, 0xfe, 0xa3, 0x4b, 0x2e, 0x05, 0xbe, 0x54, 0xa9, 0xd8, 0xa5, 0x76, 0x83, 0x5b, 0x63, 0x01, 0x1c, 0xd4, 0x56, 0x72, 0xcd, 0xdc, 0x4a, 0x1d, 0x77, 0xda, 0x8a, 0x9e, 0xba, 0xcb, 0x6c, 0xe8, 0x19, 0x5d, 0x68, 0xef, 0x8e, 0xbc, 0x6a, 0x05, 0x53, 0x0b, 0xc7, 0xc5, 0x96, 0x84, 0x04, 0xd9, 0xda, 0x4c, 0x42, 0x31, 0xd9, 0xbd, 0x99, 0x06, 0xf7, 0xa3, 0x0a, 0x19, 0x49, 0x07, 0x77, 0xf0, 0xdb, 0x7c, 0x43, 0xfa, 0xb2, 0xad, 0xb0, 0xfa, 0x87, 0x52, 0xba, 0xc9, 0x94, 0x61, 0xdc, 0xcf, 0x16, 0xac, 0x0f, 0x4a, 0xa3, 0x6b, 0x5b, 0x6e, 0x27, 0x86, 0x1f, 0xfe, 0x4d, 0x28, 0x3a, 0xa5, 0x10, 0x54, 0x6d, 0xed, 0x53, 0xf9, 0x73, 0xc6, 0x6e, 0xa8, 0xc0, 0x97, 0xcf, 0x56, 0x3b, 0x61, 0xdf, 0xab, 0x83, 0x18, 0xe8, 0x09, 0xee, 0x6a, 0xb7, 0xf5, 0xc9, 0x62, 0x55, 0x2d, 0xc7, 0x0c, 0x0d, 0xa0, 0x22, 0xd8, 0xd4, 0xd6, 0xb2, 0x12, 0x21, 0xd7, 0x73, 0x3e, 0x41, 0xb0, 0x5c, 0xd4, 0xcf, 0x98, 0xf3, 0x70, 0xe6, 0x08, 0xe6, 0x2a, 0x4f, 0x24, 0x85, 0xe8, 0x74, 0xa8, 0x41, 0x5f, 0x0e, 0xfd, 0xf1, 0xf3, 0xbe, 0x9b, 0x14, 0xfd, 0xc0, 0x73, 0x11, 0xff, 0xa5, 0x5b, 0x06, 0x34, 0xc3, 0x6c, 0x28, 0x42, 0x07, 0xfe, 0x8a, 0xa5, 0xbe, 0x72, 0x7a, 0xf7, 0xfa, 0x25, 0xec, 0x35, 0x5e, 0x98, 0x71, 0x50, 0x60, 0x35, 0x76, 0x53, 0x40, 0x1a, 0x34, 0xa5, 0x99, 0x09, 0xa2, 0xc6, 0xca, 0xa5, 0xce, 0x08, 0x50, 0x45, 0xab, 0x8d, 0xfb, 0xe3, 0xb8, 0xe4, 0x8a, 0x61, 0x48, 0x14, 0x6e, 0xf7, 0x58, 0x71, 0xe5, 0x2e, 0xbc, 0x12, 0xd1, 0x25, 0xe9, 0x65, 0x7a, 0xa1, 0x27, 0xbe, 0x3b, 0x8b, 0xe8, 0xe7, 0xbc, 0xe1, 0x05, 0xe7, 0x92, 0xeb, 0xb9, 0xdf, 0x5d, 0x53, 0x74, 0xc0, 0x63, 0x97, 0x80, 0xb8, 0x3c, 0xae, 0xf3, 0xf2, 0x09, 0x12, 0x81, 0x6c, 0x69, 0x10, 0x6f, 0xf6, 0xbe, 0x03, 0x7b, 0x88, 0xcf, 0x26, 0x6b, 0x51, 0x06, 0x23, 0x68, 0x03, 0xa1, 0xb7, 0xd3, 0x0c, 0xca, 0xbf, 0x29, 0x01, 0xa9, 0x61, 0x34, 0x75, 0x98, 0x1e, 0x05, 0x59, 0xb3, 0x46, 0x44, 0xff, 0x2b, 0x98, 0x04, 0x88, 0x89, 0xfd, 0x7f, 0xd5, 0x19, 0x8a, 0xa6, 0xf3, 0xd9, 0x44, 0xd5, 0xf9, 0x3a, 0x3c, 0xec, 0xd9, 0x9b, 0x8c, 0x93, 0x93, 0x2b, 0x44, 0x86, 0x8b, 0x80, 0x83, 0x23, 0x00, 0xdf, 0xaf, 0xff, 0x33, 0x9b, 0x78, 0x70, 0x43, 0xf1, 0x55, 0x87, 0xb1, 0xa1, 0xb3, 0x8e, 0x79, 0x02, 0x70, 0x82, 0x6c, 0x0b, 0xc1, 0xef, 0x96, 0xf1, 0xef, 0xdd, 0xa2, 0x69, 0x86, 0xc7, 0x85, 0x09, 0x7e, 0xf0, 0x2f, 0x8e, 0xa0, 0x5f, 0xea, 0x39, 0x2e, 0x24, 0xf0, 0x82, 0x30, 0x26, 0xa8, 0xa1, 0x4f, 0xc6, 0x5c, 0xec, 0x94, 0x87, 0x52, 0x9b, 0x93, 0x92, 0xf3, 0xa3, 0x1b, 0xc7, 0x8f, 0x9e, 0xb3, 0xbb, 0x32, 0x2b, 0x17, 0x54, 0xf2, 0x06, 0x0c, 0x86, 0x92, 0x0f, 0xb8, 0xe0, 0x27, 0x50, 0xaa, 0xeb, 0xf5, 0x4e, 0x2b, 0x1b, 0xb2, 0x44, 0xe6, 0x58, 0x02, 0xd7, 0x65, 0xdc, 0x31, 0x01, 0xec, 0xa6, 0xab, 0xfa, 0xa8, 0x05, 0x00, 0x37, 0x60, 0x4f, 0xa1, 0x3c, 0x4f, 0x7a, 0x9a, 0x10, 0x67, 0x95, 0xc2, 0x5b, 0x25, 0xef, 0x76, 0x0e, 0xff, 0x2d, 0x15, 0x7f, 0x23, 0x1c, 0x77, 0x56, 0x94, 0x4a, 0x18, 0x98, 0xc6, 0xd8, 0xd2, 0x29, 0x44, 0x57, 0xb8, 0x40, 0x3a, 0x93, 0x58, 0x45, 0x77, 0x36, 0x36, 0x07, 0x35, 0x2a, 0xff, 0x00, 0x94, 0x5c, 0x80, 0xe6, 0x7c, 0x1a, 0x92, 0xc1, 0x5f, 0x40, 0xc3, 0xbc, 0xf8, 0xce, 0x05, 0x77, 0x39, 0x40, 0x17, 0xcf, 0x63, 0x43, 0x77, 0x27, 0xce, 0x37, 0x86, 0x46, 0x54, 0xd6, 0xce, 0x00, 0x30, 0x36, 0xae, 0x9f, 0x24, 0x2b, 0x5a, 0xa0, 0xfe, 0xa3, 0x4b, 0x2e, 0x7e, 0xf7, 0x54, 0xa9, 0xd8, 0xa5, 0x76, 0x83, 0x7b, 0x63, 0x01, 0x1c, 0xd4, 0x56, 0x17, 0x02, 0xdc, 0x4a, 0x89, 0x77, 0xda, 0x8f, 0x9e, 0xba, 0xcb, 0x37, 0xe8, 0x19, 0x5d, 0x68, 0x38, 0x8e, 0xbc, 0x6a, 0x05, 0x53, 0x0b, 0xc7, 0xc5, 0x96, 0x84, 0x5a, 0xd9, 0x6d, 0x4c, 0x42, 0x31, 0xd9, 0xf2, 0x99, 0x06, 0xf7, 0x0c, 0x99, 0xbe, 0x49, 0x07, 0x77, 0xf0, 0x8b, 0x7c, 0x43, 0xfa, 0xb2, 0xad, 0xb0, 0xfa, 0x87, 0x52, 0xba, 0xc9, 0x94, 0x61, 0xdc, 0xcf, 0x16, 0xac, 0x0f, 0x4a, 0xa3, 0x6b, 0x5b, 0x6e, 0x27, 0x86, 0x1f, 0xfe, 0x4d, 0x28, 0x3a, 0xa5, 0x10, 0x98, 0x6d, 0xed, 0x53, 0xf9, 0x73, 0xc6, 0xa5, 0xa8, 0xf7, 0x66, 0xcf, 0x56, 0x3b, 0x61, 0xdf, 0xab, 0x83, 0x18, 0xe8, 0x09, 0xee, 0x6a, 0xb7, 0xf5, 0xc9, 0x62, 0x55, 0x2d, 0xc7, 0x0c, 0x0d, 0xa0, 0x22, 0xd8, 0xd4, 0xd6, 0xb2, 0x12, 0x21, 0xd7, 0x73, 0x3e, 0x41, 0xb0, 0x5c, 0xd4, 0xcf, 0x98, 0xf3, 0x70, 0xe6, 0x08, 0xe6, 0x2a, 0x4f, 0x92, 0x85, 0xe8, 0x74, 0xa8, 0x41, 0x5f, 0x0e, 0xfd, 0xf1, 0xf3, 0xbe, 0x9b, 0x14, 0xfd, 0xc0, 0x73, 0x11, 0xff, 0xa5, 0x5b, 0x06, 0x34, 0xc3, 0x5d, 0x28, 0x42, 0x34, 0xfe, 0x8a, 0xa5, 0xbe, 0x72, 0x7a, 0xf7, 0xfa, 0x25, 0x2b, 0x35, 0x5e, 0x98, 0x71, 0x50, 0x2c, 0x35, 0x76, 0x53, 0x4e, 0x1a, 0x34, 0xa5, 0x99, 0x09, 0xa2, 0xc6, 0xca, 0xa5, 0xce, 0x08, 0x50, 0x45, 0xab, 0x8d, 0xfb, 0xe3, 0xb8, 0xe4, 0x8a, 0x61, 0x48, 0x14, 0x6e, 0xf7, 0x58, 0x71, 0xe5, 0x2e, 0xbc, 0x12, 0xd1, 0x25, 0xe9, 0x65, 0x7a, 0xa1, 0x27, 0xbe, 0x3b, 0x8b, 0xe8, 0xe7, 0xbc, 0x77, 0x05, 0xe7, 0x92, 0xeb, 0xb9, 0xdf, 0x5d, 0x53, 0x74, 0xc0, 0x63, 0x97, 0x80, 0xb8, 0x3c, 0xae, 0xf3, 0xf2, 0x09, 0x12, 0x81, 0x6c, 0x69, 0x10, 0x6f, 0xf6, 0xbe, 0x03, 0x7b, 0x88, 0xcf, 0x26, 0x6b, 0x51, 0x06, 0x23, 0x68, 0x03, 0xa1, 0xb7, 0xd3, 0x0c, 0xca, 0xbf, 0x29, 0x01, 0xa9, 0x61, 0x34, 0x75, 0x98, 0x1e, 0x6f, 0x59, 0xb3, 0x46, 0x44, 0xff, 0x2b, 0x98, 0x04, 0x88, 0x89, 0xfd, 0x1c, 0xd5, 0x19, 0x8a, 0xa6, 0xf3, 0xd9, 0x44, 0xd5, 0xf9, 0x79, 0x26, 0x46, 0xf7 }; uint32_t request8_len = sizeof(request8); uint8_t request9[] = { 0x05, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xbf, 0xa1, 0x12, 0x73, 0x23, 0x44, 0x86, 0x8b, 0x50, 0x6a, 0x40, 0x00 }; uint32_t request9_len = sizeof(request9); TcpSession ssn; Packet *p[11]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|26 d0 cf 80|\"; distance:0; sid:1;)"; char *sig2 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|43 5b 67 26 65|\"; distance:0; sid:2;)"; char *sig3 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|71 69 75 3e|\"; distance:0; sid:3;)"; char *sig4 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|6a 68 69 3e 72|\"; distance:0; sid:4;)"; char *sig5 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|61 50 71 45 29 5b 56 3d 5a|\"; distance:0; sid:5;)"; char *sig6 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|23 75 40 5d 32 55|\"; distance:0; sid:6;)"; char *sig7 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|ee 70 32 65 c1|\"; distance:0; sid:7;)"; char *sig8 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|79 26 46 f7 bf a1|\"; distance:0; sid:8;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 11; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[1]->flowflags |= FLOW_PKT_TOCLIENT; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); s = s->next; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig3); s = s->next; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig4); s = s->next; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig5); s = s->next; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig6); s = s->next; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig7); s = s->next; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig8); s = s->next; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if ((PacketAlertCheck(p[0], 1))) { printf("sid 1 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 2))) { printf("sid 2 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 3))) { printf("sid 3 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 4))) { printf("sid 4 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 5))) { printf("sid 5 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 6))) { printf("sid 6 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 7))) { printf("sid 7 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 8))) { printf("sid 8 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 2))) { printf("sid 2 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 3))) { printf("sid 3 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 4))) { printf("sid 4 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 5))) { printf("sid 5 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 6))) { printf("sid 6 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 7))) { printf("sid 7 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 8))) { printf("sid 8 matched but shouldn't have for packet 1: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if ((PacketAlertCheck(p[2], 1))) { printf("sid 1 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 2))) { printf("sid 2 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 3))) { printf("sid 3 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 4))) { printf("sid 4 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 5))) { printf("sid 5 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 6))) { printf("sid 6 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 7))) { printf("sid 7 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 8))) { printf("sid 8 matched but shouldn't have for packet 2: "); goto end; } SCLogDebug("sending request 2"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if (!(PacketAlertCheck(p[3], 1))) { printf("sid 1 didn't match but should have for packet 3: "); goto end; } if ((PacketAlertCheck(p[3], 2))) { printf("sid 2 matched but shouldn't have for packet 3: "); goto end; } if ((PacketAlertCheck(p[3], 3))) { printf("sid 3 matched but shouldn't have for packet 3: "); goto end; } if ((PacketAlertCheck(p[3], 4))) { printf("sid 4 matched but shouldn't have for packet 3: "); goto end; } if ((PacketAlertCheck(p[3], 5))) { printf("sid 5 matched but shouldn't have for packet 3: "); goto end; } if ((PacketAlertCheck(p[3], 6))) { printf("sid 6 matched but shouldn't have for packet 3: "); goto end; } if ((PacketAlertCheck(p[3], 7))) { printf("sid 7 matched but shouldn't have for packet 3: "); goto end; } if ((PacketAlertCheck(p[3], 8))) { printf("sid 8 matched but shouldn't have for packet 3: "); goto end; } SCLogDebug("sending request 3"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SCLogDebug("inspecting packet 4"); SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); if ((PacketAlertCheck(p[4], 1))) { printf("sid 1 matched but shouldn't have for packet 4: "); goto end; } if (!(PacketAlertCheck(p[4], 2))) { printf("sid 2 didn't match but should have for packet 4: "); goto end; } if ((PacketAlertCheck(p[4], 3))) { printf("sid 3 matched but shouldn't have for packet 4: "); goto end; } if ((PacketAlertCheck(p[4], 4))) { printf("sid 4 matched but shouldn't have for packet 4: "); goto end; } if ((PacketAlertCheck(p[4], 5))) { printf("sid 5 matched but shouldn't have for packet 4: "); goto end; } if ((PacketAlertCheck(p[4], 6))) { printf("sid 6 matched but shouldn't have for packet 4: "); goto end; } if ((PacketAlertCheck(p[4], 7))) { printf("sid 7 matched but shouldn't have for packet 4: "); goto end; } if ((PacketAlertCheck(p[4], 8))) { printf("sid 8 matched but shouldn't have for packet 4: "); goto end; } SCLogDebug("sending request 4"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); if ((PacketAlertCheck(p[5], 1))) { printf("sid 1 matched but shouldn't have for packet 5: "); goto end; } if ((PacketAlertCheck(p[5], 2))) { printf("sid 2 matched but shouldn't have for packet 5: "); goto end; } if (!(PacketAlertCheck(p[5], 3))) { printf("sid 3 didn't match but should have packet 5: "); goto end; } if ((PacketAlertCheck(p[5], 4))) { printf("sid 4 matched but shouldn't have for packet 5: "); goto end; } if ((PacketAlertCheck(p[5], 5))) { printf("sid 5 matched but shouldn't have for packet 5: "); goto end; } if ((PacketAlertCheck(p[5], 6))) { printf("sid 6 matched but shouldn't have for packet 5: "); goto end; } if ((PacketAlertCheck(p[5], 7))) { printf("sid 7 matched but shouldn't have for packet 5: "); goto end; } if ((PacketAlertCheck(p[5], 8))) { printf("sid 8 matched but shouldn't have for packet 5: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[6]); if ((PacketAlertCheck(p[6], 1))) { printf("sid 1 matched but shouldn't have for packet 6: "); goto end; } if ((PacketAlertCheck(p[6], 2))) { printf("sid 2 matched but shouldn't have for packet 6: "); goto end; } if ((PacketAlertCheck(p[6], 3))) { printf("sid 3 matched but shouldn't have for packet 6: "); goto end; } if (!(PacketAlertCheck(p[6], 4))) { printf("sid 4 didn't match but should have packet 6: "); goto end; } if ((PacketAlertCheck(p[6], 5))) { printf("sid 5 matched but shouldn't have for packet 6: "); goto end; } if ((PacketAlertCheck(p[6], 6))) { printf("sid 6 matched but shouldn't have for packet 6: "); goto end; } if ((PacketAlertCheck(p[6], 7))) { printf("sid 7 matched but shouldn't have for packet 6: "); goto end; } if ((PacketAlertCheck(p[6], 8))) { printf("sid 8 matched but shouldn't have for packet 6: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[7]); if ((PacketAlertCheck(p[7], 1))) { printf("sid 1 matched but shouldn't have for packet 7: "); goto end; } if ((PacketAlertCheck(p[7], 2))) { printf("sid 2 matched but shouldn't have for packet 7: "); goto end; } if ((PacketAlertCheck(p[7], 3))) { printf("sid 3 matched but shouldn't have for packet 7: "); goto end; } if ((PacketAlertCheck(p[7], 4))) { printf("sid 4 matched but shouldn't have for packet 7: "); goto end; } if (!(PacketAlertCheck(p[7], 5))) { printf("sid 5 didn't match but should have paket 7: "); goto end; } if ((PacketAlertCheck(p[7], 6))) { printf("sid 6 matched but shouldn't have for packet 7: "); goto end; } if ((PacketAlertCheck(p[7], 7))) { printf("sid 7 matched but shouldn't have for packet 7: "); goto end; } if ((PacketAlertCheck(p[7], 8))) { printf("sid 8 matched but shouldn't have for packet 7: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request7, request7_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[8]); if ((PacketAlertCheck(p[8], 1))) { printf("sid 1 matched but shouldn't have for packet 8: "); goto end; } if ((PacketAlertCheck(p[8], 2))) { printf("sid 2 matched but shouldn't have for packet 8: "); goto end; } if ((PacketAlertCheck(p[8], 3))) { printf("sid 3 matched but shouldn't have for packet 8: "); goto end; } if ((PacketAlertCheck(p[8], 4))) { printf("sid 4 matched but shouldn't have for packet 8: "); goto end; } if ((PacketAlertCheck(p[8], 5))) { printf("sid 5 matched but shouldn't have for packet 8: "); goto end; } if (!(PacketAlertCheck(p[8], 6))) { printf("sid 6 didn't match but should have paket 8: "); goto end; } if ((PacketAlertCheck(p[8], 7))) { printf("sid 7 matched but shouldn't have for packet 8: "); goto end; } if ((PacketAlertCheck(p[8], 8))) { printf("sid 8 matched but shouldn't have for packet 8: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request8, request8_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[9]); if ((PacketAlertCheck(p[9], 1))) { printf("sid 1 matched but shouldn't have for packet 9: "); goto end; } if ((PacketAlertCheck(p[9], 2))) { printf("sid 2 matched but shouldn't have for packet 9: "); goto end; } if ((PacketAlertCheck(p[9], 3))) { printf("sid 3 matched but shouldn't have for packet 9: "); goto end; } if ((PacketAlertCheck(p[9], 4))) { printf("sid 4 matched but shouldn't have for packet 9: "); goto end; } if ((PacketAlertCheck(p[9], 5))) { printf("sid 5 matched but shouldn't have for packet 9: "); goto end; } if ((PacketAlertCheck(p[9], 6))) { printf("sid 6 matched but shouldn't have for packet 9: "); goto end; } if (!(PacketAlertCheck(p[9], 7))) { printf("sid 7 didn't match but should have for packet 9: "); goto end; } if ((PacketAlertCheck(p[9], 8))) { printf("sid 8 matched but shouldn't have for packet 9: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request9, request9_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[10]); if ((PacketAlertCheck(p[10], 1))) { printf("sid 1 matched but shouldn't have for packet 10: "); goto end; } if ((PacketAlertCheck(p[10], 2))) { printf("sid 2 matched but shouldn't have for packet 10: "); goto end; } if ((PacketAlertCheck(p[10], 3))) { printf("sid 3 matched but shouldn't have for packet 10: "); goto end; } if ((PacketAlertCheck(p[10], 4))) { printf("sid 4 matched but shouldn't have for packet 10: "); goto end; } if ((PacketAlertCheck(p[10], 5))) { printf("sid 5 matched but shouldn't have for packet 10: "); goto end; } if ((PacketAlertCheck(p[10], 6))) { printf("sid 6 matched but shouldn't have for packet 10: "); goto end; } if ((PacketAlertCheck(p[10], 7))) { printf("sid 7 matched but shouldn't have for packet 10: "); goto end; } if (!(PacketAlertCheck(p[10], 8))) { printf("sid 8 didn't match but should have for paket 10: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 11); return result; #else return 1; #endif } /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest02(void) { #if 0 int result = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); TcpSession ssn; Packet *p[4]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "sid:1;)"; char *sig2 = "alert tcp any any -> any any (dce_stub_data; " "dce_stub_data; content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 4; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[1]->flowflags |= FLOW_PKT_TOCLIENT; p[1]->flowflags &=~ FLOW_PKT_TOSERVER; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); s = s->next; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if (PacketAlertCheck(p[0], 1)) { printf("sid 1 didn't match but should have for packet 0: "); goto end; } if (PacketAlertCheck(p[0], 2)) { printf("sid 2 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 2))) { printf("sid 2 matched but shouldn't have for packet 1: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if (!(PacketAlertCheck(p[2], 1))) { printf("sid 1 didn't match but should have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 2))) { printf("sid 2 matched but shouldn't have for packet 2: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if ((PacketAlertCheck(p[3], 1))) { printf("sid 1 matched but shouldn't have for packet 3: "); goto end; } if (!(PacketAlertCheck(p[3], 2))) { printf("sid 2 didn't match but should have for packet 3: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 4); return result; #else return 1; #endif } /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest03(void) { #if 0 int result = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); TcpSession ssn; Packet *p[4]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef4; " "dce_stub_data; sid:1;)"; char *sig2 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 4; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[1]->flowflags |= FLOW_PKT_TOCLIENT; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); s = s->next; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if ((PacketAlertCheck(p[0], 1))) { printf("sid 1 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 2))) { printf("sid 2 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 2))) { printf("sid 2 matched but shouldn't have for packet 1: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if ((PacketAlertCheck(p[2], 1))) { printf("sid 1 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 2))) { printf("sid 2 matched but shouldn't have for packet 2: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if ((PacketAlertCheck(p[3], 1))) { printf("sid 1 matched but shouldn't have for packet 3: "); goto end; } if (!(PacketAlertCheck(p[3], 2))) { printf("sid 2 didn't match but should have for packet 3: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 4); return result; #else return 1; #endif } /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest04(void) { #if 0 int result = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); TcpSession ssn; Packet *p[4]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; content:\"|91 27 27 40|\"; distance:0; sid:1;)"; char *sig2 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 4; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[1]->flowflags |= FLOW_PKT_TOCLIENT; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); s = s->next; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if ((PacketAlertCheck(p[0], 1))) { printf("sid 1 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 2))) { printf("sid 2 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 2))) { printf("sid 2 matched but shouldn't have for packet 1: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if (!(PacketAlertCheck(p[2], 1))) { printf("sid 1 didn't match but should have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 2))) { printf("sid 2 matched but shouldn't have for packet 2: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if ((PacketAlertCheck(p[3], 1))) { printf("sid 1 matched but shouldn't have for packet 3: "); goto end; } if (!(PacketAlertCheck(p[3], 2))) { printf("sid 2 didn't match but should have for packet 3: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 4); return result; #else return 1; #endif } /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest05(void) { #if 0 int result = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); TcpSession ssn; Packet *p[4]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef4; " "dce_stub_data; content:\"|91 27 27 40|\"; distance:0; sid:1;)"; char *sig2 = "alert tcp any any -> any any (dce_stub_data; " "dce_stub_data; content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 4; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[1]->flowflags |= FLOW_PKT_TOCLIENT; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); s = s->next; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if ((PacketAlertCheck(p[0], 1))) { printf("sid 1 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 2))) { printf("sid 2 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 2))) { printf("sid 2 matched but shouldn't have for packet 1: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if ((PacketAlertCheck(p[2], 1))) { printf("sid 1 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 2))) { printf("sid 2 matched but shouldn't have for packet 2: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if ((PacketAlertCheck(p[3], 1))) { printf("sid 2 matched but shouldn't have for packet 3: "); goto end; } if (!(PacketAlertCheck(p[3], 2))) { printf("sid 2 didn't match but should have for packet 3: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 4); return result; #else return 1; #endif } /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest06(void) { #if 0 int result = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); TcpSession ssn; Packet *p[4]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; content:\"|91 27 27 30|\"; distance:0; sid:1;)"; char *sig2 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 4; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[1]->flowflags |= FLOW_PKT_TOCLIENT; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); s = s->next; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if ((PacketAlertCheck(p[0], 1))) { printf("sid 1 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 2))) { printf("sid 2 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 2))) { printf("sid 2 matched but shouldn't have for packet 1: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if ((PacketAlertCheck(p[2], 1))) { printf("sid 1 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 2))) { printf("sid 2 matched but shouldn't have for packet 2: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if ((PacketAlertCheck(p[3], 1))) { printf("sid 1 matched but shouldn't have for packet 3: "); goto end; } if (!(PacketAlertCheck(p[3], 2))) { printf("sid 2 didn't match but should have for packet 3: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 4); return result; #else return 1; #endif } /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest07(void) { #if 0 int result = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); TcpSession ssn; Packet *p[4]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; content:\"|91 27 27 30|\"; distance:0; sid:1;)"; char *sig2 = "alert tcp any any -> any any (dce_stub_data; " "content:\"|2d 5e 63 35 25|\"; distance:0; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 4; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[1]->flowflags |= FLOW_PKT_TOCLIENT; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); s = s->next; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if ((PacketAlertCheck(p[0], 1))) { printf("sid 1 matched but shouldn't have for packet 0: "); goto end; } if ((PacketAlertCheck(p[0], 2))) { printf("sid 2 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } if ((PacketAlertCheck(p[1], 2))) { printf("sid 2 matched but shouldn't have for packet 1: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if ((PacketAlertCheck(p[2], 1))) { printf("sid 1 matched but shouldn't have for packet 2: "); goto end; } if ((PacketAlertCheck(p[2], 2))) { printf("sid 2 matched but shouldn't have for packet 2: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if ((PacketAlertCheck(p[3], 1))) { printf("sid 1 matched but shouldn't have for packet 3: "); goto end; } if ((PacketAlertCheck(p[3], 2))) { printf("sid 2 matched but shouldn't have for packet 3: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 4); return result; #else return 1; #endif } /** * \test Positive test, to test the working of distance and within. */ int DcePayloadTest08(void) { #if 0 int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p[1]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5d 5b 35|\"; distance:0; content:\"|9e a3|\"; " "distance:0; within:2; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 1; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if (!(PacketAlertCheck(p[0], 1))) { printf("sid 1 didn't match but should have for packet 0: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 1); return result; #else return 1; #endif } /** * \test Positive test, to test the working of distance and within. */ int DcePayloadTest09(void) { #if 0 int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x5d, 0x5b, 0x35, 0x46, 0x9e, 0xa3, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p[1]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5d 5b 35|\"; distance:0; content:\"|9e a3|\"; " "distance:0; within:2; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 1; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if (!(PacketAlertCheck(p[0], 1))) { printf("sid 1 didn't match but should have for packet 0: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 1); return result; #else return 1; #endif } /** * \test Positive test, to test the working of distance and within. */ int DcePayloadTest10(void) { #if 0 int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x5d, 0x5b, 0x35, 0x46, 0x9e, 0xa3, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p[1]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|ad 0d|\"; distance:0; content:\"|ad 0d 00|\"; " "distance:-10; within:3; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 1; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if (!(PacketAlertCheck(p[0], 1))) { printf("sid 1 didn't match but should have for packet 0: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 1); return result; #else return 1; #endif } /** * \test Postive test to check the working of disance and within across frags. */ int DcePayloadTest11(void) { #if 0 int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); TcpSession ssn; Packet *p[2]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|af, 26, d0|\"; distance:0; content:\"|80 98 6d|\"; " "distance:1; within:3; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 2; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if ((PacketAlertCheck(p[0], 1))) { printf("sid 1 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if (!(PacketAlertCheck(p[1], 1))) { printf("sid 1 didn't match but should have for pacekt 1: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 2); return result; #else return 1; #endif } /** * \test Negative test the working of contents on stub data with invalid * distance. */ int DcePayloadTest12(void) { #if 0 /* payload ticks off clamav */ int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); TcpSession ssn; Packet *p[2]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|af, 26, d0|\"; distance:0; content:\"|80 98 6d|\"; " "distance:2; within:3; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 2; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if ((PacketAlertCheck(p[0], 1))) { printf("sid 1 matched but shouldn't have for packet 0: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 2); return result; #else return 1; #endif } /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest13(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; uint32_t request1_len = sizeof(request1); uint8_t response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint32_t response1_len = sizeof(response1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x5c, 0x00, 0x5c, 0x00, 0xa8, 0xb9, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x54, 0x00, 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; uint32_t request2_len = sizeof(request2); uint8_t response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint32_t response2_len = sizeof(response2); uint8_t request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x0c, 0x00, 0x0c, 0x00, 0x98, 0xda, 0x14, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x73, 0x00, 0x61, 0x00, 0x33, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x41, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; uint32_t request3_len = sizeof(request3); uint8_t response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t response3_len = sizeof(response3); TcpSession ssn; Packet *p[8]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); /* let the 7 and the 8th packet be dummy packets the client sends to the server */ for (i = 0; i < 8; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[1]->flowflags |= FLOW_PKT_TOCLIENT; p[1]->flowflags &=~ FLOW_PKT_TOSERVER; p[3]->flowflags |= FLOW_PKT_TOCLIENT; p[3]->flowflags &=~ FLOW_PKT_TOSERVER; p[5]->flowflags |= FLOW_PKT_TOCLIENT; p[5]->flowflags &=~ FLOW_PKT_TOSERVER; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if (!(PacketAlertCheck(p[0], 1))) { printf("sid 1 didn't match but should have for packet 0: "); goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[6]); if ((PacketAlertCheck(p[6], 1))) { printf("sid 1 matched but shouldn't have for packet 6: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response1, response1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ /* we should have a match for the sig once again for the same flow, since * the detection engine state for the flow has been reset because of a * fresh transaction */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if (!(PacketAlertCheck(p[2], 1))) { printf("sid 1 didn't match but should have for packet 2: "); goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[7]); if ((PacketAlertCheck(p[7], 1))) { printf("sid 1 matched but shouldn't have for packet 7: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response2, response2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if ((PacketAlertCheck(p[3], 1))) { printf("sid 1 matched but shouldn't have for packet 3: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ /* we should have a match for the sig once again for the same flow, since * the detection engine state for the flow has been reset because of a * fresh transaction */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); if (!(PacketAlertCheck(p[4], 1))) { printf("sid 1 didn't match but should have for packet 4: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response3, response3_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); if ((PacketAlertCheck(p[5], 1))) { printf("sid 1 matched but shouldn't have for packet 5: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 8); return result; } /** * \test Test the working of detection engien with respect to dce keywords. */ int DcePayloadTest14(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; uint32_t request1_len = sizeof(request1); uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x81, 0xbb, 0x7a, 0x36, 0x44, 0x98, 0xf1, 0x35, 0xad, 0x32, 0x98, 0xf0, 0x38, 0x00, 0x10, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x74, 0x73, 0x00, 0x00, 0x0d, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6e, 0x74, 0x73, 0x76, 0x63, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x64, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x5c, 0x31, 0x37, 0x31, 0x2e, 0x37, 0x31, 0x2e, 0x38, 0x34, 0x2e, 0x36, 0x37, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0f, 0x00 }; uint32_t request2_len = sizeof(request2); uint8_t response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0xc4, 0x88, 0x14, 0xef, 0x31, 0xbb, 0x4d, 0xa8, 0x13, 0xb7, 0x1b, 0x47, 0x49, 0xb5, 0xd7, 0x00, 0x00, 0x00, 0x00 }; uint32_t response2_len = sizeof(response2); TcpSession ssn; Packet *p[6]; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; int i = 0; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); for (i = 0; i < 6; i++) { p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p[i]->flow = &f; p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p[i]->flowflags |= FLOW_PKT_TOSERVER; p[i]->flowflags |= FLOW_PKT_ESTABLISHED; } p[3]->flowflags |= FLOW_PKT_TOCLIENT; p[3]->flowflags &=~ FLOW_PKT_TOSERVER; p[5]->flowflags |= FLOW_PKT_TOCLIENT; p[5]->flowflags &=~ FLOW_PKT_TOSERVER; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); if (!(PacketAlertCheck(p[0], 1))) { printf("sid 1 didn't match but should have for packet 0: "); goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); if ((PacketAlertCheck(p[1], 1))) { printf("sid 1 matched but shouldn't have for packet 1: "); goto end; } /* bind */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); if ((PacketAlertCheck(p[2], 1))) { printf("sid 1 matched but shouldn't have for packet 2: "); goto end; } /* bind_ack. A new transaction initiation */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); if ((PacketAlertCheck(p[3], 1))) { printf("sid 1 matched but shouldn't have for packet 3: "); goto end; } /* we should have a match for the sig once again for the same flow, since * the detection engine state for the flow has been reset because of a * fresh transaction */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); if (!(PacketAlertCheck(p[4], 1))) { printf("sid 1 didn't match but should have for packet 4: "); goto end; } /* response */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response2, response2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); if ((PacketAlertCheck(p[5], 1))) { printf("sid 1 matched but shouldn't have for packet 5: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(p, 6); return result; } /** * \test Test the working of byte_test endianness. */ int DcePayloadTest15(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_test:2,=,14080,0,relative,dce; sid:1;)"; char *sig2 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_test:2,=,46,5,relative,dce; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); if (s->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of byte_test endianness. */ int DcePayloadTest16(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_test:2,=,55,0,relative; sid:1;)"; char *sig2 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_test:2,=,11776,5,relative; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); if (s->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of byte_test endianness. */ int DcePayloadTest17(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_test:2,=,55,0,relative,big; sid:1;)"; char *sig2 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_test:2,=,46,5,relative,little; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); if (s->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of byte_jump endianness. */ int DcePayloadTest18(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x03, 0x00, 0x03, 0x00, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_jump:2,0,relative,dce; byte_test:2,=,46,0,relative,dce; sid:1;)"; char *sig2 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_jump:2,2,relative,dce; byte_test:2,=,14080,0,relative; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); if (s->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of byte_jump endianness. */ int DcePayloadTest19(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x03, 0x00, 0x03, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_jump:2,0,relative; byte_test:2,=,46,0,relative,dce; sid:1;)"; char *sig2 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_jump:2,2,relative; byte_test:2,=,14080,0,relative; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); if (s->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of byte_jump endianness. */ int DcePayloadTest20(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x03, 0x03, 0x00, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_jump:2,0,relative,big; byte_test:2,=,46,0,relative,dce; sid:1;)"; char *sig2 = "alert tcp any any -> any any " "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " "byte_jump:2,2,little,relative; byte_test:2,=,14080,0,relative; sid:2;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; s->next = SigInit(de_ctx, sig2); if (s->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of consecutive relative matches. */ int DcePayloadTest21(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x69, 0x73, /* "now this" */ 0x20, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x62, /* " is is b" */ 0x69, 0x67, 0x20, 0x62, 0x69, 0x67, 0x20, 0x73, /* "ig big s" */ 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, /* "tring no" */ 0x77 }; /* "w" */ uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(msg:\"testing dce consecutive relative matches\"; dce_stub_data; " "content:\"this\"; distance:0; content:\"is\"; within:6; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of consecutive relative matches. */ int DcePayloadTest22(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x69, 0x73, /* "now this" */ 0x20, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x69, /* " is is i" */ 0x73, 0x20, 0x62, 0x69, 0x67, 0x20, 0x62, 0x69, /* "s big bi" */ 0x67, 0x20, 0x62, 0x69, 0x67, 0x20, 0x73, 0x74, /* "g big st" */ 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x77 }; /* "ring now" */ uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(msg:\"testing dce consecutive relative matches\"; dce_stub_data; " "content:\"this\"; distance:0; content:\"is\"; within:9; content:\"big\"; within:12; " "content:\"string\"; within:8; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of consecutive relative matches. */ int DcePayloadTest23(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x68, 0x69, /* "this thi" */ 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x69, 0x73, /* "s now is" */ 0x20, 0x69, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, /* " is " */ 0x62, 0x69, 0x67, 0x20, 0x73, 0x74, 0x72, 0x69, /* "big stri" */ 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x77 }; /* "ng now" */ uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(msg:\"testing dce consecutive relative matches\"; dce_stub_data; " "content:\"now\"; distance:0; content:\"this\"; distance:-20; " "content:\"is\"; within:12; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; content:\"two\"; " "content:\"three\"; within:10; " "content:\"four\"; distance:4; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_stub_data; " "content:\"one\"; " "content:\"two\"; " "content:\"three\"; within:5; " "content:\"four\"; distance:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("one failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("four failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_stub_data; " "content:\"one\"; distance:10; within:5; " "content:\"two\"; within:5;" "content:\"three\"; within:5; " "content:\"four\"; distance:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] != NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("one failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("four failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_stub_data; " "content:\"one\"; distance:10; within:5; " "content:\"two\"; within:5;" "content:\"three\";" "content:\"four\";" "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("one failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("four failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectPcreData *pd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_stub_data; " "pcre:/boom/; " "content:\"one\"; distance:10; within:5; " "content:\"two\"; within:5;" "content:\"three\";" "content:\"four\";" "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; } pd = (DetectPcreData *)sm->ctx; if (pd->flags & DETECT_PCRE_RAWBYTES || pd->flags & DETECT_PCRE_RELATIVE) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("one failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("four failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytejumpData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_stub_data; " "byte_jump:2,5; " "content:\"one\"; distance:10; within:5; " "content:\"two\"; within:5;" "content:\"three\";" "content:\"four\";" "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bd = (DetectBytejumpData *)sm->ctx; if (bd->flags & DETECT_BYTEJUMP_BEGIN || bd->flags & DETECT_BYTEJUMP_LITTLE || bd->flags & DETECT_BYTEJUMP_BIG || bd->flags & DETECT_BYTEJUMP_STRING || bd->flags & DETECT_BYTEJUMP_RELATIVE || bd->flags & DETECT_BYTEJUMP_ALIGN || bd->flags & DETECT_BYTEJUMP_DCE ) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("one failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("four failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytejumpData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_stub_data; " "byte_jump:2,5,relative; " "content:\"one\"; distance:10; within:5; " "content:\"two\"; within:5;" "content:\"three\";" "content:\"four\";" "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bd = (DetectBytejumpData *)sm->ctx; if (bd->flags & DETECT_BYTEJUMP_BEGIN || bd->flags & DETECT_BYTEJUMP_LITTLE || bd->flags & DETECT_BYTEJUMP_BIG || bd->flags & DETECT_BYTEJUMP_STRING || !(bd->flags & DETECT_BYTEJUMP_RELATIVE) || bd->flags & DETECT_BYTEJUMP_ALIGN || bd->flags & DETECT_BYTEJUMP_DCE ) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("one failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("four failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytejumpData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_stub_data; " "byte_jump:2,5,relative; " "content:\"one\"; distance:10; within:5; " "content:\"two\"; within:5;" "content:\"three\";" "content:\"four\"; within:4; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bd = (DetectBytejumpData *)sm->ctx; if (bd->flags & DETECT_BYTEJUMP_BEGIN || bd->flags & DETECT_BYTEJUMP_LITTLE || bd->flags & DETECT_BYTEJUMP_BIG || bd->flags & DETECT_BYTEJUMP_STRING || !(bd->flags & DETECT_BYTEJUMP_RELATIVE) || bd->flags & DETECT_BYTEJUMP_ALIGN || bd->flags & DETECT_BYTEJUMP_DCE ) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("one failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("four failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectPcreData *pd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_stub_data; " "pcre:/boom/R; " "content:\"one\"; distance:10; within:5; " "content:\"two\"; within:5;" "content:\"three\";" "content:\"four\"; distance:5;" "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; } pd = (DetectPcreData *)sm->ctx; if ( pd->flags & DETECT_PCRE_RAWBYTES || !(pd->flags & DETECT_PCRE_RELATIVE)) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("one failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("four failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "four", 4) == 0); if (result == 0) goto end; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectPcreData *pd = NULL; DetectBytejumpData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "pcre:/boom/R; " "byte_jump:1,2,relative,align,dce; " "content:\"one\"; within:4; distance:8; " "content:\"two\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; } pd = (DetectPcreData *)sm->ctx; if ( pd->flags & DETECT_PCRE_RAWBYTES || !(pd->flags & DETECT_PCRE_RELATIVE)) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bd = (DetectBytejumpData *)sm->ctx; if (bd->flags & DETECT_BYTEJUMP_BEGIN || bd->flags & DETECT_BYTEJUMP_LITTLE || bd->flags & DETECT_BYTEJUMP_BIG || bd->flags & DETECT_BYTEJUMP_STRING || !(bd->flags & DETECT_BYTEJUMP_RELATIVE) || !(bd->flags & DETECT_BYTEJUMP_ALIGN) || !(bd->flags & DETECT_BYTEJUMP_DCE) ) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytetestData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "byte_test:1,=,0,0,relative,dce; " "content:\"one\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } bd = (DetectBytetestData *)sm->ctx; if (bd->flags & DETECT_BYTETEST_LITTLE || bd->flags & DETECT_BYTETEST_BIG || bd->flags & DETECT_BYTETEST_STRING || !(bd->flags & DETECT_BYTETEST_RELATIVE) || !(bd->flags & DETECT_BYTETEST_DCE) ) { result = 0; printf("one failed\n"); goto end; } result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectIsdataatData *isd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "isdataat:10,relative; " "content:\"one\"; within:4; distance:8; " "content:\"two\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; } isd = (DetectIsdataatData *)sm->ctx; if ( isd->flags & ISDATAAT_RAWBYTES || !(isd->flags & ISDATAAT_RELATIVE)) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest37(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytejumpData *bjd = NULL; DetectBytetestData *btd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "byte_jump:1,2,relative,align,dce; " "byte_test:1,=,2,0,relative,dce; " "content:\"one\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags & DETECT_BYTEJUMP_BEGIN || bjd->flags & DETECT_BYTEJUMP_LITTLE || bjd->flags & DETECT_BYTEJUMP_BIG || bjd->flags & DETECT_BYTEJUMP_STRING || !(bjd->flags & DETECT_BYTEJUMP_RELATIVE) || !(bjd->flags & DETECT_BYTEJUMP_ALIGN) || !(bjd->flags & DETECT_BYTEJUMP_DCE) ) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } btd = (DetectBytetestData *)sm->ctx; if (btd->flags & DETECT_BYTETEST_LITTLE || btd->flags & DETECT_BYTETEST_BIG || btd->flags & DETECT_BYTETEST_STRING || !(btd->flags & DETECT_BYTETEST_RELATIVE) || !(btd->flags & DETECT_BYTETEST_DCE) ) { result = 0; printf("one failed\n"); goto end; } result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest38(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectPcreData *pd = NULL; DetectBytejumpData *bjd = NULL; DetectBytetestData *btd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "pcre:/boom/R; " "byte_jump:1,2,relative,align,dce; " "byte_test:1,=,2,0,relative,dce; " "content:\"one\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; } pd = (DetectPcreData *)sm->ctx; if ( pd->flags & DETECT_PCRE_RAWBYTES || !(pd->flags & DETECT_PCRE_RELATIVE) ) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags & DETECT_BYTEJUMP_BEGIN || bjd->flags & DETECT_BYTEJUMP_LITTLE || bjd->flags & DETECT_BYTEJUMP_BIG || bjd->flags & DETECT_BYTEJUMP_STRING || !(bjd->flags & DETECT_BYTEJUMP_RELATIVE) || !(bjd->flags & DETECT_BYTEJUMP_ALIGN) || !(bjd->flags & DETECT_BYTEJUMP_DCE) ) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } btd = (DetectBytetestData *)sm->ctx; if (btd->flags & DETECT_BYTETEST_LITTLE || btd->flags & DETECT_BYTETEST_BIG || btd->flags & DETECT_BYTETEST_STRING || !(btd->flags & DETECT_BYTETEST_RELATIVE) || !(btd->flags & DETECT_BYTETEST_DCE) ) { result = 0; printf("one failed\n"); goto end; } result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest39(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "content:\"two\"; within:4; distance:8; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest40(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytetestData *btd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "content:\"one\"; within:10; " "content:\"two\"; distance:20; within:30; " "byte_test:1,=,2,0,relative,dce; " "content:\"three\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } btd = (DetectBytetestData *)sm->ctx; if (btd->flags & DETECT_BYTETEST_LITTLE || btd->flags & DETECT_BYTETEST_BIG || btd->flags & DETECT_BYTETEST_STRING || !(btd->flags & DETECT_BYTETEST_RELATIVE) || !(btd->flags & DETECT_BYTETEST_DCE) ) { result = 0; printf("one failed\n"); goto end; } result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest41(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytetestData *btd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "content:\"one\"; within:10; " "content:\"two\"; " "byte_test:1,=,2,0,relative,dce; " "content:\"three\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } btd = (DetectBytetestData *)sm->ctx; if (btd->flags & DETECT_BYTETEST_LITTLE || btd->flags & DETECT_BYTETEST_BIG || btd->flags & DETECT_BYTETEST_STRING || !(btd->flags & DETECT_BYTETEST_RELATIVE) || !(btd->flags & DETECT_BYTETEST_DCE) ) { result = 0; printf("one failed\n"); goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "three", 5) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test the working of consecutive relative matches with a negated content. */ int DcePayloadTest42(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x77, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, /* "we need " */ 0x74, 0x6f, 0x20, 0x66, 0x69, 0x78, 0x20, 0x74, /* "to fix t" */ 0x68, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, /* "his and " */ 0x79, 0x65, 0x73, 0x20, 0x66, 0x69, 0x78, 0x20, /* "yes fix " */ 0x74, 0x68, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x77 /* "this now" */ }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(msg:\"testing dce consecutive relative matches\"; dce_stub_data; " "content:\"fix\"; distance:0; content:\"this\"; within:6; " "content:!\"and\"; distance:0; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 matched but shouldn't have for packet: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test the working of consecutive relative pcres. */ int DcePayloadTest43(void) { int result = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x20, 0x64, 0x75, 0x70, 0x65, 0x72, 0x20, 0x6e, 0x6f, 0x76, 0x61, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x75, 0x70, 0x65, 0x72, 0x20, 0x6e, 0x6f, 0x76, 0x61, 0x20, 0x6e, 0x6f, 0x77 }; uint32_t request1_len = sizeof(request1); TcpSession ssn; Packet *p = NULL; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; int r; char *sig1 = "alert tcp any any -> any any " "(msg:\"testing dce consecutive relative matches\"; dce_stub_data; " "pcre:/super/R; content:\"nova\"; within:7; sid:1;)"; Signature *s; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); s = de_ctx->sig_list; if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if ( !(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest44(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectIsdataatData *isd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "dce_opnum:10; dce_stub_data; " "isdataat:10,relative; " "content:\"one\"; within:4; distance:8; " "content:\"two\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; } isd = (DetectIsdataatData *)sm->ctx; if ( isd->flags & ISDATAAT_RAWBYTES || !(isd->flags & ISDATAAT_RELATIVE)) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_RELATIVE_NEXT || data->flags & DETECT_CONTENT_NEGATED ) { result = 0; printf("two failed\n"); goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_RELATIVE_NEXT || data->flags & DETECT_CONTENT_NEGATED ) { printf("three failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED ) { printf("two failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest45(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytejumpData *bjd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "content:\"one\"; " "dce_opnum:10; dce_stub_data; " "byte_jump:1,2,relative,align,dce; " "content:\"two\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags & DETECT_BYTEJUMP_BEGIN || bjd->flags & DETECT_BYTEJUMP_LITTLE || bjd->flags & DETECT_BYTEJUMP_BIG || bjd->flags & DETECT_BYTEJUMP_STRING || !(bjd->flags & DETECT_BYTEJUMP_RELATIVE) || !(bjd->flags & DETECT_BYTEJUMP_ALIGN) || !(bjd->flags & DETECT_BYTEJUMP_DCE) ) { result = 0; printf("one failed\n"); goto end; } result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_RELATIVE_NEXT || data->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_RELATIVE_NEXT || data->flags & DETECT_CONTENT_NEGATED ) { printf("two failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DcePayloadParseTest46(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectBytetestData *btd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:12345678-1234-1234-1234-123456789012; " "content:\"one\"; " "dce_opnum:10; dce_stub_data; " "byte_test:1,=,2,0,relative,dce; " "content:\"two\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } btd = (DetectBytetestData *)sm->ctx; if (btd->flags & DETECT_BYTETEST_LITTLE || btd->flags & DETECT_BYTETEST_BIG || btd->flags & DETECT_BYTETEST_STRING || !(btd->flags & DETECT_BYTETEST_RELATIVE) || !(btd->flags & DETECT_BYTETEST_DCE) ) { result = 0; printf("one failed\n"); goto end; } result &= (sm->next == NULL); sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_RELATIVE_NEXT || data->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "one", 3) == 0); if (result == 0) goto end; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_RELATIVE_NEXT || data->flags & DETECT_CONTENT_NEGATED ) { printf("two failed\n"); result = 0; goto end; } result &= (strncmp((char *)data->content, "two", 3) == 0); if (result == 0) goto end; result &= (sm->next == NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ void DcePayloadRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DcePayloadTest01", DcePayloadTest01, 1); UtRegisterTest("DcePayloadTest02", DcePayloadTest02, 1); UtRegisterTest("DcePayloadTest03", DcePayloadTest03, 1); UtRegisterTest("DcePayloadTest04", DcePayloadTest04, 1); UtRegisterTest("DcePayloadTest05", DcePayloadTest05, 1); UtRegisterTest("DcePayloadTest06", DcePayloadTest06, 1); UtRegisterTest("DcePayloadTest07", DcePayloadTest07, 1); UtRegisterTest("DcePayloadTest08", DcePayloadTest08, 1); UtRegisterTest("DcePayloadTest09", DcePayloadTest09, 1); UtRegisterTest("DcePayloadTest10", DcePayloadTest10, 1); UtRegisterTest("DcePayloadTest11", DcePayloadTest11, 1); UtRegisterTest("DcePayloadTest12", DcePayloadTest12, 1); UtRegisterTest("DcePayloadTest13", DcePayloadTest13, 1); UtRegisterTest("DcePayloadTest14", DcePayloadTest14, 1); UtRegisterTest("DcePayloadTest15", DcePayloadTest15, 1); UtRegisterTest("DcePayloadTest16", DcePayloadTest16, 1); UtRegisterTest("DcePayloadTest17", DcePayloadTest17, 1); UtRegisterTest("DcePayloadTest18", DcePayloadTest18, 1); UtRegisterTest("DcePayloadTest19", DcePayloadTest19, 1); UtRegisterTest("DcePayloadTest20", DcePayloadTest20, 1); UtRegisterTest("DcePayloadTest21", DcePayloadTest21, 1); UtRegisterTest("DcePayloadTest22", DcePayloadTest22, 1); UtRegisterTest("DcePayloadTest23", DcePayloadTest23, 1); UtRegisterTest("DcePayloadParseTest25", DcePayloadParseTest25, 1); UtRegisterTest("DcePayloadParseTest26", DcePayloadParseTest26, 1); UtRegisterTest("DcePayloadParseTest27", DcePayloadParseTest27, 1); UtRegisterTest("DcePayloadParseTest28", DcePayloadParseTest28, 1); UtRegisterTest("DcePayloadParseTest29", DcePayloadParseTest29, 1); UtRegisterTest("DcePayloadParseTest30", DcePayloadParseTest30, 1); UtRegisterTest("DcePayloadParseTest31", DcePayloadParseTest31, 1); UtRegisterTest("DcePayloadParseTest32", DcePayloadParseTest32, 1); UtRegisterTest("DcePayloadParseTest33", DcePayloadParseTest33, 1); UtRegisterTest("DcePayloadParseTest34", DcePayloadParseTest34, 1); UtRegisterTest("DcePayloadParseTest35", DcePayloadParseTest35, 1); UtRegisterTest("DcePayloadParseTest36", DcePayloadParseTest36, 1); UtRegisterTest("DcePayloadParseTest37", DcePayloadParseTest37, 1); UtRegisterTest("DcePayloadParseTest38", DcePayloadParseTest38, 1); UtRegisterTest("DcePayloadParseTest39", DcePayloadParseTest39, 1); UtRegisterTest("DcePayloadParseTest40", DcePayloadParseTest40, 1); UtRegisterTest("DcePayloadParseTest41", DcePayloadParseTest41, 1); UtRegisterTest("DcePayloadTest42", DcePayloadTest42, 1); UtRegisterTest("DcePayloadTest43", DcePayloadTest43, 1); UtRegisterTest("DcePayloadParseTest44", DcePayloadParseTest44, 1); UtRegisterTest("DcePayloadParseTest45", DcePayloadParseTest45, 1); UtRegisterTest("DcePayloadParseTest46", DcePayloadParseTest46, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/runmode-erf-dag.h0000644000000000000000000000211612253546156014152 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien */ #ifndef __RUNMODE_ERF_DAG_H__ #define __RUNMODE_ERF_DAG_H__ int RunModeIdsErfDagAutoFp(DetectEngineCtx *); int RunModeIdsErfDagSingle(DetectEngineCtx *); int RunModeIdsErfDagWorkers(DetectEngineCtx *); void RunModeErfDagRegister(void); const char *RunModeErfDagGetDefaultMode(void); #endif /* __RUNMODE_ERF_DAG_H__ */ suricata-1.4.7/src/alert-unified2-alert.c0000644000000000000000000014002112253546156015106 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * \author Eric Leblond * * Logs alerts in a format compatible to Snort's unified2 format, so it should * be readable by Barnyard2. */ #include "suricata-common.h" #include "runmodes.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "conf.h" #include "pkt-var.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "util-unittest.h" #include "alert-unified2-alert.h" #include "decode-ipv4.h" #include "util-error.h" #include "util-debug.h" #include "util-time.h" #include "util-byte.h" #include "util-misc.h" #include "output.h" #include "alert-unified2-alert.h" #include "util-privs.h" #include "stream.h" #include "stream-tcp-inline.h" #include "util-optimize.h" #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif #define DEFAULT_LOG_FILENAME "unified2.alert" /**< Default log file limit in MB. */ #define DEFAULT_LIMIT 32 * 1024 * 1024 /**< Minimum log file limit in MB. */ #define MIN_LIMIT 1 * 1024 * 1024 /* Default Sensor ID value */ static uint32_t sensor_id = 0; /** * Unified2 file header struct * * Used for storing file header options. */ typedef struct Unified2AlertFileHeader_ { uint32_t type; /**< unified2 type header */ uint32_t length; /**< unified2 struct size length */ } Unified2AlertFileHeader; /** * Unified2 Ipv4 struct * * Used for storing ipv4 type values. */ typedef struct AlertIPv4Unified2_ { uint32_t sensor_id; /**< sendor id */ uint32_t event_id; /**< event id */ uint32_t event_second; /**< event second */ uint32_t event_microsecond; /**< event microsecond */ uint32_t signature_id; /**< signature id */ uint32_t generator_id; /**< generator id */ uint32_t signature_revision; /**< signature revision */ uint32_t classification_id; /**< classification id */ uint32_t priority_id; /**< priority id */ uint32_t src_ip; /**< source ip */ uint32_t dst_ip; /**< destination ip */ uint16_t sp; /**< source port */ uint16_t dp; /**< destination port */ uint8_t protocol; /**< protocol */ uint8_t packet_action; /**< packet action */ } AlertIPv4Unified2; /** * Unified2 Ipv6 type struct * * Used for storing ipv6 type values. */ typedef struct AlertIPv6Unified2_ { uint32_t sensor_id; /**< sendor id */ uint32_t event_id; /**< event id */ uint32_t event_second; /**< event second */ uint32_t event_microsecond; /**< event microsecond */ uint32_t signature_id; /**< signature id */ uint32_t generator_id; /**< generator id */ uint32_t signature_revision; /**< signature revision */ uint32_t classification_id; /**< classification id */ uint32_t priority_id; /**< priority id */ struct in6_addr src_ip; /**< source ip */ struct in6_addr dst_ip; /**< destination ip */ uint16_t sp; /**< source port */ uint16_t dp; /**< destination port */ uint8_t protocol; /**< protocol */ uint8_t packet_action; /**< packet action */ } AlertIPv6Unified2; /** * Unified2 packet type struct * * Used for storing packet type values. */ typedef struct AlertUnified2Packet_ { uint32_t sensor_id; /**< sensor id */ uint32_t event_id; /**< event id */ uint32_t event_second; /**< event second */ uint32_t packet_second; /**< packet second */ uint32_t packet_microsecond; /**< packet microsecond */ uint32_t linktype; /**< link type */ uint32_t packet_length; /**< packet length */ uint8_t packet_data[4]; /**< packet data */ } Unified2Packet; /** * Unified2 thread vars * * Used for storing file options. */ typedef struct Unified2AlertThread_ { LogFileCtx *file_ctx; /**< LogFileCtx pointer */ uint8_t *data; /**< Per function and thread data */ /** Pointer to the Unified2AlertFileHeader contained in * the pointer data. */ Unified2AlertFileHeader *hdr; /** Pointer to the Unified2Packet contained in * the pointer data. */ Unified2Packet *phdr; /** Pointer to the IPv4 or IPv6 header contained in * the pointer data. */ void *iphdr; int datalen; /**< Length of per function and thread data */ int offset; /**< Offset used to now where to fill data */ int length; /**< Length of data for current alert */ uint32_t event_id; } Unified2AlertThread; #define UNIFIED2_PACKET_SIZE (sizeof(Unified2Packet) - 4) SC_ATOMIC_DECLARE(unsigned int, unified2_event_id); /**< Atomic counter, to link relative event */ /** prototypes */ TmEcode Unified2Alert (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode Unified2AlertThreadInit(ThreadVars *, void *, void **); TmEcode Unified2AlertThreadDeinit(ThreadVars *, void *); int Unified2IPv4TypeAlert(ThreadVars *, Packet *, void *, PacketQueue *); int Unified2IPv6TypeAlert(ThreadVars *, Packet *, void *, PacketQueue *); int Unified2PacketTypeAlert(Unified2AlertThread *, Packet *, uint32_t, int); void Unified2RegisterTests(); int Unified2AlertOpenFileCtx(LogFileCtx *, const char *); static void Unified2AlertDeInitCtx(OutputCtx *); #define MODULE_NAME "Unified2Alert" void TmModuleUnified2AlertRegister (void) { tmm_modules[TMM_ALERTUNIFIED2ALERT].name = MODULE_NAME; tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadInit = Unified2AlertThreadInit; tmm_modules[TMM_ALERTUNIFIED2ALERT].Func = Unified2Alert; tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadDeinit = Unified2AlertThreadDeinit; tmm_modules[TMM_ALERTUNIFIED2ALERT].RegisterTests = Unified2RegisterTests; tmm_modules[TMM_ALERTUNIFIED2ALERT].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "unified2-alert", Unified2AlertInitCtx); } /** * \brief Function to close unified2 file * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param aun Unified2 thread variable. */ int Unified2AlertCloseFile(ThreadVars *t, Unified2AlertThread *aun) { if (aun->file_ctx->fp != NULL) { fclose(aun->file_ctx->fp); } aun->file_ctx->size_current = 0; return 0; } /** * \brief Function to rotate unified2 file * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param aun Unified2 thread variable. * \retval 0 on succces * \retval -1 on failure */ int Unified2AlertRotateFile(ThreadVars *t, Unified2AlertThread *aun) { if (Unified2AlertCloseFile(t,aun) < 0) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Error: Unified2AlertCloseFile failed"); return -1; } if (Unified2AlertOpenFileCtx(aun->file_ctx,aun->file_ctx->prefix) < 0) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Error: Unified2AlertOpenFileCtx, open new log file failed"); return -1; } return 0; } /** * \brief Wrapper for fwrite * * This function is basically a wrapper for fwrite which take * in charge a size counter. * * \return 1 in case of success */ static int Unified2Write(Unified2AlertThread *aun) { int ret; ret = fwrite(aun->data, aun->length, 1, aun->file_ctx->fp); if (ret != 1) { SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno)); return -1; } aun->file_ctx->size_current += aun->length; return 1; } /** * \brief Unified2 main entry function * * \retval TM_ECODE_OK all is good * \retval TM_ECODE_FAILED serious error */ TmEcode Unified2Alert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { int ret = 0; if (PKT_IS_IPV4(p)) { ret = Unified2IPv4TypeAlert (t, p, data, pq); } else if(PKT_IS_IPV6(p)) { ret = Unified2IPv6TypeAlert (t, p, data, pq); } else { /* we're only supporting IPv4 and IPv6 */ return TM_ECODE_OK; } if (ret != 0) { return TM_ECODE_FAILED; } return TM_ECODE_OK; } typedef struct _FakeIPv4Hdr { IPV4Hdr ip4h; TCPHdr tcph; } FakeIPv4Hdr; static int Unified2ForgeFakeIPv4Header(FakeIPv4Hdr *fakehdr, Packet *p, int pkt_len, char invert) { fakehdr->ip4h.ip_verhl = p->ip4h->ip_verhl; fakehdr->ip4h.ip_proto = p->ip4h->ip_proto; if (! invert) { fakehdr->ip4h.s_ip_src.s_addr = p->ip4h->s_ip_src.s_addr; fakehdr->ip4h.s_ip_dst.s_addr = p->ip4h->s_ip_dst.s_addr; } else { fakehdr->ip4h.s_ip_dst.s_addr = p->ip4h->s_ip_src.s_addr; fakehdr->ip4h.s_ip_src.s_addr = p->ip4h->s_ip_dst.s_addr; } fakehdr->ip4h.ip_len = htons((uint16_t)pkt_len); if (! invert) { fakehdr->tcph.th_sport = p->tcph->th_sport; fakehdr->tcph.th_dport = p->tcph->th_dport; } else { fakehdr->tcph.th_dport = p->tcph->th_sport; fakehdr->tcph.th_sport = p->tcph->th_dport; } fakehdr->tcph.th_offx2 = 0x50; /* just the TCP header, no options */ return 1; } typedef struct _FakeIPv6Hdr { IPV6Hdr ip6h; TCPHdr tcph; } FakeIPv6Hdr; /** * \param payload_len length of the payload */ static int Unified2ForgeFakeIPv6Header(FakeIPv6Hdr *fakehdr, Packet *p, int payload_len, char invert) { fakehdr->ip6h.s_ip6_vfc = p->ip6h->s_ip6_vfc; fakehdr->ip6h.s_ip6_nxt = IPPROTO_TCP; fakehdr->ip6h.s_ip6_plen = htons(sizeof(TCPHdr) + payload_len); if (!invert) { memcpy(fakehdr->ip6h.s_ip6_addrs, p->ip6h->s_ip6_addrs, 32); } else { memcpy(fakehdr->ip6h.s_ip6_src, p->ip6h->s_ip6_dst, 16); memcpy(fakehdr->ip6h.s_ip6_dst, p->ip6h->s_ip6_src, 16); } if (! invert) { fakehdr->tcph.th_sport = p->tcph->th_sport; fakehdr->tcph.th_dport = p->tcph->th_dport; } else { fakehdr->tcph.th_dport = p->tcph->th_sport; fakehdr->tcph.th_sport = p->tcph->th_dport; } fakehdr->tcph.th_offx2 = 0x50; /* just the TCP header, no options */ return 1; } /** * \brief Write a faked Packet in unified2 file for each stream segment. */ static int Unified2PrintStreamSegmentCallback(Packet *p, void *data, uint8_t *buf, uint32_t buflen) { int ret = 1; Unified2AlertThread *aun = (Unified2AlertThread *)data; Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data); Unified2Packet *phdr = (Unified2Packet *)(hdr + 1); int ethh_offset = 0; EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) }; uint32_t hdr_length = 0; int datalink = p->datalink; memset(hdr, 0, sizeof(Unified2AlertFileHeader)); memset(phdr, 0, sizeof(Unified2Packet)); hdr->type = htonl(UNIFIED2_PACKET_TYPE); aun->hdr = hdr; phdr->sensor_id = htonl(sensor_id); phdr->linktype = htonl(datalink); phdr->event_id = aun->event_id; phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec); phdr->packet_microsecond = htonl(p->ts.tv_usec); aun->phdr = phdr; if (p->datalink != DLT_EN10MB) { /* We have raw data here */ phdr->linktype = htonl(DLT_RAW); datalink = DLT_RAW; } aun->length = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE; aun->offset = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE; /* Include Packet header */ if (PKT_IS_IPV4(p)) { FakeIPv4Hdr fakehdr; hdr_length = sizeof(FakeIPv4Hdr); if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; datalink = DLT_EN10MB; phdr->linktype = htonl(datalink); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } ethhdr.eth_type = htons(ETHERNET_TYPE_IP); memcpy(aun->data + aun->offset, ðhdr, 14); aun->offset += ethh_offset; } memset(&fakehdr, 0, hdr_length); aun->length += hdr_length; Unified2ForgeFakeIPv4Header(&fakehdr, p, hdr_length + buflen, 0); if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } memcpy(aun->data + aun->offset, &fakehdr, hdr_length); aun->iphdr = (void *)(aun->data + aun->offset); aun->offset += hdr_length; } else if (PKT_IS_IPV6(p)) { FakeIPv6Hdr fakehdr; hdr_length = sizeof(FakeIPv6Hdr); if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; datalink = DLT_EN10MB; phdr->linktype = htonl(datalink); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6); memcpy(aun->data + aun->offset, ðhdr, 14); aun->offset += ethh_offset; } memset(&fakehdr, 0, hdr_length); Unified2ForgeFakeIPv6Header(&fakehdr, p, buflen, 1); aun->length += hdr_length; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } memcpy(aun->data + aun->offset, &fakehdr, hdr_length); aun->iphdr = (void *)(aun->data + aun->offset); aun->offset += hdr_length; } else { goto error; } /* update unified2 headers for length */ aun->hdr->length = htonl(UNIFIED2_PACKET_SIZE + ethh_offset + hdr_length + buflen); aun->phdr->packet_length = htonl(ethh_offset + hdr_length + buflen); /* copy stream segment payload in */ aun->length += buflen; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread" " data: %d vs %d", aun->length, aun->datalen); goto error; } memcpy(aun->data + aun->offset, buf, buflen); aun->offset += buflen; /* rebuild checksum */ if (PKT_IS_IPV6(p)) { FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr; fakehdr->tcph.th_sum = TCPV6CalculateChecksum(fakehdr->ip6h.s_ip6_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); } else { FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr; fakehdr->tcph.th_sum = TCPCalculateChecksum(fakehdr->ip4h.s_ip_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h, IPV4_GET_RAW_HLEN(&fakehdr->ip4h)); } /* write out */ ret = Unified2Write(aun); if (ret != 1) { goto error; } return 1; error: aun->length = 0; aun->offset = 0; return -1; } /** * \brief Function to fill unified2 packet format into the file. If the alert * was generated based on a stream chunk we call the stream function * to generate the record. * * Barnyard2 doesn't like DLT_RAW + IPv6, so if we don't have an ethernet * header, we create a fake one. * * No need to lock here, since it's already locked. * * \param aun thread local data * \param p Packet * \param stream pointer to stream chunk * \param event_id unique event id * \param stream state/stream match, try logging stream segments * * \retval 0 on succces * \retval -1 on failure */ int Unified2PacketTypeAlert (Unified2AlertThread *aun, Packet *p, uint32_t event_id, int stream) { int ret = 0; /* try stream logging first */ if (stream) { SCLogDebug("logging the state"); uint8_t flag; if (p->flowflags & FLOW_PKT_TOSERVER) { flag = FLOW_PKT_TOCLIENT; } else { flag = FLOW_PKT_TOSERVER; } /* make event id available to callback */ aun->event_id = event_id; /* run callback for all segments in the stream */ ret = StreamSegmentForEach(p, flag, Unified2PrintStreamSegmentCallback, (void *)aun); } /* or no segment could been logged or no segment have been logged */ if (ret == 0) { SCLogDebug("no stream, no state: falling back to payload logging"); Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data); Unified2Packet *phdr = (Unified2Packet *)(hdr + 1); int len = (sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE); int datalink = p->datalink; #ifdef HAVE_OLD_BARNYARD2 int ethh_offset = 0; EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) }; #endif memset(hdr, 0, sizeof(Unified2AlertFileHeader)); memset(phdr, 0, sizeof(Unified2Packet)); hdr->type = htonl(UNIFIED2_PACKET_TYPE); aun->hdr = hdr; phdr->sensor_id = htonl(sensor_id); phdr->linktype = htonl(datalink); phdr->event_id = event_id; phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec); phdr->packet_microsecond = htonl(p->ts.tv_usec); aun->phdr = phdr; /* we need to reset offset and length which could * have been modified by the segment logging */ aun->offset = len; len += GET_PKT_LEN(p); aun->length = len; /* Unified 2 packet header is the one of the packet. */ phdr->linktype = htonl(p->datalink); #ifdef HAVE_OLD_BARNYARD2 /* Fake datalink to avoid bug with old barnyard2 */ if (PKT_IS_IPV6(p) && (!p->ethh)) { /* Fake this */ ethh_offset = 14; datalink = DLT_EN10MB; phdr->linktype = htonl(datalink); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d", len, aun->datalen - aun->offset); return -1; } ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6); memcpy(aun->data + aun->offset, ðhdr, 14); aun->offset += ethh_offset; } #endif if (len > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d", len, aun->datalen - aun->offset); return -1; } hdr->length = htonl(UNIFIED2_PACKET_SIZE + GET_PKT_LEN(p)); phdr->packet_length = htonl(GET_PKT_LEN(p)); memcpy(aun->data + aun->offset, GET_PKT_DATA(p), GET_PKT_LEN(p)); ret = Unified2Write(aun); } if (ret < 1) { return -1; } return 1; } /** * \brief Function to fill unified2 ipv6 ids type format into the file. * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param p Packet struct used to decide for ipv4 or ipv6 * \param data Unified2 thread data. * \param pq Packet queue * * \retval 0 on succces * \retval -1 on failure */ int Unified2IPv6TypeAlert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq) { Unified2AlertThread *aun = (Unified2AlertThread *)data; Unified2AlertFileHeader hdr; AlertIPv6Unified2 *phdr = (AlertIPv6Unified2 *)(aun->data + sizeof(Unified2AlertFileHeader)); AlertIPv6Unified2 gphdr; PacketAlert *pa; int offset, length; int ret; unsigned int event_id; if (p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG)) return 0; length = (sizeof(Unified2AlertFileHeader) + sizeof(AlertIPv6Unified2)); offset = length; memset(aun->data, 0, aun->datalen); hdr.type = htonl(UNIFIED2_IDS_EVENT_IPV6_TYPE); hdr.length = htonl(sizeof(AlertIPv6Unified2)); /* fill the gphdr structure with the data of the packet */ memset(&gphdr, 0, sizeof(gphdr)); /* FIXME this need to be copied for each alert */ gphdr.sensor_id = htonl(sensor_id); gphdr.event_second = htonl(p->ts.tv_sec); gphdr.event_microsecond = htonl(p->ts.tv_usec); gphdr.src_ip = *(struct in6_addr*)GET_IPV6_SRC_ADDR(p); gphdr.dst_ip = *(struct in6_addr*)GET_IPV6_DST_ADDR(p); gphdr.protocol = p->proto; if(PACKET_TEST_ACTION(p, ACTION_DROP)) gphdr.packet_action = UNIFIED2_BLOCKED_FLAG; else gphdr.packet_action = 0; switch(gphdr.protocol) { case IPPROTO_ICMPV6: if(p->icmpv6h) { gphdr.sp = htons(p->icmpv6h->type); gphdr.dp = htons(p->icmpv6h->code); } else { gphdr.sp = 0; gphdr.dp = 0; } break; case IPPROTO_ICMP: if(p->icmpv4h) { gphdr.sp = htons(p->icmpv4h->type); gphdr.dp = htons(p->icmpv4h->code); } else { gphdr.sp = 0; gphdr.dp = 0; } break; case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: gphdr.sp = htons(p->sp); gphdr.dp = htons(p->dp); break; default: gphdr.sp = 0; gphdr.dp = 0; break; } uint16_t i = 0; for (; i < p->alerts.cnt + 1; i++) { if (i < p->alerts.cnt) pa = &p->alerts.alerts[i]; else { if (!(p->flags & PKT_HAS_TAG)) break; pa = PacketAlertGetTag(); } if (unlikely(pa->s == NULL)) continue; /* reset length and offset */ aun->offset = offset; aun->length = length; memset(aun->data + aun->offset, 0, aun->datalen - aun->offset); /* copy the part common to all alerts */ memcpy(aun->data, &hdr, sizeof(hdr)); memcpy(phdr, &gphdr, sizeof(gphdr)); /* fill the header structure with the data of the alert */ event_id = htonl(SC_ATOMIC_ADD(unified2_event_id, 1)); phdr->event_id = event_id; phdr->generator_id = htonl(pa->s->gid); phdr->signature_id = htonl(pa->s->id); phdr->signature_revision = htonl(pa->s->rev); phdr->classification_id = htonl(pa->s->class); phdr->priority_id = htonl(pa->s->prio); SCMutexLock(&aun->file_ctx->fp_mutex); if ((aun->file_ctx->size_current + length) > aun->file_ctx->size_limit) { if (Unified2AlertRotateFile(t,aun) < 0) { aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } } if (Unified2Write(aun) != 1) { aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } memset(aun->data, 0, aun->length); aun->length = 0; aun->offset = 0; ret = Unified2PacketTypeAlert(aun, p, phdr->event_id, pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0); if (ret != 1) { SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno)); aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } fflush(aun->file_ctx->fp); aun->file_ctx->alerts++; SCMutexUnlock(&aun->file_ctx->fp_mutex); } return 0; } /** * \brief Function to fill unified2 ipv4 ids type format into the file. * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param p Packet struct used to decide for ipv4 or ipv6 * \param data Unified2 thread data. * \param pq Packet queue * \retval 0 on succces * \retval -1 on failure */ int Unified2IPv4TypeAlert (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) { Unified2AlertThread *aun = (Unified2AlertThread *)data; Unified2AlertFileHeader hdr; AlertIPv4Unified2 *phdr = (AlertIPv4Unified2 *)(aun->data + sizeof(Unified2AlertFileHeader)); AlertIPv4Unified2 gphdr; PacketAlert *pa; int offset, length; int ret; unsigned int event_id; if (p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG)) return 0; length = (sizeof(Unified2AlertFileHeader) + sizeof(AlertIPv4Unified2)); offset = length; memset(aun->data, 0, aun->datalen); hdr.type = htonl(UNIFIED2_IDS_EVENT_TYPE); hdr.length = htonl(sizeof(AlertIPv4Unified2)); /* fill the gphdr structure with the data of the packet */ memset(&gphdr, 0, sizeof(gphdr)); gphdr.sensor_id = htonl(sensor_id); gphdr.event_id = 0; gphdr.event_second = htonl(p->ts.tv_sec); gphdr.event_microsecond = htonl(p->ts.tv_usec); gphdr.src_ip = p->ip4h->s_ip_src.s_addr; gphdr.dst_ip = p->ip4h->s_ip_dst.s_addr; gphdr.protocol = IPV4_GET_RAW_IPPROTO(p->ip4h); if(PACKET_TEST_ACTION(p, ACTION_DROP)) gphdr.packet_action = UNIFIED2_BLOCKED_FLAG; else gphdr.packet_action = 0; /* TODO inverse order if needed, this should be done on a * alert basis */ switch(gphdr.protocol) { case IPPROTO_ICMP: if(p->icmpv4h) { gphdr.sp = htons(p->icmpv4h->type); gphdr.dp = htons(p->icmpv4h->code); } break; case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: gphdr.sp = htons(p->sp); gphdr.dp = htons(p->dp); break; default: gphdr.sp = 0; gphdr.dp = 0; break; } uint16_t i = 0; for (; i < p->alerts.cnt + 1; i++) { if (i < p->alerts.cnt) pa = &p->alerts.alerts[i]; else { if (!(p->flags & PKT_HAS_TAG)) break; pa = PacketAlertGetTag(); } if (unlikely(pa->s == NULL)) continue; /* reset length and offset */ aun->offset = offset; aun->length = length; memset(aun->data + aun->offset, 0, aun->datalen - aun->offset); /* copy the part common to all alerts */ memcpy(aun->data, &hdr, sizeof(hdr)); memcpy(phdr, &gphdr, sizeof(gphdr)); /* fill the hdr structure with the alert data */ event_id = htonl(SC_ATOMIC_ADD(unified2_event_id, 1)); phdr->event_id = event_id; phdr->generator_id = htonl(pa->s->gid); phdr->signature_id = htonl(pa->s->id); phdr->signature_revision = htonl(pa->s->rev); phdr->classification_id = htonl(pa->s->class); phdr->priority_id = htonl(pa->s->prio); /* check and enforce the filesize limit */ SCMutexLock(&aun->file_ctx->fp_mutex); if ((aun->file_ctx->size_current + length) > aun->file_ctx->size_limit) { if (Unified2AlertRotateFile(tv,aun) < 0) { aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } } if (Unified2Write(aun) != 1) { aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } memset(aun->data, 0, aun->length); aun->length = 0; aun->offset = 0; /* Write the alert (it doesn't lock inside, since we * already locked here for rotation check) */ ret = Unified2PacketTypeAlert(aun, p, event_id, pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0); if (ret != 1) { aun->file_ctx->alerts += i; SCMutexUnlock(&aun->file_ctx->fp_mutex); return -1; } fflush(aun->file_ctx->fp); aun->file_ctx->alerts++; SCMutexUnlock(&aun->file_ctx->fp_mutex); } return 0; } /** * \brief Thread init function. * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param initdata Unified2 thread initial data. * \param data Unified2 thread data. * \retval TM_ECODE_OK on succces * \retval TM_ECODE_FAILED on failure */ TmEcode Unified2AlertThreadInit(ThreadVars *t, void *initdata, void **data) { Unified2AlertThread *aun = SCMalloc(sizeof(Unified2AlertThread)); if (unlikely(aun == NULL)) return TM_ECODE_FAILED; memset(aun, 0, sizeof(Unified2AlertThread)); if(initdata == NULL) { SCLogDebug("Error getting context for Unified2Alert. \"initdata\" argument NULL"); SCFree(aun); return TM_ECODE_FAILED; } /** Use the Ouptut Context (file pointer and mutex) */ aun->file_ctx = ((OutputCtx *)initdata)->data; aun->data = SCMalloc(sizeof(Unified2AlertFileHeader) + sizeof(Unified2Packet) + IPV4_MAXPACKET_LEN); if (aun->data == NULL) { SCFree(aun); return TM_ECODE_FAILED; } aun->datalen = sizeof(Unified2AlertFileHeader) + sizeof(Unified2Packet) + IPV4_MAXPACKET_LEN; *data = (void *)aun; return TM_ECODE_OK; } /** * \brief Thread deinit function. * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param data Unified2 thread data. * \retval TM_ECODE_OK on succces * \retval TM_ECODE_FAILED on failure */ TmEcode Unified2AlertThreadDeinit(ThreadVars *t, void *data) { Unified2AlertThread *aun = (Unified2AlertThread *)data; if (aun == NULL) { goto error; } if (!(aun->file_ctx->flags & LOGFILE_ALERTS_PRINTED)) { SCLogInfo("Alert unified2 module wrote %"PRIu64" alerts", aun->file_ctx->alerts); /* Do not print it for each thread */ aun->file_ctx->flags |= LOGFILE_ALERTS_PRINTED; } if (aun->data != NULL) { SCFree(aun->data); aun->data = NULL; } aun->datalen = 0; /* clear memory */ memset(aun, 0, sizeof(Unified2AlertThread)); SCFree(aun); return TM_ECODE_OK; error: return TM_ECODE_FAILED; } /** \brief Create a new LogFileCtx from the provided ConfNode. * \param conf The configuration node for this output. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful * */ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) { int ret = 0; LogFileCtx* file_ctx = NULL; file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Couldn't create new file_ctx"); goto error; } const char *filename = NULL; if (conf != NULL) { /* To faciliate unit tests. */ filename = ConfNodeLookupChildValue(conf, "filename"); } if (filename == NULL) filename = DEFAULT_LOG_FILENAME; file_ctx->prefix = SCStrdup(filename); const char *s_limit = NULL; file_ctx->size_limit = DEFAULT_LIMIT; if (conf != NULL) { s_limit = ConfNodeLookupChildValue(conf, "limit"); if (s_limit != NULL) { if (ParseSizeStringU64(s_limit, &file_ctx->size_limit) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid limit: %s", s_limit); exit(EXIT_FAILURE); } if (file_ctx->size_limit < 4096) { SCLogInfo("unified2-alert \"limit\" value of %"PRIu64" assumed to be pre-1.2 " "style: setting limit to %"PRIu64"mb", file_ctx->size_limit, file_ctx->size_limit); uint64_t size = file_ctx->size_limit * 1024 * 1024; file_ctx->size_limit = size; } else if (file_ctx->size_limit < MIN_LIMIT) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, limit less than " "allowed minimum: %d.", MIN_LIMIT); exit(EXIT_FAILURE); } } } if (conf != NULL) { const char *sensor_id_s = NULL; sensor_id_s = ConfNodeLookupChildValue(conf, "sensor-id"); if (sensor_id_s != NULL) { if (ByteExtractStringUint32(&sensor_id, 10, 0, sensor_id_s) == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid sensor-id: %s", sensor_id_s); exit(EXIT_FAILURE); } } } ret = Unified2AlertOpenFileCtx(file_ctx, filename); if (ret < 0) goto error; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) goto error; output_ctx->data = file_ctx; output_ctx->DeInit = Unified2AlertDeInitCtx; SCLogInfo("Unified2-alert initialized: filename %s, limit %"PRIu64" MB", filename, file_ctx->size_limit / (1024*1024)); SC_ATOMIC_INIT(unified2_event_id); return output_ctx; error: if (file_ctx != NULL) { LogFileFreeCtx(file_ctx); } return NULL; } static void Unified2AlertDeInitCtx(OutputCtx *output_ctx) { if (output_ctx != NULL) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; if (logfile_ctx != NULL) { LogFileFreeCtx(logfile_ctx); } SCFree(output_ctx); } } /** \brief Read the config set the file pointer, open the file * \param file_ctx pointer to a created LogFileCtx using LogFileNewCtx() * \param prefix Prefix of the log file. * \return -1 if failure, 0 if succesful * */ int Unified2AlertOpenFileCtx(LogFileCtx *file_ctx, const char *prefix) { int ret = 0; char *filename = NULL; if (file_ctx->filename != NULL) filename = file_ctx->filename; else { filename = file_ctx->filename = SCMalloc(PATH_MAX); /* XXX some sane default? */ if (filename == NULL) return -1; memset(filename, 0x00, PATH_MAX); } /** get the time so we can have a filename with seconds since epoch */ struct timeval ts; memset(&ts, 0x00, sizeof(struct timeval)); extern int run_mode; if (run_mode == RUNMODE_UNITTEST) TimeGet(&ts); else gettimeofday(&ts, NULL); /* create the filename to use */ char *log_dir; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec); file_ctx->fp = fopen(filename, "ab"); if (file_ctx->fp == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", filename, strerror(errno)); ret = -1; } return ret; } #ifdef UNITTESTS /** * \test Test the ethernet+ipv4+tcp unified2 test * * \retval 1 on succces * \retval 0 on failure */ static int Unified2Test01 (void) { ThreadVars tv; DecodeThreadVars dtv; PacketQueue pq; void *data = NULL; OutputCtx *oc; LogFileCtx *lf; Signature s; uint8_t raw_ipv4_tcp[] = { 0x00, 0x14, 0xbf, 0xe8, 0xcb, 0x26, 0xaa, 0x00, 0x04, 0x00, 0x0a, 0x04, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x8c, 0x55, 0x40, 0x00, 0x40, 0x06, 0x69, 0x86, 0xc0, 0xa8, 0x0a, 0x68, 0x4a, 0x7d, 0x2f, 0x53, 0xc2, 0x40, 0x00, 0x50, 0x1f, 0x00, 0xa4, 0xd4, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x3d, 0x4e, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x1c, 0x28, 0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x06}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int ret; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&pq, 0, sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&s, 0, sizeof(Signature)); PACKET_INITIALIZE(p); p->alerts.cnt++; p->alerts.alerts[p->alerts.cnt-1].s = &s; p->alerts.alerts[p->alerts.cnt-1].s->id = 1; p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv4_tcp)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&tv, &dtv, p, raw_ipv4_tcp, sizeof(raw_ipv4_tcp), &pq); FlowShutdown(); oc = Unified2AlertInitCtx(NULL); if (oc == NULL) { SCFree(p); return 0; } lf = (LogFileCtx *)oc->data; if(lf == NULL) { SCFree(p); return 0; } ret = Unified2AlertThreadInit(&tv, oc, &data); if(ret == TM_ECODE_FAILED) { SCFree(p); return 0; } ret = Unified2Alert(&tv, p, data, &pq, NULL); if(ret == TM_ECODE_FAILED) { SCFree(p); return 0; } ret = Unified2AlertThreadDeinit(&tv, data); if(ret == -1) { SCFree(p); return 0; } Unified2AlertDeInitCtx(oc); PACKET_CLEANUP(p); SCFree(p); return 1; } /** * \test Test the ethernet+ipv6+tcp unified2 test * * \retval 1 on succces * \retval 0 on failure */ static int Unified2Test02 (void) { ThreadVars tv; DecodeThreadVars dtv; PacketQueue pq; void *data = NULL; OutputCtx *oc; LogFileCtx *lf; Signature s; uint8_t raw_ipv6_tcp[] = { 0x00, 0x11, 0x25, 0x82, 0x95, 0xb5, 0x00, 0xd0, 0x09, 0xe3, 0xe8, 0xde, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x28, 0x06, 0x40, 0x20, 0x01, 0x06, 0xf8, 0x10, 0x2d, 0x00, 0x00, 0x02, 0xd0, 0x09, 0xff, 0xfe, 0xe3, 0xe8, 0xde, 0x20, 0x01, 0x06, 0xf8, 0x09, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe7, 0x41, 0x00, 0x50, 0xab, 0xdc, 0xd6, 0x60, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0x80, 0x41, 0xa2, 0x00, 0x00, 0x02, 0x04, 0x05, 0xa0, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x0a, 0x22, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x05 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int ret; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&pq, 0, sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&s, 0, sizeof(Signature)); PACKET_INITIALIZE(p); p->alerts.cnt++; p->alerts.alerts[p->alerts.cnt-1].s = &s; p->alerts.alerts[p->alerts.cnt-1].s->id = 1; p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv6_tcp)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&tv, &dtv, p, raw_ipv6_tcp, sizeof(raw_ipv6_tcp), &pq); FlowShutdown(); oc = Unified2AlertInitCtx(NULL); if (oc == NULL) { SCFree(p); return 0; } lf = (LogFileCtx *)oc->data; if(lf == NULL) { SCFree(p); return 0; } ret = Unified2AlertThreadInit(&tv, oc, &data); if(ret == -1) { SCFree(p); return 0; } ret = Unified2Alert(&tv, p, data, &pq, NULL); if(ret == TM_ECODE_FAILED) { SCFree(p); return 0; } ret = Unified2AlertThreadDeinit(&tv, data); if(ret == -1) { SCFree(p); return 0; } Unified2AlertDeInitCtx(oc); PACKET_CLEANUP(p); SCFree(p); return 1; } /** * \test Test the GRE unified2 test * * \retval 1 on succces * \retval 0 on failure */ static int Unified2Test03 (void) { ThreadVars tv; DecodeThreadVars dtv; PacketQueue pq; void *data = NULL; OutputCtx *oc; LogFileCtx *lf; Signature s; uint8_t raw_gre[] = { 0x00, 0x0e, 0x50, 0x06, 0x42, 0x96, 0xaa, 0x00, 0x04, 0x00, 0x0a, 0x04, 0x08, 0x00, 0x45, 0x00, 0x00, 0x74, 0x35, 0xa2, 0x40, 0x00, 0x40, 0x2f, 0xef, 0xcb, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x88, 0x0b, 0x00, 0x54, 0x00, 0x00, 0x00, 0x18, 0x29, 0x5f, 0xff, 0x03, 0x00, 0x21, 0x45, 0x00, 0x00, 0x50, 0xf4, 0x05, 0x40, 0x00, 0x3f, 0x06, 0x20, 0xb8, 0x50, 0x7e, 0x2b, 0x2d, 0xd4, 0xcc, 0xd6, 0x72, 0x0a, 0x92, 0x1a, 0x0b, 0xc9, 0xaf, 0x24, 0x02, 0x8c, 0xdd, 0x45, 0xf6, 0x80, 0x18, 0x21, 0xfc, 0x10, 0x7c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x08, 0x19, 0x1a, 0xda, 0x84, 0xd6, 0xda, 0x3e, 0x50, 0x49, 0x4e, 0x47, 0x20, 0x73, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x0d, 0x0a}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int ret; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&pq, 0, sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&s, 0, sizeof(Signature)); PACKET_INITIALIZE(p); p->alerts.cnt++; p->alerts.alerts[p->alerts.cnt-1].s = &s; p->alerts.alerts[p->alerts.cnt-1].s->id = 1; p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_gre)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&tv, &dtv, p, raw_gre, sizeof(raw_gre), &pq); FlowShutdown(); oc = Unified2AlertInitCtx(NULL); if (oc == NULL) { SCFree(p); return 0; } lf = (LogFileCtx *)oc->data; if(lf == NULL) { SCFree(p); return 0; } ret = Unified2AlertThreadInit(&tv, oc, &data); if(ret == -1) { SCFree(p); return 0; } ret = Unified2Alert(&tv, p, data, &pq, NULL); if(ret == TM_ECODE_FAILED) { SCFree(p); return 0; } ret = Unified2AlertThreadDeinit(&tv, data); if(ret == -1) { SCFree(p); return 0; } Unified2AlertDeInitCtx(oc); Packet *pkt = PacketDequeue(&pq); while (pkt != NULL) { SCFree(pkt); pkt = PacketDequeue(&pq); } PACKET_CLEANUP(p); SCFree(p); return 1; } /** * \test Test the PPP unified2 test * * \retval 1 on succces * \retval 0 on failure */ static int Unified2Test04 (void) { ThreadVars tv; DecodeThreadVars dtv; PacketQueue pq; void *data = NULL; OutputCtx *oc; LogFileCtx *lf; Signature s; uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00, 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int ret; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&pq, 0, sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&s, 0, sizeof(Signature)); PACKET_INITIALIZE(p); p->alerts.cnt++; p->alerts.alerts[p->alerts.cnt-1].s = &s; p->alerts.alerts[p->alerts.cnt-1].s->id = 1; p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ppp)); FlowInitConfig(FLOW_QUIET); DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp), &pq); FlowShutdown(); oc = Unified2AlertInitCtx(NULL); if (oc == NULL) { SCFree(p); return 0; } lf = (LogFileCtx *)oc->data; if(lf == NULL) { SCFree(p); return 0; } ret = Unified2AlertThreadInit(&tv, oc, &data); if(ret == -1) { SCFree(p); return 0; } ret = Unified2Alert(&tv, p, data, &pq, NULL); if(ret == TM_ECODE_FAILED) { SCFree(p); return 0; } ret = Unified2AlertThreadDeinit(&tv, data); if(ret == -1) { SCFree(p); return 0; } Unified2AlertDeInitCtx(oc); PACKET_CLEANUP(p); SCFree(p); return 1; } /** * \test Test the ethernet+ipv4+tcp droped unified2 test * * \retval 1 on succces * \retval 0 on failure */ static int Unified2Test05 (void) { ThreadVars tv; DecodeThreadVars dtv; PacketQueue pq; void *data = NULL; OutputCtx *oc; LogFileCtx *lf; Signature s; uint8_t raw_ipv4_tcp[] = { 0x00, 0x14, 0xbf, 0xe8, 0xcb, 0x26, 0xaa, 0x00, 0x04, 0x00, 0x0a, 0x04, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x8c, 0x55, 0x40, 0x00, 0x40, 0x06, 0x69, 0x86, 0xc0, 0xa8, 0x0a, 0x68, 0x4a, 0x7d, 0x2f, 0x53, 0xc2, 0x40, 0x00, 0x50, 0x1f, 0x00, 0xa4, 0xd4, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x3d, 0x4e, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x1c, 0x28, 0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x06}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int ret; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&pq, 0, sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&s, 0, sizeof(Signature)); PACKET_INITIALIZE(p); p->alerts.cnt++; p->alerts.alerts[p->alerts.cnt-1].s = &s; p->alerts.alerts[p->alerts.cnt-1].s->id = 1; p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv4_tcp)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&tv, &dtv, p, raw_ipv4_tcp, sizeof(raw_ipv4_tcp), &pq); FlowShutdown(); p->action = ACTION_DROP; oc = Unified2AlertInitCtx(NULL); if (oc == NULL) { SCFree(p); return 0; } lf = (LogFileCtx *)oc->data; if(lf == NULL) { SCFree(p); return 0; } ret = Unified2AlertThreadInit(&tv, oc, &data); if(ret == -1) { SCFree(p); return 0; } ret = Unified2Alert(&tv, p, data, &pq, NULL); if(ret == TM_ECODE_FAILED) { SCFree(p); return 0; } ret = Unified2AlertThreadDeinit(&tv, data); if(ret == TM_ECODE_FAILED) { SCFree(p); return 0; } Unified2AlertDeInitCtx(oc); PACKET_CLEANUP(p); SCFree(p); return 1; } /** * \test Test the Rotate process * * \retval 1 on succces * \retval 0 on failure */ static int Unified2TestRotate01(void) { int ret = 0; int r = 0; ThreadVars tv; OutputCtx *oc; LogFileCtx *lf; void *data = NULL; char *filename = NULL; oc = Unified2AlertInitCtx(NULL); if (oc == NULL) return 0; lf = (LogFileCtx *)oc->data; if (lf == NULL) return 0; filename = SCStrdup(lf->filename); if (unlikely(filename == NULL)) return 0; memset(&tv, 0, sizeof(ThreadVars)); ret = Unified2AlertThreadInit(&tv, oc, &data); if (ret == TM_ECODE_FAILED) { LogFileFreeCtx(lf); if (filename != NULL) SCFree(filename); return 0; } TimeSetIncrementTime(1); ret = Unified2AlertRotateFile(&tv, data); if (ret == -1) goto error; if (strcmp(filename, lf->filename) == 0) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "filename \"%s\" == \"%s\": ", filename, lf->filename); goto error; } r = 1; error: ret = Unified2AlertThreadDeinit(&tv, data); if(ret == TM_ECODE_FAILED) { printf("Unified2AlertThreadDeinit error"); } if (oc != NULL) Unified2AlertDeInitCtx(oc); if (filename != NULL) SCFree(filename); return r; } #endif /** * \brief this function registers unit tests for Unified2 */ void Unified2RegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("Unified2Test01 -- Ipv4 test", Unified2Test01, 1); UtRegisterTest("Unified2Test02 -- Ipv6 test", Unified2Test02, 1); UtRegisterTest("Unified2Test03 -- GRE test", Unified2Test03, 1); UtRegisterTest("Unified2Test04 -- PPP test", Unified2Test04, 1); UtRegisterTest("Unified2Test05 -- Inline test", Unified2Test05, 1); UtRegisterTest("Unified2TestRotate01 -- Rotate File", Unified2TestRotate01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/respond-reject.c0000644000000000000000000001105712253546156014121 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author William Metcalf * * RespondReject is a threaded wrapper for sending Rejects * * \todo RespondRejectFunc returns 1 on error, 0 on ok... why? For now it should * just return 0 always, error handling is a TODO in the threading model (VJ) */ #include "suricata-common.h" #include "decode.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "action-globals.h" #include "respond-reject.h" #include "respond-reject-libnet11.h" #include "util-debug.h" #include "util-privs.h" int RejectSendIPv4TCP(ThreadVars *, Packet *, void *); int RejectSendIPv4ICMP(ThreadVars *, Packet *, void *); int RejectSendIPv6TCP(ThreadVars *, Packet *, void *); int RejectSendIPv6ICMP(ThreadVars *, Packet *, void *); void TmModuleRespondRejectRegister (void) { tmm_modules[TMM_RESPONDREJECT].name = "RespondReject"; tmm_modules[TMM_RESPONDREJECT].ThreadInit = NULL; tmm_modules[TMM_RESPONDREJECT].Func = RespondRejectFunc; tmm_modules[TMM_RESPONDREJECT].ThreadDeinit = NULL; tmm_modules[TMM_RESPONDREJECT].RegisterTests = NULL; tmm_modules[TMM_RESPONDREJECT].cap_flags = 0; /* libnet is not compat with caps */ } TmEcode RespondRejectFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { int ret = 0; /* ACTION_REJECT defaults to rejecting the SRC */ if (!(PACKET_TEST_ACTION(p, ACTION_REJECT)) && !(PACKET_TEST_ACTION(p, ACTION_REJECT_DST)) && !(PACKET_TEST_ACTION(p, ACTION_REJECT_BOTH))) { return TM_ECODE_OK; } if (PKT_IS_IPV4(p)) { if (PKT_IS_TCP(p)) { ret = RejectSendIPv4TCP(tv, p, data); } else if(PKT_IS_UDP(p)) { ret = RejectSendIPv4ICMP(tv, p, data); } else { return TM_ECODE_OK; } } else if (PKT_IS_IPV6(p)) { if (PKT_IS_TCP(p)) { ret = RejectSendIPv6TCP(tv, p, data); } else if(PKT_IS_UDP(p)){ ret = RejectSendIPv6ICMP(tv, p, data); } else { return TM_ECODE_OK; } } else { /* we're only supporting IPv4 and IPv6 */ return TM_ECODE_OK; } if (ret) return TM_ECODE_FAILED; else return TM_ECODE_OK; } int RejectSendIPv4TCP(ThreadVars *tv, Packet *p, void *data) { if (PACKET_TEST_ACTION(p, ACTION_REJECT)) { return RejectSendLibnet11L3IPv4TCP(tv, p, data, REJECT_DIR_SRC); } else if (PACKET_TEST_ACTION(p, ACTION_REJECT_DST)) { return RejectSendLibnet11L3IPv4TCP(tv, p, data, REJECT_DIR_DST); } else if(PACKET_TEST_ACTION(p, ACTION_REJECT_BOTH)) { if (RejectSendLibnet11L3IPv4TCP(tv, p, data, REJECT_DIR_SRC) == 0 && RejectSendLibnet11L3IPv4TCP(tv, p, data, REJECT_DIR_DST) == 0) { return 0; } else { return 1; } } return 0; } int RejectSendIPv4ICMP(ThreadVars *tv, Packet *p, void *data) { if (PACKET_TEST_ACTION(p, ACTION_REJECT)) { return RejectSendLibnet11L3IPv4ICMP(tv, p, data, REJECT_DIR_SRC); } else if (PACKET_TEST_ACTION(p, ACTION_REJECT_DST)) { return RejectSendLibnet11L3IPv4ICMP(tv, p, data, REJECT_DIR_DST); } else if(PACKET_TEST_ACTION(p, ACTION_REJECT_BOTH)) { if (RejectSendLibnet11L3IPv4ICMP(tv, p, data, REJECT_DIR_SRC) == 0 && RejectSendLibnet11L3IPv4ICMP(tv, p, data, REJECT_DIR_DST) == 0) { return 0; } else { return 1; } } return 0; } /** \todo implement */ int RejectSendIPv6TCP(ThreadVars *tv, Packet *p, void *data) { SCEnter(); SCLogDebug("we would send a ipv6 tcp reset here"); SCReturnInt(0); } /** \todo implement */ int RejectSendIPv6ICMP(ThreadVars *tv, Packet *p, void *data) { SCEnter(); SCLogDebug("we would send a ipv6 icmp reset here"); SCReturnInt(0); } suricata-1.4.7/src/detect-fragbits.c0000644000000000000000000003752712253546156014256 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * * Implements fragbits keyword */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "flow-var.h" #include "decode-events.h" #include "app-layer-detect-proto.h" #include "detect-fragbits.h" #include "util-unittest.h" #include "util-debug.h" /** * Regex * fragbits: [!+*](MDR) */ #define PARSE_REGEX "^\\s*(?:([\\+\\*!]))?\\s*([MDR]+)" /** * FragBits args[0] *(3) +(2) !(1) * */ #define MODIFIER_NOT 1 #define MODIFIER_PLUS 2 #define MODIFIER_ANY 3 #define FRAGBITS_HAVE_MF 0x01 #define FRAGBITS_HAVE_DF 0x02 #define FRAGBITS_HAVE_RF 0x04 static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectFragBitsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectFragBitsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFragBitsFree(void *); /** * \brief Registration function for fragbits: keyword */ void DetectFragBitsRegister (void) { sigmatch_table[DETECT_FRAGBITS].name = "fragbits"; sigmatch_table[DETECT_FRAGBITS].desc = "check if the fragmentation and reserved bits are set in the IP header"; sigmatch_table[DETECT_FRAGBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Fragbits"; sigmatch_table[DETECT_FRAGBITS].Match = DetectFragBitsMatch; sigmatch_table[DETECT_FRAGBITS].Setup = DetectFragBitsSetup; sigmatch_table[DETECT_FRAGBITS].Free = DetectFragBitsFree; sigmatch_table[DETECT_FRAGBITS].RegisterTests = FragBitsRegisterTests; const char *eb; int opts = 0; int eo; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } error: return; } /** * \internal * \brief This function is used to match fragbits on a packet with those passed via fragbits: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param s pointer to the Signature * \param m pointer to the sigmatch * * \retval 0 no match * \retval 1 match */ static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { int ret = 0; uint16_t fragbits = 0; DetectFragBitsData *de = (DetectFragBitsData *)m->ctx; if (!de || !PKT_IS_IPV4(p) || !p || PKT_IS_PSEUDOPKT(p)) return ret; if(IPV4_GET_MF(p)) fragbits |= FRAGBITS_HAVE_MF; if(IPV4_GET_DF(p)) fragbits |= FRAGBITS_HAVE_DF; if(IPV4_GET_RF(p)) fragbits |= FRAGBITS_HAVE_RF; switch(de->modifier) { case MODIFIER_ANY: if((fragbits & de->fragbits) > 0) return 1; return ret; case MODIFIER_PLUS: if(((fragbits & de->fragbits) == de->fragbits) && (((fragbits - de->fragbits) > 0))) return 1; return ret; case MODIFIER_NOT: if((fragbits & de->fragbits) != de->fragbits) return 1; return ret; default: if(fragbits == de->fragbits) return 1; } return ret; } /** * \internal * \brief This function is used to parse fragbits options passed via fragbits: keyword * * \param rawstr Pointer to the user provided fragbits options * * \retval de pointer to DetectFragBitsData on success * \retval NULL on failure */ static DetectFragBitsData *DetectFragBitsParse (char *rawstr) { DetectFragBitsData *de = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, found = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr = NULL; char *args[2] = { NULL, NULL}; char *ptr; int i; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); goto error; } for (i = 0; i < (ret - 1); i++) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS,i + 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i] = (char *)str_ptr; } if(args[1] == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "invalid value"); goto error; } de = SCMalloc(sizeof(DetectFragBitsData)); if (unlikely(de == NULL)) goto error; memset(de,0,sizeof(DetectFragBitsData)); /** First parse args[0] */ if(args[0]) { ptr = args[0]; while (*ptr != '\0') { switch (*ptr) { case '!': de->modifier = MODIFIER_NOT; break; case '+': de->modifier = MODIFIER_PLUS; break; case '*': de->modifier = MODIFIER_ANY; break; } ptr++; } } /** Second parse first set of fragbits */ ptr = args[1]; while (*ptr != '\0') { switch (*ptr) { case 'M': case 'm': de->fragbits |= FRAGBITS_HAVE_MF; found++; break; case 'D': case 'd': de->fragbits |= FRAGBITS_HAVE_DF; found++; break; case 'R': case 'r': de->fragbits |= FRAGBITS_HAVE_RF; found++; break; default: found = 0; break; } ptr++; } if(found == 0) goto error; for (i = 0; i < 2; i++) { if (args[i] != NULL) SCFree(args[i]); } return de; error: for (i = 0; i < 2; i++) { if (args[i] != NULL) SCFree(args[i]); } if (de != NULL) SCFree(de); return NULL; } /** * \internal * \brief this function is used to add the parsed fragbits into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param m pointer to the Current SigMatch * \param rawstr pointer to the user provided fragbits options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFragBitsSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectFragBitsData *de = NULL; SigMatch *sm = NULL; de = DetectFragBitsParse(rawstr); if (de == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FRAGBITS; sm->ctx = (void *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (de) SCFree(de); if (sm) SCFree(sm); return -1; } /** * \internal * \brief this function will free memory associated with DetectFragBitsData * * \param de pointer to DetectFragBitsData */ static void DetectFragBitsFree(void *de_ptr) { DetectFragBitsData *de = (DetectFragBitsData *)de_ptr; if(de) SCFree(de); } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS /** * \test FragBitsTestParse01 is a test for a valid fragbits value * * \retval 1 on succces * \retval 0 on failure */ static int FragBitsTestParse01 (void) { DetectFragBitsData *de = NULL; de = DetectFragBitsParse("M"); if (de && (de->fragbits == FRAGBITS_HAVE_MF) ) { DetectFragBitsFree(de); return 1; } return 0; } /** * \test FragBitsTestParse02 is a test for an invalid fragbits value * * \retval 1 on succces * \retval 0 on failure */ static int FragBitsTestParse02 (void) { DetectFragBitsData *de = NULL; de = DetectFragBitsParse("G"); if (de) { DetectFragBitsFree(de); return 1; } return 0; } /** * \test FragBitsTestParse03 test if DONT FRAG is set. Must return success * * \retval 1 on success * \retval 0 on failure */ static int FragBitsTestParse03 (void) { uint8_t raw_eth[] = { 0x00 ,0x40 ,0x33 ,0xd9 ,0x7c ,0xfd ,0x00 ,0x00, 0x39 ,0xcf ,0xd9 ,0xcd ,0x08 ,0x00 ,0x45 ,0x00, 0x01 ,0x13 ,0x9c ,0x5d ,0x40 ,0x00 ,0xf6 ,0x11, 0x44 ,0xca ,0x97 ,0xa4 ,0x01 ,0x08 ,0x0a ,0x00, 0x00 ,0x06 ,0x00 ,0x35 ,0x04 ,0x0b ,0x00 ,0xff, 0x3c ,0x87 ,0x7d ,0x9e ,0x85 ,0x80 ,0x00 ,0x01, 0x00 ,0x01 ,0x00 ,0x05 ,0x00 ,0x05 ,0x06 ,0x70, 0x69 ,0x63 ,0x61 ,0x72 ,0x64 ,0x07 ,0x75 ,0x74, 0x68 ,0x73 ,0x63 ,0x73 ,0x61 ,0x03 ,0x65 ,0x64, 0x75 ,0x00 ,0x00 ,0x01 ,0x00 ,0x01 ,0xc0 ,0x0c, 0x00 ,0x01 ,0x00 ,0x01 ,0x00 ,0x00 ,0x0e ,0x10, 0x00 ,0x04 ,0x81 ,0x6f ,0x1e ,0x1b ,0x07 ,0x75, 0x74 ,0x68 ,0x73 ,0x63 ,0x73 ,0x61 ,0x03 ,0x65, 0x64 ,0x75 ,0x00 ,0x00 ,0x02 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x09 ,0x06 ,0x6b ,0x65, 0x6e ,0x6f ,0x62 ,0x69 ,0xc0 ,0x34 ,0xc0 ,0x34, 0x00 ,0x02 ,0x00 ,0x01 ,0x00 ,0x00 ,0x0e ,0x10, 0x00 ,0x07 ,0x04 ,0x6a ,0x69 ,0x6e ,0x6e ,0xc0, 0x34 ,0xc0 ,0x34 ,0x00 ,0x02 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x0c ,0x04 ,0x64 ,0x6e, 0x73 ,0x31 ,0x04 ,0x6e ,0x6a ,0x69 ,0x74 ,0xc0, 0x3c ,0xc0 ,0x34 ,0x00 ,0x02 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x08 ,0x05 ,0x65 ,0x6c, 0x7a ,0x69 ,0x70 ,0xc0 ,0x34 ,0xc0 ,0x34 ,0x00, 0x02 ,0x00 ,0x01 ,0x00 ,0x00 ,0x0e ,0x10 ,0x00, 0x08 ,0x05 ,0x61 ,0x72 ,0x77 ,0x65 ,0x6e ,0xc0, 0x34 ,0xc0 ,0x4b ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x1a, 0x06 ,0xc0 ,0x60 ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x1a, 0x07 ,0xc0 ,0x73 ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x01 ,0x03 ,0x82 ,0x00 ,0x04 ,0x80 ,0xeb ,0xfb, 0x0a ,0xc0 ,0x8b ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x01, 0x0b ,0xc0 ,0x9f ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x0b, 0x51}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; IPV4Hdr ipv4h; int ret = 0; DetectFragBitsData *de = NULL; SigMatch *sm = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ipv4h, 0, sizeof(IPV4Hdr)); AlpProtoFinalize2Thread(&dtv.udp_dp_ctx); p->ip4h = &ipv4h; FlowInitConfig(FLOW_QUIET); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth), NULL); de = DetectFragBitsParse("D"); if (de == NULL || (de->fragbits != FRAGBITS_HAVE_DF)) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FRAGBITS; sm->ctx = (void *)de; ret = DetectFragBitsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: FlowShutdown(); if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FragBitsTestParse04 test if DONT FRAG is not set. Must fails. * * \retval 1 on success * \retval 0 on failure */ static int FragBitsTestParse04 (void) { uint8_t raw_eth[] = { 0x00 ,0x40 ,0x33 ,0xd9 ,0x7c ,0xfd ,0x00 ,0x00, 0x39 ,0xcf ,0xd9 ,0xcd ,0x08 ,0x00 ,0x45 ,0x00, 0x01 ,0x13 ,0x9c ,0x5d ,0x40 ,0x00 ,0xf6 ,0x11, 0x44 ,0xca ,0x97 ,0xa4 ,0x01 ,0x08 ,0x0a ,0x00, 0x00 ,0x06 ,0x00 ,0x35 ,0x04 ,0x0b ,0x00 ,0xff, 0x3c ,0x87 ,0x7d ,0x9e ,0x85 ,0x80 ,0x00 ,0x01, 0x00 ,0x01 ,0x00 ,0x05 ,0x00 ,0x05 ,0x06 ,0x70, 0x69 ,0x63 ,0x61 ,0x72 ,0x64 ,0x07 ,0x75 ,0x74, 0x68 ,0x73 ,0x63 ,0x73 ,0x61 ,0x03 ,0x65 ,0x64, 0x75 ,0x00 ,0x00 ,0x01 ,0x00 ,0x01 ,0xc0 ,0x0c, 0x00 ,0x01 ,0x00 ,0x01 ,0x00 ,0x00 ,0x0e ,0x10, 0x00 ,0x04 ,0x81 ,0x6f ,0x1e ,0x1b ,0x07 ,0x75, 0x74 ,0x68 ,0x73 ,0x63 ,0x73 ,0x61 ,0x03 ,0x65, 0x64 ,0x75 ,0x00 ,0x00 ,0x02 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x09 ,0x06 ,0x6b ,0x65, 0x6e ,0x6f ,0x62 ,0x69 ,0xc0 ,0x34 ,0xc0 ,0x34, 0x00 ,0x02 ,0x00 ,0x01 ,0x00 ,0x00 ,0x0e ,0x10, 0x00 ,0x07 ,0x04 ,0x6a ,0x69 ,0x6e ,0x6e ,0xc0, 0x34 ,0xc0 ,0x34 ,0x00 ,0x02 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x0c ,0x04 ,0x64 ,0x6e, 0x73 ,0x31 ,0x04 ,0x6e ,0x6a ,0x69 ,0x74 ,0xc0, 0x3c ,0xc0 ,0x34 ,0x00 ,0x02 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x08 ,0x05 ,0x65 ,0x6c, 0x7a ,0x69 ,0x70 ,0xc0 ,0x34 ,0xc0 ,0x34 ,0x00, 0x02 ,0x00 ,0x01 ,0x00 ,0x00 ,0x0e ,0x10 ,0x00, 0x08 ,0x05 ,0x61 ,0x72 ,0x77 ,0x65 ,0x6e ,0xc0, 0x34 ,0xc0 ,0x4b ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x1a, 0x06 ,0xc0 ,0x60 ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x1a, 0x07 ,0xc0 ,0x73 ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x01 ,0x03 ,0x82 ,0x00 ,0x04 ,0x80 ,0xeb ,0xfb, 0x0a ,0xc0 ,0x8b ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x01, 0x0b ,0xc0 ,0x9f ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x0b, 0x51}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; IPV4Hdr ipv4h; int ret = 0; DetectFragBitsData *de = NULL; SigMatch *sm = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ipv4h, 0, sizeof(IPV4Hdr)); AlpProtoFinalize2Thread(&dtv.udp_dp_ctx); p->ip4h = &ipv4h; FlowInitConfig(FLOW_QUIET); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth), NULL); FlowShutdown(); de = DetectFragBitsParse("!D"); if (de == NULL || (de->fragbits != FRAGBITS_HAVE_DF) || (de->modifier != MODIFIER_NOT)) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FRAGBITS; sm->ctx = (void *)de; ret = DetectFragBitsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for FragBits */ void FragBitsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FragBitsTestParse01", FragBitsTestParse01, 1); UtRegisterTest("FragBitsTestParse02", FragBitsTestParse02, 0); UtRegisterTest("FragBitsTestParse03", FragBitsTestParse03, 1); UtRegisterTest("FragBitsTestParse04", FragBitsTestParse04, 0); #endif /* UNITTESTS */ } suricata-1.4.7/src/alert-debuglog.c0000644000000000000000000004421712253546156014076 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * \todo figure out a way to (thread) safely print detection engine info * \todo maybe by having a log queue in the packet * \todo maybe by accessing it just and hoping threading doesn't hurt */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "conf.h" #include "stream.h" #include "app-layer-protos.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "util-print.h" #include "pkt-var.h" #include "util-unittest.h" #include "util-debug.h" #include "util-buffer.h" #include "output.h" #include "alert-debuglog.h" #include "util-privs.h" #include "flow-var.h" #include "flow-bit.h" #include "util-var-name.h" #include "util-optimize.h" #include "util-logopenfile.h" #define DEFAULT_LOG_FILENAME "alert-debug.log" #define MODULE_NAME "AlertDebugLog" TmEcode AlertDebugLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertDebugLogIPv4(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertDebugLogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertDebugLogThreadInit(ThreadVars *, void*, void **); TmEcode AlertDebugLogThreadDeinit(ThreadVars *, void *); void AlertDebugLogExitPrintStats(ThreadVars *, void *); void TmModuleAlertDebugLogRegister (void) { tmm_modules[TMM_ALERTDEBUGLOG].name = MODULE_NAME; tmm_modules[TMM_ALERTDEBUGLOG].ThreadInit = AlertDebugLogThreadInit; tmm_modules[TMM_ALERTDEBUGLOG].Func = AlertDebugLog; tmm_modules[TMM_ALERTDEBUGLOG].ThreadExitPrintStats = AlertDebugLogExitPrintStats; tmm_modules[TMM_ALERTDEBUGLOG].ThreadDeinit = AlertDebugLogThreadDeinit; tmm_modules[TMM_ALERTDEBUGLOG].RegisterTests = NULL; tmm_modules[TMM_ALERTDEBUGLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "alert-debug", AlertDebugLogInitCtx); } typedef struct AlertDebugLogThread_ { LogFileCtx *file_ctx; /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ MemBuffer *buffer; } AlertDebugLogThread; static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); } /** * \brief Function to log the FlowVars in to alert-debug.log * * \param aft Pointer to AltertDebugLog Thread * \param p Pointer to the packet * */ static void AlertDebugLogFlowVars(AlertDebugLogThread *aft, Packet *p) { GenericVar *gv = p->flow->flowvar; uint16_t i; while (gv != NULL) { if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { FlowVar *fv = (FlowVar *) gv; if (fv->datatype == FLOWVAR_TYPE_STR) { MemBufferWriteString(aft->buffer, "FLOWVAR idx(%"PRIu32"): ", fv->idx); for (i = 0; i < fv->data.fv_str.value_len; i++) { if (isprint(fv->data.fv_str.value[i])) { MemBufferWriteString(aft->buffer, "%c", fv->data.fv_str.value[i]); } else { MemBufferWriteString(aft->buffer, "\\%02X", fv->data.fv_str.value[i]); } } } else if (fv->datatype == FLOWVAR_TYPE_INT) { MemBufferWriteString(aft->buffer, "FLOWVAR idx(%"PRIu32"): " " %" PRIu32 "\"", fv->idx, fv->data.fv_int.value); } } gv = gv->next; } } /** * \brief Function to log the FlowBits in to alert-debug.log * * \param aft Pointer to AltertDebugLog Thread * \param p Pointer to the packet * */ static void AlertDebugLogFlowBits(AlertDebugLogThread *aft, Packet *p) { int i; for (i = 0; i < p->debuglog_flowbits_names_len; i++) { if (p->debuglog_flowbits_names[i] != NULL) { MemBufferWriteString(aft->buffer, "FLOWBIT: %s\n", p->debuglog_flowbits_names[i]); } } SCFree(p->debuglog_flowbits_names); p->debuglog_flowbits_names = NULL; p->debuglog_flowbits_names_len = 0; return; } /** * \brief Function to log the PktVars in to alert-debug.log * * \param aft Pointer to AltertDebugLog Thread * \param p Pointer to the packet * */ static void AlertDebugLogPktVars(AlertDebugLogThread *aft, Packet *p) { PktVar *pv = p->pktvar; while(pv != NULL) { MemBufferWriteString(aft->buffer, "PKTVAR: %s\n", pv->name); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, pv->value, pv->value_len); pv = pv->next; } } /** \todo doc * assume we have aft lock */ static int AlertDebugPrintStreamSegmentCallback(Packet *p, void *data, uint8_t *buf, uint32_t buflen) { AlertDebugLogThread *aft = (AlertDebugLogThread *)data; MemBufferWriteString(aft->buffer, "STREAM DATA LEN: %"PRIu32"\n", buflen); MemBufferWriteString(aft->buffer, "STREAM DATA:\n"); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, buf, buflen); return 1; } TmEcode AlertDebugLogger(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertDebugLogThread *aft = (AlertDebugLogThread *)data; int i; char timebuf[64]; if (p->alerts.cnt == 0) return TM_ECODE_OK; MemBufferReset(aft->buffer); CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); MemBufferWriteString(aft->buffer, "+================\n" "TIME: %s\n", timebuf); if (p->pcap_cnt > 0) { MemBufferWriteString(aft->buffer, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt); } char srcip[46], dstip[46]; if (PKT_IS_IPV4(p)) { PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); } MemBufferWriteString(aft->buffer, "SRC IP: %s\n" "DST IP: %s\n" "PROTO: %" PRIu32 "\n", srcip, dstip, p->proto); if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { MemBufferWriteString(aft->buffer, "SRC PORT: %" PRIu32 "\n" "DST PORT: %" PRIu32 "\n", p->sp, p->dp); if (PKT_IS_TCP(p)) { MemBufferWriteString(aft->buffer, "TCP SEQ: %"PRIu32"\n" "TCP ACK: %"PRIu32"\n", TCP_GET_SEQ(p), TCP_GET_ACK(p)); } } /* flow stuff */ MemBufferWriteString(aft->buffer, "FLOW: to_server: %s, " "to_client: %s\n", p->flowflags & FLOW_PKT_TOSERVER ? "TRUE" : "FALSE", p->flowflags & FLOW_PKT_TOCLIENT ? "TRUE" : "FALSE"); if (p->flow != NULL) { FLOWLOCK_RDLOCK(p->flow); CreateTimeString(&p->flow->startts, timebuf, sizeof(timebuf)); MemBufferWriteString(aft->buffer, "FLOW Start TS: %s\n", timebuf); #ifdef DEBUG MemBufferWriteString(aft->buffer, "FLOW PKTS TODST: %"PRIu32"\n" "FLOW PKTS TOSRC: %"PRIu32"\n" "FLOW Total Bytes: %"PRIu64"\n", p->flow->todstpktcnt, p->flow->tosrcpktcnt, p->flow->bytecnt); #endif MemBufferWriteString(aft->buffer, "FLOW IPONLY SET: TOSERVER: %s, TOCLIENT: %s\n" "FLOW ACTION: DROP: %s, PASS %s\n" "FLOW NOINSPECTION: PACKET: %s, PAYLOAD: %s, APP_LAYER: %s\n" "FLOW APP_LAYER: DETECTED: %s, PROTO %"PRIu16"\n", p->flow->flags & FLOW_TOSERVER_IPONLY_SET ? "TRUE" : "FALSE", p->flow->flags & FLOW_TOCLIENT_IPONLY_SET ? "TRUE" : "FALSE", p->flow->flags & FLOW_ACTION_DROP ? "TRUE" : "FALSE", p->flow->flags & FLOW_ACTION_PASS ? "TRUE" : "FALSE", p->flow->flags & FLOW_NOPACKET_INSPECTION ? "TRUE" : "FALSE", p->flow->flags & FLOW_NOPAYLOAD_INSPECTION ? "TRUE" : "FALSE", p->flow->flags & FLOW_NO_APPLAYER_INSPECTION ? "TRUE" : "FALSE", (p->flow->alproto != ALPROTO_UNKNOWN) ? "TRUE" : "FALSE", p->flow->alproto); AlertDebugLogFlowVars(aft, p); AlertDebugLogFlowBits(aft, p); FLOWLOCK_UNLOCK(p->flow); } AlertDebugLogPktVars(aft, p); /* any stuff */ /* Sig details? */ MemBufferWriteString(aft->buffer, "PACKET LEN: %" PRIu32 "\n" "PACKET:\n", GET_PKT_LEN(p)); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, GET_PKT_DATA(p), GET_PKT_LEN(p)); MemBufferWriteString(aft->buffer, "ALERT CNT: %" PRIu32 "\n", p->alerts.cnt); for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; } MemBufferWriteString(aft->buffer, "ALERT MSG [%02d]: %s\n" "ALERT GID [%02d]: %" PRIu32 "\n" "ALERT SID [%02d]: %" PRIu32 "\n" "ALERT REV [%02d]: %" PRIu32 "\n" "ALERT CLASS [%02d]: %s\n" "ALERT PRIO [%02d]: %" PRIu32 "\n" "ALERT FOUND IN [%02d]: %s\n", i, pa->s->msg, i, pa->s->gid, i, pa->s->id, i, pa->s->rev, i, pa->s->class_msg ? pa->s->class_msg : "", i, pa->s->prio, i, pa->flags & PACKET_ALERT_FLAG_STREAM_MATCH ? "STREAM" : (pa->flags & PACKET_ALERT_FLAG_STATE_MATCH ? "STATE" : "PACKET")); if (p->payload_len > 0) { MemBufferWriteString(aft->buffer, "PAYLOAD LEN: %" PRIu32 "\n" "PAYLOAD:\n", p->payload_len); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, p->payload, p->payload_len); } if ((pa->flags & PACKET_ALERT_FLAG_STATE_MATCH) || (pa->flags & PACKET_ALERT_FLAG_STREAM_MATCH)) { /* This is an app layer or stream alert */ int ret; uint8_t flag; if ((! PKT_IS_TCP(p)) || p->flow == NULL || p->flow->protoctx == NULL) { return TM_ECODE_OK; } /* IDS mode reverse the data */ /** \todo improve the order selection policy */ if (p->flowflags & FLOW_PKT_TOSERVER) { flag = FLOW_PKT_TOCLIENT; } else { flag = FLOW_PKT_TOSERVER; } ret = StreamSegmentForEach(p, flag, AlertDebugPrintStreamSegmentCallback, (void *)aft); if (ret < 0) { return TM_ECODE_FAILED; } } } SCMutexLock(&aft->file_ctx->fp_mutex); (void)MemBufferPrintToFPAsString(aft->buffer, aft->file_ctx->fp); fflush(aft->file_ctx->fp); aft->file_ctx->alerts += p->alerts.cnt; SCMutexUnlock(&aft->file_ctx->fp_mutex); return TM_ECODE_OK; } TmEcode AlertDebugLogDecoderEvent(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertDebugLogThread *aft = (AlertDebugLogThread *)data; int i; char timebuf[64]; if (p->alerts.cnt == 0) return TM_ECODE_OK; MemBufferReset(aft->buffer); CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); MemBufferWriteString(aft->buffer, "+================\n" "TIME: %s\n", timebuf); if (p->pcap_cnt > 0) { MemBufferWriteString(aft->buffer, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt); } MemBufferWriteString(aft->buffer, "ALERT CNT: %" PRIu32 "\n", p->alerts.cnt); for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; } MemBufferWriteString(aft->buffer, "ALERT MSG [%02d]: %s\n" "ALERT GID [%02d]: %" PRIu32 "\n" "ALERT SID [%02d]: %" PRIu32 "\n" "ALERT REV [%02d]: %" PRIu32 "\n" "ALERT CLASS [%02d]: %s\n" "ALERT PRIO [%02d]: %" PRIu32 "\n", i, pa->s->msg, i, pa->s->gid, i, pa->s->id, i, pa->s->rev, i, pa->s->class_msg, i, pa->s->prio); } MemBufferWriteString(aft->buffer, "PACKET LEN: %" PRIu32 "\n" "PACKET:\n", GET_PKT_LEN(p)); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, GET_PKT_DATA(p), GET_PKT_LEN(p)); SCMutexLock(&aft->file_ctx->fp_mutex); (void)MemBufferPrintToFPAsString(aft->buffer, aft->file_ctx->fp); fflush(aft->file_ctx->fp); aft->file_ctx->alerts += p->alerts.cnt; SCMutexUnlock(&aft->file_ctx->fp_mutex); return TM_ECODE_OK; } TmEcode AlertDebugLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { if (PKT_IS_IPV4(p)) { return AlertDebugLogger(tv, p, data, pq, postpq); } else if (PKT_IS_IPV6(p)) { return AlertDebugLogger(tv, p, data, pq, postpq); } else if (p->events.cnt > 0) { return AlertDebugLogDecoderEvent(tv, p, data, pq, postpq); } return TM_ECODE_OK; } TmEcode AlertDebugLogThreadInit(ThreadVars *t, void *initdata, void **data) { AlertDebugLogThread *aft = SCMalloc(sizeof(AlertDebugLogThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(AlertDebugLogThread)); if(initdata == NULL) { SCLogDebug("Error getting context for DebugLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } /** Use the Ouptut Context (file pointer and mutex) */ aft->file_ctx = ((OutputCtx *)initdata)->data; /* 1 mb seems sufficient enough */ aft->buffer = MemBufferCreateNew(1 * 1024 * 1024); if (aft->buffer == NULL) { SCFree(aft); return TM_ECODE_FAILED; } *data = (void *)aft; return TM_ECODE_OK; } TmEcode AlertDebugLogThreadDeinit(ThreadVars *t, void *data) { AlertDebugLogThread *aft = (AlertDebugLogThread *)data; if (aft == NULL) { return TM_ECODE_OK; } MemBufferFree(aft->buffer); /* clear memory */ memset(aft, 0, sizeof(AlertDebugLogThread)); SCFree(aft); return TM_ECODE_OK; } void AlertDebugLogExitPrintStats(ThreadVars *tv, void *data) { AlertDebugLogThread *aft = (AlertDebugLogThread *)data; if (aft == NULL) { return; } SCLogInfo("(%s) Alerts %" PRIu64 "", tv->name, aft->file_ctx->alerts); } static void AlertDebugLogDeInitCtx(OutputCtx *output_ctx) { if (output_ctx != NULL) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; if (logfile_ctx != NULL) { LogFileFreeCtx(logfile_ctx); } SCFree(output_ctx); } } /** * \brief Create a new LogFileCtx for alert debug logging. * * \param ConfNode containing configuration for this logger. * * \return output_ctx if succesful, NULL otherwise */ OutputCtx *AlertDebugLogInitCtx(ConfNode *conf) { LogFileCtx *file_ctx = NULL; file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { SCLogDebug("couldn't create new file_ctx"); goto error; } if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { goto error; } OutputCtx *output_ctx = SCMalloc(sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) goto error; memset(output_ctx, 0x00, sizeof(OutputCtx)); output_ctx->data = file_ctx; output_ctx->DeInit = AlertDebugLogDeInitCtx; SCLogDebug("Alert debug log output initialized"); return output_ctx; error: if (file_ctx != NULL) { LogFileFreeCtx(file_ctx); } return NULL; } suricata-1.4.7/src/detect-engine-hcbd.h0000644000000000000000000000302212253546156014604 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HCBD_H__ #define __DETECT_ENGINE_HCBD_H__ #define ENGINE_HCBD_BUFFER_LIMIT 20000 #include "app-layer-htp.h" int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *, DetectEngineThreadCtx *, Flow *f, HtpState *, uint8_t); int DetectEngineInspectHttpClientBody(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *); void DetectEngineHttpClientBodyRegisterTests(void); #endif /* __DETECT_ENGINE_HCBD_H__ */ suricata-1.4.7/src/detect-http-raw-header.c0000644000000000000000000015372512253546156015450 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Pablo Rincon * * Implements support for http_raw_header keyword. */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "util-print.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-raw-header.h" #include "stream-tcp.h" int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpRawHeaderRegisterTests(void); void DetectHttpRawHeaderFree(void *); /** * \brief Registers the keyword handlers for the "http_raw_header" keyword. */ void DetectHttpRawHeaderRegister(void) { sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].name = "http_raw_header"; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Match = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetup; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Free = DetectHttpRawHeaderFree; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].RegisterTests = DetectHttpRawHeaderRegisterTests; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_PAYLOAD; return; } /** * \brief this function clears the memory of http_raw_header modifier keyword * * \param ptr Pointer to the Detection Header Data */ void DetectHttpRawHeaderFree(void *ptr) { DetectContentData *cd = (DetectContentData *)ptr; if (cd == NULL) return; if (cd->content != NULL) SCFree(cd->content); SCFree(cd); return; } /** * \brief The setup function for the http_raw_header keyword for a signature. * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to signature for the current Signature being parsed * from the rules. * \param m Pointer to the head of the SigMatchs for the current rule * being parsed. * \param arg Pointer to the string holding the keyword value. * * \retval 0 On success. * \retval -1 On failure. */ int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_raw_header supplied with no args"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if still we are unable to find any previous content keywords, it is an * invalid rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_raw_header\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_header\" keyword"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_header should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_header rule can not " "be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); if (pm != NULL) { /* pm is never NULL. So no NULL check */ if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* please note. reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_raw_header seen with a " "distance or within without a previous http_raw_header " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HRUDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hrhdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HRHDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: //if (cd != NULL) // DetectHttpRawHeaderFree(cd); //if (sm != NULL) // SCFree(sm); return -1; } /************************************Unittests*********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Test that a signature containting a http_header is correctly parsed * and the keyword is registered. */ static int DetectHttpRawHeaderTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; SigMatch *sm = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; flow:to_server; " "content:\"one\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("Error parsing signature: "); goto end; } sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; if (sm != NULL) { result &= (sm->type == DETECT_CONTENT); result &= (sm->next == NULL); } else { result = 0; printf("Error updating content pattern to http_header pattern: "); } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a signature containing an valid http_header entry is * parsed. */ static int DetectHttpRawHeaderTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; flow:to_server; " "content:\"one\"; http_raw_header:; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; else printf("Error parsing signature: "); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing no content but a http_header * is invalidated. */ static int DetectHttpRawHeaderTest03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; flow:to_server; " "http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; else printf("Error parsing signature: "); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_header is invalidated. */ static int DetectHttpRawHeaderTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; flow:to_server; " "content:\"one\"; rawbytes; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; else printf("Error parsing signature: "); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_header is invalidated. */ static int DetectHttpRawHeaderTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; flow:to_server; " "content:\"one\"; nocase; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; else printf("Error parsing signature: "); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectHttpRawHeaderTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"Content-Type: text/html\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectHttpRawHeaderTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozi"; uint8_t http2_buf[] = "lla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\nContent-Type: text/html\r\n" "Content-Length: 67\r\n" "\r\n" "This is dummy message body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"Mozilla\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ( (PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectHttpRawHeaderTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n"; uint8_t http2_buf[] = "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 67\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"Gecko/20091221 Firefox/3.5.7\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content, against a cross boundary present pattern. */ static int DetectHttpRawHeaderTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n"; uint8_t http2_buf[] = "Content-Type: text/html\r\n" "Content-Length: 67\r\n" "\r\n" "This is dummy body\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"Firefox/3.5.7|0D 0A|Content\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_header content matches against a http request * against a case insensitive pattern. */ static int DetectHttpRawHeaderTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n"; uint8_t http2_buf[] = "Content-Type: text/html\r\n" "Content-Length: 67\r\n" "\r\n" "This is dummy body"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"firefox/3.5.7|0D 0A|content\"; nocase; http_raw_header;" "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the negated http_header content matches against a * http request which doesn't hold the content. */ static int DetectHttpRawHeaderTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:!\"lalalalala\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Negative test that the negated http_header content matches against a * http request which holds hold the content. */ static int DetectHttpRawHeaderTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:!\"User-Agent: Mozilla/5.0 \"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectHttpRawHeaderTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 100\r\n" "\r\n" "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; flow:to_server; " "content:\"Host: www.openinfosecfoundation.org\"; http_raw_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } int DetectHttpRawHeaderTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; content:\"one\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (cd->id == hrhd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (cd->id == hrhd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; content:\"one\"; content:\"one\"; http_raw_header; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (cd->id != 0 || hrhd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (cd->id != 1 || hrhd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; " "content:\"one\"; content:\"one\"; http_raw_header; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; DetectContentData *hrhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (cd->id != 1 || hrhd1->id != 0 || hrhd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; " "content:\"one\"; content:\"one\"; http_raw_header; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; DetectContentData *hrhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; if (cd->id != 2 || hrhd1->id != 0 || hrhd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; " "content:\"two\"; distance:0; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } DetectContentData *hrhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; DetectContentData *hrhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (hrhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hrhd1->content, "one", hrhd1->content_len) != 0 || hrhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hrhd2->content, "two", hrhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; " "content:\"two\"; within:5; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } DetectContentData *hrhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; DetectContentData *hrhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (hrhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hrhd1->content, "one", hrhd1->content_len) != 0 || hrhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hrhd2->content, "two", hrhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; within:5; http_raw_header; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; http_raw_header; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; pcre:/one/D; " "content:\"two\"; within:5; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_RAW_HEADER) || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; content:\"two\"; http_raw_header; " "pcre:/one/DR; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_PCRE || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_CONTENT) { goto end; } DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_RAW_HEADER) || hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "two", hhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawHeaderTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(flow:to_server; pcre:/one/D; " "content:\"two\"; distance:5; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_RAW_HEADER) || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ void DetectHttpRawHeaderRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectHttpRawHeaderTest01", DetectHttpRawHeaderTest01, 1); UtRegisterTest("DetectHttpRawHeaderTest02", DetectHttpRawHeaderTest02, 1); UtRegisterTest("DetectHttpRawHeaderTest03", DetectHttpRawHeaderTest03, 1); UtRegisterTest("DetectHttpRawHeaderTest04", DetectHttpRawHeaderTest04, 1); UtRegisterTest("DetectHttpRawHeaderTest05", DetectHttpRawHeaderTest05, 1); UtRegisterTest("DetectHttpRawHeaderTest06", DetectHttpRawHeaderTest06, 1); UtRegisterTest("DetectHttpRawHeaderTest07", DetectHttpRawHeaderTest07, 1); UtRegisterTest("DetectHttpRawHeaderTest08", DetectHttpRawHeaderTest08, 1); UtRegisterTest("DetectHttpRawHeaderTest09", DetectHttpRawHeaderTest09, 1); UtRegisterTest("DetectHttpRawHeaderTest10", DetectHttpRawHeaderTest10, 1); UtRegisterTest("DetectHttpRawHeaderTest11", DetectHttpRawHeaderTest11, 1); UtRegisterTest("DetectHttpRawHeaderTest12", DetectHttpRawHeaderTest12, 1); UtRegisterTest("DetectHttpRawHeaderTest13", DetectHttpRawHeaderTest13, 1); UtRegisterTest("DetectHttpRawHeaderTest14", DetectHttpRawHeaderTest14, 1); UtRegisterTest("DetectHttpRawHeaderTest15", DetectHttpRawHeaderTest15, 1); UtRegisterTest("DetectHttpRawHeaderTest16", DetectHttpRawHeaderTest16, 1); UtRegisterTest("DetectHttpRawHeaderTest17", DetectHttpRawHeaderTest17, 1); UtRegisterTest("DetectHttpRawHeaderTest18", DetectHttpRawHeaderTest18, 1); UtRegisterTest("DetectHttpRawHeaderTest19", DetectHttpRawHeaderTest19, 1); UtRegisterTest("DetectHttpRawHeaderTest20", DetectHttpRawHeaderTest20, 1); UtRegisterTest("DetectHttpRawHeaderTest21", DetectHttpRawHeaderTest21, 1); UtRegisterTest("DetectHttpRawHeaderTest22", DetectHttpRawHeaderTest22, 1); UtRegisterTest("DetectHttpRawHeaderTest23", DetectHttpRawHeaderTest23, 1); UtRegisterTest("DetectHttpRawHeaderTest24", DetectHttpRawHeaderTest24, 1); UtRegisterTest("DetectHttpRawHeaderTest25", DetectHttpRawHeaderTest25, 1); UtRegisterTest("DetectHttpRawHeaderTest26", DetectHttpRawHeaderTest26, 1); UtRegisterTest("DetectHttpRawHeaderTest27", DetectHttpRawHeaderTest27, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-http-cookie.c0000644000000000000000000012673412253546156014702 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Gurvinder Singh * * Implements the http_cookie keyword */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-error.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "util-print.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-cookie.h" #include "stream-tcp.h" static int DetectHttpCookieSetup (DetectEngineCtx *, Signature *, char *); void DetectHttpCookieRegisterTests(void); void DetectHttpCookieFree(void *); /** * \brief Registration function for keyword: http_cookie */ void DetectHttpCookieRegister (void) { sigmatch_table[DETECT_AL_HTTP_COOKIE].name = "http_cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].desc = "content modifier to match only on the HTTP cookie-buffer"; sigmatch_table[DETECT_AL_HTTP_COOKIE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_COOKIE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_COOKIE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup; sigmatch_table[DETECT_AL_HTTP_COOKIE].Free = DetectHttpCookieFree; sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests; sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_PAYLOAD; } /** * \brief this function clears the memory of http_cookie modifier keyword * * \param ptr Pointer to the Detection Cookie data */ void DetectHttpCookieFree(void *ptr) { DetectContentData *hcd = (DetectContentData *)ptr; if (hcd == NULL) return; if (hcd->content != NULL) SCFree(hcd->content); SCFree(hcd); } /** * \brief this function setups the http_cookie modifier keyword used in the rule * * \param de_ctx Pointer to the Detection Engine Context * \param s Pointer to the Signature to which the current keyword belongs * \param str Should hold an empty string always * * \retval 0 On success * \retval -1 On failure */ static int DetectHttpCookieSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (str != NULL && strcmp(str, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_cookie shouldn't be supplied " "with an argument"); return -1; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { SCLogError(SC_ERR_HTTP_COOKIE_NEEDS_PRECEEDING_CONTENT, "http_cookie " "found inside the rule, without any preceding content keywords"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (sm == NULL) { SCLogWarning(SC_ERR_HTTP_COOKIE_NEEDS_PRECEEDING_CONTENT, "http_cookie " "found inside the rule, without a content context. Please use a " "content keyword before using http_cookie"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_cookie should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_HTTP_COOKIE_INCOMPATIBLE_WITH_RAWBYTES, "http_cookie " "rule can not be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains keywords" "that conflict with http_cookie"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); if (pm != NULL) { /* pm is never NULL. So no NULL check */ if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* please note. reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_HTTP_COOKIE_RELATIVE_MISSING, "http_cookie with " "a distance or within requires preceding http_cookie " "content, but none was found"); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HCDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hcdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HCDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } /******************************** UNITESTS **********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Checks if a http_cookie is registered in a Signature, if content is not * specified in the signature */ int DetectHttpCookieTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_cookie\"; http_cookie;sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature, if some parameter * is specified with http_cookie in the signature */ int DetectHttpCookieTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"me\"; " "http_cookie:woo; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature */ int DetectHttpCookieTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"one\"; " "http_cookie; content:\"two\"; http_cookie; " "content:\"two\"; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; } while (sm != NULL) { if (sm->type == DETECT_CONTENT) { result = 1; } else { printf("expected DETECT_CONTENT for http_cookie, got %d: ", sm->type); goto end; } sm = sm->next; } end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature, when fast_pattern * is also specified in the signature (now it should) */ int DetectHttpCookieTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"one\"; " "fast_pattern; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature, when rawbytes is * also specified in the signature */ int DetectHttpCookieTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"one\"; " "rawbytes; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_cookie is registered in a Signature, when rawbytes is * also specified in the signature */ int DetectHttpCookieTest06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_cookie\"; content:\"one\"; " "http_cookie; uricontent:\"abc\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; Signature *s = de_ctx->sig_list; BUG_ON(s->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL); if (s->sm_lists[DETECT_SM_LIST_HCDMATCH]->type != DETECT_CONTENT) goto end; if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("expected another SigMatch, got NULL: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_UMATCH]->type != DETECT_CONTENT) { goto end; } result = 1; end: if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } return result; } int DetectHttpCookieTest07(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"one\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (cd->id == hcd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest08(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (cd->id == hcd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest09(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_cookie; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (cd->id != 0 || hcd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest10(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if (cd->id != 1 || hcd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest11(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; " "content:\"one\"; content:\"one\"; http_cookie; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; DetectContentData *hcd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (cd->id != 1 || hcd1->id != 0 || hcd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpCookieTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; " "content:\"one\"; content:\"one\"; http_cookie; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; DetectContentData *hcd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; if (cd->id != 2 || hcd1->id != 0 || hcd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** \test Check the signature working to alert when http_cookie is matched . */ static int DetectHttpCookieSigTest01(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\nCookie:" " hellocatchme\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:\"me\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " "cookie\"; content:\"go\"; http_cookie; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sid 2 matched but shouldn't: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest02(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:\"me\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest03(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:\"boo\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest04(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:!\"boo\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest05(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: DuMmY\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:\"dummy\"; nocase; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest06(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: DuMmY\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:\"dummy\"; " "http_cookie; nocase; sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 failed to match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_cookie is not present */ static int DetectHttpCookieSigTest07(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; content:!\"dummy\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Check the signature working to alert against set-cookie */ static int DetectHttpCookieSigTest08(void) { int result = 0; Flow f; uint8_t httpbuf_request[] = "GET / HTTP/1.1\r\n" "User-Agent: Mozilla/1.0\r\n" "\r\n"; uint32_t httpbuf_request_len = sizeof(httpbuf_request) - 1; /* minus the \0 */ uint8_t httpbuf_response[] = "HTTP/1.1 200 OK\r\n" "Set-Cookie: response_user_agent\r\n" "\r\n"; uint32_t httpbuf_response_len = sizeof(httpbuf_response) - 1; /* minus the \0 */ TcpSession ssn; Packet *p1 = NULL, *p2 = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_HTTP; p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(flow:to_client; content:\"response_user_agent\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request */ int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf_request, httpbuf_request_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { goto end; } /* response */ r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf_response, httpbuf_response_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** * \test Check the signature working to alert against cookie/set-cookie */ static int DetectHttpCookieSigTest09(void) { int result = 0; Flow f; uint8_t httpbuf_request[] = "GET / HTTP/1.1\r\n" "Cookie: request_user_agent\r\n" "User-Agent: Mozilla/1.0\r\n" "\r\n"; uint32_t httpbuf_request_len = sizeof(httpbuf_request) - 1; /* minus the \0 */ uint8_t httpbuf_response[] = "HTTP/1.1 200 OK\r\n" "Set-Cookie: response_user_agent\r\n" "\r\n"; uint32_t httpbuf_response_len = sizeof(httpbuf_response) - 1; /* minus the \0 */ TcpSession ssn; Packet *p1 = NULL, *p2 = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_HTTP; p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(flow:to_server; content:\"request_user_agent\"; " "http_cookie; sid:1;)"); if (s == NULL) { goto end; } s = de_ctx->sig_list->next = SigInit(de_ctx,"alert http any any -> any any " "(flow:to_client; content:\"response_user_agent\"; " "http_cookie; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request */ int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf_request, httpbuf_request_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!PacketAlertCheck(p1, 1) || PacketAlertCheck(p1, 2)) { goto end; } /* response */ r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf_response, httpbuf_response_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1) || !PacketAlertCheck(p2, 2)) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } #endif /* UNITTESTS */ /** * \brief Register the UNITTESTS for the http_cookie keyword */ void DetectHttpCookieRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectHttpCookieTest01", DetectHttpCookieTest01, 1); UtRegisterTest("DetectHttpCookieTest02", DetectHttpCookieTest02, 1); UtRegisterTest("DetectHttpCookieTest03", DetectHttpCookieTest03, 1); UtRegisterTest("DetectHttpCookieTest04", DetectHttpCookieTest04, 1); UtRegisterTest("DetectHttpCookieTest05", DetectHttpCookieTest05, 1); UtRegisterTest("DetectHttpCookieTest06", DetectHttpCookieTest06, 1); UtRegisterTest("DetectHttpCookieTest07", DetectHttpCookieTest07, 1); UtRegisterTest("DetectHttpCookieTest08", DetectHttpCookieTest08, 1); UtRegisterTest("DetectHttpCookieTest09", DetectHttpCookieTest09, 1); UtRegisterTest("DetectHttpCookieTest10", DetectHttpCookieTest10, 1); UtRegisterTest("DetectHttpCookieTest11", DetectHttpCookieTest11, 1); UtRegisterTest("DetectHttpCookieTest12", DetectHttpCookieTest12, 1); UtRegisterTest("DetectHttpCookieSigTest01", DetectHttpCookieSigTest01, 1); UtRegisterTest("DetectHttpCookieSigTest02", DetectHttpCookieSigTest02, 1); UtRegisterTest("DetectHttpCookieSigTest03", DetectHttpCookieSigTest03, 1); UtRegisterTest("DetectHttpCookieSigTest04", DetectHttpCookieSigTest04, 1); UtRegisterTest("DetectHttpCookieSigTest05", DetectHttpCookieSigTest05, 1); UtRegisterTest("DetectHttpCookieSigTest06", DetectHttpCookieSigTest06, 1); UtRegisterTest("DetectHttpCookieSigTest07", DetectHttpCookieSigTest07, 1); UtRegisterTest("DetectHttpCookieSigTest08", DetectHttpCookieSigTest08, 1); UtRegisterTest("DetectHttpCookieSigTest09", DetectHttpCookieSigTest09, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/util-decode-asn1.c0000644000000000000000000005564312253546156014244 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * Implements ASN1 decoding (needed for the asn1 keyword, BER, CER & DER) */ #include "suricata.h" #include "suricata-common.h" #include "decode.h" #include "util-debug.h" #include "util-unittest.h" #include "util-print.h" #include "util-decode-asn1.h" #include "conf.h" uint16_t asn1_max_frames_config = ASN1_MAX_FRAMES; void SCAsn1LoadConfig() { intmax_t value = 0; /** set config defaults */ if ((ConfGetInt("asn1-max-frames", &value)) == 1) { asn1_max_frames_config = (uint16_t)value; SCLogDebug("Max stack frame set to %"PRIu16, asn1_max_frames_config); } } /** * \brief Decode and check the identifier information of the * current node that is in extended format * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint8_t SCAsn1GetHighTagNumber(Asn1Ctx *ac) { uint8_t ret = 0; uint32_t tag_num = 0; /* If we have a high tag num, skip the id octet */ ac->iter++; Asn1Node *node = ASN1CTX_CUR_NODE(ac); ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ret; } uint8_t raw_id = *ac->iter; tag_num += ASN1_BER_GET_HIGH_TAG_NUM(raw_id); if (ASN1_BER_GET_HIGH_TAG_NUM(raw_id) == 0) { /* Set event, invalid id */ node->flags |= ASN1_BER_EVENT_INVALID_ID; ac->parser_status |= ASN1_STATUS_INVALID; return ASN1_PARSER_ERR; } ac->iter++; if (!ASN1_BER_IS_HIGH_TAG_END(raw_id)) { do { ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ret; } raw_id = *ac->iter; if ((uint64_t) ((uint64_t)tag_num + (uint64_t)ASN1_BER_GET_HIGH_TAG_NUM(raw_id)) > UINT32_MAX) { node->flags |= ASN1_BER_EVENT_ID_TOO_LONG; ac->parser_status |= ASN1_STATUS_INVALID; return ASN1_PARSER_ERR; } tag_num += ASN1_BER_GET_HIGH_TAG_NUM(raw_id); ac->iter++; } while (!ASN1_BER_IS_HIGH_TAG_END(raw_id)); } node->id.tag_num = tag_num; return ASN1_PARSER_OK; } /** * \brief Decode and check the length, of the current node * in definite but extended format, that we are parsing, * checking invalid opts * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint32_t SCAsn1GetLengthLongForm(Asn1Ctx *ac) { uint8_t raw_len = *ac->iter; uint8_t ret = 0; uint32_t content_len = 0; uint8_t oct_len = ASN1_BER_GET_LONG_LEN_OCTETS(raw_len); uint8_t i = 0; Asn1Node *node = ASN1CTX_CUR_NODE(ac); for (; i < oct_len; i++) { ac->iter++; ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ASN1_PARSER_ERR; } raw_len = *ac->iter; if (raw_len == 0xFF && ac->iter == node->len.ptr + 1) { /* 8.1.3.5, 0xFF shall not be used */ node->flags |= ASN1_BER_EVENT_INVALID_LEN; ac->parser_status = ASN1_STATUS_INVALID; return ASN1_PARSER_ERR; } if ((uint64_t) ((uint64_t)content_len + (uint64_t) ASN1_BER_GET_HIGH_TAG_NUM(raw_len)) > UINT32_MAX) { node->flags |= ASN1_BER_EVENT_LEN_TOO_LONG; ac->parser_status = ASN1_STATUS_INVALID; return ASN1_PARSER_ERR; } content_len += raw_len; } ac->iter++; node->len.len = content_len; return ASN1_PARSER_OK; } /** * \brief Check the content length and perform other inspections * and decodings if necessary * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint8_t SCAsn1DecodeContent(Asn1Ctx *ac) { Asn1Node *node = ASN1CTX_CUR_NODE(ac); /* Uops, if we are done, we break here */ if (node->flags & ASN1_NODE_IS_EOC) return ASN1_PARSER_OK; /* First check the form of length (BER, DER, CER) * and if we are on a zero length */ if (node->len.form != ASN1_BER_LEN_INDEFINITE && node->len.len == 0) { node->data.len = 0; return ASN1_PARSER_OK; } node->data.ptr = ac->iter; /* If we have a complete length, check that * it is in bounds */ if (ac->iter + node->len.len > ac->end) { /* We do not have all the content octets! */ node->data.len = ac->end - ac->iter; } else { /* We have all the content octets */ node->data.len = node->len.len; } return ASN1_PARSER_OK; } /** * \brief Decode and check the length, of the current node * that we are parsing, also check invalid opts * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint8_t SCAsn1DecodeLength(Asn1Ctx *ac) { uint8_t ret = 0; ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ASN1_PARSER_ERR; } Asn1Node *node = ASN1CTX_CUR_NODE(ac); /* Store the position */ node->len.ptr = ac->iter; uint8_t len_byte = *ac->iter; //SCPrintByteBin(len_byte); if (*node->id.ptr == 0 && len_byte == 0) { node->flags |= ASN1_NODE_IS_EOC; ac->iter++; return ASN1_PARSER_OK; } if (ASN1_BER_IS_INDEFINITE_LEN(len_byte)) { node->len.form = ASN1_BER_LEN_INDEFINITE; node->len.len = 0; ac->iter++; uint8_t *tmp_iter = ac->iter; /* Check that e-o-c is in bounds */ for (; tmp_iter < ac->end - 1; tmp_iter++) { if (ASN1_BER_IS_EOC(tmp_iter)) { node->data.len = tmp_iter - ac->iter; node->len.len = tmp_iter - ac->iter; return ASN1_PARSER_OK; } } /* EOC Not found */ ac->parser_status |= ASN1_STATUS_INVALID; node->flags |= ASN1_BER_EVENT_EOC_NOT_FOUND; return ASN1_PARSER_ERR; } else { /* Look which form we get (and if it apply to the id type) */ if (ASN1_BER_IS_SHORT_LEN(len_byte)) { node->len.form = ASN1_BER_LEN_SHORT; node->len.len = ASN1_BER_GET_SHORT_LEN(len_byte); ac->iter++; } else { node->len.form = ASN1_BER_LEN_LONG; /* Ok, let's parse the long form */ return SCAsn1GetLengthLongForm(ac); } } return ASN1_PARSER_OK; } /** * \brief Decode and check the identifier information of the * current node that we are parsing, also check invalid opts * * \param ac pointer to the ASN1 Context data * * \retval byte of the status of the parser */ uint8_t SCAsn1DecodeIdentifier(Asn1Ctx *ac) { uint8_t ret = 0; ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB; return ret; } Asn1Node *node = ASN1CTX_CUR_NODE(ac); /* Store the position */ node->id.ptr = ac->iter; //SCPrintByteBin(*ac->iter); node->id.class_tag = ASN1_BER_GET_CLASS_TAG(*ac->iter); node->id.tag_type = ASN1_BER_IS_CONSTRUCTED(*ac->iter); if (ASN1_BER_IS_HIGH_TAG(*ac->iter)) { return SCAsn1GetHighTagNumber(ac); } else { node->id.tag_num = ASN1_BER_GET_LOW_TAG_NUM(*ac->iter); ac->iter++; } return ASN1_PARSER_OK; } /** * \brief Helper function that print the bits of a byte * to check encoding internals * \param byte value of the byte */ void SCPrintByteBin(uint8_t byte) { uint8_t i = 0; for (i = 8; i > 0; i--) { printf("%"PRIu8, ((byte >> (i - 1)) & 0x01)); if (i == 5) printf(" "); } printf("\n"); } /** * \brief check if we have remaining data available, * otherwise the parser should stop * \param ac Asn1Ctx pointer initialized * \retval 1 if we are out of bounds, 0 if not */ uint8_t SCAsn1CheckBounds(Asn1Ctx *ac) { return (ac->iter < ac->end && ac->iter >= ac->data)? ASN1_PARSER_OK : ASN1_PARSER_ERR; } /** * \brief Create a new ASN1 Parsing context * * \retval Asn1Ctx pointer to the new ctx */ Asn1Ctx *SCAsn1CtxNew(void) { Asn1Ctx *ac = SCMalloc(sizeof(Asn1Ctx)); if (unlikely(ac == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); return NULL; } memset(ac, 0, sizeof(Asn1Ctx)); ac->asn1_stack = SCMalloc(sizeof(Asn1Node *) * asn1_max_frames_config); if (ac->asn1_stack == NULL) { SCFree(ac); return NULL; } memset(ac->asn1_stack, 0, sizeof(Asn1Node *) * asn1_max_frames_config); return ac; } /** * \brief Destroy an ASN1 Parsing context * * \param Asn1Ctx pointer to the new ctx */ void SCAsn1CtxDestroy(Asn1Ctx *ac) { if (ac == NULL) return; uint16_t i = 0; for (; i < ac->cur_frame; i++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, i); if (node != NULL) { SCFree(node); } } SCFree(ac); } /** * \brief Create a new node at the array stack of frames in the ctx * * \param ac pointer to the ASN1 ctx * \param node index of the frame that we are going to allocate * at the asn1 stack in the parser * * \retval Asn1Node pointer to the new node allocated */ Asn1Node *SCAsn1CtxNewFrame(Asn1Ctx *ac, uint16_t node) { if (node >= asn1_max_frames_config) { return NULL; } if (ac->asn1_stack[node] == NULL) ac->asn1_stack[node] = SCMalloc(sizeof(Asn1Node)); if (ac->asn1_stack[node] == NULL) return NULL; memset(ac->asn1_stack[node], 0, sizeof(Asn1Node)); return ac->asn1_stack[node]; } /** * \brief Initialize the data of the ASN1 parser ctx with the asn1 raw buffer * * \param ac pointer to the ASN1 ctx * \param data pointer to the data to process (binary raw of asn1) * \param length length of the asn1 raw buffer * * \retval void */ void SCAsn1CtxInit(Asn1Ctx *ac, uint8_t *data, uint16_t length) { ac->data = data; ac->iter = data; ac->len = length; ac->end = data + length; ac->parser_status = ASN1_STATUS_OK; } /** * \brief Decode the nodes/frames located at certain position/level * * \param ac pointer to the ASN1 ctx * \param node_id node index at the asn1 stack of the ctx * * \retval byte of parser status */ uint8_t SCAsn1Decode(Asn1Ctx *ac, uint16_t node_id) { Asn1Node *node = NULL; uint8_t ret = 0; /* while remaining data, and no fatal error, or end, or max stack frames */ while (ac->iter < ac->end && !(ac->parser_status & ASN1_STATUS_DONE) && ac->cur_frame < asn1_max_frames_config) { /* Prepare a new frame */ if (SCAsn1CtxNewFrame(ac, node_id) == NULL) break; ac->cur_frame = node_id; node = ASN1CTX_GET_NODE(ac, node_id); SCLogDebug("ASN1 Getting ID, cur:%x remaining %"PRIu32, (uint8_t)*ac->iter, (uint32_t)(ac->end - ac->iter)); /* Get identifier/tag */ ret = SCAsn1DecodeIdentifier(ac); if (ret == ASN1_PARSER_ERR) { SCLogDebug("Error parsing identifier"); node->flags |= ASN1_BER_EVENT_INVALID_ID; ac->ctx_flags |= node->flags; break; } SCLogDebug("ASN1 Getting LEN"); /* Get length of content */ ret = SCAsn1DecodeLength(ac); if (ret == ASN1_PARSER_ERR) { SCLogDebug("Error parsing length"); node->flags |= ASN1_BER_EVENT_INVALID_LEN; ac->ctx_flags |= node->flags; break; } if ( !(node->flags & ASN1_NODE_IS_EOC)) { SCLogDebug("ASN1 Getting CONTENT"); /* Inspect content */ ret = SCAsn1DecodeContent(ac); if (ret == ASN1_PARSER_ERR) { SCLogDebug("Error parsing content"); break; } /* Skip to the next record (if any) */ if (node->id.tag_type != ASN1_TAG_TYPE_CONSTRUCTED) /* Is primitive, skip it all (no need to decode it)*/ ac->iter += node->data.len; } /* Check if we are done with data */ ret = SCAsn1CheckBounds(ac); if (ret == ASN1_PARSER_ERR) { ac->parser_status |= ASN1_STATUS_DONE; /* There's no more data available */ ret = ASN1_PARSER_OK; break; } #if 0 printf("Tag Num: %"PRIu32", Tag Type: %"PRIu8", Class:%"PRIu8", Length: %"PRIu32"\n", node->id.tag_num, node->id.tag_type, node->id.class_tag, node->len.len); printf("Data: \n"); PrintRawDataFp(stdout, node->data.ptr, node->len.len); printf(" -- EOD --\n"); #endif /* Stack flags/events here, so we have the resume at the ctx flags */ ac->ctx_flags |= node->flags; /* Check if it's not a primitive type, * then we need to decode contents */ if (node->id.tag_type == ASN1_TAG_TYPE_CONSTRUCTED) { ret = SCAsn1Decode(ac, node_id + 1); } /* Else we have reached a primitive type and stop the recursion, * look if we have other branches at the same level */ /* But first check if it's a constructed node, and the sum of child * lengths was more than the length of this frame * this would mean that we have an overflow at the attributes */ if (ac->iter > node->data.ptr + node->data.len + 1) { /* We decoded more length on this frame */ } node_id = ac->cur_frame + 1; } return ret; } /* ----------------------- Unit tests ------------------------ */ #ifdef UNITTESTS /** * \test Check we handle extended identifiers correctly */ int DecodeAsn1Test01(void) { uint8_t *str = (uint8_t *) "\x3F\x84\x06"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 3; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if (node->id.tag_num != 10) { ret = 0; printf("Error, expected tag_num 10, got %"PRIu32" :", node->id.tag_num); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Check we handle extended identifiers correctly */ int DecodeAsn1Test02(void) { uint8_t *str = (uint8_t *) "\x3F\x81\x81\x81\x81\x06"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 6; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if (node->id.tag_num != 10) { ret = 0; printf("Error, expected tag_num 10, got %"PRIu32": ", node->id.tag_num); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Check we handle short identifiers correctly */ int DecodeAsn1Test03(void) { uint8_t *str = (uint8_t *) "\x28"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 1; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if (node->id.tag_num != 8) { ret = 0; printf("Error, expected tag_num 10, got %"PRIu32": ", node->id.tag_num); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Check we handle extended lengths correctly with indefinite form */ int DecodeAsn1Test04(void) { uint8_t *str = (uint8_t *) "\x3F\x84\x06\x80\x12\x12\x12\x00\x00"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 9; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if (node->len.len != 3) { ret = 0; printf("Error, expected length 3, got %"PRIu32": ", node->len.len); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Check we handle extended lengths correctly * in the definite form */ int DecodeAsn1Test05(void) { uint8_t *str = (uint8_t *) "\x3F\x84\x06\x82\x10\x10"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 6; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if (node->len.len!= 32) { ret = 0; printf("Error, expected length 10, got %"PRIu32": ", node->len.len); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Check we handle short lengths correctly */ int DecodeAsn1Test06(void) { uint8_t *str = (uint8_t *) "\x3F\x84\x06\x26"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 4; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if (node->len.len != 38) { ret = 0; printf("Error, expected length 10, got %"PRIu32": ", node->len.len); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Check we handle events correctly */ int DecodeAsn1Test07(void) { uint8_t *str = (uint8_t *) "\x3F\x00\x84\x06"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 4; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if ( !(ac->ctx_flags & ASN1_BER_EVENT_INVALID_ID) || !(node->flags & ASN1_BER_EVENT_INVALID_ID)) { ret = 0; printf("Error, expected invalid id, got flags %"PRIu8": ", ac->ctx_flags); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Check we handle events correctly */ int DecodeAsn1Test08(void) { uint8_t *str = (uint8_t *) "\x3F\x84\x06\x81\xFF"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 5; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if ( !(ac->ctx_flags & ASN1_BER_EVENT_INVALID_LEN) || !(node->flags & ASN1_BER_EVENT_INVALID_LEN)) { ret = 0; printf("Error, expected invalid length, got flags %"PRIu8": ", ac->ctx_flags); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Check we handle events correctly */ int DecodeAsn1Test09(void) { uint8_t *str = (uint8_t *) "\x3F\x84\x06\x80\xAB\xCD\xEF"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = 7; SCAsn1CtxInit(ac, str, len); SCAsn1Decode(ac, ac->cur_frame); Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if ( !(ac->ctx_flags & ASN1_BER_EVENT_EOC_NOT_FOUND) || !(node->flags & ASN1_BER_EVENT_EOC_NOT_FOUND)) { ret = 0; printf("Error, expected eoc not found, got flags %"PRIu8": ", ac->ctx_flags); goto end; } end: SCAsn1CtxDestroy(ac); return ret; } /** * \test Decode a big chunk of data */ int DecodeAsn1Test10(void) { // Example from the specification X.690-0207 Appendix A.3 uint8_t *str = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" "Jones""\xA0\x0A\x43\x08""19590717" "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones" "\xA0\x0A\x43\x08""19590717"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) return 0; uint8_t ret = 1; uint16_t len = strlen((char *)str)-1; SCAsn1CtxInit(ac, str, len); ret = SCAsn1Decode(ac, ac->cur_frame); /* General checks */ if (ret != ASN1_PARSER_OK) { printf("Error decoding asn1 data: "); ret = 0; goto end; } if (ac->cur_frame != 59) { printf("Error decoding asn1 data, not all the nodes" "were correctly decoded: "); ret = 0; goto end; } if (ac->iter != ac->end) { printf("Error decoding asn1 data, not all the nodes" "were correctly decoded: "); ret = 0; goto end; } Asn1Node *node = ASN1CTX_GET_NODE(ac, 0); if (node->len.len != 133) { printf("Error decoding asn1 data, not all the nodes" "were correctly decoded: "); ret = 0; goto end; } node = ASN1CTX_GET_NODE(ac, 30); if (node->len.len != 133) { printf("Error decoding asn1 data, not all the nodes" "were correctly decoded: "); ret = 0; goto end; } end: SCAsn1CtxDestroy(ac); return ret; } #endif void DecodeAsn1RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeAsn1Test01", DecodeAsn1Test01, 1); UtRegisterTest("DecodeAsn1Test02", DecodeAsn1Test02, 1); UtRegisterTest("DecodeAsn1Test03", DecodeAsn1Test03, 1); UtRegisterTest("DecodeAsn1Test04", DecodeAsn1Test04, 1); UtRegisterTest("DecodeAsn1Test05", DecodeAsn1Test05, 1); UtRegisterTest("DecodeAsn1Test06", DecodeAsn1Test06, 1); UtRegisterTest("DecodeAsn1Test07", DecodeAsn1Test07, 1); UtRegisterTest("DecodeAsn1Test08", DecodeAsn1Test08, 1); UtRegisterTest("DecodeAsn1Test09", DecodeAsn1Test09, 1); UtRegisterTest("DecodeAsn1Test10", DecodeAsn1Test10, 1); #endif } suricata-1.4.7/src/reputation.h0000644000000000000000000001073412253546156013375 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * \author Victor Julien * Original Idea by Matt Jonkman */ #ifndef __REPUTATION_H__ #define __REPUTATION_H__ #include "detect.h" #include "host.h" #define SREP_MAX_CATS 60 typedef struct SReputation_ { uint32_t version; uint8_t rep[SREP_MAX_CATS]; } SReputation; uint8_t SRepCatGetByShortname(char *shortname); int SRepInit(DetectEngineCtx *de_ctx); void SRepReloadComplete(void); int SRepHostTimedOut(Host *); /** Reputation numbers (types) that we can use to lookup/update, etc * Please, dont convert this to a enum since we want the same reputation * codes always. */ #define REPUTATION_SPAM 0 /**< spammer */ #define REPUTATION_CNC 1 /**< CnC server */ #define REPUTATION_SCAN 2 /**< scanner */ #define REPUTATION_HOSTILE 3 /**< hijacked nets, RBN nets, etc */ #define REPUTATION_DYNAMIC 4 /**< Known dial up, residential, user networks */ #define REPUTATION_PUBLICACCESS 5 /**< known internet cafe's open access points */ #define REPUTATION_PROXY 6 /**< known tor out nodes, proxy servers, etc */ #define REPUTATION_P2P 7 /**< Heavy p2p node, torrent server, other sharing services */ #define REPUTATION_UTILITY 8 /**< known good places like google, yahoo, msn.com, etc */ #define REPUTATION_DDOS 9 /**< Known ddos participant */ #define REPUTATION_PHISH 10 /**< Known Phishing site */ #define REPUTATION_MALWARE 11 /**< Known Malware distribution site. Hacked web server, etc */ #define REPUTATION_ZOMBIE 12 /**< Known Zombie (botnet member) They typically are Scanner or Hostile, but if collaboration with botnet snooping, like we did back in 2005 or so, can proactively identify online zombies that joined a botnet, you may want to break those out separately */ #define REPUTATION_NUMBER 13 /**< number of rep types we have for data structure size (be careful with this) */ /* Flags for reputation */ #define REPUTATION_FLAG_NEEDSYNC 0x01 /**< rep was changed by engine, needs sync with external hub */ /** Reputation Context for IPV4 IPV6 */ typedef struct IPReputationCtx_ { /** Radix trees that holds the host reputation information */ SCRadixTree *reputationIPV4_tree; SCRadixTree *reputationIPV6_tree; /** Mutex to support concurrent access */ SCMutex reputationIPV4_lock; SCMutex reputationIPV6_lock; }IPReputationCtx; /** Reputation Data */ //TODO: Add a timestamp here to know the last update of this reputation. typedef struct Reputation_ { uint8_t reps[REPUTATION_NUMBER]; /**< array of 8 bit reputations */ uint8_t flags; /**< reputation flags */ time_t ctime; /**< creation time (epoch) */ time_t mtime; /**< modification time (epoch) */ } Reputation; /* flags for transactions */ #define TRANSACTION_FLAG_NEEDSYNC 0x01 /**< We will apply the transaction only if necesary */ #define TRANSACTION_FLAG_INCS 0x02 /**< We will increment only if necesary */ #define TRANSACTION_FLAG_DECS 0x03 /**< We will decrement only if necesary */ /* transaction for feedback */ typedef struct ReputationTransaction_ { uint16_t inc[REPUTATION_NUMBER]; uint16_t dec[REPUTATION_NUMBER]; uint8_t flags; } ReputationTransaction; /* API */ Reputation *SCReputationAllocData(); Reputation *SCReputationClone(Reputation *); void SCReputationFreeData(void *); IPReputationCtx *SCReputationInitCtx(void); void SCReputationFreeCtx(IPReputationCtx *); void SCReputationPrint(Reputation *); void SCReputationRegisterTests(void); #endif /* __REPUTATION_H__ */ suricata-1.4.7/src/detect-reference.h0000644000000000000000000000274712253546156014414 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DETECT_REFERENCE_H__ #define __DETECT_REFERENCE_H__ #include "decode-events.h" #include "decode-ipv4.h" #include "decode-tcp.h" /** * \brief Signature reference list. */ typedef struct DetectReference_ { /* pointer to key */ char *key; /* reference data */ char *reference; /* next reference in the signature */ struct DetectReference_ *next; } DetectReference; /** * Registration function for Reference keyword */ void DetectReferenceRegister(void); /** * This function registers unit tests for Reference keyword. */ void ReferenceRegisterTests(void); /** * Free function for a Reference object */ void DetectReferenceFree(DetectReference *); #endif /*__DETECT_REFERENCE_H__ */ suricata-1.4.7/src/decode-raw.h0000644000000000000000000000161412253546156013212 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author William Metcalf */ #ifndef __DECODE_RAW_H__ #define __DECODE_RAW_H__ void DecodeRawRegisterTests(void); #endif /* __DECODE_RAW_H__ */ suricata-1.4.7/src/alert-syslog.h0000644000000000000000000000204312253546156013622 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * alert syslog modeule header file * */ #ifndef __ALERT_SYSLOG_H__ #define __ALERT_SYSLOG_H__ void TmModuleAlertSyslogRegister (void); void TmModuleAlertSyslogIPv4Register (void); void TmModuleAlertSyslogIPv6Register (void); #endif /* __ALERT_SYSLOG_H__ */ suricata-1.4.7/src/util-hashlist.c0000644000000000000000000003113712253546156013770 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Chained hash table implementation * * The 'Free' pointer can be used to have the API free your * hashed data. If it's NULL it's the callers responsebility */ #include "suricata-common.h" #include "util-hashlist.h" #include "util-unittest.h" #include "util-debug.h" #include "util-memcmp.h" HashListTable* HashListTableInit(uint32_t size, uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t), char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)) { HashListTable *ht = NULL; if (size == 0) { goto error; } if (Hash == NULL) { //printf("ERROR: HashListTableInit no Hash function\n"); goto error; } /* setup the filter */ ht = SCMalloc(sizeof(HashListTable)); if (unlikely(ht == NULL)) goto error; memset(ht,0,sizeof(HashListTable)); ht->array_size = size; ht->Hash = Hash; ht->Free = Free; if (Compare != NULL) ht->Compare = Compare; else ht->Compare = HashListTableDefaultCompare; /* setup the bitarray */ ht->array = SCMalloc(ht->array_size * sizeof(HashListTableBucket *)); if (ht->array == NULL) goto error; memset(ht->array,0,ht->array_size * sizeof(HashListTableBucket *)); ht->listhead = NULL; ht->listtail = NULL; return ht; error: if (ht != NULL) { if (ht->array != NULL) SCFree(ht->array); SCFree(ht); } return NULL; } void HashListTableFree(HashListTable *ht) { uint32_t i = 0; if (ht == NULL) return; /* free the buckets */ for (i = 0; i < ht->array_size; i++) { HashListTableBucket *hashbucket = ht->array[i]; while (hashbucket != NULL) { HashListTableBucket *next_hashbucket = hashbucket->bucknext; if (ht->Free != NULL) ht->Free(hashbucket->data); SCFree(hashbucket); hashbucket = next_hashbucket; } } /* free the array */ if (ht->array != NULL) SCFree(ht->array); SCFree(ht); } void HashListTablePrint(HashListTable *ht) { printf("\n----------- Hash Table Stats ------------\n"); printf("Buckets: %" PRIu32 "\n", ht->array_size); printf("Hash function pointer: %p\n", ht->Hash); printf("-----------------------------------------\n"); } int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen) { if (ht == NULL || data == NULL) return -1; uint32_t hash = ht->Hash(ht, data, datalen); SCLogDebug("ht %p hash %"PRIu32"", ht, hash); HashListTableBucket *hb = SCMalloc(sizeof(HashListTableBucket)); if (unlikely(hb == NULL)) goto error; memset(hb, 0, sizeof(HashListTableBucket)); hb->data = data; hb->size = datalen; hb->bucknext = NULL; hb->listnext = NULL; hb->listprev = NULL; if (ht->array[hash] == NULL) { ht->array[hash] = hb; } else { hb->bucknext = ht->array[hash]; ht->array[hash] = hb; } if (ht->listtail == NULL) { ht->listhead = hb; ht->listtail = hb; } else { hb->listprev = ht->listtail; ht->listtail->listnext = hb; ht->listtail = hb; } return 0; error: return -1; } int HashListTableRemove(HashListTable *ht, void *data, uint16_t datalen) { uint32_t hash = ht->Hash(ht, data, datalen); SCLogDebug("ht %p hash %"PRIu32"", ht, hash); if (ht->array[hash] == NULL) { SCLogDebug("ht->array[hash] NULL"); return -1; } /* fast track for just one data part */ if (ht->array[hash]->bucknext == NULL) { HashListTableBucket *hb = ht->array[hash]; if (ht->Compare(hb->data,hb->size,data,datalen) == 1) { /* remove from the list */ if (hb->listprev == NULL) { ht->listhead = hb->listnext; } else { hb->listprev->listnext = hb->listnext; } if (hb->listnext == NULL) { ht->listtail = hb->listprev; } else { hb->listnext->listprev = hb->listprev; } if (ht->Free != NULL) ht->Free(hb->data); SCFree(ht->array[hash]); ht->array[hash] = NULL; return 0; } SCLogDebug("fast track default case"); return -1; } /* more data in this bucket */ HashListTableBucket *hashbucket = ht->array[hash], *prev_hashbucket = NULL; do { if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1) { /* remove from the list */ if (hashbucket->listprev == NULL) { ht->listhead = hashbucket->listnext; } else { hashbucket->listprev->listnext = hashbucket->listnext; } if (hashbucket->listnext == NULL) { ht->listtail = hashbucket->listprev; } else { hashbucket->listnext->listprev = hashbucket->listprev; } if (prev_hashbucket == NULL) { /* root bucket */ ht->array[hash] = hashbucket->bucknext; } else { /* child bucket */ prev_hashbucket->bucknext = hashbucket->bucknext; } /* remove this */ if (ht->Free != NULL) ht->Free(hashbucket->data); SCFree(hashbucket); return 0; } prev_hashbucket = hashbucket; hashbucket = hashbucket->bucknext; } while (hashbucket != NULL); SCLogDebug("slow track default case"); return -1; } char HashListTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2) { if (len1 != len2) return 0; if (SCMemcmp(data1,data2,len1) != 0) return 0; return 1; } void *HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen) { if (ht == NULL) { SCLogDebug("Hash List table is NULL"); return NULL; } uint32_t hash = ht->Hash(ht, data, datalen); if (ht->array[hash] == NULL) { return NULL; } HashListTableBucket *hashbucket = ht->array[hash]; do { if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1) return hashbucket->data; hashbucket = hashbucket->bucknext; } while (hashbucket != NULL); return NULL; } uint32_t HashListTableGenericHash(HashListTable *ht, void *data, uint16_t datalen) { uint8_t *d = (uint8_t *)data; uint32_t i; uint32_t hash = 0; for (i = 0; i < datalen; i++) { if (i == 0) hash += (((uint32_t)*d++)); else if (i == 1) hash += (((uint32_t)*d++) * datalen); else hash *= (((uint32_t)*d++) * i) + datalen + i; } hash *= datalen; hash %= ht->array_size; return hash; } HashListTableBucket *HashListTableGetListHead(HashListTable *ht) { return ht->listhead; } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS static int HashListTableTestInit01 (void) { HashListTable *ht = HashListTableInit(1024, HashListTableGenericHash, NULL, NULL); if (ht == NULL) return 0; HashListTableFree(ht); return 1; } /* no hash function, so it should fail */ static int HashListTableTestInit02 (void) { HashListTable *ht = HashListTableInit(1024, NULL, NULL, NULL); if (ht == NULL) return 1; HashListTableFree(ht); return 0; } static int HashListTableTestInit03 (void) { int result = 0; HashListTable *ht = HashListTableInit(1024, HashListTableGenericHash, NULL, NULL); if (ht == NULL) return 0; if (ht->Hash == HashListTableGenericHash) result = 1; HashListTableFree(ht); return result; } static int HashListTableTestInit04 (void) { HashListTable *ht = HashListTableInit(0, HashListTableGenericHash, NULL, NULL); if (ht == NULL) return 1; HashListTableFree(ht); return 0; } static int HashListTableTestAdd01 (void) { int result = 0; HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashListTableAdd(ht, "test", 0); if (r != 0) goto end; /* all is good! */ result = 1; end: if (ht != NULL) HashListTableFree(ht); return result; } static int HashListTableTestAdd02 (void) { int result = 0; HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashListTableAdd(ht, NULL, 4); if (r == 0) goto end; /* all is good! */ result = 1; end: if (ht != NULL) HashListTableFree(ht); return result; } static int HashListTableTestAdd03 (void) { int result = 0; HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashListTableAdd(ht, "test", 0); if (r != 0) goto end; if (ht->listhead == NULL) { printf("ht->listhead == NULL: "); goto end; } if (ht->listtail == NULL) { printf("ht->listtail == NULL: "); goto end; } /* all is good! */ result = 1; end: if (ht != NULL) HashListTableFree(ht); return result; } static int HashListTableTestAdd04 (void) { int result = 0; HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashListTableAdd(ht, "test", 4); if (r != 0) goto end; char *rp = HashListTableLookup(ht, "test", 4); if (rp == NULL) goto end; HashListTableBucket *htb = HashListTableGetListHead(ht); if (htb == NULL) { printf("htb == NULL: "); goto end; } char *rp2 = HashListTableGetListData(htb); if (rp2 == NULL) { printf("rp2 == NULL: "); goto end; } if (rp != rp2) { printf("rp != rp2: "); goto end; } /* all is good! */ result = 1; end: if (ht != NULL) HashListTableFree(ht); return result; } static int HashListTableTestFull01 (void) { int result = 0; HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashListTableAdd(ht, "test", 4); if (r != 0) goto end; char *rp = HashListTableLookup(ht, "test", 4); if (rp == NULL) goto end; r = HashListTableRemove(ht, "test", 4); if (r != 0) goto end; /* all is good! */ result = 1; end: if (ht != NULL) HashListTableFree(ht); return result; } static int HashListTableTestFull02 (void) { int result = 0; HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashListTableAdd(ht, "test", 4); if (r != 0) goto end; char *rp = HashListTableLookup(ht, "test", 4); if (rp == NULL) goto end; r = HashListTableRemove(ht, "test2", 5); if (r == 0) goto end; /* all is good! */ result = 1; end: if (ht != NULL) HashListTableFree(ht); return result; } #endif /* UNITTESTS */ void HashListTableRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01, 1); UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02, 1); UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03, 1); UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04, 1); UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01, 1); UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02, 1); UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03, 1); UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04, 1); UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01, 1); UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-profiling.h0000644000000000000000000002461112253546156014146 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited. * \author Victor Julien */ #ifndef __UTIL_PROFILE_H__ #define __UTIL_PROFILE_H__ #ifdef PROFILING #include "util-profiling-locks.h" #include "util-cpu.h" extern int profiling_rules_enabled; extern int profiling_packets_enabled; extern __thread int profiling_rules_entered; void SCProfilingPrintPacketProfile(Packet *); void SCProfilingAddPacket(Packet *); #define RULE_PROFILING_START \ uint64_t profile_rule_start_ = 0; \ uint64_t profile_rule_end_ = 0; \ if (profiling_rules_enabled) { \ if (profiling_rules_entered > 0) { \ SCLogError(SC_ERR_FATAL, "Re-entered profiling, exiting."); \ exit(1); \ } \ profiling_rules_entered++; \ profile_rule_start_ = UtilCpuGetTicks(); \ } #define RULE_PROFILING_END(ctx, r, m) \ if (profiling_rules_enabled) { \ profile_rule_end_ = UtilCpuGetTicks(); \ SCProfilingRuleUpdateCounter(ctx, r->profiling_id, \ profile_rule_end_ - profile_rule_start_, m); \ profiling_rules_entered--; \ } #define PACKET_PROFILING_START(p) \ if (profiling_packets_enabled) { \ (p)->profile.ticks_start = UtilCpuGetTicks(); \ } #define PACKET_PROFILING_END(p) \ if (profiling_packets_enabled) { \ (p)->profile.ticks_end = UtilCpuGetTicks(); \ SCProfilingAddPacket((p)); \ } #ifdef PROFILE_LOCKING #define PACKET_PROFILING_RESET_LOCKS do { \ mutex_lock_cnt = 0; \ mutex_lock_wait_ticks = 0; \ mutex_lock_contention = 0; \ spin_lock_cnt = 0; \ spin_lock_wait_ticks = 0; \ spin_lock_contention = 0; \ rww_lock_cnt = 0; \ rww_lock_wait_ticks = 0; \ rww_lock_contention = 0; \ rwr_lock_cnt = 0; \ rwr_lock_wait_ticks = 0; \ rwr_lock_contention = 0; \ locks_idx = 0; \ record_locks = 1;\ } while (0) #define PACKET_PROFILING_COPY_LOCKS(p, id) do { \ (p)->profile.tmm[(id)].mutex_lock_cnt = mutex_lock_cnt; \ (p)->profile.tmm[(id)].mutex_lock_wait_ticks = mutex_lock_wait_ticks; \ (p)->profile.tmm[(id)].mutex_lock_contention = mutex_lock_contention; \ (p)->profile.tmm[(id)].spin_lock_cnt = spin_lock_cnt; \ (p)->profile.tmm[(id)].spin_lock_wait_ticks = spin_lock_wait_ticks; \ (p)->profile.tmm[(id)].spin_lock_contention = spin_lock_contention; \ (p)->profile.tmm[(id)].rww_lock_cnt = rww_lock_cnt; \ (p)->profile.tmm[(id)].rww_lock_wait_ticks = rww_lock_wait_ticks; \ (p)->profile.tmm[(id)].rww_lock_contention = rww_lock_contention; \ (p)->profile.tmm[(id)].rwr_lock_cnt = rwr_lock_cnt; \ (p)->profile.tmm[(id)].rwr_lock_wait_ticks = rwr_lock_wait_ticks; \ (p)->profile.tmm[(id)].rwr_lock_contention = rwr_lock_contention; \ record_locks = 0;\ SCProfilingAddPacketLocks((p)); \ } while(0) #else #define PACKET_PROFILING_RESET_LOCKS #define PACKET_PROFILING_COPY_LOCKS(p, id) #endif #define PACKET_PROFILING_TMM_START(p, id) \ if (profiling_packets_enabled) { \ if ((id) < TMM_SIZE) { \ (p)->profile.tmm[(id)].ticks_start = UtilCpuGetTicks(); \ PACKET_PROFILING_RESET_LOCKS; \ } \ } #define PACKET_PROFILING_TMM_END(p, id) \ if (profiling_packets_enabled) { \ if ((id) < TMM_SIZE) { \ PACKET_PROFILING_COPY_LOCKS((p), (id)); \ (p)->profile.tmm[(id)].ticks_end = UtilCpuGetTicks(); \ } \ } #define PACKET_PROFILING_RESET(p) \ if (profiling_packets_enabled) { \ memset(&(p)->profile, 0x00, sizeof(PktProfiling)); \ } #define PACKET_PROFILING_APP_START(dp, id) \ if (profiling_packets_enabled) { \ (dp)->ticks_start = UtilCpuGetTicks(); \ (dp)->alproto = (id); \ } #define PACKET_PROFILING_APP_END(dp, id) \ if (profiling_packets_enabled) { \ BUG_ON((id) != (dp)->alproto); \ (dp)->ticks_end = UtilCpuGetTicks(); \ if ((dp)->ticks_start != 0 && (dp)->ticks_start < ((dp)->ticks_end)) { \ (dp)->ticks_spent = ((dp)->ticks_end - (dp)->ticks_start); \ } \ } #define PACKET_PROFILING_APP_PD_START(dp) \ if (profiling_packets_enabled) { \ (dp)->proto_detect_ticks_start = UtilCpuGetTicks(); \ } #define PACKET_PROFILING_APP_PD_END(dp) \ if (profiling_packets_enabled) { \ (dp)->proto_detect_ticks_end = UtilCpuGetTicks(); \ if ((dp)->proto_detect_ticks_start != 0 && (dp)->proto_detect_ticks_start < ((dp)->proto_detect_ticks_end)) { \ (dp)->proto_detect_ticks_spent = \ ((dp)->proto_detect_ticks_end - (dp)->proto_detect_ticks_start); \ } \ } #define PACKET_PROFILING_APP_RESET(dp) \ if (profiling_packets_enabled) { \ (dp)->ticks_start = 0; \ (dp)->ticks_end = 0; \ (dp)->ticks_spent = 0; \ (dp)->alproto = 0; \ (dp)->proto_detect_ticks_start = 0; \ (dp)->proto_detect_ticks_end = 0; \ (dp)->proto_detect_ticks_spent = 0; \ } #define PACKET_PROFILING_APP_STORE(dp, p) \ if (profiling_packets_enabled) { \ if ((dp)->alproto < ALPROTO_MAX) { \ (p)->profile.app[(dp)->alproto].ticks_spent += (dp)->ticks_spent; \ (p)->profile.proto_detect += (dp)->proto_detect_ticks_spent; \ } \ } #define PACKET_PROFILING_DETECT_START(p, id) \ if (profiling_packets_enabled) { \ if ((id) < PROF_DETECT_SIZE) { \ (p)->profile.detect[(id)].ticks_start = UtilCpuGetTicks(); \ } \ } #define PACKET_PROFILING_DETECT_END(p, id) \ if (profiling_packets_enabled) { \ if ((id) < PROF_DETECT_SIZE) { \ (p)->profile.detect[(id)].ticks_end = UtilCpuGetTicks();\ if ((p)->profile.detect[(id)].ticks_start != 0 && \ (p)->profile.detect[(id)].ticks_start < (p)->profile.detect[(id)].ticks_end) { \ (p)->profile.detect[(id)].ticks_spent += \ ((p)->profile.detect[(id)].ticks_end - (p)->profile.detect[(id)].ticks_start); \ } \ } \ } void SCProfilingRulesGlobalInit(void); void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *); void SCProfilingRuleInitCounters(DetectEngineCtx *); void SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *, uint16_t, uint64_t, int); void SCProfilingRuleThreadSetup(struct SCProfileDetectCtx_ *, DetectEngineThreadCtx *); void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *); void SCProfilingInit(void); void SCProfilingDestroy(void); void SCProfilingRegisterTests(void); void SCProfilingDump(void); #else #define RULE_PROFILING_START #define RULE_PROFILING_END(a,b,c) #define PACKET_PROFILING_START(p) #define PACKET_PROFILING_END(p) #define PACKET_PROFILING_TMM_START(p, id) #define PACKET_PROFILING_TMM_END(p, id) #define PACKET_PROFILING_RESET(p) #define PACKET_PROFILING_APP_START(dp, id) #define PACKET_PROFILING_APP_END(dp, id) #define PACKET_PROFILING_APP_RESET(dp) #define PACKET_PROFILING_APP_STORE(dp, p) #define PACKET_PROFILING_APP_PD_START(dp) #define PACKET_PROFILING_APP_PD_END(dp) #define PACKET_PROFILING_DETECT_START(p, id) #define PACKET_PROFILING_DETECT_END(p, id) #endif /* PROFILING */ #endif /* ! __UTIL_PROFILE_H__ */ suricata-1.4.7/src/win32-misc.c0000644000000000000000000000600312253546156013063 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Jan Jezek * * Misc Windows utility functions */ #ifdef OS_WIN32 #include "suricata-common.h" #include "win32-misc.h" #include "direct.h" void setenv(const char *name, const char *value, int overwrite) { if (overwrite || NULL == getenv(name)) { char *str = SCMalloc(strlen(name) + strlen(value) + 2); if (unlikely(str == NULL)) return; snprintf(str, strlen(name) + strlen(value) + 1, "%s=%s", name, value); putenv(str); SCFree(str); } } void unsetenv(const char *name) { char *str = SCMalloc(strlen(name) + 2); if (unlikely(str == NULL)) return; snprintf(str, strlen(name) + 1, "%s=", name); putenv(str); SCFree(str); } const char* inet_ntop(int af, const void *src, char *dst, uint32_t cnt) { if (af == AF_INET) { struct sockaddr_in in; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; memcpy(&in.sin_addr, src, sizeof(struct in_addr)); if (0 == getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST)) return dst; } else if (af == AF_INET6) { struct sockaddr_in6 in6; memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; memcpy(&in6.sin6_addr, src, sizeof(struct in_addr6)); if (0 == getnameinfo((struct sockaddr *)&in6, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST)) return dst; } return NULL; } int inet_pton(int af, const char *src, void *dst) { struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = af; struct addrinfo* result = NULL; if (0 != getaddrinfo(src, NULL, &hints, &result)) return -1; if (result) { if (result->ai_family == AF_INET) { struct sockaddr_in* in = (struct sockaddr_in*)result->ai_addr; memcpy(dst, &in->sin_addr, 4); } else if (result->ai_family == AF_INET6) { struct sockaddr_in6* in6 = (struct sockaddr_in6*)result->ai_addr; memcpy(dst, &in6->sin6_addr, 16); } else { freeaddrinfo(result); return -1; } freeaddrinfo(result); return 1; } return -1; } #endif /* OS_WIN32 */ suricata-1.4.7/src/detect-tls.c0000644000000000000000000006011112253546156013240 00000000000000/* * Copyright (C) 2011-2012 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * \author Pierre Chifflier * * Implements the tls.* keywords */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-ssl.h" #include "detect-tls.h" #include "stream-tcp.h" /** * \brief Regex for parsing "id" option, matching number or "number" */ #define PARSE_REGEX "^\\s*(\\!*)\\s*([A-z0-9\\s\\-\\.=,\\*]+|\"[A-z0-9\\s\\-\\.=,\\*]+\")\\s*$" #define PARSE_REGEX_FINGERPRINT "^\\s*(\\!*)\\s*([A-z0-9\\:\\*]+|\"[A-z0-9\\:\\* ]+\")\\s*$" static pcre *subject_parse_regex; static pcre_extra *subject_parse_regex_study; static pcre *issuerdn_parse_regex; static pcre_extra *issuerdn_parse_regex_study; static pcre *fingerprint_parse_regex; static pcre_extra *fingerprint_parse_regex_study; static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectTlsSubjectSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsSubjectRegisterTests(void); static void DetectTlsSubjectFree(void *); static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectTlsIssuerDNSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsIssuerDNRegisterTests(void); static void DetectTlsIssuerDNFree(void *); static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsFingerprintFree(void *); static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, char *); static int DetectTlsStoreMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); /** * \brief Registration function for keyword: tls.version */ void DetectTlsRegister (void) { sigmatch_table[DETECT_AL_TLS_SUBJECT].name = "tls.subject"; sigmatch_table[DETECT_AL_TLS_SUBJECT].desc = "match TLS/SSL certificate Subject field"; sigmatch_table[DETECT_AL_TLS_SUBJECT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlssubject"; sigmatch_table[DETECT_AL_TLS_SUBJECT].Match = NULL; sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerMatch = DetectTlsSubjectMatch; sigmatch_table[DETECT_AL_TLS_SUBJECT].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; sigmatch_table[DETECT_AL_TLS_SUBJECT].Free = DetectTlsSubjectFree; sigmatch_table[DETECT_AL_TLS_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; sigmatch_table[DETECT_AL_TLS_ISSUERDN].name = "tls.issuerdn"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsissuerdn"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Match = NULL; sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerMatch = DetectTlsIssuerDNMatch; sigmatch_table[DETECT_AL_TLS_ISSUERDN].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free = DetectTlsIssuerDNFree; sigmatch_table[DETECT_AL_TLS_ISSUERDN].RegisterTests = DetectTlsIssuerDNRegisterTests; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsfingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Match = NULL; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].AppLayerMatch = DetectTlsFingerprintMatch; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].RegisterTests = NULL; sigmatch_table[DETECT_AL_TLS_STORE].name = "tls.store"; sigmatch_table[DETECT_AL_TLS_STORE].desc = "store TLS/SSL certificate on disk"; sigmatch_table[DETECT_AL_TLS_STORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsstore"; sigmatch_table[DETECT_AL_TLS_STORE].Match = NULL; sigmatch_table[DETECT_AL_TLS_STORE].AppLayerMatch = DetectTlsStoreMatch; sigmatch_table[DETECT_AL_TLS_STORE].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup; sigmatch_table[DETECT_AL_TLS_STORE].Free = NULL; sigmatch_table[DETECT_AL_TLS_STORE].RegisterTests = NULL; sigmatch_table[DETECT_AL_TLS_STORE].flags |= SIGMATCH_NOOPT; const char *eb; int eo; int opts = 0; SCLogDebug("registering tls.subject rule option"); subject_parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (subject_parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } subject_parse_regex_study = pcre_study(subject_parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } SCLogDebug("registering tls.issuerdn rule option"); issuerdn_parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (issuerdn_parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } issuerdn_parse_regex_study = pcre_study(issuerdn_parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } SCLogDebug("registering tls.fingerprint rule option"); fingerprint_parse_regex = pcre_compile(PARSE_REGEX_FINGERPRINT, opts, &eb, &eo, NULL); if (fingerprint_parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX_FINGERPRINT, eo, eb); goto error; } fingerprint_parse_regex_study = pcre_study(fingerprint_parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief match the specified Subject on a tls session * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectTlsData * * \retval 0 no match * \retval 1 match */ static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); DetectTlsData *tls_data = (DetectTlsData *)m->ctx; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); SCReturnInt(0); } int ret = 0; FLOWLOCK_RDLOCK(f); if (tls_data->flags & DETECT_CONTENT_NEGATED) { ret = 1; } else { ret = 0; } SSLStateConnp *connp = NULL; if (flags & STREAM_TOSERVER) { connp = &ssl_state->client_connp; } else { connp = &ssl_state->server_connp; } if (connp->cert0_subject != NULL) { SCLogDebug("TLS: Subject is [%s], looking for [%s]\n", connp->cert0_subject, tls_data->subject); if (strstr(connp->cert0_subject, tls_data->subject) != NULL) { if (tls_data->flags & DETECT_CONTENT_NEGATED) { ret = 0; } else { ret = 1; } } } FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" * * \param idstr Pointer to the user provided id option * * \retval id_d pointer to DetectTlsData on success * \retval NULL on failure */ static DetectTlsData *DetectTlsSubjectParse (char *str) { DetectTlsData *tls = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr; char *orig; char *tmp_str; uint32_t flag = 0; ret = pcre_exec(subject_parse_regex, subject_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 3) { SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.subject option"); goto error; } res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct id option */ tls = SCMalloc(sizeof(DetectTlsData)); if (unlikely(tls == NULL)) goto error; tls->subject = NULL; tls->flags = flag; orig = SCStrdup((char*)str_ptr); if (unlikely(orig == NULL)) { goto error; } tmp_str=orig; /* Let's see if we need to escape "'s */ if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } tls->subject = SCStrdup(tmp_str); SCFree(orig); SCLogDebug("will look for TLS subject %s", tls->subject); return tls; error: if (tls != NULL) DetectTlsSubjectFree(tls); return NULL; } /** * \brief this function is used to add the parsed "id" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "id" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectTlsData *tls = NULL; SigMatch *sm = NULL; tls = DetectTlsSubjectParse(str); if (tls == 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_AL_TLS_SUBJECT; sm->ctx = (void *)tls; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_TLS; return 0; error: if (tls != NULL) DetectTlsSubjectFree(tls); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectTlsData * * \param id_d pointer to DetectTlsData */ static void DetectTlsSubjectFree(void *ptr) { DetectTlsData *id_d = (DetectTlsData *)ptr; if (ptr == NULL) return; if (id_d->subject != NULL) SCFree(id_d->subject); SCFree(id_d); } /** * \brief this function registers unit tests for DetectTlsSubject */ static void DetectTlsSubjectRegisterTests(void) { } /** * \brief match the specified IssuerDN on a tls session * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectTlsData * * \retval 0 no match * \retval 1 match */ static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); DetectTlsData *tls_data = (DetectTlsData *)m->ctx; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); SCReturnInt(0); } int ret = 0; FLOWLOCK_RDLOCK(f); if (tls_data->flags & DETECT_CONTENT_NEGATED) { ret = 1; } else { ret = 0; } SSLStateConnp *connp = NULL; if (flags & STREAM_TOSERVER) { connp = &ssl_state->client_connp; } else { connp = &ssl_state->server_connp; } if (connp->cert0_issuerdn != NULL) { SCLogDebug("TLS: IssuerDN is [%s], looking for [%s]\n", connp->cert0_issuerdn, tls_data->issuerdn); if (strstr(connp->cert0_issuerdn, tls_data->issuerdn) != NULL) { if (tls_data->flags & DETECT_CONTENT_NEGATED) { ret = 0; } else { ret = 1; } } } FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" * * \param idstr Pointer to the user provided id option * * \retval id_d pointer to DetectTlsData on success * \retval NULL on failure */ static DetectTlsData *DetectTlsIssuerDNParse(char *str) { DetectTlsData *tls = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr; char *orig; char *tmp_str; uint32_t flag = 0; ret = pcre_exec(issuerdn_parse_regex, issuerdn_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 3) { SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.issuerdn option"); goto error; } res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct id option */ tls = SCMalloc(sizeof(DetectTlsData)); if (unlikely(tls == NULL)) goto error; tls->issuerdn = NULL; tls->flags = flag; orig = SCStrdup((char*)str_ptr); if (unlikely(orig == NULL)) { goto error; } tmp_str=orig; /* Let's see if we need to escape "'s */ if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } tls->issuerdn = SCStrdup(tmp_str); SCFree(orig); SCLogDebug("Will look for TLS issuerdn %s", tls->issuerdn); return tls; error: if (tls != NULL) DetectTlsIssuerDNFree(tls); return NULL; } /** * \brief this function is used to add the parsed "id" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "id" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectTlsData *tls = NULL; SigMatch *sm = NULL; tls = DetectTlsIssuerDNParse(str); if (tls == 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_AL_TLS_ISSUERDN; sm->ctx = (void *)tls; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_TLS; return 0; error: if (tls != NULL) DetectTlsIssuerDNFree(tls); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectTlsData * * \param id_d pointer to DetectTlsData */ static void DetectTlsIssuerDNFree(void *ptr) { DetectTlsData *id_d = (DetectTlsData *)ptr; SCFree(id_d->issuerdn); SCFree(id_d); } /** * \brief This function is used to parse fingerprint passed via keyword: "fingerprint" * * \param idstr Pointer to the user provided fingerprint option * * \retval pointer to DetectTlsData on success * \retval NULL on failure */ static DetectTlsData *DetectTlsFingerprintParse (char *str) { DetectTlsData *tls = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr; char *orig; char *tmp_str; uint32_t flag = 0; ret = pcre_exec(fingerprint_parse_regex, fingerprint_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 3) { SCLogError(SC_ERR_PCRE_MATCH, "invalid tls.fingerprint option"); goto error; } res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct id option */ tls = SCMalloc(sizeof(DetectTlsData)); if (unlikely(tls == NULL)) goto error; tls->fingerprint = NULL; tls->flags = flag; orig = SCStrdup((char*)str_ptr); if (unlikely(orig == NULL)) { goto error; } tmp_str=orig; /* Let's see if we need to escape "'s */ if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } tls->fingerprint = SCStrdup(tmp_str); if (tls->fingerprint == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate fingerprint"); } SCFree(orig); SCLogDebug("will look for TLS fingerprint %s", tls->subject); return tls; error: if (tls != NULL) DetectTlsFingerprintFree(tls); return NULL; } /** * \brief match the specified fingerprint on a tls session * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectTlsData * * \retval 0 no match * \retval 1 match */ static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); DetectTlsData *tls_data = (DetectTlsData *)m->ctx; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); SCReturnInt(0); } int ret = 0; FLOWLOCK_RDLOCK(f); if (tls_data->flags & DETECT_CONTENT_NEGATED) { ret = 1; } else { ret = 0; } if (ssl_state->server_connp.cert0_fingerprint != NULL) { SCLogDebug("TLS: Fingerprint is [%s], looking for [%s]\n", ssl_state->server_connp.cert0_fingerprint, tls_data->fingerprint); if (tls_data->fingerprint && (strstr(ssl_state->server_connp.cert0_fingerprint, tls_data->fingerprint) != NULL)) { if (tls_data->flags & DETECT_CONTENT_NEGATED) { ret = 0; } else { ret = 1; } } } FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief this function is used to add the parsed "fingerprint" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param id pointer to the user provided "fingerprint" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectTlsData *tls = NULL; SigMatch *sm = NULL; tls = DetectTlsFingerprintParse(str); if (tls == 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_AL_TLS_FINGERPRINT; sm->ctx = (void *)tls; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_TLS; return 0; error: if (tls != NULL) DetectTlsFingerprintFree(tls); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectTlsData * * \param pointer to DetectTlsData */ static void DetectTlsFingerprintFree(void *ptr) { DetectTlsData *id_d = (DetectTlsData *)ptr; if (id_d->fingerprint) SCFree(id_d->fingerprint); SCFree(id_d); } /** * \brief this function is used to add the parsed "store" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "store" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SigMatch *sm = NULL; s->flags |= SIG_FLAG_TLSSTORE; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_AL_TLS_STORE; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_TLS; return 0; error: if (sm != NULL) SCFree(sm); return -1; } static int DetectTlsStoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); SCReturnInt(1); } FLOWLOCK_WRLOCK(f); if (s->flags & SIG_FLAG_TLSSTORE) { ssl_state->server_connp.cert_log_flag |= SSL_TLS_LOG_PEM; } FLOWLOCK_UNLOCK(f); SCReturnInt(1); } /** * \brief this function registers unit tests for DetectTlsIssuerDN */ static void DetectTlsIssuerDNRegisterTests(void) { } suricata-1.4.7/src/detect-filemd5.h0000644000000000000000000000203512253546156013771 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_FILEMD5_H__ #define __DETECT_FILEMD5_H__ #include "util-rohash.h" typedef struct DetectFileMd5Data { ROHashTable *hash; int negated; } DetectFileMd5Data; /* prototypes */ void DetectFileMd5Register (void); #endif /* __DETECT_FILEMD5_H__ */ suricata-1.4.7/src/detect-msg.c0000644000000000000000000001362412253546156013233 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the msg keyword */ #include "suricata-common.h" #include "detect.h" #include "util-classification-config.h" #include "util-debug.h" #include "util-unittest.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" static int DetectMsgSetup (DetectEngineCtx *, Signature *, char *); void DetectMsgRegisterTests(void); void DetectMsgRegister (void) { sigmatch_table[DETECT_MSG].name = "msg"; sigmatch_table[DETECT_MSG].desc = "information about the rule and the possible alert"; sigmatch_table[DETECT_MSG].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#msg-message"; sigmatch_table[DETECT_MSG].Match = NULL; sigmatch_table[DETECT_MSG].Setup = DetectMsgSetup; sigmatch_table[DETECT_MSG].Free = NULL; sigmatch_table[DETECT_MSG].RegisterTests = DetectMsgRegisterTests; } static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) { char *str = NULL; uint16_t len; if (strlen(msgstr) == 0) goto error; /* strip "'s */ if (msgstr[0] == '\"' && msgstr[strlen(msgstr)-1] == '\"') { str = SCStrdup(msgstr+1); if (unlikely(str == NULL)) goto error; str[strlen(msgstr)-2] = '\0'; } else if (msgstr[1] == '\"' && msgstr[strlen(msgstr)-1] == '\"') { /* XXX do this parsing in a better way */ str = SCStrdup(msgstr+2); if (unlikely(str == NULL)) goto error; str[strlen(msgstr)-3] = '\0'; //printf("DetectMsgSetup: format hack applied: \'%s\'\n", str); } else { SCLogError(SC_ERR_INVALID_VALUE, "format error \'%s\'", msgstr); goto error; } len = strlen(str); if (len == 0) goto error; char converted = 0; { uint16_t i, x; uint8_t escape = 0; /* it doesn't matter if we need to escape or not we remove the extra "\" to mimic snort */ for (i = 0, x = 0; i < len; i++) { //printf("str[%02u]: %c\n", i, str[i]); if(!escape && str[i] == '\\') { escape = 1; } else if (escape) { if (str[i] != ':' && str[i] != ';' && str[i] != '\\' && str[i] != '\"') { SCLogDebug("character \"%c\" does not need to be escaped but is" ,str[i]); } escape = 0; converted = 1; str[x] = str[i]; x++; }else{ str[x] = str[i]; x++; } } #if 0 //def DEBUG if (SCLogDebugEnabled()) { for (i = 0; i < x; i++) { printf("%c", str[i]); } printf("\n"); } #endif if (converted) { len = x; str[len] = '\0'; } } s->msg = SCMalloc(len + 1); if (s->msg == NULL) goto error; strlcpy(s->msg, str, len + 1); SCFree(str); return 0; error: SCFree(str); return -1; } /* -------------------------------------Unittests-----------------------------*/ #ifdef UNITTESTS static int DetectMsgParseTest01(void) { int result = 0; Signature *sig = NULL; char *teststringparsed = "flow stateless to_server"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"flow stateless to_server\"; flow:stateless,to_server; content:\"flowstatelesscheck\"; classtype:bad-unknown; sid: 40000002; rev: 1;)"); if(sig == NULL) goto end; if (strcmp(sig->msg, teststringparsed) != 0) { printf("got \"%s\", expected: \"%s\": ", sig->msg, teststringparsed); goto end; } result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } static int DetectMsgParseTest02(void) { int result = 0; Signature *sig = NULL; char *teststringparsed = "msg escape tests wxy'\"\\;:"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"msg escape tests \\w\\x\\y\\'\\\"\\\\;\\:\"; flow:to_server,established; content:\"blah\"; uricontent:\"/blah/\"; sid: 100;)"); if(sig == NULL) goto end; if (strcmp(sig->msg, teststringparsed) != 0) { printf("got \"%s\", expected: \"%s\": ",sig->msg, teststringparsed); goto end; } result = 1; end: if (sig != NULL) SigFree(sig); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectMsg */ void DetectMsgRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectMsgParseTest01", DetectMsgParseTest01, 1); UtRegisterTest("DetectMsgParseTest02", DetectMsgParseTest02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-filestore.h0000644000000000000000000000266612253546156014452 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_FILESTORE_H__ #define __DETECT_FILESTORE_H__ #define FILESTORE_DIR_DEFAULT 0 /* rule dir */ #define FILESTORE_DIR_TOSERVER 1 #define FILESTORE_DIR_TOCLIENT 2 #define FILESTORE_DIR_BOTH 3 #define FILESTORE_SCOPE_DEFAULT 0 /* per file */ #define FILESTORE_SCOPE_TX 1 /* per transaction */ #define FILESTORE_SCOPE_SSN 2 /* per flow/ssn */ typedef struct DetectFilestoreData_ { int16_t direction; int16_t scope; } DetectFilestoreData; /* prototypes */ void DetectFilestoreRegister (void); int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *); #endif /* __DETECT_FILESTORE_H__ */ suricata-1.4.7/src/detect-engine-mpm.h0000644000000000000000000000732212253546156014504 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_MPM_H__ #define __DETECT_ENGINE_MPM_H__ #include "tm-threads.h" #include "detect.h" #include "detect-content.h" #include "detect-uricontent.h" #include "stream.h" uint16_t PatternMatchDefaultMatcher(void); uint32_t PatternStrength(uint8_t *, uint16_t); uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *, Packet *); uint32_t PacketPatternSearch(DetectEngineThreadCtx *, Packet *); uint32_t UriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint16_t, uint8_t); uint32_t StreamPatternSearch(DetectEngineThreadCtx *, Packet *, StreamMsg *, uint8_t); uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *); void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg); void PatternMatchPrepare(MpmCtx *, uint16_t); void PatternMatchThreadPrepare(MpmThreadCtx *, uint16_t type, uint32_t max_id); void PatternMatchDestroy(MpmCtx *, uint16_t); void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t); void PatternMatchThreadPrint(MpmThreadCtx *, uint16_t); int PatternMatchPrepareGroup(DetectEngineCtx *, SigGroupHead *); void DetectEngineThreadCtxInfo(ThreadVars *, DetectEngineThreadCtx *); void PatternMatchDestroyGroup(SigGroupHead *); TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); void DbgPrintSearchStats(); MpmPatternIdStore *MpmPatternIdTableInitHash(void); void MpmPatternIdTableFreeHash(MpmPatternIdStore *); uint32_t MpmPatternIdStoreGetMaxId(MpmPatternIdStore *); uint32_t DetectContentGetId(MpmPatternIdStore *, DetectContentData *); uint32_t DetectUricontentGetId(MpmPatternIdStore *, DetectContentData *); uint32_t DetectPatternGetId(MpmPatternIdStore *, void *, uint8_t); int SignatureHasPacketContent(Signature *); int SignatureHasStreamContent(Signature *); SigMatch *RetrieveFPForSig(Signature *s); #endif /* __DETECT_ENGINE_MPM_H__ */ suricata-1.4.7/src/util-hash.h0000644000000000000000000000356312253546156013103 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __HASH_H__ #define __HASH_H__ /* hash bucket structure */ typedef struct HashTableBucket_ { void *data; uint16_t size; struct HashTableBucket_ *next; } HashTableBucket; /* hash table structure */ typedef struct HashTable_ { HashTableBucket **array; uint32_t array_size; #ifdef UNITTESTS uint32_t count; #endif uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t); char (*Compare)(void *, uint16_t, void *, uint16_t); void (*Free)(void *); } HashTable; #define HASH_NO_SIZE 0 /* prototypes */ HashTable* HashTableInit(uint32_t, uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)); void HashTableFree(HashTable *); void HashTablePrint(HashTable *); int HashTableAdd(HashTable *, void *, uint16_t); int HashTableRemove(HashTable *, void *, uint16_t); void *HashTableLookup(HashTable *, void *, uint16_t); uint32_t HashTableGenericHash(HashTable *, void *, uint16_t); char HashTableDefaultCompare(void *, uint16_t, void *, uint16_t); void HashTableRegisterTests(void); #endif /* __HASH_H__ */ suricata-1.4.7/src/util-mpm-b2g.h0000644000000000000000000000651112253546156013415 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_MPM_B2G_H__ #define __UTIL_MPM_B2G_H__ #include "util-mpm.h" #include "util-bloomfilter.h" #define B2G_HASHSHIFT_MAX 8 #define B2G_HASHSHIFT_HIGHER 7 #define B2G_HASHSHIFT_HIGH 6 #define B2G_HASHSHIFT_MEDIUM 5 #define B2G_HASHSHIFT_LOW 4 #define B2G_HASHSHIFT_LOWEST 3 //#define B2G_TYPE uint64_t #define B2G_TYPE uint32_t //#define B2G_TYPE uint16_t //#define B2G_TYPE uint8_t //#define B2G_WORD_SIZE 64 #define B2G_WORD_SIZE 32 //#define B2G_WORD_SIZE 16 //#define B2G_WORD_SIZE 8 #define B2G_Q 2 #define B2G_SEARCHFUNC B2gSearchBNDMq //#define B2G_SEARCHFUNC B2gSearch //#define B2G_SEARCH2 //#define B2G_COUNTERS typedef struct B2gPattern_ { uint16_t len; /**< \todo we're limited to 32/64 byte lengths, uint8_t would be fine here */ uint8_t flags; uint8_t pad0; uint32_t id; uint8_t *original_pat; uint8_t *ci; /* case INsensitive */ uint8_t *cs; /* case sensitive */ struct B2gPattern_ *next; } B2gPattern; typedef struct B2gCtx_ { B2G_TYPE *B2G; B2G_TYPE m; BloomFilter **bloom; uint8_t *pminlen; /* array containing the minimal length of the patters in a hash bucket. Used for the BloomFilter. */ /* pattern arrays */ B2gPattern **parray; uint16_t pat_1_cnt; #ifdef B2G_SEARCH2 uint16_t pat_2_cnt; #endif uint16_t pat_x_cnt; uint32_t hash_size; B2gPattern **hash; B2gPattern hash1[256]; #ifdef B2G_SEARCH2 B2gHashItem **hash2; #endif /* hash used during ctx initialization */ B2gPattern **init_hash; uint8_t s0; /* we store our own multi byte search func ptr here for B2gSearch1 */ uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* we store our own multi byte search func ptr here for B2gSearch1 */ uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); } B2gCtx; typedef struct B2gThreadCtx_ { #ifdef B2G_COUNTERS uint32_t stat_pminlen_calls; uint32_t stat_pminlen_total; uint32_t stat_bloom_calls; uint32_t stat_bloom_hits; uint32_t stat_calls; uint32_t stat_m_total; uint32_t stat_d0; uint32_t stat_d0_hashloop; uint32_t stat_loop_match; uint32_t stat_loop_no_match; uint32_t stat_num_shift; uint32_t stat_total_shift; #endif /* B2G_COUNTERS */ } B2gThreadCtx; void MpmB2gRegister(void); #endif suricata-1.4.7/src/runmode-napatech.h0000644000000000000000000000223512253546156014432 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \autor nPulse Technologies, LLC. * \author Matt Keeler */ #ifndef __RUNMODE_NAPATECH_H__ #define __RUNMODE_NAPATECH_H__ #ifdef HAVE_NAPATECH #include #endif int RunModeNapatechAuto(DetectEngineCtx *); int RunModeNapatechAutoFp(DetectEngineCtx *); int RunModeNapatechWorkers(DetectEngineCtx *); void RunModeNapatechRegister(void); const char *RunModeNapatechGetDefaultMode(void); #endif /* __RUNMODE_NAPATECH_H__ */ suricata-1.4.7/src/runmode-af-packet.h0000644000000000000000000000214712253546156014504 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Eric Leblond */ #ifndef __RUNMODE_AF_PACKET_H__ #define __RUNMODE_AF_PACKET_H__ int RunModeIdsAFPAuto(DetectEngineCtx *); int RunModeIdsAFPSingle(DetectEngineCtx *); int RunModeIdsAFPAutoFp(DetectEngineCtx *); int RunModeIdsAFPWorkers(DetectEngineCtx *); void RunModeIdsAFPRegister(void); const char *RunModeAFPGetDefaultMode(void); #endif /* __RUNMODE_AF_PACKET_H__ */ suricata-1.4.7/src/defrag-hash.c0000644000000000000000000005163112253546156013350 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "conf.h" #include "defrag-hash.h" #include "defrag-queue.h" #include "util-random.h" #include "util-byte.h" #include "util-misc.h" #include "util-hash-lookup3.h" static DefragTracker *DefragTrackerGetUsedDefragTracker(void); /** queue with spare tracker */ static DefragTrackerQueue defragtracker_spare_q; uint32_t DefragTrackerSpareQueueGetSize(void) { return DefragTrackerQueueLen(&defragtracker_spare_q); } void DefragTrackerMoveToSpare(DefragTracker *h) { DefragTrackerEnqueue(&defragtracker_spare_q, h); (void) SC_ATOMIC_SUB(defragtracker_counter, 1); } DefragTracker *DefragTrackerAlloc(void) { if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) { return NULL; } (void) SC_ATOMIC_ADD(defrag_memuse, sizeof(DefragTracker)); DefragTracker *dt = SCMalloc(sizeof(DefragTracker)); if (unlikely(dt == NULL)) goto error; memset(dt, 0x00, sizeof(DefragTracker)); SCMutexInit(&dt->lock, NULL); SC_ATOMIC_INIT(dt->use_cnt); return dt; error: return NULL; } void DefragTrackerFree(DefragTracker *dt) { if (dt != NULL) { DefragTrackerClearMemory(dt); SCMutexDestroy(&dt->lock); SCFree(dt); (void) SC_ATOMIC_SUB(defrag_memuse, sizeof(DefragTracker)); } } #define DefragTrackerIncrUsecnt(dt) \ SC_ATOMIC_ADD((dt)->use_cnt, 1) #define DefragTrackerDecrUsecnt(dt) \ SC_ATOMIC_SUB((dt)->use_cnt, 1) static void DefragTrackerInit(DefragTracker *dt, Packet *p) { /* copy address */ COPY_ADDRESS(&p->src, &dt->src_addr); COPY_ADDRESS(&p->dst, &dt->dst_addr); if (PKT_IS_IPV4(p)) { dt->id = (int32_t)IPV4_GET_IPID(p); dt->af = AF_INET; } else { dt->id = (int32_t)IPV6_EXTHDR_GET_FH_ID(p); dt->af = AF_INET6; } dt->policy = DefragGetOsPolicy(p); TAILQ_INIT(&dt->frags); (void) DefragTrackerIncrUsecnt(dt); } static DefragTracker *DefragTrackerNew(Packet *p) { DefragTracker *dt = DefragTrackerAlloc(); if (dt == NULL) goto error; DefragTrackerInit(dt, p); return dt; error: return NULL; } void DefragTrackerRelease(DefragTracker *t) { (void) DefragTrackerDecrUsecnt(t); SCMutexUnlock(&t->lock); } void DefragTrackerClearMemory(DefragTracker *dt) { DefragTrackerFreeFrags(dt); SC_ATOMIC_DESTROY(dt->use_cnt); } #define DEFRAG_DEFAULT_HASHSIZE 4096 #define DEFRAG_DEFAULT_MEMCAP 16777216 #define DEFRAG_DEFAULT_PREALLOC 1000 /** \brief initialize the configuration * \warning Not thread safe */ void DefragInitConfig(char quiet) { SCLogDebug("initializing defrag engine..."); memset(&defrag_config, 0, sizeof(defrag_config)); //SC_ATOMIC_INIT(flow_flags); SC_ATOMIC_INIT(defragtracker_counter); SC_ATOMIC_INIT(defrag_memuse); SC_ATOMIC_INIT(defragtracker_prune_idx); DefragTrackerQueueInit(&defragtracker_spare_q); unsigned int seed = RandomTimePreseed(); /* set defaults */ defrag_config.hash_rand = (int)(DEFRAG_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); defrag_config.hash_size = DEFRAG_DEFAULT_HASHSIZE; defrag_config.memcap = DEFRAG_DEFAULT_MEMCAP; defrag_config.prealloc = DEFRAG_DEFAULT_PREALLOC; /* Check if we have memcap and hash_size defined at config */ char *conf_val; uint32_t configval = 0; /** set config values for memcap, prealloc and hash_size */ if ((ConfGet("defrag.memcap", &conf_val)) == 1) { if (ParseSizeStringU64(conf_val, &defrag_config.memcap) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing defrag.memcap " "from conf file - %s. Killing engine", conf_val); exit(EXIT_FAILURE); } } if ((ConfGet("defrag.hash-size", &conf_val)) == 1) { if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { defrag_config.hash_size = configval; } } if ((ConfGet("defrag.trackers", &conf_val)) == 1) { if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { defrag_config.prealloc = configval; } } SCLogDebug("DefragTracker config from suricata.yaml: memcap: %"PRIu64", hash-size: " "%"PRIu32", prealloc: %"PRIu32, defrag_config.memcap, defrag_config.hash_size, defrag_config.prealloc); /* alloc hash memory */ uint64_t hash_size = defrag_config.hash_size * sizeof(DefragTrackerHashRow); if (!(DEFRAG_CHECK_MEMCAP(hash_size))) { SCLogError(SC_ERR_DEFRAG_INIT, "allocating defrag hash failed: " "max defrag memcap is smaller than projected hash size. " "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate " "total hash size by multiplying \"defrag.hash-size\" with %"PRIuMAX", " "which is the hash bucket size.", defrag_config.memcap, hash_size, (uintmax_t)sizeof(DefragTrackerHashRow)); exit(EXIT_FAILURE); } defragtracker_hash = SCCalloc(defrag_config.hash_size, sizeof(DefragTrackerHashRow)); if (unlikely(defragtracker_hash == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in DefragTrackerInitConfig. Exiting..."); exit(EXIT_FAILURE); } memset(defragtracker_hash, 0, defrag_config.hash_size * sizeof(DefragTrackerHashRow)); uint32_t i = 0; for (i = 0; i < defrag_config.hash_size; i++) { DRLOCK_INIT(&defragtracker_hash[i]); } (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow))); if (quiet == FALSE) { SCLogInfo("allocated %llu bytes of memory for the defrag hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size, (uintmax_t)sizeof(DefragTrackerHashRow)); } if ((ConfGet("defrag.prealloc", &conf_val)) == 1) { if (ConfValIsTrue(conf_val)) { /* pre allocate defrag trackers */ for (i = 0; i < defrag_config.prealloc; i++) { if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) { SCLogError(SC_ERR_DEFRAG_INIT, "preallocating defrag trackers failed: " "max defrag memcap reached. Memcap %"PRIu64", " "Memuse %"PRIu64".", defrag_config.memcap, ((uint64_t)SC_ATOMIC_GET(defrag_memuse) + (uint64_t)sizeof(DefragTracker))); exit(EXIT_FAILURE); } DefragTracker *h = DefragTrackerAlloc(); if (h == NULL) { SCLogError(SC_ERR_DEFRAG_INIT, "preallocating defrag failed: %s", strerror(errno)); exit(EXIT_FAILURE); } DefragTrackerEnqueue(&defragtracker_spare_q,h); } if (quiet == FALSE) { SCLogInfo("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "", defragtracker_spare_q.len, (uintmax_t)sizeof(DefragTracker)); } } } if (quiet == FALSE) { SCLogInfo("defrag memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(defrag_memuse), defrag_config.memcap); } return; } /** \brief print some defrag stats * \warning Not thread safe */ static void DefragTrackerPrintStats (void) { } /** \brief shutdown the flow engine * \warning Not thread safe */ void DefragHashShutdown(void) { DefragTracker *dt; uint32_t u; DefragTrackerPrintStats(); /* free spare queue */ while((dt = DefragTrackerDequeue(&defragtracker_spare_q))) { BUG_ON(SC_ATOMIC_GET(dt->use_cnt) > 0); DefragTrackerFree(dt); } /* clear and free the hash */ if (defragtracker_hash != NULL) { for (u = 0; u < defrag_config.hash_size; u++) { dt = defragtracker_hash[u].head; while (dt) { DefragTracker *n = dt->hnext; DefragTrackerClearMemory(dt); DefragTrackerFree(dt); dt = n; } DRLOCK_DESTROY(&defragtracker_hash[u]); } SCFree(defragtracker_hash); defragtracker_hash = NULL; } (void) SC_ATOMIC_SUB(defrag_memuse, defrag_config.hash_size * sizeof(DefragTrackerHashRow)); DefragTrackerQueueDestroy(&defragtracker_spare_q); SC_ATOMIC_DESTROY(defragtracker_prune_idx); SC_ATOMIC_DESTROY(defrag_memuse); SC_ATOMIC_DESTROY(defragtracker_counter); //SC_ATOMIC_DESTROY(flow_flags); return; } /** \brief compare two raw ipv6 addrs * * \note we don't care about the real ipv6 ip's, this is just * to consistently fill the DefragHashKey6 struct, without all * the ntohl calls. * * \warning do not use elsewhere unless you know what you're doing. * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely * what you are looking for. */ static inline int DefragHashRawAddressIPv6GtU32(uint32_t *a, uint32_t *b) { int i; for (i = 0; i < 4; i++) { if (a[i] > b[i]) return 1; if (a[i] < b[i]) break; } return 0; } typedef struct DefragHashKey4_ { union { struct { uint32_t src, dst; uint32_t id; }; uint32_t u32[3]; }; } DefragHashKey4; typedef struct DefragHashKey6_ { union { struct { uint32_t src[4], dst[4]; uint32_t id; }; uint32_t u32[9]; }; } DefragHashKey6; /* calculate the hash key for this packet * * we're using: * hash_rand -- set at init time * source address * destination address * id */ static inline uint32_t DefragHashGetKey(Packet *p) { uint32_t key; if (p->ip4h != NULL) { DefragHashKey4 dhk; if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { dhk.src = p->src.addr_data32[0]; dhk.dst = p->dst.addr_data32[0]; } else { dhk.src = p->dst.addr_data32[0]; dhk.dst = p->src.addr_data32[0]; } dhk.id = (uint32_t)IPV4_GET_IPID(p); uint32_t hash = hashword(dhk.u32, 3, defrag_config.hash_rand); key = hash % defrag_config.hash_size; } else if (p->ip6h != NULL) { DefragHashKey6 dhk; if (DefragHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { dhk.src[0] = p->src.addr_data32[0]; dhk.src[1] = p->src.addr_data32[1]; dhk.src[2] = p->src.addr_data32[2]; dhk.src[3] = p->src.addr_data32[3]; dhk.dst[0] = p->dst.addr_data32[0]; dhk.dst[1] = p->dst.addr_data32[1]; dhk.dst[2] = p->dst.addr_data32[2]; dhk.dst[3] = p->dst.addr_data32[3]; } else { dhk.src[0] = p->dst.addr_data32[0]; dhk.src[1] = p->dst.addr_data32[1]; dhk.src[2] = p->dst.addr_data32[2]; dhk.src[3] = p->dst.addr_data32[3]; dhk.dst[0] = p->src.addr_data32[0]; dhk.dst[1] = p->src.addr_data32[1]; dhk.dst[2] = p->src.addr_data32[2]; dhk.dst[3] = p->src.addr_data32[3]; } dhk.id = IPV6_EXTHDR_GET_FH_ID(p); uint32_t hash = hashword(dhk.u32, 9, defrag_config.hash_rand); key = hash % defrag_config.hash_size; } else key = 0; return key; } /* Since two or more trackers can have the same hash key, we need to compare * the tracker with the current tracker key. */ #define CMP_DEFRAGTRACKER(d1,d2,id) \ (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && \ CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \ (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && \ CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \ (d1)->id == (id)) static inline int DefragTrackerCompare(DefragTracker *t, Packet *p) { uint32_t id; if (PKT_IS_IPV4(p)) { id = (uint32_t)IPV4_GET_IPID(p); } else { id = IPV6_EXTHDR_GET_FH_ID(p); } return CMP_DEFRAGTRACKER(t, p, id); } /** * \brief Get a new defrag tracker * * Get a new defrag tracker. We're checking memcap first and will try to make room * if the memcap is reached. * * \retval dt *LOCKED* tracker on succes, NULL on error. */ static DefragTracker *DefragTrackerGetNew(Packet *p) { DefragTracker *dt = NULL; /* get a tracker from the spare queue */ dt = DefragTrackerDequeue(&defragtracker_spare_q); if (dt == NULL) { /* If we reached the max memcap, we get a used tracker */ if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) { /* declare state of emergency */ //if (!(SC_ATOMIC_GET(defragtracker_flags) & DEFRAG_EMERGENCY)) { // SC_ATOMIC_OR(defragtracker_flags, DEFRAG_EMERGENCY); /* under high load, waking up the flow mgr each time leads * to high cpu usage. Flows are not timed out much faster if * we check a 1000 times a second. */ // FlowWakeupFlowManagerThread(); //} dt = DefragTrackerGetUsedDefragTracker(); if (dt == NULL) { return NULL; } /* freed a tracker, but it's unlocked */ } else { /* now see if we can alloc a new tracker */ dt = DefragTrackerNew(p); if (dt == NULL) { return NULL; } /* tracker is initialized but *unlocked* */ } } else { /* tracker has been recycled before it went into the spare queue */ /* tracker is initialized (recylced) but *unlocked* */ } (void) SC_ATOMIC_ADD(defragtracker_counter, 1); SCMutexLock(&dt->lock); return dt; } /* DefragGetTrackerFromHash * * Hash retrieval function for trackers. Looks up the hash bucket containing the * tracker pointer. Then compares the packet with the found tracker to see if it is * the tracker we need. If it isn't, walk the list until the right tracker is found. * * returns a *LOCKED* tracker or NULL */ DefragTracker *DefragGetTrackerFromHash (Packet *p) { DefragTracker *dt = NULL; /* get the key to our bucket */ uint32_t key = DefragHashGetKey(p); /* get our hash bucket and lock it */ DefragTrackerHashRow *hb = &defragtracker_hash[key]; DRLOCK_LOCK(hb); /* see if the bucket already has a tracker */ if (hb->head == NULL) { dt = DefragTrackerGetNew(p); if (dt == NULL) { DRLOCK_UNLOCK(hb); return NULL; } /* tracker is locked */ hb->head = dt; hb->tail = dt; /* got one, now lock, initialize and return */ DefragTrackerInit(dt,p); DRLOCK_UNLOCK(hb); return dt; } /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */ dt = hb->head; /* see if this is the tracker we are looking for */ if (DefragTrackerCompare(dt, p) == 0) { DefragTracker *pdt = NULL; /* previous tracker */ while (dt) { pdt = dt; dt = dt->hnext; if (dt == NULL) { dt = pdt->hnext = DefragTrackerGetNew(p); if (dt == NULL) { DRLOCK_UNLOCK(hb); return NULL; } hb->tail = dt; /* tracker is locked */ dt->hprev = pdt; /* initialize and return */ DefragTrackerInit(dt,p); DRLOCK_UNLOCK(hb); return dt; } if (DefragTrackerCompare(dt, p) != 0) { /* we found our tracker, lets put it on top of the * hash list -- this rewards active trackers */ if (dt->hnext) { dt->hnext->hprev = dt->hprev; } if (dt->hprev) { dt->hprev->hnext = dt->hnext; } if (dt == hb->tail) { hb->tail = dt->hprev; } dt->hnext = hb->head; dt->hprev = NULL; hb->head->hprev = dt; hb->head = dt; /* found our tracker, lock & return */ SCMutexLock(&dt->lock); (void) DefragTrackerIncrUsecnt(dt); DRLOCK_UNLOCK(hb); return dt; } } } /* lock & return */ SCMutexLock(&dt->lock); (void) DefragTrackerIncrUsecnt(dt); DRLOCK_UNLOCK(hb); return dt; } /** \brief look up a tracker in the hash * * \param a address to look up * * \retval h *LOCKED* tracker or NULL */ DefragTracker *DefragLookupTrackerFromHash (Packet *p) { DefragTracker *dt = NULL; /* get the key to our bucket */ uint32_t key = DefragHashGetKey(p); /* get our hash bucket and lock it */ DefragTrackerHashRow *hb = &defragtracker_hash[key]; DRLOCK_LOCK(hb); /* see if the bucket already has a tracker */ if (hb->head == NULL) { DRLOCK_UNLOCK(hb); return dt; } /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */ dt = hb->head; /* see if this is the tracker we are looking for */ if (DefragTrackerCompare(dt, p) == 0) { while (dt) { dt = dt->hnext; if (dt == NULL) { DRLOCK_UNLOCK(hb); return dt; } if (DefragTrackerCompare(dt, p) != 0) { /* we found our tracker, lets put it on top of the * hash list -- this rewards active tracker */ if (dt->hnext) { dt->hnext->hprev = dt->hprev; } if (dt->hprev) { dt->hprev->hnext = dt->hnext; } if (dt == hb->tail) { hb->tail = dt->hprev; } dt->hnext = hb->head; dt->hprev = NULL; hb->head->hprev = dt; hb->head = dt; /* found our tracker, lock & return */ SCMutexLock(&dt->lock); (void) DefragTrackerIncrUsecnt(dt); DRLOCK_UNLOCK(hb); return dt; } } } /* lock & return */ SCMutexLock(&dt->lock); (void) DefragTrackerIncrUsecnt(dt); DRLOCK_UNLOCK(hb); return dt; } /** \internal * \brief Get a tracker from the hash directly. * * Called in conditions where the spare queue is empty and memcap is reached. * * Walks the hash until a tracker can be freed. "defragtracker_prune_idx" atomic int makes * sure we don't start at the top each time since that would clear the top of * the hash leading to longer and longer search times under high pressure (observed). * * \retval dt tracker or NULL */ static DefragTracker *DefragTrackerGetUsedDefragTracker(void) { uint32_t idx = SC_ATOMIC_GET(defragtracker_prune_idx) % defrag_config.hash_size; uint32_t cnt = defrag_config.hash_size; while (cnt--) { if (++idx >= defrag_config.hash_size) idx = 0; DefragTrackerHashRow *hb = &defragtracker_hash[idx]; if (DRLOCK_TRYLOCK(hb) != 0) continue; DefragTracker *dt = hb->tail; if (dt == NULL) { DRLOCK_UNLOCK(hb); continue; } if (SCMutexTrylock(&dt->lock) != 0) { DRLOCK_UNLOCK(hb); continue; } /** never prune a tracker that is used by a packets * we are currently processing in one of the threads */ if (SC_ATOMIC_GET(dt->use_cnt) > 0) { DRLOCK_UNLOCK(hb); SCMutexUnlock(&dt->lock); continue; } /* remove from the hash */ if (dt->hprev != NULL) dt->hprev->hnext = dt->hnext; if (dt->hnext != NULL) dt->hnext->hprev = dt->hprev; if (hb->head == dt) hb->head = dt->hnext; if (hb->tail == dt) hb->tail = dt->hprev; dt->hnext = NULL; dt->hprev = NULL; DRLOCK_UNLOCK(hb); DefragTrackerClearMemory(dt); SCMutexUnlock(&dt->lock); (void) SC_ATOMIC_ADD(defragtracker_prune_idx, (defrag_config.hash_size - cnt)); return dt; } return NULL; } suricata-1.4.7/src/source-pcap-file.h0000644000000000000000000000171612253546156014341 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __SOURCE_PCAP_FILE_H__ #define __SOURCE_PCAP_FILE_H__ void TmModuleReceivePcapFileRegister (void); void TmModuleDecodePcapFileRegister (void); #endif /* __SOURCE_PCAP_FILE_H__ */ suricata-1.4.7/src/util-time.h0000644000000000000000000000247412253546156013116 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_TIME_H__ #define __UTIL_TIME_H__ /** * A timeval with 32 bit fields. * * Used by the unified on disk file format. */ typedef struct SCTimeval32_ { uint32_t tv_sec; uint32_t tv_usec; } SCTimeval32; void TimeInit(void); void TimeDeinit(void); void TimeSet(struct timeval *); void TimeGet(struct timeval *); void TimeSetToCurrentTime(void); void TimeSetIncrementTime(uint32_t); void TimeModeSetLive(void); void TimeModeSetOffline (void); struct tm *SCLocalTime(time_t timep, struct tm *result); #endif /* __UTIL_TIME_H__ */ suricata-1.4.7/src/detect-classtype.h0000644000000000000000000000165712253546156014464 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_CLASSTYPE_H__ #define __DETECT_CLASSTYPE_H__ /* prototypes */ void DetectClasstypeRegister(void); #endif /* __DETECT_CLASSTYPE_H__ */ suricata-1.4.7/src/util-mpm-ac-gfbs.c0000644000000000000000000026117612253546156014252 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implementation of aho-corasick MPM from - * * Efficient String Matching: An Aid to Bibliographic Search * Alfred V. Aho and Margaret J. Corasick * * - We use the goto-failure table to calculate transitions. * - If we cross 2 ** 16 states, we use 4 bytes in the transition table * to hold each state, otherwise we use 2 bytes. * - To reduce memory consumption, we throw all the failure transitions * out and use binary search to pick out the right transition in * the modified goto table. * * \todo - Do a proper analyis of our existing MPMs and suggest a good one based * on the pattern distribution and the expected traffic(say http). * - Tried out loop unrolling without any perf increase. Need to dig deeper. * - Try out holding whether they are any output strings from a particular * state in one of the bytes of a state var. Will be useful in cuda esp. */ #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "util-mpm-ac-gfbs.h" #include "conf.h" #include "util-memcmp.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" void SCACGfbsInitCtx(MpmCtx *, int); void SCACGfbsInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void SCACGfbsDestroyCtx(MpmCtx *); void SCACGfbsDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACGfbsAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int SCACGfbsAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int SCACGfbsPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); void SCACGfbsPrintInfo(MpmCtx *mpm_ctx); void SCACGfbsPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACGfbsRegisterTests(void); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_GFBS_FAIL (-1) /* size of the hash table used to speed up pattern insertions initially */ #define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 /** * \brief Helper structure used by AC during state table creation */ typedef struct StateQueue_ { int32_t store[STATE_QUEUE_CONTAINER_SIZE]; int top; int bot; } StateQueue; /** * \brief Register the goto failure table based aho-corasick mpm. */ void MpmACGfbsRegister(void) { mpm_table[MPM_AC_GFBS].name = "ac-gfbs"; /* don't need this. isn't that awesome? no more chopping and blah blah */ mpm_table[MPM_AC_GFBS].max_pattern_length = 0; mpm_table[MPM_AC_GFBS].InitCtx = SCACGfbsInitCtx; mpm_table[MPM_AC_GFBS].InitThreadCtx = SCACGfbsInitThreadCtx; mpm_table[MPM_AC_GFBS].DestroyCtx = SCACGfbsDestroyCtx; mpm_table[MPM_AC_GFBS].DestroyThreadCtx = SCACGfbsDestroyThreadCtx; mpm_table[MPM_AC_GFBS].AddPattern = SCACGfbsAddPatternCS; mpm_table[MPM_AC_GFBS].AddPatternNocase = SCACGfbsAddPatternCI; mpm_table[MPM_AC_GFBS].Prepare = SCACGfbsPreparePatterns; mpm_table[MPM_AC_GFBS].Search = SCACGfbsSearch; mpm_table[MPM_AC_GFBS].Cleanup = NULL; mpm_table[MPM_AC_GFBS].PrintCtx = SCACGfbsPrintInfo; mpm_table[MPM_AC_GFBS].PrintThreadCtx = SCACGfbsPrintSearchStats; mpm_table[MPM_AC_GFBS].RegisterUnittests = SCACGfbsRegisterTests; return; } /** * \internal * \brief Initialize the AC context with user specified conf parameters. We * aren't retrieving anything for AC conf now, but we will certainly * need it, when we customize AC. */ static void SCACGfbsGetConfig() { //ConfNode *ac_conf; //const char *hash_val = NULL; //ConfNode *pm = ConfGetNode("pattern-matcher"); return; } /** * \internal * \brief Compares 2 patterns. We use it for the hashing process during the * the initial pattern insertion time, to cull duplicate sigs. * * \param p Pointer to the first pattern(SCACGfbsPattern). * \param pat Pointer to the second pattern(raw pattern array). * \param patlen Pattern length. * \param flags Flags. We don't need this. * * \retval hash A 32 bit unsigned hash. */ static inline int SCACGfbsCmpPattern(SCACGfbsPattern *p, uint8_t *pat, uint16_t patlen, char flags) { if (p->len != patlen) return 0; if (p->flags != flags) return 0; if (memcmp(p->cs, pat, patlen) != 0) return 0; return 1; } /** * \internal * \brief Creates a hash of the pattern. We use it for the hashing process * during the initial pattern insertion time, to cull duplicate sigs. * * \param pat Pointer to the pattern. * \param patlen Pattern length. * * \retval hash A 32 bit unsigned hash. */ static inline uint32_t SCACGfbsInitHashRaw(uint8_t *pat, uint16_t patlen) { uint32_t hash = patlen * pat[0]; if (patlen > 1) hash += pat[1]; return (hash % INIT_HASH_SIZE); } /** * \internal * \brief Looks up a pattern. We use it for the hashing process during the * the initial pattern insertion time, to cull duplicate sigs. * * \param ctx Pointer to the AC ctx. * \param pat Pointer to the pattern. * \param patlen Pattern length. * \param flags Flags. We don't need this. * * \retval hash A 32 bit unsigned hash. */ static inline SCACGfbsPattern *SCACGfbsInitHashLookup(SCACGfbsCtx *ctx, uint8_t *pat, uint16_t patlen, char flags, uint32_t pid) { uint32_t hash = SCACGfbsInitHashRaw(pat, patlen); if (ctx->init_hash == NULL || ctx->init_hash[hash] == NULL) { return NULL; } SCACGfbsPattern *t = ctx->init_hash[hash]; for ( ; t != NULL; t = t->next) { //if (SCACGfbsCmpPattern(t, pat, patlen, flags) == 1) if (t->flags == flags && t->id == pid) return t; } return NULL; } /** * \internal * \brief Allocs a new pattern instance. * * \param mpm_ctx Pointer to the mpm context. * * \retval p Pointer to the newly created pattern. */ static inline SCACGfbsPattern *SCACGfbsAllocPattern(MpmCtx *mpm_ctx) { SCACGfbsPattern *p = SCMalloc(sizeof(SCACGfbsPattern)); if (unlikely(p == NULL)) { exit(EXIT_FAILURE); } memset(p, 0, sizeof(SCACGfbsPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(SCACGfbsPattern); return p; } /** * \internal * \brief Used to free SCACGfbsPattern instances. * * \param mpm_ctx Pointer to the mpm context. * \param p Pointer to the SCACGfbsPattern instance to be freed. */ static inline void SCACGfbsFreePattern(MpmCtx *mpm_ctx, SCACGfbsPattern *p) { if (p != NULL && p->cs != NULL && p->cs != p->ci) { SCFree(p->cs); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL && p->ci != NULL) { SCFree(p->ci); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL && p->original_pat != NULL) { SCFree(p->original_pat); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL) { SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(SCACGfbsPattern); } return; } /** * \internal * \brief Does a memcpy of the input string to lowercase. * * \param d Pointer to the target area for memcpy. * \param s Pointer to the src string for memcpy. * \param len len of the string sent in s. */ static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) d[i] = u8_tolower(s[i]); return; } static inline uint32_t SCACGfbsInitHash(SCACGfbsPattern *p) { uint32_t hash = p->len * p->original_pat[0]; if (p->len > 1) hash += p->original_pat[1]; return (hash % INIT_HASH_SIZE); } static inline int SCACGfbsInitHashAdd(SCACGfbsCtx *ctx, SCACGfbsPattern *p) { uint32_t hash = SCACGfbsInitHash(p); if (ctx->init_hash == NULL) { return 0; } if (ctx->init_hash[hash] == NULL) { ctx->init_hash[hash] = p; return 0; } SCACGfbsPattern *tt = NULL; SCACGfbsPattern *t = ctx->init_hash[hash]; /* get the list tail */ do { tt = t; t = t->next; } while (t != NULL); tt->next = p; return 0; } /** * \internal * \brief Add a pattern to the mpm-ac context. * * \param mpm_ctx Mpm context. * \param pat Pointer to the pattern. * \param patlen Length of the pattern. * \param pid Pattern id * \param sid Signature id (internal id). * \param flags Pattern's MPM_PATTERN_* flags. * * \retval 0 On success. * \retval -1 On failure. */ static int SCACGfbsAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, ctx, patlen, pid); if (patlen == 0) { SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); return 0; } /* check if we have already inserted this pattern */ SCACGfbsPattern *p = SCACGfbsInitHashLookup(ctx, pat, patlen, flags, pid); if (p == NULL) { SCLogDebug("Allocing new pattern"); /* p will never be NULL */ p = SCACGfbsAllocPattern(mpm_ctx); p->len = patlen; p->flags = flags; p->id = pid; p->original_pat = SCMalloc(patlen); if (p->original_pat == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->original_pat, pat, patlen); p->ci = SCMalloc(patlen); if (p->ci == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy_tolower(p->ci, pat, patlen); /* setup the case sensitive part of the pattern */ if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* nocase means no difference between cs and ci */ p->cs = p->ci; } else { if (memcmp(p->ci, pat, p->len) == 0) { /* no diff between cs and ci: pat is lowercase */ p->cs = p->ci; } else { p->cs = SCMalloc(patlen); if (p->cs == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->cs, pat, patlen); } } /* put in the pattern hash */ SCACGfbsInitHashAdd(ctx, p); if (mpm_ctx->pattern_cnt == 65535) { SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " "insert anymore. Exiting"); exit(EXIT_FAILURE); } mpm_ctx->pattern_cnt++; if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) { mpm_ctx->minlen = patlen; } else { if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } /* we need the max pat id */ if (pid > ctx->max_pat_id) ctx->max_pat_id = pid; } return 0; error: SCACGfbsFreePattern(mpm_ctx, p); return -1; } /** * \internal * \brief Initialize a new state in the goto and output tables. * * \param mpm_ctx Pointer to the mpm context. * * \retval The state id, of the newly created state. */ static inline int SCACGfbsInitNewState(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; int ascii_code = 0; int size = 0; /* reallocate space in the goto table to include a new state */ size = (ctx->state_count + 1) * 1024; ctx->goto_table = SCRealloc(ctx->goto_table, size); if (ctx->goto_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } /* set all transitions for the newly assigned state as FAIL transitions */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_GFBS_FAIL; } /* reallocate space in the output table for the new state */ size = (ctx->state_count + 1) * sizeof(SCACGfbsOutputTable); ctx->output_table = SCRealloc(ctx->output_table, size); if (ctx->output_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->output_table + ctx->state_count, 0, sizeof(SCACGfbsOutputTable)); /* \todo using it temporarily now during dev, since I have restricted * state var in SCACGfbsCtx->state_table to uint16_t. */ //if (ctx->state_count > 65536) { // printf("state count exceeded\n"); // exit(EXIT_FAILURE); //} return ctx->state_count++; } /** * \internal * \brief Adds a pid to the output table for a state. * * \param state The state to whose output table we should add the pid. * \param pid The pattern id to add. * \param mpm_ctx Pointer to the mpm context. */ static void SCACGfbsSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; SCACGfbsOutputTable *output_state = &ctx->output_table[state]; uint32_t i = 0; for (i = 0; i < output_state->no_of_entries; i++) { if (output_state->pids[i] == pid) return; } output_state->no_of_entries++; output_state->pids = SCRealloc(output_state->pids, output_state->no_of_entries * sizeof(uint32_t)); if (output_state->pids == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } output_state->pids[output_state->no_of_entries - 1] = pid; return; } /** * \brief Helper function used by SCACGfbsCreateGotoTable. Adds a pattern to the * goto table. * * \param pattern Pointer to the pattern. * \param pattern_len Pattern length. * \param pid The pattern id, that corresponds to this pattern. We * need it to updated the output table for this pattern. * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACGfbsEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; int32_t state = 0; int32_t newstate = 0; int i = 0; int p = 0; /* walk down the trie till we have a match for the pattern prefix */ state = 0; for (i = 0; i < pattern_len; i++) { if (ctx->goto_table[state][pattern[i]] != SC_AC_GFBS_FAIL) { state = ctx->goto_table[state][pattern[i]]; } else { break; } } /* add the non-matching pattern suffix to the trie, from the last state * we left off */ for (p = i; p < pattern_len; p++) { newstate = SCACGfbsInitNewState(mpm_ctx); ctx->goto_table[state][pattern[p]] = newstate; state = newstate; } /* add this pattern id, to the output table of the last state, where the * pattern ends in the trie */ SCACGfbsSetOutputState(state, pid, mpm_ctx); return; } /** * \internal * \brief Create the goto table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACGfbsCreateGotoTable(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; uint32_t i = 0; /* add each pattern to create the goto table */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { SCACGfbsEnter(ctx->parray[i]->ci, ctx->parray[i]->len, ctx->parray[i]->id, mpm_ctx); } int ascii_code = 0; for (ascii_code = 0; ascii_code < 256; ascii_code++) { if (ctx->goto_table[0][ascii_code] == SC_AC_GFBS_FAIL) { ctx->goto_table[0][ascii_code] = 0; } } return; } static inline int SCACGfbsStateQueueIsEmpty(StateQueue *q) { if (q->top == q->bot) return 1; else return 0; } static inline void SCACGfbsEnqueue(StateQueue *q, int32_t state) { int i = 0; /*if we already have this */ for (i = q->bot; i < q->top; i++) { if (q->store[i] == state) return; } q->store[q->top++] = state; if (q->top == STATE_QUEUE_CONTAINER_SIZE) q->top = 0; if (q->top == q->bot) { SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " "Fatal Error. Exiting. Please file a bug report on this"); exit(EXIT_FAILURE); } return; } static inline int32_t SCACGfbsDequeue(StateQueue *q) { if (q->bot == STATE_QUEUE_CONTAINER_SIZE) q->bot = 0; if (q->bot == q->top) { SCLogCritical(SC_ERR_AHO_CORASICK, "StateQueue behaving weirdly. " "Fatal Error. Exiting. Please file a bug report on this"); exit(EXIT_FAILURE); } return q->store[q->bot++]; } /* #define SCACGfbsStateQueueIsEmpty(q) (((q)->top == (q)->bot) ? 1 : 0) #define SCACGfbsEnqueue(q, state) do { \ int i = 0; \ \ for (i = (q)->bot; i < (q)->top; i++) { \ if ((q)->store[i] == state) \ return; \ } \ \ (q)->store[(q)->top++] = state; \ \ if ((q)->top == STATE_QUEUE_CONTAINER_SIZE) \ (q)->top = 0; \ \ if ((q)->top == (q)->bot) { \ SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " \ "Fatal Error. Exiting. Please file a bug report on this"); \ exit(EXIT_FAILURE); \ } \ } while (0) #define SCACGfbsDequeue(q) ( (((q)->bot == STATE_QUEUE_CONTAINER_SIZE)? ((q)->bot = 0): 0), \ (((q)->bot == (q)->top) ? \ (printf("StateQueue behaving " \ "weirdly. Fatal Error. Exiting. Please " \ "file a bug report on this"), \ exit(EXIT_FAILURE)) : 0), \ (q)->store[(q)->bot++]) \ */ /** * \internal * \brief Club the output data from 2 states and store it in the 1st state. * dst_state_data = {dst_state_data} UNION {src_state_data} * * \todo Use a better way to find union of 2 sets. * * \param dst_state First state(also the destination) for the union operation. * \param src_state Second state for the union operation. * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACGfbsClubOutputStates(int32_t dst_state, int32_t src_state, MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; uint32_t i = 0; uint32_t j = 0; SCACGfbsOutputTable *output_dst_state = &ctx->output_table[dst_state]; SCACGfbsOutputTable *output_src_state = &ctx->output_table[src_state]; for (i = 0; i < output_src_state->no_of_entries; i++) { for (j = 0; j < output_dst_state->no_of_entries; j++) { if (output_src_state->pids[i] == output_dst_state->pids[j]) { break; } } if (j == output_dst_state->no_of_entries) { output_dst_state->no_of_entries++; output_dst_state->pids = SCRealloc(output_dst_state->pids, (output_dst_state->no_of_entries * sizeof(uint32_t)) ); if (output_dst_state->pids == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } output_dst_state->pids[output_dst_state->no_of_entries - 1] = output_src_state->pids[i]; } } return; } /** * \internal * \brief Create the failure table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACGfbsCreateFailureTable(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; int ascii_code = 0; int32_t state = 0; int32_t r_state = 0; StateQueue q; memset(&q, 0, sizeof(StateQueue)); /* allot space for the failure table. A failure entry in the table for * every state(SCACGfbsCtx->state_count) */ ctx->failure_table = SCMalloc(ctx->state_count * sizeof(int32_t)); if (ctx->failure_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->failure_table, 0, ctx->state_count * sizeof(int32_t)); /* add the failure transitions for the 0th state, and add every non-fail * transition from the 0th state to the queue for further processing * of failure states */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[0][ascii_code]; if (temp_state != 0) { SCACGfbsEnqueue(&q, temp_state); ctx->failure_table[temp_state] = 0; } } while (!SCACGfbsStateQueueIsEmpty(&q)) { /* pick up every state from the queue and add failure transitions */ r_state = SCACGfbsDequeue(&q); for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[r_state][ascii_code]; if (temp_state == SC_AC_GFBS_FAIL) continue; SCACGfbsEnqueue(&q, temp_state); state = ctx->failure_table[r_state]; while(ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) state = ctx->failure_table[state]; ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code]; SCACGfbsClubOutputStates(temp_state, ctx->failure_table[temp_state], mpm_ctx); } } return; } /** * \internal * \brief Creates a new goto table structure(throw out all the failure * transitions), to hold the existing goto table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACGfbsCreateModGotoTable(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; if (ctx->state_count < 32767) { int size = 0; int32_t state = 0; for (state = 1; state < ctx->state_count; state++) { int k = 0; int ascii_code = 0; for (; ascii_code < 256; ascii_code++) { if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) continue; k++; } if ((k % 2) != 0) size += 1; } /* Let us use uint16_t for all. That way we don't have to worry about * alignment. Technically 8 bits is all we need to store ascii codes, * but by avoiding it, we save a lot of time on handling alignment */ size += (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 3 + ctx->state_count * sizeof(uint8_t) + 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 1); ctx->goto_table_mod = SCMalloc(size); if (ctx->goto_table_mod == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->goto_table_mod, 0, size); //printf("size- %d\n", size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += size; /* buffer to hold pointers in the buffer, so that a state can use it * directly to access its state data */ ctx->goto_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *)); if (ctx->goto_table_mod_pointers == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->goto_table_mod_pointers, 0, ctx->state_count * sizeof(uint8_t *)); SC_AC_GFBS_STATE_TYPE_U16 temp_states[256]; uint16_t *curr_loc = (uint16_t *)ctx->goto_table_mod; uint16_t *no_of_entries = NULL; uint16_t *failure_entry = NULL; uint8_t *ascii_codes = NULL; uint16_t ascii_code = 0; uint16_t k = 0; for (state = 0; state < ctx->state_count; state++) { /* store the starting location in the buffer for this state */ ctx->goto_table_mod_pointers[state] = (uint8_t *)curr_loc; no_of_entries = curr_loc++; failure_entry = curr_loc++; ascii_codes = (uint8_t *)curr_loc; k = 0; /* store all states that have non fail transitions in the temp buffer */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) continue; ascii_codes[k] = ascii_code; temp_states[k] = ctx->goto_table[state][ascii_code]; k++; } /* if we have any non fail transitions from our previous for search, * store the acii codes as well the corresponding states */ if (k > 0) { no_of_entries[0] = k; if (state != 0) { int jump = (k + 1) & 0xFFE; curr_loc += jump / 2; } memcpy(curr_loc, temp_states, k * sizeof(SC_AC_GFBS_STATE_TYPE_U16)); curr_loc += k; } failure_entry[0] = ctx->failure_table[state]; } /* > 33766 */ } else { int size = 0; int32_t state = 0; for (state = 1; state < ctx->state_count; state++) { int k = 0; int ascii_code = 0; for (; ascii_code < 256; ascii_code++) { if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) continue; k++; } if ( (k % 4) != 0) size += (4 - (k % 4)); } /* Let us use uint32_t for all. That way we don't have to worry about * alignment. Technically 8 bits is all we need to store ascii codes, * but by avoiding it, we save a lot of time on handling alignment */ size += (ctx->state_count * (sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 3)+ ctx->state_count * sizeof(uint8_t) + 256 * (sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 1)); ctx->goto_table_mod = SCMalloc(size); if (ctx->goto_table_mod == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->goto_table_mod, 0, size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += size; /* buffer to hold pointers in the buffer, so that a state can use it * directly to access its state data */ ctx->goto_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *)); if (ctx->goto_table_mod_pointers == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->goto_table_mod_pointers, 0, ctx->state_count * sizeof(uint8_t *)); SC_AC_GFBS_STATE_TYPE_U32 temp_states[256]; uint32_t *curr_loc = (uint32_t *)ctx->goto_table_mod; uint32_t *no_of_entries = NULL; uint32_t *failure_entry = NULL; uint8_t *ascii_codes = NULL; uint16_t ascii_code = 0; uint16_t k = 0; for (state = 0; state < ctx->state_count; state++) { /* store the starting location in the buffer for this state */ ctx->goto_table_mod_pointers[state] = (uint8_t *)curr_loc; no_of_entries = curr_loc++; failure_entry = curr_loc++; ascii_codes = (uint8_t *)curr_loc; k = 0; /* store all states that have non fail transitions in the temp buffer */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) continue; ascii_codes[k] = ascii_code; temp_states[k] = ctx->goto_table[state][ascii_code]; k++; } /* if we have any non fail transitions from our previous for search, * store the acii codes as well the corresponding states */ if (k > 0) { no_of_entries[0] = k; if (state != 0) { int jump = (k + 3) & 0xFFC; curr_loc += jump / 4; } memcpy(curr_loc, temp_states, k * sizeof(SC_AC_GFBS_STATE_TYPE_U32)); curr_loc += k; } failure_entry[0] = ctx->failure_table[state]; } } return; } static inline void SCACGfbsClubOutputStatePresenceWithModGotoTable(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; int state = 0; int no_of_entries; int i; if (ctx->state_count < 32767) { uint16_t *states; for (state = 0; state < ctx->state_count; state++) { no_of_entries = *((uint16_t *)ctx->goto_table_mod_pointers[state]); if (no_of_entries == 0) continue; //if (*((uint16_t *)ctx->goto_table_mod_pointers[state] + 1) != 0) { if (ctx->output_table[((uint16_t *)ctx->goto_table_mod_pointers[state] + 1)[0]].no_of_entries != 0) { *((uint16_t *)ctx->goto_table_mod_pointers[state] + 1) |= (1 << 15); } if (state == 0) states = ((uint16_t *)ctx->goto_table_mod_pointers[state] + 2); else states = ((uint16_t *)ctx->goto_table_mod_pointers[state] + 2 + ((no_of_entries + 1) & 0xFFE) / 2); for (i = 0; i < no_of_entries; i++) { //if (states[i] == 0) if (ctx->output_table[states[i]].no_of_entries == 0) continue; states[i] |= (1 << 15); } } } else { uint32_t *states; for (state = 0; state < ctx->state_count; state++) { no_of_entries = *((uint32_t *)ctx->goto_table_mod_pointers[state]); if (no_of_entries == 0) continue; //if (*((uint32_t *)ctx->goto_table_mod_pointers[state] + 1) != 0) { if (ctx->output_table[((uint32_t *)ctx->goto_table_mod_pointers[state] + 1)[0]].no_of_entries != 0) { *((uint32_t *)ctx->goto_table_mod_pointers[state] + 1) |= (1 << 24); } if (state == 0) states = ((uint32_t *)ctx->goto_table_mod_pointers[state] + 2); else states = ((uint32_t *)ctx->goto_table_mod_pointers[state] + 2 + ((no_of_entries + 3) & 0xFFC) / 4); for (i = 0; i < no_of_entries; i++) { //if (states[i] == 0) if (ctx->output_table[states[i]].no_of_entries == 0) continue; states[i] |= (1 << 24); } } } return; } static inline void SCACGfbsInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; int32_t state = 0; uint32_t k = 0; for (state = 0; state < ctx->state_count; state++) { if (ctx->output_table[state].no_of_entries == 0) continue; for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { ctx->output_table[state].pids[k] &= 0x0000FFFF; ctx->output_table[state].pids[k] |= 1 << 16; } } } return; } /** * \brief Process the patterns and prepare the state table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACGfbsPrepareStateTable(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; /* create the 0th state in the goto table and output_table */ SCACGfbsInitNewState(mpm_ctx); /* create the goto table */ SCACGfbsCreateGotoTable(mpm_ctx); /* create the failure table */ SCACGfbsCreateFailureTable(mpm_ctx); /* create the final state(delta) table */ SCACGfbsCreateModGotoTable(mpm_ctx); /* club the output state presence with transition entries */ SCACGfbsClubOutputStatePresenceWithModGotoTable(mpm_ctx); /* club nocase entries */ SCACGfbsInsertCaseSensitiveEntriesForPatterns(mpm_ctx); /* we don't need this anymore */ SCFree(ctx->goto_table); ctx->goto_table = NULL; SCFree(ctx->failure_table); ctx->failure_table = NULL; return; } /** * \brief Process the patterns added to the mpm, and create the internal tables. * * \param mpm_ctx Pointer to the mpm context. */ int SCACGfbsPreparePatterns(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { SCLogDebug("No patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ ctx->parray = (SCACGfbsPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); if (ctx->parray == NULL) goto error; memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; for (i = 0; i < INIT_HASH_SIZE; i++) { SCACGfbsPattern *node = ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; ctx->parray[p++] = node; node = nnode; } } /* we no longer need the hash, so free it's memory */ SCFree(ctx->init_hash); ctx->init_hash = NULL; /* the memory consumed by a single state in our goto table */ //ctx->single_state_size = sizeof(int32_t) * 256; /* handle no case patterns */ ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACGfbsPatternList)); if (ctx->pid_pat_list == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACGfbsPatternList)); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE) { if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 0) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 1; else if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 1) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 1; else ctx->pid_pat_list[ctx->parray[i]->id].case_state = 3; } else { ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, ctx->parray[i]->original_pat, ctx->parray[i]->len); ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 0) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 2; else if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 2) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 2; else ctx->pid_pat_list[ctx->parray[i]->id].case_state = 3; } } /* prepare the state table required by AC */ SCACGfbsPrepareStateTable(mpm_ctx); /* free all the stored patterns. Should save us a good 100-200 mbs */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { SCACGfbsFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); return 0; error: return -1; } /** * \brief Init the mpm thread context. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. * \param matchsize We don't need this. */ void SCACGfbsInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); mpm_thread_ctx->ctx = SCMalloc(sizeof(SCACGfbsThreadCtx)); if (mpm_thread_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_thread_ctx->ctx, 0, sizeof(SCACGfbsThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(SCACGfbsThreadCtx); return; } /** * \brief Initialize the AC context. * * \param mpm_ctx Mpm context. * \param module_handle Cuda module handle from the cuda handler API. We don't * have to worry about this here. */ void SCACGfbsInitCtx(MpmCtx *mpm_ctx, int module_handle) { if (mpm_ctx->ctx != NULL) return; mpm_ctx->ctx = SCMalloc(sizeof(SCACGfbsCtx)); if (mpm_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_ctx->ctx, 0, sizeof(SCACGfbsCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(SCACGfbsCtx); /* initialize the hash we use to speed up pattern insertions */ SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; ctx->init_hash = SCMalloc(sizeof(SCACGfbsPattern *) * INIT_HASH_SIZE); if (ctx->init_hash == NULL) { exit(EXIT_FAILURE); } memset(ctx->init_hash, 0, sizeof(SCACGfbsPattern *) * INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ SCACGfbsGetConfig(); SCReturn; } /** * \brief Destroy the mpm thread context. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. */ void SCACGfbsDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { SCACGfbsPrintSearchStats(mpm_thread_ctx); if (mpm_thread_ctx->ctx != NULL) { SCFree(mpm_thread_ctx->ctx); mpm_thread_ctx->ctx = NULL; mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(SCACGfbsThreadCtx); } return; } /** * \brief Destroy the mpm context. * * \param mpm_ctx Pointer to the mpm context. */ void SCACGfbsDestroyCtx(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->init_hash != NULL) { SCFree(ctx->init_hash); ctx->init_hash = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACGfbsPattern *)); } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { SCACGfbsFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); } if (ctx->goto_table_mod != NULL) { SCFree(ctx->goto_table_mod); ctx->goto_table_mod = NULL; mpm_ctx->memory_cnt--; if (ctx->state_count < 32767) { mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 3 + 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 2); } else { mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 3 + 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 2); } } if (ctx->goto_table_mod_pointers != NULL) { SCFree(ctx->goto_table_mod_pointers); ctx->goto_table_mod_pointers = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= ctx->state_count * sizeof(uint8_t *); } if (ctx->output_table != NULL) { int32_t state_count; for (state_count = 0; state_count < ctx->state_count; state_count++) { if (ctx->output_table[state_count].pids != NULL) { SCFree(ctx->output_table[state_count].pids); } } SCFree(ctx->output_table); } if (ctx->pid_pat_list != NULL) { int i; for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); } SCFree(ctx->pid_pat_list); } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(SCACGfbsCtx); return; } /** * \brief The aho corasick search function. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. * \param pmq Pointer to the Pattern Matcher Queue to hold * search matches. * \param buf Buffer to be searched. * \param buflen Buffer length. * * \retval matches Match count. */ uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; int matches = 0; uint8_t buf_local; SCACGfbsPatternList *pid_pat_list = ctx->pid_pat_list; /* really hate the extra cmp here, but can't help it */ if (ctx->state_count < 32767) { /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ int32_t temp_state; uint16_t no_of_entries; uint8_t *ascii_codes; uint16_t **goto_table_mod_pointers = (uint16_t **)ctx->goto_table_mod_pointers; //int32_t *failure_table = ctx->failure_table; int i; /* \todo tried loop unrolling with register var, with no perf increase. Need * to dig deeper */ /* with so many var declarations the register declaration here is useless */ register int32_t state = 0; for (i = 0; i < buflen; i++) { if (state == 0) { state = (goto_table_mod_pointers[0] + 2)[u8_tolower(buf[i])]; } else { /* get the goto state transition */ no_of_entries = *(goto_table_mod_pointers[state & 0x7FFF]); if (no_of_entries == 0) { temp_state = SC_AC_GFBS_FAIL; } else { if (no_of_entries == 1) { ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); buf_local = u8_tolower(buf[i]); if (buf_local == ascii_codes[0]) temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[0]; else temp_state = SC_AC_GFBS_FAIL; } else { buf_local = u8_tolower(buf[i]); ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); int low = 0; int high = no_of_entries; int mid; temp_state = SC_AC_GFBS_FAIL; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[mid]; break; } else if (ascii_codes[mid] < buf_local) { low = mid + 1; } else { high = mid - 1; } } } } while (temp_state == SC_AC_GFBS_FAIL) { state = *(goto_table_mod_pointers[state & 0x7FFF] + 1); /* get the goto state transition */ no_of_entries = *(goto_table_mod_pointers[state & 0x7FFF]); if (no_of_entries == 0) { temp_state = SC_AC_GFBS_FAIL; } else { if (no_of_entries == 1) { ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); buf_local = u8_tolower(buf[i]); if (buf_local == ascii_codes[0]) temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[0]; else temp_state = SC_AC_GFBS_FAIL; } else { ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); buf_local = u8_tolower(buf[i]); if (state == 0) { temp_state = ((uint16_t *)ascii_codes)[buf_local]; } else { int low = 0; int high = no_of_entries; int mid; temp_state = SC_AC_GFBS_FAIL; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[mid]; break; } else if (ascii_codes[mid] < buf_local) { low = mid + 1; } else { high = mid - 1; } } } } } /* else - if (no_of_entries == 0) */ } /* while (temp_state == SC_AC_GFBS_FAIL) */ state = temp_state; } if (state & 0x8000) { uint32_t no_of_pid_entries = ctx->output_table[state & 0x7FFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; uint32_t k = 0; for (k = 0; k < no_of_pid_entries; k++) { if (pids[k] & 0xFFFF0000) { if ((i + 1) < pid_pat_list[pids[k] & 0x0000FFFF].patlen) continue; if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { /* inside loop */ if (pid_pat_list[pids[k] & 0x0000FFFF].case_state != 3) { continue; } } if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (pids[k] & 0x0000FFFF); } matches++; } else { if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; } matches++; } } } /* if (ctx->output_table[state].no_of_entries != 0) */ } /* for (i = 0; i < buflen; i++) */ } else { /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ int32_t temp_state = 0; uint32_t no_of_entries; uint8_t *ascii_codes = NULL; uint32_t **goto_table_mod_pointers = (uint32_t **)ctx->goto_table_mod_pointers; //int32_t *failure_table = ctx->failure_table; int i = 0; /* \todo tried loop unrolling with register var, with no perf increase. Need * to dig deeper */ register int32_t state = 0; for (i = 0; i < buflen; i++) { if (state == 0) { state = (goto_table_mod_pointers[0] + 2)[u8_tolower(buf[i])]; } else { /* get the goto state transition */ no_of_entries = *(goto_table_mod_pointers[state & 0x00FFFFFF]); if (no_of_entries == 0) { temp_state = SC_AC_GFBS_FAIL; } else { if (no_of_entries == 1) { ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); buf_local = u8_tolower(buf[i]); if (buf_local == ascii_codes[0]) temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[0]; else temp_state = SC_AC_GFBS_FAIL; } else { buf_local = u8_tolower(buf[i]); ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); int low = 0; int high = no_of_entries; int mid; temp_state = SC_AC_GFBS_FAIL; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[mid]; break; } else if (ascii_codes[mid] < buf_local) { low = mid + 1; } else { high = mid - 1; } } } } while (temp_state == SC_AC_GFBS_FAIL) { state = *(goto_table_mod_pointers[state & 0x00FFFFFF] + 1); /* get the goto state transition */ no_of_entries = *(goto_table_mod_pointers[state & 0x00FFFFFF]); if (no_of_entries == 0) { temp_state = SC_AC_GFBS_FAIL; } else { if (no_of_entries == 1) { ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); buf_local = u8_tolower(buf[i]); if (buf_local == ascii_codes[0]) temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[0]; else temp_state = SC_AC_GFBS_FAIL; } else { ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); buf_local = u8_tolower(buf[i]); if (state == 0) { temp_state = ((uint32_t *)ascii_codes)[buf_local]; } else { int low = 0; int high = no_of_entries; int mid; temp_state = SC_AC_GFBS_FAIL; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[mid]; break; } else if (ascii_codes[mid] < buf_local) { low = mid + 1; } else { high = mid - 1; } } } } /* else - if (no_of_entries[0] == 1) */ } /* else - if (no_of_entries[0] == 0) */ } /* while (temp_state == SC_AC_GFBS_FAIL) */ state = temp_state; } if (state & 0x01000000) { uint32_t no_of_pid_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; uint32_t k = 0; for (k = 0; k < no_of_pid_entries; k++) { if (pids[k] & 0xFFFF0000) { if ((i + 1) < pid_pat_list[pids[k] & 0x0000FFFF].patlen) continue; if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { /* inside loop */ if (pid_pat_list[pids[k] & 0x0000FFFF].case_state != 3) { continue; } continue; } if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (pids[k] & 0x0000FFFF); } matches++; } else { if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; } matches++; } //loop1: //; } } /* if (ctx->output_table[state].no_of_entries != 0) */ } /* for (i = 0; i < buflen; i++) */ } return matches; } /** * \brief Add a case insensitive pattern. Although we have different calls for * adding case sensitive and insensitive patterns, we make a single call * for either case. No special treatment for either case. * * \param mpm_ctx Pointer to the mpm context. * \param pat The pattern to add. * \param patnen The pattern length. * \param offset Ignored. * \param depth Ignored. * \param pid The pattern id. * \param sid Ignored. * \param flags Flags associated with this pattern. * * \retval 0 On success. * \retval -1 On failure. */ int SCACGfbsAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return SCACGfbsAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } /** * \brief Add a case sensitive pattern. Although we have different calls for * adding case sensitive and insensitive patterns, we make a single call * for either case. No special treatment for either case. * * \param mpm_ctx Pointer to the mpm context. * \param pat The pattern to add. * \param patnen The pattern length. * \param offset Ignored. * \param depth Ignored. * \param pid The pattern id. * \param sid Ignored. * \param flags Flags associated with this pattern. * * \retval 0 On success. * \retval -1 On failure. */ int SCACGfbsAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return SCACGfbsAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } void SCACGfbsPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef SC_AC_COUNTERS SCACGfbsThreadCtx *ctx = (SCACGfbsThreadCtx *)mpm_thread_ctx->ctx; printf("AC Thread Search stats (ctx %p)\n", ctx); printf("Total calls: %" PRIu32 "\n", ctx->total_calls); printf("Total matches: %" PRIu64 "\n", ctx->total_matches); #endif /* SC_AC_COUNTERS */ return; } void SCACGfbsPrintInfo(MpmCtx *mpm_ctx) { SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; printf("MPM AC Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); printf(" Sizeof:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" SCACGfbsCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsCtx)); printf(" SCACGfbsPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsPattern)); printf(" SCACGfbsPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count); printf("\n"); return; } /*************************************Unittests********************************/ #ifdef UNITTESTS static int SCACGfbsTest01(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest02(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest03(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest04(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest05(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACGfbsAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); SCACGfbsAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); SCACGfbsAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest06(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcd"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest07(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* should match 30 times */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 29 times */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 28 times */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* 26 */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 21 */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 1 */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* total matches: 135 */ PmqSetup(&pmq, 0, 6); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest08(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest09(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest10(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "abcdefgh" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest11(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); if (SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; if (SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) goto end; if (SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) goto end; if (SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; PmqSetup(&pmq, 0, 4); if (SCACGfbsPreparePatterns(&mpm_ctx) == -1) goto end; result = 1; char *buf = "he"; result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); buf = "she"; result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); buf = "his"; result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); buf = "hers"; result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); end: SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest12(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest13(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest14(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest15(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest16(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABC"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest17(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzAB"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest18(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest19(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest20(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest21(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest22(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest23(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); if (cnt == 0) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest24(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACGfbsAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest25(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACGfbsAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); SCACGfbsAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); SCACGfbsAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest26(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACGfbsAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "works"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest27(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 0 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "tone"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest28(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_GFBS, -1); SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 0 match */ SCACGfbsAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACGfbsPreparePatterns(&mpm_ctx); char *buf = "tONE"; uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACGfbsDestroyCtx(&mpm_ctx); SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACGfbsTest29(void) { uint8_t *buf = (uint8_t *)"onetwothreefourfivesixseveneightnine"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->mpm_matcher = MPM_AC_GFBS; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); if (de_ctx->sig_list->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) != 1) { printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); goto end; } if (PacketAlertCheck(p, 2) != 1) { printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void SCACGfbsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCACGfbsTest01", SCACGfbsTest01, 1); UtRegisterTest("SCACGfbsTest02", SCACGfbsTest02, 1); UtRegisterTest("SCACGfbsTest03", SCACGfbsTest03, 1); UtRegisterTest("SCACGfbsTest04", SCACGfbsTest04, 1); UtRegisterTest("SCACGfbsTest05", SCACGfbsTest05, 1); UtRegisterTest("SCACGfbsTest06", SCACGfbsTest06, 1); UtRegisterTest("SCACGfbsTest07", SCACGfbsTest07, 1); UtRegisterTest("SCACGfbsTest08", SCACGfbsTest08, 1); UtRegisterTest("SCACGfbsTest09", SCACGfbsTest09, 1); UtRegisterTest("SCACGfbsTest10", SCACGfbsTest10, 1); UtRegisterTest("SCACGfbsTest11", SCACGfbsTest11, 1); UtRegisterTest("SCACGfbsTest12", SCACGfbsTest12, 1); UtRegisterTest("SCACGfbsTest13", SCACGfbsTest13, 1); UtRegisterTest("SCACGfbsTest14", SCACGfbsTest14, 1); UtRegisterTest("SCACGfbsTest15", SCACGfbsTest15, 1); UtRegisterTest("SCACGfbsTest16", SCACGfbsTest16, 1); UtRegisterTest("SCACGfbsTest17", SCACGfbsTest17, 1); UtRegisterTest("SCACGfbsTest18", SCACGfbsTest18, 1); UtRegisterTest("SCACGfbsTest19", SCACGfbsTest19, 1); UtRegisterTest("SCACGfbsTest20", SCACGfbsTest20, 1); UtRegisterTest("SCACGfbsTest21", SCACGfbsTest21, 1); UtRegisterTest("SCACGfbsTest22", SCACGfbsTest22, 1); UtRegisterTest("SCACGfbsTest23", SCACGfbsTest23, 1); UtRegisterTest("SCACGfbsTest24", SCACGfbsTest24, 1); UtRegisterTest("SCACGfbsTest25", SCACGfbsTest25, 1); UtRegisterTest("SCACGfbsTest26", SCACGfbsTest26, 1); UtRegisterTest("SCACGfbsTest27", SCACGfbsTest27, 1); UtRegisterTest("SCACGfbsTest28", SCACGfbsTest28, 1); UtRegisterTest("SCACGfbsTest29", SCACGfbsTest29, 1); #endif return; } suricata-1.4.7/src/tm-threads-common.h0000644000000000000000000000463212253546156014541 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha */ #ifndef __TM_THREADS_COMMON_H__ #define __TM_THREADS_COMMON_H__ /** \brief Thread Model Module id's. * * \note anything added here should also be added to TmModuleTmmIdToString * in tm-modules.c */ typedef enum { TMM_DECODENFQ, TMM_VERDICTNFQ, TMM_RECEIVENFQ, TMM_RECEIVEPCAP, TMM_RECEIVEPCAPFILE, TMM_DECODEPCAP, TMM_DECODEPCAPFILE, TMM_RECEIVEPFRING, TMM_DECODEPFRING, TMM_DETECT, TMM_ALERTFASTLOG, TMM_ALERTFASTLOG4, TMM_ALERTFASTLOG6, TMM_ALERTUNIFIED2ALERT, TMM_ALERTPRELUDE, TMM_ALERTDEBUGLOG, TMM_ALERTSYSLOG, TMM_LOGDROPLOG, TMM_ALERTSYSLOG4, TMM_ALERTSYSLOG6, TMM_RESPONDREJECT, TMM_LOGHTTPLOG, TMM_LOGHTTPLOG4, TMM_LOGHTTPLOG6, TMM_LOGTLSLOG, TMM_LOGTLSLOG4, TMM_LOGTLSLOG6, TMM_PCAPLOG, TMM_FILELOG, TMM_FILESTORE, TMM_STREAMTCP, TMM_DECODEIPFW, TMM_VERDICTIPFW, TMM_RECEIVEIPFW, #ifdef __SC_CUDA_SUPPORT__ TMM_CUDA_MPM_B2G, TMM_CUDA_PACKET_BATCHER, #endif TMM_RECEIVEERFFILE, TMM_DECODEERFFILE, TMM_RECEIVEERFDAG, TMM_DECODEERFDAG, TMM_RECEIVEAFP, TMM_DECODEAFP, TMM_ALERTPCAPINFO, TMM_RECEIVENAPATECH, TMM_DECODENAPATECH, TMM_SIZE, } TmmId; /*Error codes for the thread modules*/ typedef enum { TM_ECODE_OK = 0, /**< Thread module exits OK*/ TM_ECODE_FAILED, /**< Thread module exits due to failure*/ TM_ECODE_DONE, /**< Thread module task is finished*/ } TmEcode; /* ThreadVars type */ enum { TVT_PPT, TVT_MGMT, TVT_CMD, TVT_MAX, }; #endif /* __TM_THREADS_COMMON_H__ */ suricata-1.4.7/src/flow-queue.h0000644000000000000000000000440412253546156013271 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __FLOW_QUEUE_H__ #define __FLOW_QUEUE_H__ #include "suricata-common.h" #include "flow.h" /** Spinlocks or Mutex for the flow queues. */ //#define FQLOCK_SPIN #define FQLOCK_MUTEX #ifdef FQLOCK_SPIN #ifdef FQLOCK_MUTEX #error Cannot enable both FQLOCK_SPIN and FQLOCK_MUTEX #endif #endif /* Define a queue for storing flows */ typedef struct FlowQueue_ { Flow *top; Flow *bot; uint32_t len; #ifdef DBG_PERF uint32_t dbg_maxlen; #endif /* DBG_PERF */ #ifdef FQLOCK_MUTEX SCMutex m; #elif defined FQLOCK_SPIN SCSpinlock s; #else #error Enable FQLOCK_SPIN or FQLOCK_MUTEX #endif } FlowQueue; #ifdef FQLOCK_SPIN #define FQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) #define FQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) #define FQLOCK_LOCK(q) SCSpinLock(&(q)->s) #define FQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) #define FQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) #elif defined FQLOCK_MUTEX #define FQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) #define FQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) #define FQLOCK_LOCK(q) SCMutexLock(&(q)->m) #define FQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) #define FQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) #else #error Enable FQLOCK_SPIN or FQLOCK_MUTEX #endif /* prototypes */ FlowQueue *FlowQueueNew(); FlowQueue *FlowQueueInit(FlowQueue *); void FlowQueueDestroy (FlowQueue *); void FlowEnqueue (FlowQueue *, Flow *); Flow *FlowDequeue (FlowQueue *); void FlowMoveToSpare(Flow *); #endif /* __FLOW_QUEUE_H__ */ suricata-1.4.7/src/detect-engine-hsbd.c0000644000000000000000000021770512253546156014636 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * \author Victor Julien * * \brief Handle HTTP response body match corresponding to http_server_body * keyword. * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" #include "conf.h" #include "conf-yaml-loader.h" #define BUFFER_STEP 50 static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) { if (size > det_ctx->hsbd_buffers_size) { det_ctx->hsbd = SCRealloc(det_ctx->hsbd, (det_ctx->hsbd_buffers_size + BUFFER_STEP) * sizeof(HttpReassembledBody)); if (det_ctx->hsbd == NULL) { det_ctx->hsbd_buffers_size = 0; det_ctx->hsbd_buffers_list_len = 0; return -1; } memset(det_ctx->hsbd + det_ctx->hsbd_buffers_size, 0, BUFFER_STEP * sizeof(HttpReassembledBody)); det_ctx->hsbd_buffers_size += BUFFER_STEP; } for (int i = det_ctx->hsbd_buffers_list_len; i < (size); i++) { det_ctx->hsbd[i].buffer_len = 0; det_ctx->hsbd[i].offset = 0; } return 0; } static uint8_t *DetectEngineHSBDGetBufferForTX(int tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, uint32_t *buffer_len, uint32_t *stream_start_offset) { int index = 0; uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; if (det_ctx->hsbd_buffers_list_len == 0) { if (HSBDCreateSpace(det_ctx, 1) < 0) goto end; index = 0; if (det_ctx->hsbd_buffers_list_len == 0) { det_ctx->hsbd_start_tx_id = tx_id; } det_ctx->hsbd_buffers_list_len++; } else { if ((tx_id - det_ctx->hsbd_start_tx_id) < det_ctx->hsbd_buffers_list_len) { if (det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer_len != 0) { *buffer_len = det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer_len; *stream_start_offset = det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].offset; return det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer; } } else { if (HSBDCreateSpace(det_ctx, (tx_id - det_ctx->hsbd_start_tx_id) + 1) < 0) goto end; if (det_ctx->hsbd_buffers_list_len == 0) { det_ctx->hsbd_start_tx_id = tx_id; } det_ctx->hsbd_buffers_list_len++; } index = (tx_id - det_ctx->hsbd_start_tx_id); } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL) { SCLogDebug("no tx"); goto end; } HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); if (htud == NULL) { SCLogDebug("no htud"); goto end; } /* no new data */ if (htud->response_body.body_inspected == htud->response_body.content_len_so_far) { SCLogDebug("no new data"); goto end; } HtpBodyChunk *cur = htud->response_body.first; if (cur == NULL) { SCLogDebug("No http chunks to inspect for this transacation"); goto end; } /* in case of chunked transfer encoding, we don't have the length * of the response body until we see a chunk with length 0. This * doesn't let us use the response body callback function to * figure out the end of response body. Instead we do it here. If * the length is 0, and we have already seen content, it indicates * chunked transfer. We also check if the parser has truly seen * the last chunk by checking the progress state for the * transaction. If we are done parsing all the chunks, we would * have it set to something other than TX_PROGRESS_REQ_BODY. * Either ways we should be moving away from buffering in the end * and running content validation on this buffer type of architecture * to a stateful inspection, where we can inspect body chunks as and * when they come */ if (htud->response_body.content_len == 0) { if ((htud->response_body.content_len_so_far > 0) && tx->progress != TX_PROGRESS_RES_BODY) { /* final length of the body */ htud->tcflags |= HTP_RES_BODY_COMPLETE; } } else { if (htud->response_body.content_len == tx->response_entity_len) { SCLogDebug("content_len reached"); htud->tcflags |= HTP_RES_BODY_COMPLETE; } } if (flags & STREAM_EOF) { htud->tcflags |= HTP_RES_BODY_COMPLETE; } /* inspect the body if the transfer is complete or we have hit * our body size limit */ if (htud->response_body.content_len_so_far < htp_state->cfg->response_inspect_min_size && !(htud->tcflags & HTP_RES_BODY_COMPLETE)) { SCLogDebug("we still haven't seen the entire response body. " "Let's defer body inspection till we see the " "entire body."); goto end; } int first = 1; while (cur != NULL) { /* see if we can filter out chunks */ if (htud->response_body.body_inspected > 0) { if (cur->stream_offset < htud->response_body.body_inspected) { if ((htud->response_body.body_inspected - cur->stream_offset) > htp_state->cfg->response_inspect_window) { cur = cur->next; continue; } else { /* include this one */ } } else { /* include this one */ } } if (first) { det_ctx->hsbd[index].offset = cur->stream_offset; first = 0; } /* see if we need to grow the buffer */ if (det_ctx->hsbd[index].buffer == NULL || (det_ctx->hsbd[index].buffer_len + cur->len) > det_ctx->hsbd[index].buffer_size) { det_ctx->hsbd[index].buffer_size += cur->len * 2; if ((det_ctx->hsbd[index].buffer = SCRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size)) == NULL) { det_ctx->hsbd[index].buffer_size = 0; det_ctx->hsbd[index].buffer_len = 0; goto end; } } memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data, cur->len); det_ctx->hsbd[index].buffer_len += cur->len; cur = cur->next; } /* update inspected tracker */ htud->response_body.body_inspected = htud->response_body.last->stream_offset + htud->response_body.last->len; buffer = det_ctx->hsbd[index].buffer; *buffer_len = det_ctx->hsbd[index].buffer_len; *stream_start_offset = det_ctx->hsbd[index].offset; end: return buffer; } int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { uint32_t stream_start_offset = 0; uint32_t cnt = 0; if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } FLOWLOCK_WRLOCK(f); if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } /* get the transaction id */ int idx = AppLayerTransactionGetInspectId(f); /* error! get out of here */ if (idx == -1) goto end; int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { uint32_t buffer_len = 0; uint8_t *buffer = DetectEngineHSBDGetBufferForTX(idx, de_ctx, det_ctx, f, htp_state, flags, &buffer_len, &stream_start_offset); if (buffer_len == 0) continue; cnt += HttpServerBodyPatternSearch(det_ctx,buffer, buffer_len, flags); } end: FLOWLOCK_UNLOCK(f); return cnt; } int DetectEngineInspectHttpServerBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { uint32_t stream_start_offset = 0; HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx_id, de_ctx, det_ctx, f, htp_state, flags, &buffer_len, &stream_start_offset); if (buffer_len == 0) return 0; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HSBDMATCH], f, buffer, buffer_len, stream_start_offset, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, NULL); if (r == 1) return 1; return 0; } void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx) { if (det_ctx->hsbd_buffers_list_len > 0) { for (int i = 0; i < det_ctx->hsbd_buffers_list_len; i++) { det_ctx->hsbd[i].buffer_len = 0; det_ctx->hsbd[i].offset = 0; } } det_ctx->hsbd_buffers_list_len = 0; det_ctx->hsbd_start_tx_id = 0; return; } /***********************************Unittests**********************************/ #ifdef UNITTESTS static int DetectEngineHttpServerBodyTest01(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 7\r\n" "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"message\"; http_server_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest02(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 7\r\n" "\r\n" "xxxxABC"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"ABC\"; http_server_body; offset:4; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpServerBodyTest03(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; int result = 0; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 17\r\n" "\r\n" "1234567"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "8901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"ABC\"; http_server_body; offset:14; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest04(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:!\"abc\"; http_server_body; offset:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest05(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"abc\"; http_server_body; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest06(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:!\"def\"; http_server_body; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:!\"def\"; http_server_body; offset:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:!\"abc\"; http_server_body; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"abc\"; http_server_body; depth:3; " "content:\"def\"; http_server_body; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"abc\"; http_server_body; depth:3; " "content:!\"xyz\"; http_server_body; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest11(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"abc\"; http_server_body; depth:3; " "content:\"xyz\"; http_server_body; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 did match but should not have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest12(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"ab\"; http_server_body; depth:2; " "content:\"ef\"; http_server_body; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest13(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"ab\"; http_server_body; depth:3; " "content:!\"yz\"; http_server_body; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest14(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "pcre:/ab/Q; " "content:\"ef\"; http_server_body; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest15(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "pcre:/abc/Q; " "content:!\"xyz\"; http_server_body; distance:0; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyTest16(void) { char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ request-body-limit: 0\n\ response-body-limit: 0\n\ \n\ request-body-inspect-window: 0\n\ response-body-inspect-window: 0\n\ request-body-minimal-inspect-size: 0\n\ response-body-minimal-inspect-size: 0\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; int result = 0; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 17\r\n" "\r\n" "1234567"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "8901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"890\"; depth:3; http_server_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } result = 1; end: HtpConfigRestoreBackup(); ConfRestoreContextBackup(); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyFileDataTest01(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "file_data; pcre:/ab/; " "content:\"ef\"; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpServerBodyFileDataTest02(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "file_data; pcre:/abc/; " "content:!\"xyz\"; distance:0; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpServerBodyRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpServerBodyTest01", DetectEngineHttpServerBodyTest01, 1); UtRegisterTest("DetectEngineHttpServerBodyTest02", DetectEngineHttpServerBodyTest02, 1); UtRegisterTest("DetectEngineHttpServerBodyTest03", DetectEngineHttpServerBodyTest03, 1); UtRegisterTest("DetectEngineHttpServerBodyTest04", DetectEngineHttpServerBodyTest04, 1); UtRegisterTest("DetectEngineHttpServerBodyTest05", DetectEngineHttpServerBodyTest05, 1); UtRegisterTest("DetectEngineHttpServerBodyTest06", DetectEngineHttpServerBodyTest06, 1); UtRegisterTest("DetectEngineHttpServerBodyTest07", DetectEngineHttpServerBodyTest07, 1); UtRegisterTest("DetectEngineHttpServerBodyTest08", DetectEngineHttpServerBodyTest08, 1); UtRegisterTest("DetectEngineHttpServerBodyTest09", DetectEngineHttpServerBodyTest09, 1); UtRegisterTest("DetectEngineHttpServerBodyTest10", DetectEngineHttpServerBodyTest10, 1); UtRegisterTest("DetectEngineHttpServerBodyTest11", DetectEngineHttpServerBodyTest11, 1); UtRegisterTest("DetectEngineHttpServerBodyTest12", DetectEngineHttpServerBodyTest12, 1); UtRegisterTest("DetectEngineHttpServerBodyTest13", DetectEngineHttpServerBodyTest13, 1); UtRegisterTest("DetectEngineHttpServerBodyTest14", DetectEngineHttpServerBodyTest14, 1); UtRegisterTest("DetectEngineHttpServerBodyTest15", DetectEngineHttpServerBodyTest15, 1); UtRegisterTest("DetectEngineHttpServerBodyTest16", DetectEngineHttpServerBodyTest16, 1); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest01", DetectEngineHttpServerBodyFileDataTest01, 1); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest02", DetectEngineHttpServerBodyFileDataTest02, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-luajit.c0000644000000000000000000006160712253546156013741 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #include "suricata-common.h" #include "conf.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-spm-bm.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "stream-tcp.h" #include "detect-luajit.h" #include "queue.h" #include "util-cpu.h" #ifndef HAVE_LUAJIT static int DetectLuajitSetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) { SCLogError(SC_ERR_NO_LUAJIT_SUPPORT, "no LuaJIT support built in, needed for luajit keyword"); return -1; } /** * \brief Registration function for keyword: luajit */ void DetectLuajitRegister(void) { sigmatch_table[DETECT_LUAJIT].name = "luajit"; sigmatch_table[DETECT_LUAJIT].Setup = DetectLuajitSetupNoSupport; sigmatch_table[DETECT_LUAJIT].Free = NULL; sigmatch_table[DETECT_LUAJIT].RegisterTests = NULL; sigmatch_table[DETECT_LUAJIT].flags = SIGMATCH_NOT_BUILT; SCLogDebug("registering luajit rule option"); return; } #else /* HAVE_LUAJIT */ #include "util-pool.h" static int DetectLuajitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectLuajitSetup (DetectEngineCtx *, Signature *, char *); static void DetectLuajitRegisterTests(void); static void DetectLuajitFree(void *); /** * \brief Registration function for keyword: luajit */ void DetectLuajitRegister(void) { sigmatch_table[DETECT_LUAJIT].name = "luajit"; sigmatch_table[DETECT_LUAJIT].desc = "match via a luajit script"; sigmatch_table[DETECT_LUAJIT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Lua_scripting"; sigmatch_table[DETECT_LUAJIT].Match = DetectLuajitMatch; sigmatch_table[DETECT_LUAJIT].Setup = DetectLuajitSetup; sigmatch_table[DETECT_LUAJIT].Free = DetectLuajitFree; sigmatch_table[DETECT_LUAJIT].RegisterTests = DetectLuajitRegisterTests; SCLogDebug("registering luajit rule option"); return; } /** \brief lua_State pool * * Luajit requires states to be alloc'd in memory <2GB. For this reason we * prealloc the states early during engine startup so we have a better chance * of getting the states. We protect the pool with a lock as the detect * threads access it during their init and cleanup. * * Pool size is automagically determined based on number of keyword occurences, * cpus/cores and rule reloads being enabled or not. * * Alternatively, the "detect-engine.luajit-states" var can be set. */ static Pool *luajit_states = NULL; static pthread_mutex_t luajit_states_lock = PTHREAD_MUTEX_INITIALIZER; #define DATATYPE_PACKET (1<<0) #define DATATYPE_PAYLOAD (1<<1) #define DATATYPE_STREAM (1<<2) #define DATATYPE_HTTP_URI (1<<3) #define DATATYPE_HTTP_URI_RAW (1<<4) #define DATATYPE_HTTP_REQUEST_HEADERS (1<<5) #define DATATYPE_HTTP_REQUEST_HEADERS_RAW (1<<6) #define DATATYPE_HTTP_REQUEST_COOKIE (1<<7) #define DATATYPE_HTTP_REQUEST_UA (1<<8) #define DATATYPE_HTTP_REQUEST_LINE (1<<9) #define DATATYPE_HTTP_REQUEST_BODY (1<<10) #define DATATYPE_HTTP_RESPONSE_COOKIE (1<<11) #define DATATYPE_HTTP_RESPONSE_BODY (1<<12) #define DATATYPE_HTTP_RESPONSE_HEADERS (1<<13) #define DATATYPE_HTTP_RESPONSE_HEADERS_RAW (1<<14) static void *LuaStatePoolAlloc(void) { return luaL_newstate(); } static void LuaStatePoolFree(void *d) { lua_State *s = (lua_State *)d; if (s != NULL) lua_close(s); } /** \brief Populate lua states pool * * \param num keyword instances * \param reloads bool indicating we have rule reloads enabled */ int DetectLuajitSetupStatesPool(int num, int reloads) { int retval = 0; pthread_mutex_lock(&luajit_states_lock); if (luajit_states == NULL) { int cnt = 0; char *conf_val = NULL; if ((ConfGet("detect-engine.luajit-states", &conf_val)) == 1) { cnt = (int)atoi(conf_val); } else { int cpus = UtilCpuGetNumProcessorsOnline(); if (cpus == 0) { cpus = 10; } cnt = num * cpus; cnt *= 3; /* assume 3 threads per core */ /* alloc a bunch extra so reload can add new rules/instances */ if (reloads) cnt *= 5; } luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, NULL, LuaStatePoolFree); if (luajit_states == NULL) { SCLogError(SC_ERR_LUAJIT_ERROR, "luastate pool init failed, luajit keywords won't work"); retval = -1; } } pthread_mutex_unlock(&luajit_states_lock); return retval; } static lua_State *DetectLuajitGetState(void) { lua_State *s = NULL; pthread_mutex_lock(&luajit_states_lock); if (luajit_states != NULL) s = (lua_State *)PoolGet(luajit_states); pthread_mutex_unlock(&luajit_states_lock); return s; } static void DetectLuajitReturnState(lua_State *s) { if (s != NULL) { pthread_mutex_lock(&luajit_states_lock); PoolReturn(luajit_states, (void *)s); pthread_mutex_unlock(&luajit_states_lock); } } /** \brief dump stack from lua state to screen */ void LuaDumpStack(lua_State *state) { int size = lua_gettop(state); int i; for (i = 1; i <= size; i++) { int type = lua_type(state, i); printf("Stack size=%d, level=%d, type=%d, ", size, i, type); switch (type) { case LUA_TFUNCTION: printf("function %s", lua_tostring(state, i) ? "true" : "false"); break; case LUA_TBOOLEAN: printf("bool %s", lua_toboolean(state, i) ? "true" : "false"); break; case LUA_TNUMBER: printf("number %g", lua_tonumber(state, i)); break; case LUA_TSTRING: printf("string `%s'", lua_tostring(state, i)); break; case LUA_TTABLE: printf("table `%s'", lua_tostring(state, i)); break; default: printf("other %s", lua_typename(state, type)); break; } printf("\n"); } } int DetectLuajitMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, uint8_t *buffer, uint32_t buffer_len, uint32_t offset) { SCEnter(); int ret = 0; if (buffer == NULL || buffer_len == 0) SCReturnInt(0); DetectLuajitData *luajit = (DetectLuajitData *)sm->ctx; if (luajit == NULL) SCReturnInt(0); DetectLuajitThreadData *tluajit = (DetectLuajitThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id); if (tluajit == NULL) SCReturnInt(0); lua_getglobal(tluajit->luastate, "match"); lua_newtable(tluajit->luastate); /* stack at -1 */ lua_pushliteral (tluajit->luastate, "offset"); /* stack at -2 */ lua_pushnumber (tluajit->luastate, (int)(offset + 1)); lua_settable(tluajit->luastate, -3); lua_pushstring (tluajit->luastate, luajit->buffername); /* stack at -2 */ lua_pushlstring (tluajit->luastate, (const char *)buffer, (size_t)buffer_len); lua_settable(tluajit->luastate, -3); int retval = lua_pcall(tluajit->luastate, 1, 1, 0); if (retval != 0) { SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1)); } /* process returns from script */ if (lua_gettop(tluajit->luastate) > 0) { /* script returns a number (return 1 or return 0) */ if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) { double script_ret = lua_tonumber(tluajit->luastate, 1); SCLogDebug("script_ret %f", script_ret); lua_pop(tluajit->luastate, 1); if (script_ret == 1.0) ret = 1; /* script returns a table */ } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) { lua_pushnil(tluajit->luastate); const char *k, *v; while (lua_next(tluajit->luastate, -2)) { v = lua_tostring(tluajit->luastate, -1); lua_pop(tluajit->luastate, 1); k = lua_tostring(tluajit->luastate, -1); if (!k || !v) continue; SCLogDebug("k='%s', v='%s'", k, v); if (strcmp(k, "retval") == 0) { if (atoi(v) == 1) ret = 1; } else { /* set flow var? */ } } /* pop the table */ lua_pop(tluajit->luastate, 1); } } else { SCLogDebug("no stack"); } if (luajit->negated) { if (ret == 1) ret = 0; else ret = 1; } SCReturnInt(ret); } /** * \brief match the specified luajit * * \param t thread local vars * \param det_ctx pattern matcher thread local data * \param p packet * \param s signature being inspected * \param m sigmatch that we will cast into DetectLuajitData * * \retval 0 no match * \retval 1 match */ static int DetectLuajitMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; DetectLuajitData *luajit = (DetectLuajitData *)m->ctx; if (luajit == NULL) SCReturnInt(0); DetectLuajitThreadData *tluajit = (DetectLuajitThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id); if (tluajit == NULL) SCReturnInt(0); if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len == 0) SCReturnInt(0); if ((tluajit->flags & DATATYPE_PACKET) && GET_PKT_LEN(p) == 0) SCReturnInt(0); if (tluajit->alproto != ALPROTO_UNKNOWN) { if (p->flow == NULL) SCReturnInt(0); FLOWLOCK_RDLOCK(p->flow); int alproto = p->flow->alproto; FLOWLOCK_UNLOCK(p->flow); if (tluajit->alproto != alproto) SCReturnInt(0); } lua_getglobal(tluajit->luastate, "match"); lua_newtable(tluajit->luastate); /* stack at -1 */ if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len) { lua_pushliteral(tluajit->luastate, "payload"); /* stack at -2 */ lua_pushlstring (tluajit->luastate, (const char *)p->payload, (size_t)p->payload_len); /* stack at -3 */ lua_settable(tluajit->luastate, -3); } if ((tluajit->flags & DATATYPE_PACKET) && GET_PKT_LEN(p)) { lua_pushliteral(tluajit->luastate, "packet"); /* stack at -2 */ lua_pushlstring (tluajit->luastate, (const char *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p)); /* stack at -3 */ lua_settable(tluajit->luastate, -3); } if (tluajit->alproto == ALPROTO_HTTP) { FLOWLOCK_RDLOCK(p->flow); HtpState *htp_state = p->flow->alstate; if (htp_state != NULL && htp_state->connp != NULL && htp_state->connp->conn != NULL) { int idx = AppLayerTransactionGetInspectId(p->flow); if (idx != -1) { htp_tx_t *tx = NULL; int size = (int)list_size(htp_state->connp->conn->transactions); for ( ; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL) continue; if ((tluajit->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && bstr_len(tx->request_line) > 0) { lua_pushliteral(tluajit->luastate, "http.request_line"); /* stack at -2 */ lua_pushlstring (tluajit->luastate, (const char *)bstr_ptr(tx->request_line), bstr_len(tx->request_line)); lua_settable(tluajit->luastate, -3); } } } } FLOWLOCK_UNLOCK(p->flow); } int retval = lua_pcall(tluajit->luastate, 1, 1, 0); if (retval != 0) { SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1)); } /* process returns from script */ if (lua_gettop(tluajit->luastate) > 0) { /* script returns a number (return 1 or return 0) */ if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) { double script_ret = lua_tonumber(tluajit->luastate, 1); SCLogDebug("script_ret %f", script_ret); lua_pop(tluajit->luastate, 1); if (script_ret == 1.0) ret = 1; /* script returns a table */ } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) { lua_pushnil(tluajit->luastate); const char *k, *v; while (lua_next(tluajit->luastate, -2)) { v = lua_tostring(tluajit->luastate, -1); lua_pop(tluajit->luastate, 1); k = lua_tostring(tluajit->luastate, -1); if (!k || !v) continue; SCLogDebug("k='%s', v='%s'", k, v); if (strcmp(k, "retval") == 0) { if (atoi(v) == 1) ret = 1; } else { /* set flow var? */ } } /* pop the table */ lua_pop(tluajit->luastate, 1); } } if (luajit->negated) { if (ret == 1) ret = 0; else ret = 1; } SCReturnInt(ret); } static void *DetectLuajitThreadInit(void *data) { DetectLuajitData *luajit = (DetectLuajitData *)data; BUG_ON(luajit == NULL); DetectLuajitThreadData *t = SCMalloc(sizeof(DetectLuajitThreadData)); if (unlikely(t == NULL)) { SCLogError(SC_ERR_LUAJIT_ERROR, "couldn't alloc ctx memory"); return NULL; } memset(t, 0x00, sizeof(DetectLuajitThreadData)); t->alproto = luajit->alproto; t->flags = luajit->flags; t->luastate = DetectLuajitGetState(); if (t->luastate == NULL) { SCLogError(SC_ERR_LUAJIT_ERROR, "luastate pool depleted"); goto error; } luaL_openlibs(t->luastate); int status = luaL_loadfile(t->luastate, luajit->filename); if (status) { SCLogError(SC_ERR_LUAJIT_ERROR, "couldn't load file: %s", lua_tostring(t->luastate, -1)); goto error; } /* prime the script (or something) */ if (lua_pcall(t->luastate, 0, 0, 0) != 0) { SCLogError(SC_ERR_LUAJIT_ERROR, "couldn't prime file: %s", lua_tostring(t->luastate, -1)); goto error; } return (void *)t; error: if (t->luastate != NULL) DetectLuajitReturnState(t->luastate); SCFree(t); return NULL; } static void DetectLuajitThreadFree(void *ctx) { if (ctx != NULL) { DetectLuajitThreadData *t = (DetectLuajitThreadData *)ctx; if (t->luastate != NULL) DetectLuajitReturnState(t->luastate); SCFree(t); } } /** * \brief Parse the luajit keyword * * \param str Pointer to the user provided option * * \retval luajit pointer to DetectLuajitData on success * \retval NULL on failure */ static DetectLuajitData *DetectLuajitParse (char *str) { DetectLuajitData *luajit = NULL; /* We have a correct luajit option */ luajit = SCMalloc(sizeof(DetectLuajitData)); if (unlikely(luajit == NULL)) goto error; memset(luajit, 0x00, sizeof(DetectLuajitData)); if (strlen(str) && str[0] == '!') { luajit->negated = 1; str++; } /* get full filename */ luajit->filename = DetectLoadCompleteSigPath(str); if (luajit->filename == NULL) { goto error; } return luajit; error: if (luajit != NULL) DetectLuajitFree(luajit); return NULL; } static int DetectLuaSetupPrime(DetectLuajitData *ld) { lua_State *luastate = luaL_newstate(); if (luastate == NULL) goto error; luaL_openlibs(luastate); int status = luaL_loadfile(luastate, ld->filename); if (status) { SCLogError(SC_ERR_LUAJIT_ERROR, "couldn't load file: %s", lua_tostring(luastate, -1)); goto error; } /* prime the script (or something) */ if (lua_pcall(luastate, 0, 0, 0) != 0) { SCLogError(SC_ERR_LUAJIT_ERROR, "couldn't prime file: %s", lua_tostring(luastate, -1)); goto error; } lua_getglobal(luastate, "init"); if (lua_type(luastate, -1) != LUA_TFUNCTION) { SCLogError(SC_ERR_LUAJIT_ERROR, "no init function in script"); goto error; } lua_newtable(luastate); /* stack at -1 */ if (lua_gettop(luastate) == 0 || lua_type(luastate, 2) != LUA_TTABLE) { SCLogError(SC_ERR_LUAJIT_ERROR, "no table setup"); goto error; } lua_pushliteral(luastate, "script_api_ver"); /* stack at -2 */ lua_pushnumber (luastate, 1); /* stack at -3 */ lua_settable(luastate, -3); if (lua_pcall(luastate, 1, 1, 0) != 0) { SCLogError(SC_ERR_LUAJIT_ERROR, "couldn't run script 'init' function: %s", lua_tostring(luastate, -1)); goto error; } /* process returns from script */ if (lua_gettop(luastate) == 0) { SCLogError(SC_ERR_LUAJIT_ERROR, "init function in script should return table, nothing returned"); goto error; } if (lua_type(luastate, 1) != LUA_TTABLE) { SCLogError(SC_ERR_LUAJIT_ERROR, "init function in script should return table, returned is not table"); goto error; } lua_pushnil(luastate); const char *k, *v; while (lua_next(luastate, -2)) { v = lua_tostring(luastate, -1); lua_pop(luastate, 1); k = lua_tostring(luastate, -1); if (!k || !v) continue; SCLogDebug("k='%s', v='%s'", k, v); if (strcmp(k, "packet") == 0 && strcmp(v, "true") == 0) { ld->flags |= DATATYPE_PACKET; } else if (strcmp(k, "payload") == 0 && strcmp(v, "true") == 0) { ld->flags |= DATATYPE_PAYLOAD; } else if (strncmp(k, "http", 4) == 0 && strcmp(v, "true") == 0) { if (ld->alproto != ALPROTO_UNKNOWN && ld->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_LUAJIT_ERROR, "can just inspect script against one app layer proto like HTTP at a time"); goto error; } if (ld->flags != 0) { SCLogError(SC_ERR_LUAJIT_ERROR, "when inspecting HTTP buffers only a single buffer can be inspected"); goto error; } /* http types */ ld->alproto = ALPROTO_HTTP; if (strcmp(k, "http.uri") == 0) ld->flags |= DATATYPE_HTTP_URI; else if (strcmp(k, "http.uri.raw") == 0) ld->flags |= DATATYPE_HTTP_URI_RAW; else if (strcmp(k, "http.request_line") == 0) ld->flags |= DATATYPE_HTTP_REQUEST_LINE; else if (strcmp(k, "http.request_headers") == 0) ld->flags |= DATATYPE_HTTP_REQUEST_HEADERS; else if (strcmp(k, "http.request_headers.raw") == 0) ld->flags |= DATATYPE_HTTP_REQUEST_HEADERS_RAW; else if (strcmp(k, "http.request_cookie") == 0) ld->flags |= DATATYPE_HTTP_REQUEST_COOKIE; else if (strcmp(k, "http.request_user_agent") == 0) ld->flags |= DATATYPE_HTTP_REQUEST_UA; else if (strcmp(k, "http.request_body") == 0) ld->flags |= DATATYPE_HTTP_REQUEST_BODY; else if (strcmp(k, "http.response_body") == 0) ld->flags |= DATATYPE_HTTP_RESPONSE_BODY; else if (strcmp(k, "http.response_cookie") == 0) ld->flags |= DATATYPE_HTTP_RESPONSE_COOKIE; else if (strcmp(k, "http.response_headers") == 0) ld->flags |= DATATYPE_HTTP_RESPONSE_HEADERS; else if (strcmp(k, "http.response_headers.raw") == 0) ld->flags |= DATATYPE_HTTP_RESPONSE_HEADERS_RAW; else { SCLogError(SC_ERR_LUAJIT_ERROR, "unsupported http data type %s", k); goto error; } ld->buffername = SCStrdup(k); if (ld->buffername == NULL) { SCLogError(SC_ERR_LUAJIT_ERROR, "alloc error"); goto error; } } else { SCLogError(SC_ERR_LUAJIT_ERROR, "unsupported data type %s", k); goto error; } } /* pop the table */ lua_pop(luastate, 1); lua_close(luastate); return 0; error: lua_close(luastate); return -1; } /** * \brief this function is used to parse luajit options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param str pointer to the user provided "luajit" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectLuajitSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectLuajitData *luajit = NULL; SigMatch *sm = NULL; luajit = DetectLuajitParse(str); if (luajit == NULL) goto error; if (DetectLuaSetupPrime(luajit) == -1) { goto error; } luajit->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "luajit", DetectLuajitThreadInit, (void *)luajit, DetectLuajitThreadFree, 0); if (luajit->thread_ctx_id == -1) goto error; if (luajit->alproto != ALPROTO_UNKNOWN) { if (s->alproto != ALPROTO_UNKNOWN && luajit->alproto != s->alproto) { goto error; } s->alproto = luajit->alproto; } /* 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_LUAJIT; sm->ctx = (void *)luajit; if (luajit->alproto == ALPROTO_UNKNOWN) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); else if (luajit->alproto == ALPROTO_HTTP) { if (luajit->flags & DATATYPE_HTTP_RESPONSE_BODY) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); else if (luajit->flags & DATATYPE_HTTP_REQUEST_BODY) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); else if (luajit->flags & DATATYPE_HTTP_URI) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); else if (luajit->flags & DATATYPE_HTTP_URI_RAW) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); else if (luajit->flags & DATATYPE_HTTP_REQUEST_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); else if (luajit->flags & DATATYPE_HTTP_REQUEST_UA) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HUADMATCH); else if (luajit->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHDMATCH); else if (luajit->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH); else if (luajit->flags & DATATYPE_HTTP_RESPONSE_COOKIE) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); } else { SCLogError(SC_ERR_LUAJIT_ERROR, "luajit can't be used with protocol %s", AppLayerGetProtoString(luajit->alproto)); goto error; } de_ctx->detect_luajit_instances++; return 0; error: if (luajit != NULL) DetectLuajitFree(luajit); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectLuajitData * * \param luajit pointer to DetectLuajitData */ static void DetectLuajitFree(void *ptr) { if (ptr != NULL) { DetectLuajitData *luajit = (DetectLuajitData *)ptr; if (luajit->buffername) SCFree(luajit->buffername); SCFree(luajit); } } #ifdef UNITTESTS static int LuajitMatchTest01(void) { return 1; } #endif void DetectLuajitRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("LuajitMatchTest01", LuajitMatchTest01, 1); #endif } #endif /* HAVE_LUAJIT */ suricata-1.4.7/src/source-ipfw.c0000644000000000000000000005641712253546156013451 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Nick Rogness * \author Eric Leblond * * IPFW packet acquisition support */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "source-ipfw.h" #include "util-debug.h" #include "conf.h" #include "util-byte.h" #include "util-privs.h" #include "util-device.h" #include "runmodes.h" #define IPFW_ACCEPT 0 #define IPFW_DROP 1 #define IPFW_SOCKET_POLL_MSEC 300 #ifndef IP_MAXPACKET #define IP_MAXPACKET 65535 #endif #ifndef IPFW /* Handle the case if --enable-ipfw was not used * */ TmEcode NoIPFWSupportExit(ThreadVars *, void *, void **); void TmModuleReceiveIPFWRegister (void) { tmm_modules[TMM_RECEIVEIPFW].name = "ReceiveIPFW"; tmm_modules[TMM_RECEIVEIPFW].ThreadInit = NoIPFWSupportExit; tmm_modules[TMM_RECEIVEIPFW].Func = NULL; tmm_modules[TMM_RECEIVEIPFW].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVEIPFW].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEIPFW].RegisterTests = NULL; tmm_modules[TMM_RECEIVEIPFW].flags = TM_FLAG_RECEIVE_TM; } void TmModuleVerdictIPFWRegister (void) { tmm_modules[TMM_VERDICTIPFW].name = "VerdictIPFW"; tmm_modules[TMM_VERDICTIPFW].ThreadInit = NoIPFWSupportExit; tmm_modules[TMM_VERDICTIPFW].Func = NULL; tmm_modules[TMM_VERDICTIPFW].ThreadExitPrintStats = NULL; tmm_modules[TMM_VERDICTIPFW].ThreadDeinit = NULL; tmm_modules[TMM_VERDICTIPFW].RegisterTests = NULL; } void TmModuleDecodeIPFWRegister (void) { tmm_modules[TMM_DECODEIPFW].name = "DecodeIPFW"; tmm_modules[TMM_DECODEIPFW].ThreadInit = NoIPFWSupportExit; tmm_modules[TMM_DECODEIPFW].Func = NULL; tmm_modules[TMM_DECODEIPFW].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEIPFW].ThreadDeinit = NULL; tmm_modules[TMM_DECODEIPFW].RegisterTests = NULL; tmm_modules[TMM_DECODEIPFW].cap_flags = 0; tmm_modules[TMM_DECODEIPFW].flags = TM_FLAG_DECODE_TM; } TmEcode NoIPFWSupportExit(ThreadVars *tv, void *initdata, void **data) { SCLogError(SC_ERR_IPFW_NOSUPPORT,"Error creating thread %s: you do not have support for ipfw " "enabled please recompile with --enable-ipfw", tv->name); exit(EXIT_FAILURE); } #else /* We have IPFW compiled in */ extern int max_pending_packets; /** * \brief Structure to hold thread specific variables. */ typedef struct IPFWThreadVars_ { /* data link type for the thread, probably not needed */ int datalink; /* this one should be not changing after init */ uint16_t port_num; /* position into the NFQ queue var array */ uint16_t ipfw_index; /* counters */ uint32_t pkts; uint64_t bytes; uint32_t errs; uint32_t accepted; uint32_t dropped; } IPFWThreadVars; static IPFWThreadVars ipfw_t[IPFW_MAX_QUEUE]; static IPFWQueueVars ipfw_q[IPFW_MAX_QUEUE]; static uint16_t receive_port_num = 0; static SCMutex ipfw_init_lock; /* IPFW Prototypes */ void *IPFWGetQueue(int number); TmEcode ReceiveIPFWThreadInit(ThreadVars *, void *, void **); TmEcode ReceiveIPFW(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot); void ReceiveIPFWThreadExitStats(ThreadVars *, void *); TmEcode ReceiveIPFWThreadDeinit(ThreadVars *, void *); TmEcode IPFWSetVerdict(ThreadVars *, IPFWThreadVars *, Packet *); TmEcode VerdictIPFW(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode VerdictIPFWThreadInit(ThreadVars *, void *, void **); void VerdictIPFWThreadExitStats(ThreadVars *, void *); TmEcode VerdictIPFWThreadDeinit(ThreadVars *, void *); TmEcode DecodeIPFWThreadInit(ThreadVars *, void *, void **); TmEcode DecodeIPFW(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); /** * \brief Registration Function for RecieveIPFW. * \todo Unit tests are needed for this module. */ void TmModuleReceiveIPFWRegister (void) { SCMutexInit(&ipfw_init_lock, NULL); tmm_modules[TMM_RECEIVEIPFW].name = "ReceiveIPFW"; tmm_modules[TMM_RECEIVEIPFW].ThreadInit = ReceiveIPFWThreadInit; tmm_modules[TMM_RECEIVEIPFW].Func = NULL; tmm_modules[TMM_RECEIVEIPFW].PktAcqLoop = ReceiveIPFWLoop; tmm_modules[TMM_RECEIVEIPFW].ThreadExitPrintStats = ReceiveIPFWThreadExitStats; tmm_modules[TMM_RECEIVEIPFW].ThreadDeinit = ReceiveIPFWThreadDeinit; tmm_modules[TMM_RECEIVEIPFW].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | SC_CAP_NET_BIND_SERVICE | SC_CAP_NET_BROADCAST; /** \todo untested */ tmm_modules[TMM_RECEIVEIPFW].RegisterTests = NULL; tmm_modules[TMM_RECEIVEIPFW].flags = TM_FLAG_RECEIVE_TM; } /** * \brief Registration Function for VerdictIPFW. * \todo Unit tests are needed for this module. */ void TmModuleVerdictIPFWRegister (void) { tmm_modules[TMM_VERDICTIPFW].name = "VerdictIPFW"; tmm_modules[TMM_VERDICTIPFW].ThreadInit = VerdictIPFWThreadInit; tmm_modules[TMM_VERDICTIPFW].Func = VerdictIPFW; tmm_modules[TMM_VERDICTIPFW].ThreadExitPrintStats = VerdictIPFWThreadExitStats; tmm_modules[TMM_VERDICTIPFW].ThreadDeinit = VerdictIPFWThreadDeinit; tmm_modules[TMM_VERDICTIPFW].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | SC_CAP_NET_BIND_SERVICE; /** \todo untested */ tmm_modules[TMM_VERDICTIPFW].RegisterTests = NULL; } /** * \brief Registration Function for DecodeIPFW. * \todo Unit tests are needed for this module. */ void TmModuleDecodeIPFWRegister (void) { tmm_modules[TMM_DECODEIPFW].name = "DecodeIPFW"; tmm_modules[TMM_DECODEIPFW].ThreadInit = DecodeIPFWThreadInit; tmm_modules[TMM_DECODEIPFW].Func = DecodeIPFW; tmm_modules[TMM_DECODEIPFW].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEIPFW].ThreadDeinit = NULL; tmm_modules[TMM_DECODEIPFW].RegisterTests = NULL; tmm_modules[TMM_DECODEIPFW].flags = TM_FLAG_DECODE_TM; } static inline void IPFWMutexInit(IPFWQueueVars *nq) { char *active_runmode = RunmodeGetActive(); if (active_runmode && !strcmp("workers", active_runmode)) { nq->use_mutex = 0; SCLogInfo("IPFW running in 'workers' runmode, will not use mutex."); } else { nq->use_mutex = 1; } if (nq->use_mutex) SCMutexInit(&nq->socket_lock, NULL); } static inline void IPFWMutexLock(IPFWQueueVars *nq) { if (nq->use_mutex) SCMutexLock(&nq->socket_lock); } static inline void IPFWMutexUnlock(IPFWQueueVars *nq) { if (nq->use_mutex) SCMutexUnlock(&nq->socket_lock); } TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); IPFWThreadVars *ptv = (IPFWThreadVars *)data; IPFWQueueVars *nq = NULL; uint8_t pkt[IP_MAXPACKET]; int pktlen=0; struct pollfd IPFWpoll; struct timeval IPFWts; Packet *p = NULL; uint16_t packet_q_len = 0; nq = IPFWGetQueue(ptv->ipfw_index); if (nq == NULL) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Can't get thread variable"); SCReturnInt(TM_ECODE_FAILED); } SCLogInfo("Thread '%s' will run on port %d (item %d)", tv->name, nq->port_num, ptv->ipfw_index); while (1) { if (suricata_ctl_flags & (SURICATA_STOP || SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } IPFWpoll.fd = nq->fd; IPFWpoll.events = POLLRDNORM; /* Poll the socket for status */ if ( (poll(&IPFWpoll, 1, IPFW_SOCKET_POLL_MSEC)) > 0) { if (!(IPFWpoll.revents & (POLLRDNORM | POLLERR))) continue; } if ((pktlen = recvfrom(nq->fd, pkt, sizeof(pkt), 0, (struct sockaddr *)&nq->ipfw_sin, &nq->ipfw_sinlen)) == -1) { /* We received an error on socket read */ if (errno == EINTR || errno == EWOULDBLOCK) { /* Nothing for us to process */ continue; } else { SCLogWarning(SC_WARN_IPFW_RECV, "Read from IPFW divert socket failed: %s", strerror(errno)); SCReturnInt(TM_ECODE_FAILED); } } /* We have a packet to process */ memset (&IPFWts, 0, sizeof(struct timeval)); gettimeofday(&IPFWts, NULL); /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCReturnInt(TM_ECODE_FAILED); } PKT_SET_SRC(p, PKT_SRC_WIRE); SCLogDebug("Received Packet Len: %d", pktlen); p->ts.tv_sec = IPFWts.tv_sec; p->ts.tv_usec = IPFWts.tv_usec; ptv->pkts++; ptv->bytes += pktlen; p->datalink = ptv->datalink; p->ipfw_v.ipfw_index = ptv->ipfw_index; PacketCopyData(p, pkt, pktlen); SCLogDebug("Packet info: pkt_len: %" PRIu32 " (pkt %02x, pkt_data %02x)", GET_PKT_LEN(p), *pkt, GET_PKT_DATA(p)); if (TmThreadsSlotProcessPkt(tv, ((TmSlot *) slot)->slot_next, p) != TM_ECODE_OK) { TmqhOutputPacketpool(tv, p); SCReturnInt(TM_ECODE_FAILED); } SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); } /** * \brief Init function for RecieveIPFW. * * This is a setup function for recieving packets * via ipfw divert, binds a socket, and prepares to * to read from it. * * \param tv pointer to ThreadVars * \param initdata pointer to the divert port passed from the user * \param data pointer gets populated with IPFWThreadVars * */ TmEcode ReceiveIPFWThreadInit(ThreadVars *tv, void *initdata, void **data) { struct timeval timev; int flag; IPFWThreadVars *ntv = (IPFWThreadVars *) initdata; IPFWQueueVars *nq = IPFWGetQueue(ntv->ipfw_index); sigset_t sigs; sigfillset(&sigs); pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); SCEnter(); IPFWMutexInit(nq); /* We need a divert socket to play with */ if ((nq->fd = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT)) == -1) { SCLogError(SC_ERR_IPFW_SOCK,"Can't create divert socket: %s", strerror(errno)); SCReturnInt(TM_ECODE_FAILED); } /* set a timeout to the socket so we can check for a signal * in case we don't get packets for a longer period. */ timev.tv_sec = 1; timev.tv_usec = 0; if (setsockopt(nq->fd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev)) == -1) { SCLogError(SC_ERR_IPFW_SETSOCKOPT,"Can't set IPFW divert socket timeout: %s", strerror(errno)); SCReturnInt(TM_ECODE_FAILED); } /* set SO_BROADCAST on the divert socket, otherwise sendto() * returns EACCES when reinjecting broadcast packets. */ flag = 1; if (setsockopt(nq->fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag)) == -1) { SCLogError(SC_ERR_IPFW_SETSOCKOPT,"Can't set IPFW divert socket broadcast flag: %s", strerror(errno)); SCReturnInt(TM_ECODE_FAILED); } nq->ipfw_sinlen=sizeof(nq->ipfw_sin); memset(&nq->ipfw_sin, 0, nq->ipfw_sinlen); nq->ipfw_sin.sin_family = PF_INET; nq->ipfw_sin.sin_addr.s_addr = INADDR_ANY; nq->ipfw_sin.sin_port = htons(nq->port_num); /* Bind that SOB */ if (bind(nq->fd, (struct sockaddr *)&nq->ipfw_sin, nq->ipfw_sinlen) == -1) { SCLogError(SC_ERR_IPFW_BIND,"Can't bind divert socket on port %d: %s",nq->port_num,strerror(errno)); SCReturnInt(TM_ECODE_FAILED); } ntv->datalink = DLT_RAW; *data = (void *)ntv; SCReturnInt(TM_ECODE_OK); } /** * \brief This function prints stats to the screen at exit. * \todo Unit tests are needed for this module. * \param tv pointer to ThreadVars * \param data pointer that gets cast into IPFWThreadVars for ptv */ void ReceiveIPFWThreadExitStats(ThreadVars *tv, void *data) { IPFWThreadVars *ptv = (IPFWThreadVars *)data; SCEnter(); SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); SCReturn; } /** * \brief DeInit function closes divert socket at exit. * \todo Unit tests are needed for this module. * \param tv pointer to ThreadVars * \param data pointer that gets cast into IPFWThreadVars for ptv */ TmEcode ReceiveIPFWThreadDeinit(ThreadVars *tv, void *data) { IPFWThreadVars *ptv = (IPFWThreadVars *)data; IPFWQueueVars *nq = IPFWGetQueue(ptv->ipfw_index); SCEnter(); /* Attempt to shut the socket down...close instead? */ if (shutdown(nq->fd, SHUT_RD) < 0) { SCLogWarning(SC_WARN_IPFW_UNBIND,"Unable to disable ipfw socket: %s",strerror(errno)); SCReturnInt(TM_ECODE_FAILED); } data = (void *)ptv; SCReturnInt(TM_ECODE_OK); } /** * \brief This function passes off to link type decoders. * \todo Unit tests are needed for this module. * * DecodeIPFW reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param tv pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into IPFWThreadVars for ptv * \param pq pointer to the PacketQueue */ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p); IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; SCEnter(); /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); /* Process IP packets */ if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("DecodeIPFW ip4 processing"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if(IPV6_GET_RAW_VER(ip6h) == 6) { SCLogDebug("DecodeIPFW ip6 processing"); DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else { /* We don't support anything besides IP packets for now, bridged packets? */ SCLogInfo("IPFW unknown protocol support %02x", *GET_PKT_DATA(p)); SCReturnInt(TM_ECODE_FAILED); } SCReturnInt(TM_ECODE_OK); } /** * \brief This function initializes the DecodeThreadVariables * * * \param tv pointer to ThreadVars * \param initdata pointer for passing in args * \param data pointer that gets cast into IPFWThreadVars for ptv */ TmEcode DecodeIPFWThreadInit(ThreadVars *tv, void *initdata, void **data) { DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if (dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; SCReturnInt(TM_ECODE_OK); } /** * \brief This function sets the Verdict and processes the packet * * * \param tv pointer to ThreadVars * \param p pointer to the Packet */ TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) { uint32_t verdict; struct pollfd IPFWpoll; IPFWQueueVars *nq = NULL; SCEnter(); if (p == NULL) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Packet is NULL"); SCReturnInt(TM_ECODE_FAILED); } nq = IPFWGetQueue(p->ipfw_v.ipfw_index); if (nq == NULL) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "No thread found"); SCReturnInt(TM_ECODE_FAILED); } IPFWpoll.fd = nq->fd; IPFWpoll.events = POLLWRNORM; if (PACKET_TEST_ACTION(p, ACTION_DROP)) { verdict = IPFW_DROP; } else { verdict = IPFW_ACCEPT; } if (verdict == IPFW_ACCEPT) { SCLogDebug("IPFW Verdict is to Accept"); ptv->accepted++; /* For divert sockets, accepting means writing the * packet back to the socket for ipfw to pick up */ SCLogDebug("IPFWSetVerdict writing to socket %d, %p, %u", nq->fd, GET_PKT_DATA(p),GET_PKT_LEN(p)); #if 0 while ((poll(&IPFWpoll,1,IPFW_SOCKET_POLL_MSEC)) < 1) { /* Did we receive a signal to shutdown */ if (TmThreadsCheckFlag(tv, THV_KILL) || TmThreadsCheckFlag(tv, THV_PAUSE)) { SCLogInfo("Received ThreadShutdown: IPFW divert socket writing interrupted"); SCReturnInt(TM_ECODE_OK); } } #endif IPFWMutexLock(nq); if (sendto(nq->fd, GET_PKT_DATA(p), GET_PKT_LEN(p), 0,(struct sockaddr *)&nq->ipfw_sin, nq->ipfw_sinlen) == -1) { int r = errno; switch (r) { default: SCLogWarning(SC_WARN_IPFW_XMIT,"Write to ipfw divert socket failed: %s",strerror(r)); IPFWMutexUnlock(nq); SCReturnInt(TM_ECODE_FAILED); case EHOSTDOWN: case ENETDOWN: break; } } IPFWMutexUnlock(nq); SCLogDebug("Sent Packet back into IPFW Len: %d",GET_PKT_LEN(p)); } /* end IPFW_ACCEPT */ if (verdict == IPFW_DROP) { SCLogDebug("IPFW SetVerdict is to DROP"); ptv->dropped++; /** \todo For divert sockets, dropping means not writing the packet back to the socket. * Need to see if there is some better way to free the packet from the queue */ } /* end IPFW_DROP */ SCReturnInt(TM_ECODE_OK); } /** * \brief This function handles the Verdict processing * \todo Unit tests are needed for this module. * * * \param tv pointer to ThreadVars * \param p pointer to the Packet * \param data pointer that gets cast into IPFWThreadVars for ptv * \param pq pointer for the Packet Queue access (Not used) */ TmEcode VerdictIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { IPFWThreadVars *ptv = (IPFWThreadVars *)data; TmEcode retval = TM_ECODE_OK; SCEnter(); /* can't verdict a "fake" packet */ if (p->flags & PKT_PSEUDO_STREAM_END) { SCReturnInt(TM_ECODE_OK); } /* This came from NFQ. * if this is a tunnel packet we check if we are ready to verdict * already. */ if (IS_TUNNEL_PKT(p)) { char verdict = 1; SCMutex *m = p->root ? &p->root->tunnel_mutex : &p->tunnel_mutex; SCMutexLock(m); /* if there are more tunnel packets than ready to verdict packets, * we won't verdict this one */ if (TUNNEL_PKT_TPR(p) > TUNNEL_PKT_RTV(p)) { SCLogDebug("VerdictIPFW: not ready to verdict yet: " "TUNNEL_PKT_TPR(p) > TUNNEL_PKT_RTV(p) = %" PRId32 " > %" PRId32 "", TUNNEL_PKT_TPR(p), TUNNEL_PKT_RTV(p)); verdict = 0; } SCMutexUnlock(m); /* don't verdict if we are not ready */ if (verdict == 1) { SCLogDebug("Setting verdict on tunnel"); retval = IPFWSetVerdict(tv, ptv, p->root ? p->root : p); } else { TUNNEL_INCR_PKT_RTV(p); } } else { /* no tunnel, verdict normally */ SCLogDebug("Setting verdict on non-tunnel"); retval = IPFWSetVerdict(tv, ptv, p); } /* IS_TUNNEL_PKT end */ SCReturnInt(retval); } /** * \brief This function initializes the VerdictThread * * * \param t pointer to ThreadVars * \param initdata pointer for passing in args * \param data pointer that gets cast into IPFWThreadVars for ptv */ TmEcode VerdictIPFWThreadInit(ThreadVars *tv, void *initdata, void **data) { IPFWThreadVars *ptv = NULL; SCEnter(); /* Setup Thread vars */ if ( (ptv = SCMalloc(sizeof(IPFWThreadVars))) == NULL) SCReturnInt(TM_ECODE_FAILED); memset(ptv, 0, sizeof(IPFWThreadVars)); *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); } /** * \brief This function deinitializes the VerdictThread * * * \param tv pointer to ThreadVars * \param data pointer that gets cast into IPFWThreadVars for ptv */ TmEcode VerdictIPFWThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); /* We don't need to do anything...not sure quite yet */ SCReturnInt(TM_ECODE_OK); } /** * \brief This function prints stats for the VerdictThread * * * \param tv pointer to ThreadVars * \param data pointer that gets cast into IPFWThreadVars for ptv */ void VerdictIPFWThreadExitStats(ThreadVars *tv, void *data) { IPFWThreadVars *ptv = (IPFWThreadVars *)data; SCLogInfo("IPFW Processing: - (%s) Pkts accepted %" PRIu32 ", dropped %" PRIu32 "", tv->name, ptv->accepted, ptv->dropped); } /** * \brief Add an IPFW divert * * \param string with the queue name * * \retval 0 on success. * \retval -1 on failure. */ int IPFWRegisterQueue(char *queue) { IPFWThreadVars *ntv = NULL; IPFWQueueVars *nq = NULL; /* Extract the queue number from the specified command line argument */ uint16_t port_num = 0; if ((ByteExtractStringUint16(&port_num, 10, strlen(queue), queue)) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified queue number %s is not " "valid", queue); return -1; } SCMutexLock(&ipfw_init_lock); if (receive_port_num >= IPFW_MAX_QUEUE) { SCLogError(SC_ERR_INVALID_ARGUMENT, "too much IPFW divert port registered (%d)", receive_port_num); SCMutexUnlock(&ipfw_init_lock); return -1; } if (receive_port_num == 0) { memset(&ipfw_t, 0, sizeof(ipfw_t)); memset(&ipfw_q, 0, sizeof(ipfw_q)); } ntv = &ipfw_t[receive_port_num]; ntv->ipfw_index = receive_port_num; nq = &ipfw_q[receive_port_num]; nq->port_num = port_num; receive_port_num++; SCMutexUnlock(&ipfw_init_lock); LiveRegisterDevice(queue); SCLogDebug("Queue \"%s\" registered.", queue); return 0; } /** * \brief Get a pointer to the IPFW queue at index * * \param number idx of the queue in our array * * \retval ptr pointer to the IPFWThreadVars at index * \retval NULL on error */ void *IPFWGetQueue(int number) { if (number >= receive_port_num) return NULL; return (void *)&ipfw_q[number]; } /** * \brief Get a pointer to the IPFW thread at index * * This function is temporary used as configuration parser. * * \param number idx of the queue in our array * * \retval ptr pointer to the IPFWThreadVars at index * \retval NULL on error */ void *IPFWGetThread(int number) { if (number >= receive_port_num) return NULL; return (void *)&ipfw_t[number]; } #endif /* End ifdef IPFW */ /* eof */ suricata-1.4.7/src/source-nfq-prototypes.h0000644000000000000000000000177312253546156015516 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __SOURCE_NFQ_PROTOTYPES_H__ #define __SOURCE_NFQ_PROTOTYPES_H__ void TmModuleReceiveNFQRegister (void); void TmModuleVerdictNFQRegister (void); void TmModuleDecodeNFQRegister (void); #endif /* __SOURCE_NFQ_PROTOTYPES_H__ */ suricata-1.4.7/src/util-debug-filters.h0000644000000000000000000000655112253546156014714 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DEBUG_FILTERS_H__ #define __DEBUG_FILTERS_H__ #include #include "threads.h" #include "util-mem.h" /** * \brief Enum that holds the different kinds of filters available */ enum { SC_LOG_FILTER_BL = 0, SC_LOG_FILTER_WL = 1, SC_LOG_FILTER_MAX = 2, }; /** * \brief Structure used to hold the line_no details of a FG filter */ typedef struct SCLogFGFilterLine_ { int line; struct SCLogFGFilterLine_ *next; } SCLogFGFilterLine; /** * \brief structure used to hold the function details of a FG filter */ typedef struct SCLogFGFilterFunc_ { char *func; SCLogFGFilterLine *line; struct SCLogFGFilterFunc_ *next; } SCLogFGFilterFunc; /** * \brief Structure used to hold FG filters. Encapsulates filename details, * func details, which inturn encapsulates the line_no details */ typedef struct SCLogFGFilterFile_ { char *file; SCLogFGFilterFunc *func; struct SCLogFGFilterFile_ *next; } SCLogFGFilterFile; /** * \brief Structure used to hold the thread_list used by FD filters */ typedef struct SCLogFDFilterThreadList_ { int entered; pthread_t t; // pid_t t; struct SCLogFDFilterThreadList_ *next; } SCLogFDFilterThreadList; /** * \brief Structure that holds the FD filters */ typedef struct SCLogFDFilter_ { char *func; struct SCLogFDFilter_ *next; } SCLogFDFilter; extern int sc_log_fg_filters_present; extern int sc_log_fd_filters_present; int SCLogAddFGFilterWL(const char *, const char *, int); int SCLogAddFGFilterBL(const char *, const char *, int); int SCLogMatchFGFilterBL(const char *, const char *, int); int SCLogMatchFGFilterWL(const char *, const char *, int); void SCLogReleaseFGFilters(void); int SCLogAddFDFilter(const char *); int SCLogPrintFDFilters(void); void SCLogReleaseFDFilters(void); int SCLogRemoveFDFilter(const char *); int SCLogCheckFDFilterEntry(const char *); void SCLogCheckFDFilterExit(const char *); int SCLogMatchFDFilter(const char *); int SCLogPrintFGFilters(void); void SCLogAddToFGFFileList(SCLogFGFilterFile *, const char *, const char *, int, int); void SCLogAddToFGFFuncList(SCLogFGFilterFile *, SCLogFGFilterFunc *, const char *, int); void SCLogAddToFGFLineList(SCLogFGFilterFunc *, SCLogFGFilterLine *, int); void SCLogReleaseFDFilter(SCLogFDFilter *); #endif /* __DEBUG_H__ */ suricata-1.4.7/src/util-action.c0000644000000000000000000013361612253546156013433 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #include "suricata-common.h" #include "action-globals.h" #include "conf.h" #include "conf-yaml-loader.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-sigorder.h" #include "util-unittest.h" #include "util-action.h" #include "util-unittest-helper.h" #include "util-debug.h" /* Default order: */ uint8_t action_order_sigs[4] = {ACTION_PASS, ACTION_DROP, ACTION_REJECT, ACTION_ALERT}; /* This order can be changed from config */ /** * \brief Return the priority associated to an action (to order sigs * as specified at config) * action_order_sigs has this priority by index val * so action_order_sigs[0] has to be inspected first. * This function is called from detect-engine-sigorder * \param action can be one of ACTION_PASS, ACTION_DROP, * ACTION_REJECT or ACTION_ALERT * \retval uint8_t the priority (order of this actions) */ uint8_t ActionOrderVal(uint8_t action) { /* reject_both and reject_dst have the same prio as reject */ if( (action & ACTION_REJECT) || (action & ACTION_REJECT_BOTH) || (action & ACTION_REJECT_DST)) { action = ACTION_REJECT; } uint8_t i = 0; for (; i < 4; i++) { if (action_order_sigs[i] == action) return i; } /* Unknown action, set just a low prio (high val) */ return 10; } /** * \brief Return the ACTION_* bit from their ascii value * \param action can be one of "pass", "drop", * "reject" or "alert" * \retval uint8_t can be one of ACTION_PASS, ACTION_DROP, * ACTION_REJECT or ACTION_ALERT */ uint8_t ActionAsciiToFlag(char *action) { if (strcmp(action,"pass") == 0) return ACTION_PASS; if (strcmp(action,"drop") == 0) return ACTION_DROP; if (strcmp(action,"reject") == 0) return ACTION_REJECT; if (strcmp(action,"alert") == 0) return ACTION_ALERT; return 0; } /** * \brief Load the action order from config. If none is provided, * it will be default to ACTION_PASS, ACTION_DROP, * ACTION_REJECT, ACTION_ALERT (pass has the highest prio) * * \retval 0 on success; -1 on fatal error; */ int ActionInitConfig() { uint8_t actions_used = 0; uint8_t action_flag = 0; uint8_t actions_config[4] = {0, 0, 0, 0}; int order = 0; ConfNode *action_order; ConfNode *action = NULL; /* Let's load the order of actions from the general config */ action_order = ConfGetNode("action-order"); if (action_order != NULL) { TAILQ_FOREACH(action, &action_order->head, next) { SCLogDebug("Loading action order : %s", action->val); action_flag = ActionAsciiToFlag(action->val); if (action_flag == 0) { SCLogError(SC_ERR_ACTION_ORDER, "action-order, invalid action: \"%s\". Please, use" " \"pass\",\"drop\",\"alert\",\"reject\". You have" " to specify all of them, without quotes and without" " capital letters", action->val); goto error; } if (actions_used & action_flag) { SCLogError(SC_ERR_ACTION_ORDER, "action-order, action already set: \"%s\". Please," " use \"pass\",\"drop\",\"alert\",\"reject\". You" " have to specify all of them, without quotes and" " without capital letters", action->val); goto error; } if (order >= 4) { SCLogError(SC_ERR_ACTION_ORDER, "action-order, you have already specified all the " "possible actions plus \"%s\". Please, use \"pass\"," "\"drop\",\"alert\",\"reject\". You have to specify" " all of them, without quotes and without capital" " letters", action->val); goto error; } actions_used |= action_flag; actions_config[order++] = action_flag; } } if (order < 4) { SCLogError(SC_ERR_ACTION_ORDER, "action-order, the config didn't specify all of the " "actions. Please, use \"pass\",\"drop\",\"alert\"," "\"reject\". You have to specify all of them, without" " quotes and without capital letters"); goto error; } /* Now, it's a valid config. Override the default preset */ for (order = 0; order < 4; order++) { action_order_sigs[order] = actions_config[order]; } return 0; error: return -1; } #ifdef UNITTESTS #include "util-unittest.h" /** * \test Check that we invalidate duplicated actions * (It should default to pass, drop, reject, alert) */ int UtilActionTest01(void) { int res = 1; char config[] = "\ %YAML 1.1\n\ ---\n\ action-order:\n\ - alert\n\ - drop\n\ - reject\n\ - alert\n"; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ActionInitConfig(); if (action_order_sigs[0] != ACTION_PASS || action_order_sigs[1] != ACTION_DROP || action_order_sigs[2] != ACTION_REJECT || action_order_sigs[3] != ACTION_ALERT) { res = 0; } ConfRestoreContextBackup(); /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we invalidate with unknown keywords * (It should default to pass, drop, reject, alert) */ int UtilActionTest02(void) { int res = 1; char config[] = "\ %YAML 1.1\n\ ---\n\ action-order:\n\ - alert\n\ - drop\n\ - reject\n\ - ftw\n"; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ActionInitConfig(); if (action_order_sigs[0] != ACTION_PASS || action_order_sigs[1] != ACTION_DROP || action_order_sigs[2] != ACTION_REJECT || action_order_sigs[3] != ACTION_ALERT) { res = 0; } ConfRestoreContextBackup(); /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we invalidate if any action is missing * (It should default to pass, drop, reject, alert) */ int UtilActionTest03(void) { int res = 1; char config[] = "\ %YAML 1.1\n\ ---\n\ action-order:\n\ - alert\n\ - drop\n\ - reject\n"; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ActionInitConfig(); if (action_order_sigs[0] != ACTION_PASS || action_order_sigs[1] != ACTION_DROP || action_order_sigs[2] != ACTION_REJECT || action_order_sigs[3] != ACTION_ALERT) { res = 0; } ConfRestoreContextBackup(); /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we invalidate if any action is missing * (It should default to pass, drop, reject, alert) */ int UtilActionTest04(void) { int res = 1; char config[] = "\ %YAML 1.1\n\ ---\n\ action-order:\n"; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ActionInitConfig(); if (action_order_sigs[0] != ACTION_PASS || action_order_sigs[1] != ACTION_DROP || action_order_sigs[2] != ACTION_REJECT || action_order_sigs[3] != ACTION_ALERT) { res = 0; } ConfRestoreContextBackup(); /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we invalidate with unknown keywords * and/or more than the expected * (It should default to pass, drop, reject, alert) */ int UtilActionTest05(void) { int res = 1; char config[] = "\ %YAML 1.1\n\ ---\n\ action-order:\n\ - alert\n\ - drop\n\ - reject\n\ - pass\n\ - whatever\n"; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ActionInitConfig(); if (action_order_sigs[0] != ACTION_PASS || action_order_sigs[1] != ACTION_DROP || action_order_sigs[2] != ACTION_REJECT || action_order_sigs[3] != ACTION_ALERT) { res = 0; } ConfRestoreContextBackup(); /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we load a valid config */ int UtilActionTest06(void) { int res = 1; char config[] = "\ %YAML 1.1\n\ ---\n\ action-order:\n\ - alert\n\ - drop\n\ - reject\n\ - pass\n"; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ActionInitConfig(); if (action_order_sigs[0] != ACTION_ALERT || action_order_sigs[1] != ACTION_DROP || action_order_sigs[2] != ACTION_REJECT || action_order_sigs[3] != ACTION_PASS) { res = 0; } ConfRestoreContextBackup(); /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we load a valid config */ int UtilActionTest07(void) { int res = 1; char config[] = "\ %YAML 1.1\n\ ---\n\ action-order:\n\ - pass\n\ - alert\n\ - drop\n\ - reject\n"; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ActionInitConfig(); if (action_order_sigs[0] != ACTION_PASS || action_order_sigs[1] != ACTION_ALERT || action_order_sigs[2] != ACTION_DROP || action_order_sigs[3] != ACTION_REJECT) { res = 0; } ConfRestoreContextBackup(); /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we handle the "pass" action * correctly at the IP Only engine in the default case */ int UtilActionTest08(void) { int res = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert ip any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "pass ip 192.168.1.1 80 -> any any (msg:\"sig 2\"; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {1, 0, 1}, {0, 0, 0}, {1, 0, 1} }; /* This means that with the second packet, the results will be * all ({0,0,0}) since, we should match the "pass" rule first */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return res; } /** * \test Check that we handle the "pass" action * correctly at the IP Only engine with more * prio to drop */ int UtilActionTest09(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_PASS; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert ip any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "pass ip 192.168.1.1 80 -> any any (msg:\"sig 2\"; sid:2;)"; sigs[2]= "drop ip any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {1, 0, 1}, {0, 0, 1}, {1, 0, 1} }; /* This means that with the second packet, the results will be * all ({0,0,1}) since, we should match the "drop" rule first. * Later the "pass" rule will avoid the "alert" rule match */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we handle the "pass" action * correctly at the detection engine in the default case */ int UtilActionTest10(void) { int res = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t *buf2 = (uint8_t *)"wo!"; uint16_t buflen2 = strlen((char *)buf2); Packet *p[3]; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf2, buflen2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert ip any any -> any any (msg:\"sig 1\"; content:\"Hi all\"; sid:1;)"; sigs[1]= "pass ip any any -> any any (msg:\"sig 2\"; content:\"wo\"; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"sig 3\"; content:\"Hi all\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {1, 0, 1}, {0, 0, 0}, {1, 0, 1} }; /* This means that with the second packet, the results will be * all ({0,0,0}) since, we should match the "pass" rule first */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return res; } /** * \test Check that we handle the "pass" action * correctly at the detection engine with more * prio to drop */ int UtilActionTest11(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t *buf2 = (uint8_t *)"Hi all wo!"; uint16_t buflen2 = strlen((char *)buf2); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_PASS; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf2, buflen2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert tcp any any -> any any (msg:\"sig 1\"; content:\"Hi all\"; sid:1;)"; sigs[1]= "pass tcp any any -> any any (msg:\"sig 2\"; content:\"wo\"; sid:2;)"; sigs[2]= "drop tcp any any -> any any (msg:\"sig 3\"; content:\"Hi all\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {1, 0, 1}, {0, 0, 1}, {1, 0, 1} }; /* This means that with the second packet, the results will be * all ({0,0,1}) since, we should match the "drop" rule first. * Later the "pass" rule will avoid the "alert" rule match */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we handle the "pass" action * correctly at the detection engine in the default case */ int UtilActionTest12(void) { int res = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert ip any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "pass ip any any -> any any (msg:\"Testing normal 2\"; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} }; /* All should match the 3 sigs, but the action pass has prio */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return res; } /** * \test Check that we handle the "pass" action * correctly at the detection engine with more * prio to drop */ int UtilActionTest13(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_PASS; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert tcp any any -> any any (msg:\"sig 1\"; content:\"Hi all\"; sid:1;)"; sigs[1]= "pass tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "drop tcp any any -> any any (msg:\"sig 3\"; content:\"Hi all\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {0, 0, 1}, {0, 0, 1}, {0, 0, 1} }; /* All the patckets should match the 3 sigs. As drop has more * priority than pass, it should alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check that we handle the "pass" action * correctly at the detection engine with more * prio to drop and alert */ int UtilActionTest14(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_ALERT; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_PASS; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert tcp any any -> any any (msg:\"sig 1\"; content:\"Hi all\"; sid:1;)"; sigs[1]= "pass tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "drop tcp any any -> any any (msg:\"sig 3\"; content:\"Hi all\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {1, 0, 1}, {1, 0, 1}, {1, 0, 1} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check mixed sigs (iponly and normal) */ int UtilActionTest15(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "pass tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "drop tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return res; } /** * \test Check mixed sigs (iponly and normal) */ int UtilActionTest16(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "drop tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "alert tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "pass tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return res; } /** * \test Check mixed sigs (iponly and normal) */ int UtilActionTest17(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "pass tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "drop tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "alert tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return res; } /** * \test Check mixed sigs (iponly and normal) with more prio for drop */ int UtilActionTest18(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_PASS; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "pass tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "drop tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {0, 0, 1}, {0, 0, 1}, {0, 0, 1} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check mixed sigs (iponly and normal) with more prio for drop */ int UtilActionTest19(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_PASS; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "drop tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "alert tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "pass tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {1, 0, 0}, {1, 0, 0}, {1, 0, 0} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check mixed sigs (iponly and normal) with more prio for drop */ int UtilActionTest20(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_PASS; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "pass tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "drop tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "alert tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {0, 1, 0}, {0, 1, 0}, {0, 1, 0} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return res; } /** * \test Check mixed sigs (iponly and normal) with more prio for alert and drop */ int UtilActionTest21(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_ALERT; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_PASS; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "alert tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "pass tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "drop tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {1, 0, 1}, {1, 0, 1}, {1, 0, 1} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check mixed sigs (iponly and normal) with more prio for alert and drop */ int UtilActionTest22(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_ALERT; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_PASS; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "drop tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "alert tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "pass tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {1, 1, 0}, {1, 1, 0}, {1, 1, 0} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: /* Restore default values */ action_order_sigs[0] = ACTION_PASS; action_order_sigs[1] = ACTION_DROP; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_ALERT; return res; } /** * \test Check mixed sigs (iponly and normal) with more prio for alert and drop */ int UtilActionTest23(void) { int res = 1; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; action_order_sigs[0] = ACTION_DROP; action_order_sigs[1] = ACTION_ALERT; action_order_sigs[2] = ACTION_REJECT; action_order_sigs[3] = ACTION_PASS; p[0] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[2] = UTHBuildPacketReal((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[3]; sigs[0]= "pass tcp any any -> any any (msg:\"sig 1\"; sid:1;)"; sigs[1]= "drop tcp any any -> any any (msg:\"sig 2\"; content:\"Hi all\"; sid:2;)"; sigs[2]= "alert tcp any any -> any any (msg:\"sig 3\"; sid:3;)"; uint32_t sid[3] = {1, 2, 3}; uint32_t results[3][3] = { {0, 1, 1}, {0, 1, 1}, {0, 1, 1} }; /* All the patckets should match the 3 sigs. As drop * and alert have more priority than pass, both should * alert on each packet */ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto cleanup; de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, 3) == 0) goto cleanup; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); res = UTHMatchPacketsWithResults(de_ctx, p, 3, sid, (uint32_t *) results, 3); cleanup: UTHFreePackets(p, 3); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return res; } #endif /* Register unittests */ void UtilActionRegisterTests(void) { #ifdef UNITTESTS /* Generic tests */ UtRegisterTest("UtilActionTest01", UtilActionTest01, 1); UtRegisterTest("UtilActionTest02", UtilActionTest02, 1); UtRegisterTest("UtilActionTest02", UtilActionTest02, 1); UtRegisterTest("UtilActionTest03", UtilActionTest03, 1); UtRegisterTest("UtilActionTest04", UtilActionTest04, 1); UtRegisterTest("UtilActionTest05", UtilActionTest05, 1); UtRegisterTest("UtilActionTest06", UtilActionTest06, 1); UtRegisterTest("UtilActionTest07", UtilActionTest07, 1); UtRegisterTest("UtilActionTest08", UtilActionTest08, 1); UtRegisterTest("UtilActionTest09", UtilActionTest09, 1); UtRegisterTest("UtilActionTest10", UtilActionTest10, 1); UtRegisterTest("UtilActionTest11", UtilActionTest11, 1); UtRegisterTest("UtilActionTest12", UtilActionTest12, 1); UtRegisterTest("UtilActionTest13", UtilActionTest13, 1); UtRegisterTest("UtilActionTest14", UtilActionTest14, 1); UtRegisterTest("UtilActionTest15", UtilActionTest15, 1); UtRegisterTest("UtilActionTest16", UtilActionTest16, 1); UtRegisterTest("UtilActionTest17", UtilActionTest17, 1); UtRegisterTest("UtilActionTest18", UtilActionTest18, 1); UtRegisterTest("UtilActionTest19", UtilActionTest19, 1); UtRegisterTest("UtilActionTest20", UtilActionTest20, 1); UtRegisterTest("UtilActionTest21", UtilActionTest21, 1); UtRegisterTest("UtilActionTest22", UtilActionTest22, 1); UtRegisterTest("UtilActionTest23", UtilActionTest23, 1); #endif } suricata-1.4.7/src/util-atomic.c0000644000000000000000000000320112253546156013414 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "suricata.h" #include "util-atomic.h" #include "util-unittest.h" #ifdef UNITTESTS static int SCAtomicTest01(void) { int result = 0; int a = 10; int b = 20; int *temp_int = NULL; SC_ATOMIC_DECL_AND_INIT(void *, temp); temp_int = SC_ATOMIC_GET(temp); if (temp_int != NULL) goto end; (void)SC_ATOMIC_SET(temp, &a); temp_int = SC_ATOMIC_GET(temp); if (temp_int == NULL) goto end; if (*temp_int != a) goto end; (void)SC_ATOMIC_SET(temp, &b); temp_int = SC_ATOMIC_GET(temp); if (temp_int == NULL) goto end; if (*temp_int != b) goto end; result = 1; end: return result; } #endif /* UNITTESTS */ void SCAtomicRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCAtomicTest01", SCAtomicTest01, 1); #endif return; } suricata-1.4.7/src/decode-vlan.h0000644000000000000000000000276512253546156013371 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DECODE_VLAN_H__ #define __DECODE_VLAN_H__ /** Vlan type */ #define ETHERNET_TYPE_VLAN 0x8100 /** Vlan macros to access Vlan priority, Vlan CFI and VID */ #define GET_VLAN_PRIORITY(vlanh) ((ntohs((vlanh)->vlan_cfi) & 0xe000) >> 13) #define GET_VLAN_CFI(vlanh) ((ntohs((vlanh)->vlan_cfi) & 0x0100) >> 12) #define GET_VLAN_ID(vlanh) ((uint16_t)(ntohs((vlanh)->vlan_cfi) & 0x0FFF)) #define GET_VLAN_PROTO(vlanh) ((ntohs((vlanh)->protocol))) /** Vlan header struct */ typedef struct VLANHdr_ { uint16_t vlan_cfi; uint16_t protocol; /**< protocol field */ } VLANHdr; /** VLAN header length */ #define VLAN_HEADER_LEN 4 void DecodeVLANRegisterTests(void); #endif /* __DECODE_VLAN_H__ */ suricata-1.4.7/src/flow-timeout.h0000644000000000000000000000207612253546156013636 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __FLOW_TIMEOUT_H__ #define __FLOW_TIMEOUT_H__ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client); int FlowForceReassemblyNeedReassmbly(Flow *f, int *server, int *client); void FlowForceReassembly(void); void FlowForceReassemblySetup(void); #endif /* __FLOW_TIMEOUT_H__ */ suricata-1.4.7/src/source-af-packet.h0000644000000000000000000000660012253546156014331 00000000000000/* Copyright (C) 2011,2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #ifndef __SOURCE_AFP_H__ #define __SOURCE_AFP_H__ #ifndef HAVE_PACKET_FANOUT /* not defined if linux/if_packet.h trying to force */ #define HAVE_PACKET_FANOUT 1 #define PACKET_FANOUT 18 #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 #define PACKET_FANOUT_CPU 2 #define PACKET_FANOUT_FLAG_DEFRAG 0x8000 #else /* HAVE_PACKET_FANOUT */ #include #endif /* HAVE_PACKET_FANOUT */ #include "queue.h" /* value for flags */ #define AFP_RING_MODE (1<<0) #define AFP_ZERO_COPY (1<<1) #define AFP_SOCK_PROTECT (1<<2) #define AFP_EMERGENCY_MODE (1<<3) #define AFP_COPY_MODE_NONE 0 #define AFP_COPY_MODE_TAP 1 #define AFP_COPY_MODE_IPS 2 #define AFP_FILE_MAX_PKTS 256 #define AFP_IFACE_NAME_LENGTH 48 typedef struct AFPIfaceConfig_ { char iface[AFP_IFACE_NAME_LENGTH]; /* number of threads */ int threads; /* socket buffer size */ int buffer_size; /* ring size in number of packets */ int ring_size; /* cluster param */ int cluster_id; int cluster_type; /* promisc mode */ int promisc; /* misc use flags including ring mode */ int flags; int copy_mode; ChecksumValidationMode checksum_mode; char *bpf_filter; char *out_iface; SC_ATOMIC_DECLARE(unsigned int, ref); void (*DerefFunc)(void *); } AFPIfaceConfig; /** * \ingroup afppeers * @{ */ typedef struct AFPPeer_ { char iface[AFP_IFACE_NAME_LENGTH]; SC_ATOMIC_DECLARE(int, socket); SC_ATOMIC_DECLARE(int, sock_usage); SC_ATOMIC_DECLARE(int, if_idx); SC_ATOMIC_DECLARE(uint8_t, state); SCMutex sock_protect; int flags; int turn; /**< Field used to store initialisation order. */ struct AFPPeer_ *peer; TAILQ_ENTRY(AFPPeer_) next; } AFPPeer; /** * \brief per packet AF_PACKET vars * * This structure is used y the release data system and is cleaned * up by the AFPV_CLEANUP macro below. */ typedef struct AFPPacketVars_ { void *relptr; int copy_mode; AFPPeer *peer; /**< Sending peer for IPS/TAP mode */ /** Pointer to ::AFPPeer used for capture. Field is used to be able * to do reference counting. */ AFPPeer *mpeer; } AFPPacketVars; #define AFPV_CLEANUP(afpv) do { \ (afpv)->relptr = NULL; \ (afpv)->copy_mode = 0; \ (afpv)->peer = NULL; \ (afpv)->mpeer = NULL; \ } while(0) /** * @} */ void TmModuleReceiveAFPRegister (void); void TmModuleDecodeAFPRegister (void); TmEcode AFPPeersListInit(); TmEcode AFPPeersListCheck(); void AFPPeersListClean(); #endif /* __SOURCE_AFP_H__ */ suricata-1.4.7/src/detect-engine-hua.c0000644000000000000000000013466612253546156014477 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP user agent match * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" #include "detect-engine-hua.h" int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { htp_tx_t *tx = NULL; uint32_t cnt = 0; int idx; /* we need to lock because the buffers are not actually true buffers * but are ones that point to a buffer given by libhtp */ FLOWLOCK_RDLOCK(f); if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL) continue; htp_header_t *h = (htp_header_t *)table_getc(tx->request_headers, "User-Agent"); if (h == NULL) { SCLogDebug("HTTP user agent header not present in this request"); continue; } cnt += HttpUAPatternSearch(det_ctx, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), flags); } end: FLOWLOCK_UNLOCK(f); return cnt; } /** * \brief Do the http_user_agent content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpUA(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL) return 0; htp_header_t *h = (htp_header_t *)table_getc(tx->request_headers, "User-Agent"); if (h == NULL) { SCLogDebug("HTTP user agent header not present in this request"); return 0; } det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HUADMATCH], f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest01(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"CONNECT\"; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest02(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"CO\"; depth:4; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest03(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_user_agent test\"; " "content:!\"ECT\"; depth:4; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest04(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"ECT\"; depth:4; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest05(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:!\"CON\"; depth:4; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"ECT\"; offset:3; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest07(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:!\"CO\"; offset:3; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest08(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:!\"ECT\"; offset:3; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest09(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"CON\"; offset:3; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest10(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_user_agent test\"; " "content:\"CO\"; http_user_agent; " "content:\"EC\"; within:4; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"CO\"; http_user_agent; " "content:!\"EC\"; within:3; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_user_agent test\"; " "content:\"CO\"; http_user_agent; " "content:\"EC\"; within:3; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"CO\"; http_user_agent; " "content:!\"EC\"; within:4; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest14(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_user_agent test\"; " "content:\"CO\"; http_user_agent; " "content:\"EC\"; distance:2; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest15(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"CO\"; http_user_agent; " "content:!\"EC\"; distance:3; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest16(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http user agent test\"; " "content:\"CO\"; http_user_agent; " "content:\"EC\"; distance:3; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_user_agent content matches against a http request * which holds the content. */ static int DetectEngineHttpUATest17(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "User-Agent: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_user_agent test\"; " "content:\"CO\"; http_user_agent; " "content:!\"EC\"; distance:2; http_user_agent; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpUARegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpUATest01", DetectEngineHttpUATest01, 1); UtRegisterTest("DetectEngineHttpUATest02", DetectEngineHttpUATest02, 1); UtRegisterTest("DetectEngineHttpUATest03", DetectEngineHttpUATest03, 1); UtRegisterTest("DetectEngineHttpUATest04", DetectEngineHttpUATest04, 1); UtRegisterTest("DetectEngineHttpUATest05", DetectEngineHttpUATest05, 1); UtRegisterTest("DetectEngineHttpUATest06", DetectEngineHttpUATest06, 1); UtRegisterTest("DetectEngineHttpUATest07", DetectEngineHttpUATest07, 1); UtRegisterTest("DetectEngineHttpUATest08", DetectEngineHttpUATest08, 1); UtRegisterTest("DetectEngineHttpUATest09", DetectEngineHttpUATest09, 1); UtRegisterTest("DetectEngineHttpUATest10", DetectEngineHttpUATest10, 1); UtRegisterTest("DetectEngineHttpUATest11", DetectEngineHttpUATest11, 1); UtRegisterTest("DetectEngineHttpUATest12", DetectEngineHttpUATest12, 1); UtRegisterTest("DetectEngineHttpUATest13", DetectEngineHttpUATest13, 1); UtRegisterTest("DetectEngineHttpUATest14", DetectEngineHttpUATest14, 1); UtRegisterTest("DetectEngineHttpUATest15", DetectEngineHttpUATest15, 1); UtRegisterTest("DetectEngineHttpUATest16", DetectEngineHttpUATest16, 1); UtRegisterTest("DetectEngineHttpUATest17", DetectEngineHttpUATest17, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/source-erf-dag.h0000644000000000000000000000175312253546156014007 00000000000000/* Copyright (C) 2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited * \author Jason MacLulich */ #ifndef __SOURCE_ERR_DAG_H__ #define __SOURCE_ERF_DAG_H__ void TmModuleReceiveErfDagRegister(void); void TmModuleDecodeErfDagRegister(void); #endif /* __SOURCE_ERF_DAG_H__ */ suricata-1.4.7/src/decode-events.h0000644000000000000000000004124512253546156013731 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha */ #ifndef __DECODE_EVENTS_H__ #define __DECODE_EVENTS_H__ enum { /* IPV4 EVENTS */ IPV4_PKT_TOO_SMALL = 1, /**< ipv4 pkt smaller than minimum header size */ IPV4_HLEN_TOO_SMALL, /**< ipv4 header smaller than minimum size */ IPV4_IPLEN_SMALLER_THAN_HLEN, /**< ipv4 pkt len smaller than ip header size */ IPV4_TRUNC_PKT, /**< truncated ipv4 packet */ /* IPV4 OPTIONS */ IPV4_OPT_INVALID, /**< invalid ip options */ IPV4_OPT_INVALID_LEN, /**< ip options with invalid len */ IPV4_OPT_MALFORMED, /**< malformed ip options */ IPV4_OPT_PAD_REQUIRED, /**< pad bytes are needed in ip options */ IPV4_OPT_EOL_REQUIRED, /**< "end of list" needed in ip options */ IPV4_OPT_DUPLICATE, /**< duplicated ip option */ IPV4_OPT_UNKNOWN, /**< unknown ip option */ IPV4_WRONG_IP_VER, /**< wrong ip version in ip options */ /* ICMP EVENTS */ ICMPV4_PKT_TOO_SMALL, /**< icmpv4 packet smaller than minimum size */ ICMPV4_UNKNOWN_TYPE, /**< icmpv4 unknown type */ ICMPV4_UNKNOWN_CODE, /**< icmpv4 unknown code */ ICMPV4_IPV4_TRUNC_PKT, /**< truncated icmpv4 packet */ ICMPV4_IPV4_UNKNOWN_VER, /**< unknown version in icmpv4 packet*/ /* ICMPv6 EVENTS */ ICMPV6_UNKNOWN_TYPE, /**< icmpv6 unknown type */ ICMPV6_UNKNOWN_CODE, /**< icmpv6 unknown code */ ICMPV6_PKT_TOO_SMALL, /**< icmpv6 smaller than minimum size */ ICMPV6_IPV6_UNKNOWN_VER, /**< unknown version in icmpv6 packet */ ICMPV6_IPV6_TRUNC_PKT, /**< truncated icmpv6 packet */ /* IPV6 EVENTS */ IPV6_PKT_TOO_SMALL, /**< ipv6 packet smaller than minimum size */ IPV6_TRUNC_PKT, /**< truncated ipv6 packet */ IPV6_TRUNC_EXTHDR, /**< truncated ipv6 extension header */ IPV6_EXTHDR_DUPL_FH, /**< duplicated "fragment" header in ipv6 extension headers */ IPV6_EXTHDR_USELESS_FH, /**< useless FH: offset 0 + no more fragments */ IPV6_EXTHDR_DUPL_RH, /**< duplicated "routing" header in ipv6 extension headers */ IPV6_EXTHDR_DUPL_HH, /**< duplicated "hop-by-hop" header in ipv6 extension headers */ IPV6_EXTHDR_DUPL_DH, /**< duplicated "destination" header in ipv6 extension headers */ IPV6_EXTHDR_DUPL_AH, /**< duplicated "authentication" header in ipv6 extension headers */ IPV6_EXTHDR_DUPL_EH, /**< duplicated "ESP" header in ipv6 extension headers */ IPV6_EXTHDR_INVALID_OPTLEN, /**< the opt len in an hop or dst hdr is invalid. */ IPV6_WRONG_IP_VER, /**< wrong version in ipv6 */ IPV6_EXTHDR_AH_RES_NOT_NULL, /**< AH hdr reserved fields not null (rfc 4302) */ IPV6_HOPOPTS_UNKNOWN_OPT, /**< unknown HOP opt */ IPV6_HOPOPTS_ONLY_PADDING, /**< all options in HOP opts are padding */ IPV6_DSTOPTS_UNKNOWN_OPT, /**< unknown DST opt */ IPV6_DSTOPTS_ONLY_PADDING, /**< all options in DST opts are padding */ IPV6_WITH_ICMPV4, /**< IPv6 packet with ICMPv4 header */ /* TCP EVENTS */ TCP_PKT_TOO_SMALL, /**< tcp packet smaller than minimum size */ TCP_HLEN_TOO_SMALL, /**< tcp header smaller than minimum size */ TCP_INVALID_OPTLEN, /**< invalid len in tcp options */ /* TCP OPTIONS */ TCP_OPT_INVALID_LEN, /**< tcp option with invalid len */ TCP_OPT_DUPLICATE, /**< duplicated tcp option */ /* UDP EVENTS */ UDP_PKT_TOO_SMALL, /**< udp packet smaller than minimum size */ UDP_HLEN_TOO_SMALL, /**< udp header smaller than minimum size */ UDP_HLEN_INVALID, /**< invalid len of upd header */ /* SLL EVENTS */ SLL_PKT_TOO_SMALL, /**< sll packet smaller than minimum size */ /* ETHERNET EVENTS */ ETHERNET_PKT_TOO_SMALL, /**< ethernet packet smaller than minimum size */ /* PPP EVENTS */ PPP_PKT_TOO_SMALL, /**< ppp packet smaller than minimum size */ PPPVJU_PKT_TOO_SMALL, /**< ppp vj uncompressed packet smaller than minimum size */ PPPIPV4_PKT_TOO_SMALL, /**< ppp ipv4 packet smaller than minimum size */ PPPIPV6_PKT_TOO_SMALL, /**< ppp ipv6 packet smaller than minimum size */ PPP_WRONG_TYPE, /**< wrong type in ppp frame */ PPP_UNSUP_PROTO, /**< protocol not supported for ppp */ /* PPPOE EVENTS */ PPPOE_PKT_TOO_SMALL, /**< pppoe packet smaller than minimum size */ PPPOE_WRONG_CODE, /**< wrong code for pppoe */ PPPOE_MALFORMED_TAGS, /**< malformed tags in pppoe */ /* GRE EVENTS */ GRE_PKT_TOO_SMALL, /**< gre packet smaller than minimum size */ GRE_WRONG_VERSION, /**< wrong version in gre header */ GRE_VERSION0_RECUR, /**< gre v0 recursion control */ GRE_VERSION0_FLAGS, /**< gre v0 flags */ GRE_VERSION0_HDR_TOO_BIG, /**< gre v0 header bigger than maximum size */ GRE_VERSION0_MALFORMED_SRE_HDR, /**< gre v0 malformed source route entry header */ GRE_VERSION1_CHKSUM, /**< gre v1 checksum */ GRE_VERSION1_ROUTE, /**< gre v1 routing */ GRE_VERSION1_SSR, /**< gre v1 strict source route */ GRE_VERSION1_RECUR, /**< gre v1 recursion control */ GRE_VERSION1_FLAGS, /**< gre v1 flags */ GRE_VERSION1_NO_KEY, /**< gre v1 no key present in header */ GRE_VERSION1_WRONG_PROTOCOL, /**< gre v1 wrong protocol */ GRE_VERSION1_MALFORMED_SRE_HDR, /**< gre v1 malformed source route entry header */ GRE_VERSION1_HDR_TOO_BIG, /**< gre v1 header too big */ /* VLAN EVENTS */ VLAN_HEADER_TOO_SMALL, /**< vlan header smaller than minimum size */ VLAN_UNKNOWN_TYPE, /**< vlan unknown type */ /* RAW EVENTS */ IPRAW_INVALID_IPV, /**< invalid ip version in ip raw */ STREAM_3WHS_ACK_IN_WRONG_DIR, STREAM_3WHS_ASYNC_WRONG_SEQ, STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION, STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION, STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK, STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ, STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV, STREAM_3WHS_SYNACK_WITH_WRONG_ACK, STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV, STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV, STREAM_3WHS_WRONG_SEQ_WRONG_ACK, STREAM_4WHS_SYNACK_WITH_WRONG_ACK, STREAM_4WHS_SYNACK_WITH_WRONG_SYN, STREAM_4WHS_WRONG_SEQ, STREAM_4WHS_INVALID_ACK, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK, STREAM_CLOSEWAIT_INVALID_ACK, STREAM_CLOSING_ACK_WRONG_SEQ, STREAM_CLOSING_INVALID_ACK, STREAM_EST_PACKET_OUT_OF_WINDOW, STREAM_EST_PKT_BEFORE_LAST_ACK, STREAM_EST_SYNACK_RESEND, STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK, STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ, STREAM_EST_SYNACK_TOSERVER, STREAM_EST_SYN_RESEND, STREAM_EST_SYN_RESEND_DIFF_SEQ, STREAM_EST_SYN_TOCLIENT, STREAM_EST_INVALID_ACK, STREAM_FIN_INVALID_ACK, STREAM_FIN1_ACK_WRONG_SEQ, STREAM_FIN1_FIN_WRONG_SEQ, STREAM_FIN1_INVALID_ACK, STREAM_FIN2_ACK_WRONG_SEQ, STREAM_FIN2_FIN_WRONG_SEQ, STREAM_FIN2_INVALID_ACK, STREAM_FIN_BUT_NO_SESSION, STREAM_FIN_OUT_OF_WINDOW, STREAM_LASTACK_ACK_WRONG_SEQ, STREAM_LASTACK_INVALID_ACK, STREAM_RST_BUT_NO_SESSION, STREAM_TIMEWAIT_ACK_WRONG_SEQ, STREAM_TIMEWAIT_INVALID_ACK, STREAM_SHUTDOWN_SYN_RESEND, STREAM_PKT_INVALID_TIMESTAMP, STREAM_PKT_INVALID_ACK, STREAM_PKT_BROKEN_ACK, STREAM_RST_INVALID_ACK, STREAM_PKT_RETRANSMISSION, STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ, STREAM_REASSEMBLY_NO_SEGMENT, STREAM_REASSEMBLY_SEQ_GAP, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, /* SCTP EVENTS */ SCTP_PKT_TOO_SMALL, /**< sctp packet smaller than minimum size */ /* Fragmentation reasembly events. */ IPV4_FRAG_PKT_TOO_LARGE, IPV4_FRAG_OVERLAP, IPV6_FRAG_PKT_TOO_LARGE, IPV6_FRAG_OVERLAP, IPV4_FRAG_TOO_LARGE, IPV6_FRAG_TOO_LARGE, /* Fragment ignored due to internal error */ IPV4_FRAG_IGNORED, IPV6_FRAG_IGNORED, /* IPv4 in IPv6 events */ IPV4_IN_IPV6_PKT_TOO_SMALL, IPV4_IN_IPV6_WRONG_IP_VER, /* IPv6 in IPv6 events */ IPV6_IN_IPV6_PKT_TOO_SMALL, IPV6_IN_IPV6_WRONG_IP_VER, /* should always be last! */ DECODE_EVENT_MAX, }; #define DECODER_EVENTS_BUFFER_STEPS 5 /** * \brief Data structure to store app layer decoder events. */ typedef struct AppLayerDecoderEvents_ { /* array of events */ uint8_t *events; /* number of events in the above buffer */ uint8_t cnt; /* current event buffer size */ uint8_t events_buffer_size; } AppLayerDecoderEvents; /** * \brief Store decoder event module */ typedef struct AppLayerDecoderEventsModule_ { /* the alproto module for which we are storing the event table */ uint16_t alproto; /* the event table map */ SCEnumCharMap *table; struct AppLayerDecoderEventsModule_ *next; } AppLayerDecoderEventsModule; #if 0 #define AppLayerDecoderEventsSetEvent(module_id, devents_head, event) \ do { \ DecoderEvents devents = *devents_head; \ while (devents != NULL && devents->module_id != module_id) { \ devents = devents->next; \ } \ if (devents == NULL) { \ DecoderEvents new_devents = SCMalloc(sizeof(DecoderEvents));\ if (new_devents == NULL) \ return; \ memset(new_devents, 0, sizeof(DecoderEvents)); \ devents_head = new_devents; \ } \ if ((devents)->cnt == events_buffer_size) { \ devents->events = SCRealloc(devents->events, \ (devents->cnt + \ DECODER_EVENTS_BUFFER_STEPS) * \ sizeof(uint8_t)); \ if (devents->events == NULL) { \ devents->events_buffer_size = 0; \ devents->cnt = 0; \ break; \ } \ devents->events_buffer_size += DECODER_EVENTS_BUFFER_STEPS; \ } \ devents->events[devents->cnt++] = event; \ } while (0) static inline int AppLayerDecoderEventsIsEventSet(int module_id, DecoderEvents *devents, uint8_t event) { while (devents != NULL && devents->module_id != module_id) { devents = devents->next; } if (devents == NULL) return 0; int i; int cnt = devents->cnt; for (i = 0; i < cnt; i++) { if (devents->events[i] == event) return 1; } return 0; } #define DecoderEventsFreeEvents(devents) \ do { \ while ((devents) != NULL) { \ if ((devents)->events != NULL) \ SCFree((devents)->events); \ (devents) = (devents)->next; \ } \ } while (0) #endif /* #if 0 */ /** * \brief Set an app layer decoder event. * * \param devents_head Pointer to a DecoderEvents pointer head. If * the head points to a DecoderEvents instance, a * new instance would be created and the pointer head would * would be updated with this new instance * \param event The event to be stored. */ #define AppLayerDecoderEventsSetEvent(f, event) \ do { \ AppLayerParserStateStore *parser_state_store = \ (AppLayerParserStateStore *)(f)->alparser; \ AppLayerDecoderEvents *devents = \ parser_state_store->decoder_events; \ if (devents == NULL) { \ AppLayerDecoderEvents *new_devents = \ SCMalloc(sizeof(AppLayerDecoderEvents)); \ if (new_devents == NULL) \ break; \ memset(new_devents, 0, sizeof(AppLayerDecoderEvents)); \ parser_state_store->decoder_events = new_devents; \ devents = new_devents; \ } \ if (devents->cnt == devents->events_buffer_size) { \ devents->events = SCRealloc(devents->events, \ (devents->cnt + \ DECODER_EVENTS_BUFFER_STEPS) * \ sizeof(uint8_t)); \ if (devents->events == NULL) { \ devents->events_buffer_size = 0; \ devents->cnt = 0; \ break; \ } \ devents->events_buffer_size += DECODER_EVENTS_BUFFER_STEPS; \ } \ devents->events[devents->cnt++] = (event); \ SCLogDebug("setting app-layer-event %u", (event)); \ } while (0) static inline int AppLayerDecoderEventsIsEventSet(AppLayerDecoderEvents *devents, uint8_t event) { if (devents == NULL) return 0; int i; int cnt = devents->cnt; for (i = 0; i < cnt; i++) { if (devents->events[i] == event) return 1; } return 0; } #define AppLayerDecoderEventsFreeEvents(devents) \ do { \ if ((devents) != NULL) { \ if ((devents)->events != NULL) \ SCFree((devents)->events); \ } \ SCFree((devents)); \ } while (0) void AppLayerDecoderEventsModuleRegister(uint16_t, SCEnumCharMap *); uint16_t AppLayerDecoderEventsModuleGetAlproto(const char *); int AppLayerDecoderEventsModuleGetEventId(uint16_t, const char *); void AppLayerDecodeEventsModuleDeRegister(void); /***** Unittest helper functions *****/ void AppLayerDecoderEventsModuleCreateBackup(void); void AppLayerDecoderEventsModuleRestoreBackup(void); #endif /* __DECODE_EVENTS_H__ */ suricata-1.4.7/src/detect-engine-threshold.c0000644000000000000000000004701412253546156015704 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \defgroup threshold Thresholding * * This feature is used to reduce the number of logged alerts for noisy rules. * This can be tuned to significantly reduce false alarms, and it can also be * used to write a newer breed of rules. Thresholding commands limit the number * of times a particular event is logged during a specified time interval. * * @{ */ /** * \file * * \author Breno Silva * \author Victor Julien * * Threshold part of the detection engine. */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "host.h" #include "detect-parse.h" #include "detect-engine-sigorder.h" #include "detect-engine-siggroup.h" #include "detect-engine-address.h" #include "detect-engine-port.h" #include "detect-engine-mpm.h" #include "detect-engine-iponly.h" #include "detect-engine.h" #include "detect-engine-threshold.h" #include "detect-content.h" #include "detect-uricontent.h" #include "util-hash.h" #include "util-time.h" #include "util-error.h" #include "util-debug.h" #include "util-var-name.h" #include "tm-threads.h" /** * \brief Return next DetectThresholdData for signature * * \param sig Signature pointer * \param p Packet structure * \param sm Pointer to a Signature Match pointer * * \retval tsh Return the threshold data from signature or NULL if not found * * */ DetectThresholdData *SigGetThresholdTypeIter(Signature *sig, Packet *p, SigMatch **psm) { SigMatch *sm = NULL; DetectThresholdData *tsh = NULL; if (sig == NULL) return NULL; if (*psm == NULL) { sm = sig->sm_lists_tail[DETECT_SM_LIST_THRESHOLD]; } else { /* Iteration in progress, using provided value */ sm = *psm; } if (p == NULL) return NULL; while (sm != NULL) { if (sm->type == DETECT_THRESHOLD || sm->type == DETECT_DETECTION_FILTER) { tsh = (DetectThresholdData *)sm->ctx; *psm = sm->prev; return tsh; } sm = sm->prev; } *psm = NULL; return NULL; } /** * \brief Check if a certain signature has threshold option * * \param sig Signature pointer * \param p Packet structure * * \retval tsh Return the threshold data from signature or NULL if not found */ DetectThresholdData *SigGetThresholdType(Signature *sig, Packet *p) { SigMatch *psm = NULL; return SigGetThresholdTypeIter(sig, p, &psm); } /** * \brief Remove timeout threshold hash elements * * \param de_ctx Dectection Context * */ int ThresholdTimeoutCheck(Host *host, struct timeval *tv) { DetectThresholdEntry *tde = NULL; DetectThresholdEntry *tmp = NULL; DetectThresholdEntry *prev = NULL; int retval = 1; if (host->threshold == NULL) return 1; tmp = host->threshold; prev = NULL; while (tmp != NULL) { if ((tv->tv_sec - tmp->tv_sec1) <= tmp->seconds) { prev = tmp; tmp = tmp->next; retval = 0; continue; } /* timed out */ if (prev != NULL) { prev->next = tmp->next; tde = tmp; tmp = tde->next; SCFree(tde); } else { host->threshold = tmp->next; tde = tmp; tmp = tde->next; SCFree(tde); } } return retval; } static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) { SCEnter(); DetectThresholdEntry *ste = SCMalloc(sizeof(DetectThresholdEntry)); if (unlikely(ste == NULL)) { SCReturnPtr(NULL, "DetectThresholdEntry"); } ste->sid = sid; ste->gid = gid; ste->track = td->track; ste->seconds = td->seconds; ste->tv_timeout = 0; SCReturnPtr(ste, "DetectThresholdEntry"); } static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, uint32_t sid, uint32_t gid) { DetectThresholdEntry *e; for (e = h->threshold; e != NULL; e = e->next) { if (e->sid == sid && e->gid == gid) break; } return e; } /** * \retval 2 silent match (no alert but apply actions) * \retval 1 normal match * \retval 0 no match */ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) { int ret = 0; DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid); SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid); switch(td->type) { case TYPE_LIMIT: { SCLogDebug("limit"); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count <= td->count) { ret = 1; } else { ret = 2; } } else { lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; ret = 1; } } else { DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->tv_sec1 = p->ts.tv_sec; e->current_count = 1; ret = 1; e->next = h->threshold; h->threshold = e; } break; } case TYPE_THRESHOLD: { SCLogDebug("threshold"); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count >= td->count) { ret = 1; lookup_tsh->current_count = 0; } } else { lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; } } else { if (td->count == 1) { ret = 1; } else { DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->next = h->threshold; h->threshold = e; } } break; } case TYPE_BOTH: { SCLogDebug("both"); if (lookup_tsh != NULL) { if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { /* within time limit */ lookup_tsh->current_count++; if (lookup_tsh->current_count == td->count) { ret = 1; } else if (lookup_tsh->current_count > td->count) { /* silent match */ ret = 2; } } else { /* expired, so reset */ lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; /* if we have a limit of 1, this is a match */ if (lookup_tsh->current_count == td->count) { ret = 1; } } } else { DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->next = h->threshold; h->threshold = e; /* for the first match we return 1 to * indicate we should alert */ if (td->count == 1) { ret = 1; } } break; } /* detection_filter */ case TYPE_DETECTION: { SCLogDebug("detection_filter"); if (lookup_tsh != NULL) { long double time_diff = ((p->ts.tv_sec + p->ts.tv_usec/1000000.0) - (lookup_tsh->tv_sec1 + lookup_tsh->tv_usec1/1000000.0)); if (time_diff < td->seconds) { /* within timeout */ lookup_tsh->current_count++; if (lookup_tsh->current_count > td->count) { ret = 1; } } else { /* expired, reset */ lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->tv_usec1 = p->ts.tv_usec; lookup_tsh->current_count = 1; } } else { DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->tv_usec1 = p->ts.tv_usec; e->next = h->threshold; h->threshold = e; } break; } /* rate_filter */ case TYPE_RATE: { SCLogDebug("rate_filter"); ret = 1; if (lookup_tsh != NULL) { /* Check if we have a timeout enabled, if so, * we still matching (and enabling the new_action) */ if (lookup_tsh->tv_timeout != 0) { if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) { /* Ok, we are done, timeout reached */ lookup_tsh->tv_timeout = 0; } else { /* Already matching */ /* Take the action to perform */ switch (td->new_action) { case TH_ACTION_ALERT: ALERT_PACKET(p); break; case TH_ACTION_DROP: DROP_PACKET(p); break; case TH_ACTION_REJECT: REJECT_PACKET(p); break; case TH_ACTION_PASS: PASS_PACKET(p); break; default: /* Weird, leave the default action */ break; } ret = 1; } /* else - if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) */ } else { /* Update the matching state with the timeout interval */ if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count > td->count) { /* Then we must enable the new action by setting a * timeout */ lookup_tsh->tv_timeout = p->ts.tv_sec; /* Take the action to perform */ switch (td->new_action) { case TH_ACTION_ALERT: ALERT_PACKET(p); break; case TH_ACTION_DROP: DROP_PACKET(p); break; case TH_ACTION_REJECT: REJECT_PACKET(p); break; case TH_ACTION_PASS: PASS_PACKET(p); break; default: /* Weird, leave the default action */ break; } ret = 1; } } else { lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; } } /* else - if (lookup_tsh->tv_timeout != 0) */ } else { if (td->count == 1) { ret = 1; } DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); if (e == NULL) { break; } e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->tv_timeout = 0; e->next = h->threshold; h->threshold = e; } break; } case TYPE_SUPPRESS: { int res = 0; switch (td->track) { case TRACK_DST: res = DetectAddressMatch(td->addr, &p->dst); break; case TRACK_SRC: res = DetectAddressMatch(td->addr, &p->src); break; case TRACK_RULE: default: SCLogError(SC_ERR_INVALID_VALUE, "track mode %d is not supported", td->track); break; } if (res == 0) ret = 1; else ret = 2; /* suppressed but still need actions */ break; } default: SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type); } return ret; } static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectThresholdData *td, Signature *s) { int ret = 0; if (td->type != TYPE_RATE) return 1; DetectThresholdEntry* lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num]; if (lookup_tsh != NULL) { /* Check if we have a timeout enabled, if so, * we still matching (and enabling the new_action) */ if ( (p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) { /* Ok, we are done, timeout reached */ td->timeout = 0; } else { /* Already matching */ /* Take the action to perform */ switch (td->new_action) { case TH_ACTION_ALERT: ALERT_PACKET(p); break; case TH_ACTION_DROP: DROP_PACKET(p); break; case TH_ACTION_REJECT: REJECT_PACKET(p); break; case TH_ACTION_PASS: PASS_PACKET(p); break; default: /* Weird, leave the default action */ break; } ret = 1; } /* Update the matching state with the timeout interval */ if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count >= td->count) { /* Then we must enable the new action by setting a * timeout */ lookup_tsh->tv_timeout = p->ts.tv_sec; /* Take the action to perform */ switch (td->new_action) { case TH_ACTION_ALERT: ALERT_PACKET(p); break; case TH_ACTION_DROP: DROP_PACKET(p); break; case TH_ACTION_REJECT: REJECT_PACKET(p); break; case TH_ACTION_PASS: PASS_PACKET(p); break; default: /* Weird, leave the default action */ break; } ret = 1; } } else { lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->current_count = 1; } } else { if (td->count == 1) { ret = 1; } DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s->id, s->gid); if (e != NULL) { e->current_count = 1; e->tv_sec1 = p->ts.tv_sec; e->tv_timeout = 0; de_ctx->ths_ctx.th_entry[s->num] = e; } } return ret; } /** * \brief Make the threshold logic for signatures * * \param de_ctx Dectection Context * \param tsh_ptr Threshold element * \param p Packet structure * \param s Signature structure * * \retval 2 silent match (no alert but apply actions) * \retval 1 alert on this event * \retval 0 do not alert on this event */ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, DetectThresholdData *td, Packet *p, Signature *s) { SCEnter(); int ret = 0; if (td == NULL) { SCReturnInt(0); } if (td->track == TRACK_SRC) { Host *src = HostGetHostFromHash(&p->src); if (src) { ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid); HostRelease(src); } } else if (td->track == TRACK_DST) { Host *dst = HostGetHostFromHash(&p->dst); if (dst) { ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid); HostRelease(dst); } } else if (td->track == TRACK_RULE) { SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock); ret = ThresholdHandlePacketRule(de_ctx,p,td,s); SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock); } SCReturnInt(ret); } /** * \brief Init threshold context hash tables * * \param de_ctx Dectection Context * */ void ThresholdHashInit(DetectEngineCtx *de_ctx) { if (SCMutexInit(&de_ctx->ths_ctx.threshold_table_lock, NULL) != 0) { SCLogError(SC_ERR_MEM_ALLOC, "Threshold: Failed to initialize hash table mutex."); exit(EXIT_FAILURE); } } /** * \brief Destroy threshold context hash tables * * \param de_ctx Dectection Context * */ void ThresholdContextDestroy(DetectEngineCtx *de_ctx) { if (de_ctx->ths_ctx.th_entry != NULL) SCFree(de_ctx->ths_ctx.th_entry); SCMutexDestroy(&de_ctx->ths_ctx.threshold_table_lock); } /** * \brief this function will free all the entries of a list * DetectTagDataEntry * * \param td pointer to DetectTagDataEntryList */ void ThresholdListFree(void *ptr) { if (ptr != NULL) { DetectThresholdEntry *entry = ptr; while (entry != NULL) { DetectThresholdEntry *next_entry = entry->next; SCFree(entry); entry = next_entry; } } } /** * @} */ suricata-1.4.7/src/util-atomic.h0000644000000000000000000003155412253546156013435 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon * * API for atomic operations. Uses atomic instructions (GCC only at this time) * where available, falls back to (spin)locked* operations otherwise. * * To prevent developers from accidentally working with the atomic variables * directly instead of through the proper macro's, a marco trick is performed * that exposes different variable names than the developer uses. So if the dev * uses "somevar", internally "somevar_sc_atomic__" is used. * * Where available, we use __sync_fetch_and_add and * __sync_bool_compare_and_swap. If those are unavailable, the API * transparently created a matching (spin)lock for each atomic variable. The * lock will be named "somevar_sc_lock__" * * (*) where spinlocks are unavailable, the threading api falls back to mutex */ #ifndef __UTIL_ATOMIC_H__ #define __UTIL_ATOMIC_H__ /* test if we have atomic operations support */ #if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || \ !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) /** * \brief wrapper to declare an atomic variable including a (spin) lock * to protect it. * * \warning Variable and lock are _not_ initialized. */ #define SC_ATOMIC_DECLARE(type, name) \ type name ## _sc_atomic__; \ SCSpinlock name ## _sc_lock__ /** * \brief wrapper to reference an atomic variable already declared on another file (including the spin lock) * */ #define SC_ATOMIC_EXTERN(type, name) \ extern type name ## _sc_atomic__; \ extern SCSpinlock name ## _sc_lock__ /** * \brief wrapper to declare an atomic variable including a (spin) lock * to protect it and initialize them. */ #define SC_ATOMIC_DECL_AND_INIT(type, name) \ type name ## _sc_atomic__ = 0; \ SCSpinlock name ## _sc_lock__; \ SCSpinInit(&(name ## _sc_lock__), 0) /** * \brief Initialize the previously declared atomic variable and it's * lock. */ #define SC_ATOMIC_INIT(name) do { \ SCSpinInit(&(name ## _sc_lock__), 0); \ (name ## _sc_atomic__) = 0; \ } while(0) /** * \brief Initialize the previously declared atomic variable and it's * lock. */ #define SC_ATOMIC_RESET(name) do { \ (name ## _sc_atomic__) = 0; \ } while(0) /** * \brief Destroy the lock used to protect this variable */ #define SC_ATOMIC_DESTROY(name) do { \ SCSpinDestroy(&(name ## _sc_lock__)); \ } while (0) /** * \brief add a value to our atomic variable * * \param name the atomic variable * \param val the value to add to the variable */ #define SC_ATOMIC_ADD(name, val) ({\ typeof(name ## _sc_atomic__) var; \ do { \ SCSpinLock(&(name ## _sc_lock__)); \ (name ## _sc_atomic__) += (val); \ var = (name ## _sc_atomic__); \ SCSpinUnlock(&(name ## _sc_lock__)); \ } while(0); \ var ; \ }) /** * \brief sub a value from our atomic variable * * \param name the atomic variable * \param val the value to sub from the variable */ #define SC_ATOMIC_SUB(name, val) ({ \ typeof(name ## _sc_atomic__) var; \ do { \ SCSpinLock(&(name ## _sc_lock__)); \ (name ## _sc_atomic__) -= (val); \ var = (name ## _sc_atomic__); \ SCSpinUnlock(&(name ## _sc_lock__)); \ } while(0); \ var ; \ }) /** * \brief Bitwise AND a value from our atomic variable * * \param name the atomic variable * \param val the value to sub from the variable */ #define SC_ATOMIC_AND(name, val) \ do { \ SCSpinLock(&(name ## _sc_lock__)); \ (name ## _sc_atomic__) &= (val); \ SCSpinUnlock(&(name ## _sc_lock__)); \ } while(0) /** * \brief Bitwise OR a value from our atomic variable * * \param name the atomic variable * \param val the value to sub from the variable */ #define SC_ATOMIC_OR(name, val) \ do { \ SCSpinLock(&(name ## _sc_lock__)); \ (name ## _sc_atomic__) |= (val); \ SCSpinUnlock(&(name ## _sc_lock__)); \ } while(0) /** * \brief Bitwise NAND a value from our atomic variable * * \param name the atomic variable * \param val the value to sub from the variable */ #define SC_ATOMIC_NAND(name, val) \ do { \ SCSpinLock(&(name ## _sc_lock__)); \ (name ## _sc_atomic__) = ~(name ## _sc_atomic__) & (val); \ SCSpinUnlock(&(name ## _sc_lock__)); \ } while(0) /** * \brief Bitwise XOR a value from our atomic variable * * \param name the atomic variable * \param val the value to sub from the variable */ #define SC_ATOMIC_XOR(name, val) \ do { \ SCSpinLock(&(name ## _sc_lock__)); \ (name ## _sc_atomic__) ^= (val); \ SCSpinUnlock(&(name ## _sc_lock__)); \ } while(0) /** * \brief Get the value from the atomic variable. * * \retval var value */ #define SC_ATOMIC_GET(name) ({ \ typeof(name ## _sc_atomic__) var; \ do { \ SCSpinLock(&(name ## _sc_lock__)); \ var = (name ## _sc_atomic__); \ SCSpinUnlock(&(name ## _sc_lock__)); \ } while (0); \ var; \ }) /** * \brief Set the value for the atomic variable. * * \retval var value */ #define SC_ATOMIC_SET(name, val) ({ \ typeof(name ## _sc_atomic__) var; \ do { \ SCSpinLock(&(name ## _sc_lock__)); \ var = (name ## _sc_atomic__) = val; \ SCSpinUnlock(&(name ## _sc_lock__)); \ } while (0); \ var; \ }) /** * \brief atomic Compare and Switch * * \warning "name" is passed to us as "&var" */ #define SC_ATOMIC_CAS(name, cmpval, newval) ({ \ char r = 0; \ do { \ SCSpinLock((name ## _sc_lock__)); \ if (*(name ## _sc_atomic__) == (cmpval)) { \ *(name ## _sc_atomic__) = (newval); \ r = 1; \ } \ SCSpinUnlock((name ## _sc_lock__)); \ } while(0); \ r; \ }) #else /* we do have support for CAS */ /** * \brief wrapper for OS/compiler specific atomic compare and swap (CAS) * function. * * \param addr Address of the variable to CAS * \param tv Test value to compare the value at address against * \param nv New value to set the variable at addr to * * \retval 0 CAS failed * \retval 1 CAS succeeded */ #define SCAtomicCompareAndSwap(addr, tv, nv) \ __sync_bool_compare_and_swap((addr), (tv), (nv)) /** * \brief wrapper for OS/compiler specific atomic fetch and add * function. * * \param addr Address of the variable to add to * \param value Value to add to the variable at addr */ #define SCAtomicFetchAndAdd(addr, value) \ __sync_fetch_and_add((addr), (value)) /** * \brief wrapper for OS/compiler specific atomic fetch and sub * function. * * \param addr Address of the variable to add to * \param value Value to sub from the variable at addr */ #define SCAtomicFetchAndSub(addr, value) \ __sync_fetch_and_sub((addr), (value)) /** * \brief wrapper for OS/compiler specific atomic fetch and add * function. * * \param addr Address of the variable to add to * \param value Value to add to the variable at addr */ #define SCAtomicAddAndFetch(addr, value) \ __sync_add_and_fetch((addr), (value)) /** * \brief wrapper for OS/compiler specific atomic fetch and sub * function. * * \param addr Address of the variable to add to * \param value Value to sub from the variable at addr */ #define SCAtomicSubAndFetch(addr, value) \ __sync_sub_and_fetch((addr), (value)) /** * \brief wrapper for OS/compiler specific atomic fetch and "AND" * function. * * \param addr Address of the variable to AND to * \param value Value to add to the variable at addr */ #define SCAtomicFetchAndAnd(addr, value) \ __sync_fetch_and_and((addr), (value)) /** * \brief wrapper for OS/compiler specific atomic fetch and "NAND" * function. * * \param addr Address of the variable to NAND to * \param value Value to add to the variable at addr */ #define SCAtomicFetchAndNand(addr, value) \ __sync_fetch_and_nand((addr), (value)) /** * \brief wrapper for OS/compiler specific atomic fetch and "XOR" * function. * * \param addr Address of the variable to XOR to * \param value Value to add to the variable at addr */ #define SCAtomicFetchAndXor(addr, value) \ __sync_fetch_and_xor((addr), (value)) /** * \brief wrapper for OS/compiler specific atomic fetch and or * function. * * \param addr Address of the variable to or to * \param value Value to add to the variable at addr */ #define SCAtomicFetchAndOr(addr, value) \ __sync_fetch_and_or((addr), (value)) /** * \brief wrapper for declaring atomic variables. * * \warning Only char, short, int, long, long long and their unsigned * versions are supported. * * \param type Type of the variable (char, short, int, long, long long) * \param name Name of the variable. * * We just declare the variable here as we rely on atomic operations * to modify it, so no need for locks. * * \warning variable is not initialized */ #define SC_ATOMIC_DECLARE(type, name) \ type name ## _sc_atomic__ /** * \brief wrapper for referencing an atomic variable declared on another file. * * \warning Only char, short, int, long, long long and their unsigned * versions are supported. * * \param type Type of the variable (char, short, int, long, long long) * \param name Name of the variable. * * We just declare the variable here as we rely on atomic operations * to modify it, so no need for locks. * */ #define SC_ATOMIC_EXTERN(type, name) \ extern type name ## _sc_atomic__ /** * \brief wrapper for declaring an atomic variable and initializing it. **/ #define SC_ATOMIC_DECL_AND_INIT(type, name) \ type name ## _sc_atomic__ = 0 /** * \brief wrapper for initializing an atomic variable. **/ #define SC_ATOMIC_INIT(name) \ (name ## _sc_atomic__) = 0 /** * \brief wrapper for reinitializing an atomic variable. **/ #define SC_ATOMIC_RESET(name) \ (name ## _sc_atomic__) = 0 /** * \brief No-op. */ #define SC_ATOMIC_DESTROY(name) /** * \brief add a value to our atomic variable * * \param name the atomic variable * \param val the value to add to the variable */ #define SC_ATOMIC_ADD(name, val) \ SCAtomicAddAndFetch(&(name ## _sc_atomic__), (val)) /** * \brief sub a value from our atomic variable * * \param name the atomic variable * \param val the value to sub from the variable */ #define SC_ATOMIC_SUB(name, val) \ SCAtomicSubAndFetch(&(name ## _sc_atomic__), (val)) /** * \brief Bitwise OR a value to our atomic variable * * \param name the atomic variable * \param val the value to OR to the variable */ #define SC_ATOMIC_OR(name, val) \ SCAtomicFetchAndOr(&(name ## _sc_atomic__), (val)) /** * \brief Bitwise AND a value to our atomic variable * * \param name the atomic variable * \param val the value to AND to the variable */ #define SC_ATOMIC_AND(name, val) \ SCAtomicFetchAndAnd(&(name ## _sc_atomic__), (val)) /** * \brief Bitwise NAND a value to our atomic variable * * \param name the atomic variable * \param val the value to NAND to the variable */ #define SC_ATOMIC_NAND(name, val) \ SCAtomicFetchAndNand(&(name ## _sc_atomic__), (val)) /** * \brief Bitwise XOR a value to our atomic variable * * \param name the atomic variable * \param val the value to XOR to the variable */ #define SC_ATOMIC_XOR(name, val) \ SCAtomicFetchAndXor(&(name ## _sc_atomic__), (val)) /** * \brief atomic Compare and Switch * * \warning "name" is passed to us as "&var" */ #define SC_ATOMIC_CAS(name, cmpval, newval) \ SCAtomicCompareAndSwap((name ## _sc_atomic__), cmpval, newval) /** * \brief Get the value from the atomic variable. * * \retval var value */ #define SC_ATOMIC_GET(name) \ (name ## _sc_atomic__) /** * \brief Set the value for the atomic variable. * * \retval var value */ #define SC_ATOMIC_SET(name, val) ({ \ while (SC_ATOMIC_CAS(&name, SC_ATOMIC_GET(name), val) == 0) \ ; \ }) #endif /* !no atomic operations */ void SCAtomicRegisterTests(void); #endif /* __UTIL_ATOMIC_H__ */ suricata-1.4.7/src/host.h0000644000000000000000000001017312253546156012155 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __HOST_H__ #define __HOST_H__ #include "decode.h" /** Spinlocks or Mutex for the flow buckets. */ //#define HRLOCK_SPIN #define HRLOCK_MUTEX #ifdef HRLOCK_SPIN #ifdef HRLOCK_MUTEX #error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX #endif #endif #ifdef HRLOCK_SPIN #define HRLOCK_TYPE SCSpinlock #define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) #define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) #define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) #define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) #define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) #elif defined HRLOCK_MUTEX #define HRLOCK_TYPE SCMutex #define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) #define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) #define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) #define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) #define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) #else #error Enable HRLOCK_SPIN or HRLOCK_MUTEX #endif typedef struct Host_ { /** host mutex */ SCMutex m; /** host address -- ipv4 or ipv6 */ Address a; /** use cnt, reference counter */ SC_ATOMIC_DECLARE(unsigned short, use_cnt); /** pointers to tag and threshold storage */ void *tag; void *threshold; void *iprep; /** hash pointers, protected by hash row mutex/spin */ struct Host_ *hnext; struct Host_ *hprev; /** list pointers, protected by host-queue mutex/spin */ struct Host_ *lnext; struct Host_ *lprev; } Host; typedef struct HostHashRow_ { HRLOCK_TYPE lock; Host *head; Host *tail; } HostHashRow; /** host hash table */ HostHashRow *host_hash; #define HOST_VERBOSE 0 #define HOST_QUIET 1 typedef struct HostConfig_ { uint64_t memcap; uint32_t hash_rand; uint32_t hash_size; uint32_t prealloc; } HostConfig; /** \brief check if a memory alloc would fit in the memcap * * \param size memory allocation size to check * * \retval 1 it fits * \retval 0 no fit */ #define HOST_CHECK_MEMCAP(size) \ ((((uint64_t)SC_ATOMIC_GET(host_memuse) + (uint64_t)(size)) <= host_config.memcap)) #define HostIncrUsecnt(h) \ (void)SC_ATOMIC_ADD((h)->use_cnt, 1) #define HostDecrUsecnt(h) \ (void)SC_ATOMIC_SUB((h)->use_cnt, 1) #define HostReference(dst_h_ptr, h) do { \ if ((h) != NULL) { \ HostIncrUsecnt((h)); \ *(dst_h_ptr) = h; \ } \ } while (0) #define HostDeReference(src_h_ptr) do { \ if (*(src_h_ptr) != NULL) { \ HostDecrUsecnt(*(src_h_ptr)); \ *(src_h_ptr) = NULL; \ } \ } while (0) HostConfig host_config; SC_ATOMIC_DECLARE(unsigned long long int,host_memuse); SC_ATOMIC_DECLARE(unsigned int,host_counter); SC_ATOMIC_DECLARE(unsigned int,host_prune_idx); void HostInitConfig(char quiet); void HostShutdown(void); void HostCleanup(void); Host *HostLookupHostFromHash (Address *); Host *HostGetHostFromHash (Address *); void HostRelease(Host *); void HostLock(Host *); void HostClearMemory(Host *); void HostMoveToSpare(Host *); uint32_t HostSpareQueueGetSize(void); void HostPrintStats (void); #endif /* __HOST_H__ */ suricata-1.4.7/src/app-layer-htp-body.h0000644000000000000000000000234312253546156014616 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Gurvinder Singh * \author Pablo Rincon * * This file provides a HTTP protocol support for the engine using HTP library. */ #ifndef __APP_LAYER_HTP_BODY_H__ #define __APP_LAYER_HTP_BODY_H__ int HtpBodyAppendChunk(HtpTxUserData *, HtpBody *, uint8_t *, uint32_t); void HtpBodyPrint(HtpBody *); void HtpBodyFree(HtpBody *); void HtpBodyPrune(HtpBody *); #endif /* __APP_LAYER_HTP_BODY_H__ */ suricata-1.4.7/src/conf-yaml-loader.c0000644000000000000000000003453512253546156014334 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited - Jason Ish * * YAML configuration loader. */ #include #include "suricata-common.h" #include "conf.h" #include "util-debug.h" #include "util-unittest.h" #define YAML_VERSION_MAJOR 1 #define YAML_VERSION_MINOR 1 /* Sometimes we'll have to create a node name on the fly (integer * conversion, etc), so this is a default length to allocate that will * work most of the time. */ #define DEFAULT_NAME_LEN 16 #define MANGLE_ERRORS_MAX 10 static int mangle_errors = 0; /* Configuration processing states. */ enum conf_state { CONF_KEY = 0, CONF_VAL, }; /** * \brief Mangle unsupported characters. * * \param string A pointer to an null terminated string. * * \retval none */ static void Mangle(char *string) { char *c; while ((c = strchr(string, '_'))) *c = '-'; return; } /** * \brief Parse a YAML layer. * * \param parser A pointer to an active yaml_parser_t. * \param parent The parent configuration node. * * \retval 0 on success, -1 on failure. */ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) { ConfNode *node = parent; yaml_event_t event; int done = 0; int state = 0; int seq_idx = 0; while (!done) { if (!yaml_parser_parse(parser, &event)) { fprintf(stderr, "Failed to parse configuration file at line %" PRIuMAX ": %s\n", (uintmax_t)parser->problem_mark.line, parser->problem); return -1; } if (event.type == YAML_DOCUMENT_START_EVENT) { /* Verify YAML version - its more likely to be a valid * Suricata configuration file if the version is * correct. */ yaml_version_directive_t *ver = event.data.document_start.version_directive; if (ver == NULL) { fprintf(stderr, "ERROR: Invalid configuration file.\n\n"); fprintf(stderr, "The configuration file must begin with the following two lines:\n\n"); fprintf(stderr, "%%YAML 1.1\n---\n\n"); goto fail; } int major = event.data.document_start.version_directive->major; int minor = event.data.document_start.version_directive->minor; if (!(major == YAML_VERSION_MAJOR && minor == YAML_VERSION_MINOR)) { fprintf(stderr, "ERROR: Invalid YAML version. Must be 1.1\n"); goto fail; } } else if (event.type == YAML_SCALAR_EVENT) { char *value = (char *)event.data.scalar.value; SCLogDebug("event.type = YAML_SCALAR_EVENT (%s) inseq=%d", value, inseq); if (inseq) { ConfNode *seq_node = ConfNodeNew(); seq_node->name = SCCalloc(1, DEFAULT_NAME_LEN); if (seq_node->name == NULL) return -1; snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++); seq_node->val = SCStrdup(value); TAILQ_INSERT_TAIL(&parent->head, seq_node, next); } else { if (state == CONF_KEY) { if (parent->is_seq) { if (parent->val == NULL) { parent->val = SCStrdup(value); if (parent->val && strchr(parent->val, '_')) Mangle(parent->val); } } ConfNode *n0 = ConfNodeLookupChild(parent, value); if (n0 != NULL) { node = n0; } else { node = ConfNodeNew(); node->name = SCStrdup(value); if (node->name && strchr(node->name, '_')) { if (!(parent->name && ((strcmp(parent->name, "address-groups") == 0) || (strcmp(parent->name, "port-groups") == 0)))) { Mangle(node->name); if (mangle_errors < MANGLE_ERRORS_MAX) { SCLogWarning(SC_WARN_DEPRECATED, "%s is deprecated. Please use %s on line %"PRIuMAX".", value, node->name, (uintmax_t)parser->mark.line+1); mangle_errors++; if (mangle_errors >= MANGLE_ERRORS_MAX) SCLogWarning(SC_WARN_DEPRECATED, "not showing more " "parameter name warnings."); } } } TAILQ_INSERT_TAIL(&parent->head, node, next); } state = CONF_VAL; } else { if (node->allow_override) { if (node->val != NULL) SCFree(node->val); node->val = SCStrdup(value); } state = CONF_KEY; } } } else if (event.type == YAML_SEQUENCE_START_EVENT) { SCLogDebug("event.type = YAML_SEQUENCE_START_EVENT"); if (ConfYamlParse(parser, node, 1) != 0) goto fail; state = CONF_KEY; } else if (event.type == YAML_SEQUENCE_END_EVENT) { SCLogDebug("event.type = YAML_SEQUENCE_END_EVENT"); return 0; } else if (event.type == YAML_MAPPING_START_EVENT) { SCLogDebug("event.type = YAML_MAPPING_START_EVENT"); if (inseq) { ConfNode *seq_node = ConfNodeNew(); seq_node->is_seq = 1; seq_node->name = SCCalloc(1, DEFAULT_NAME_LEN); if (seq_node->name == NULL) return -1; snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++); TAILQ_INSERT_TAIL(&node->head, seq_node, next); if (ConfYamlParse(parser, seq_node, 0) != 0) goto fail; } else { if (ConfYamlParse(parser, node, inseq) != 0) goto fail; } state = CONF_KEY; } else if (event.type == YAML_MAPPING_END_EVENT) { SCLogDebug("event.type = YAML_MAPPING_END_EVENT"); done = 1; } else if (event.type == YAML_STREAM_END_EVENT) { done = 1; } yaml_event_delete(&event); continue; fail: yaml_event_delete(&event); return -1; } return 0; } /** * \brief Load configuration from a YAML file. * * This function will load a configuration file. On failure -1 will * be returned and it is suggested that the program then exit. Any * errors while loading the configuration file will have already been * logged. * * \param filename Filename of configuration file to load. * * \retval 0 on success, -1 on failure. */ int ConfYamlLoadFile(const char *filename) { FILE *infile; yaml_parser_t parser; int ret; ConfNode *root = ConfGetRootNode(); if (yaml_parser_initialize(&parser) != 1) { fprintf(stderr, "Failed to initialize yaml parser.\n"); return -1; } infile = fopen(filename, "r"); if (infile == NULL) { fprintf(stderr, "Failed to open file: %s: %s\n", filename, strerror(errno)); yaml_parser_delete(&parser); return -1; } yaml_parser_set_input_file(&parser, infile); ret = ConfYamlParse(&parser, root, 0); yaml_parser_delete(&parser); fclose(infile); return ret; } /** * \brief Load configuration from a YAML string. */ int ConfYamlLoadString(const char *string, size_t len) { ConfNode *root = ConfGetRootNode(); yaml_parser_t parser; int ret; if (yaml_parser_initialize(&parser) != 1) { fprintf(stderr, "Failed to initialize yaml parser.\n"); exit(EXIT_FAILURE); } yaml_parser_set_input_string(&parser, (const unsigned char *)string, len); ret = ConfYamlParse(&parser, root, 0); yaml_parser_delete(&parser); return ret; } #ifdef UNITTESTS static int ConfYamlRuleFileTest(void) { char input[] = "\ %YAML 1.1\n\ ---\n\ rule-files:\n\ - netbios.rules\n\ - x11.rules\n\ \n\ default-log-dir: /tmp\n\ "; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(input, strlen(input)); ConfNode *node; node = ConfGetNode("rule-files"); if (node == NULL) return 0; if (TAILQ_EMPTY(&node->head)) return 0; int i = 0; ConfNode *filename; TAILQ_FOREACH(filename, &node->head, next) { if (i == 0) { if (strcmp(filename->val, "netbios.rules") != 0) return 0; } else if (i == 1) { if (strcmp(filename->val, "x11.rules") != 0) return 0; } else { return 0; } i++; } ConfDeInit(); ConfRestoreContextBackup(); return 1; } static int ConfYamlLoggingOutputTest(void) { char input[] = "\ %YAML 1.1\n\ ---\n\ logging:\n\ output:\n\ - interface: console\n\ log-level: error\n\ - interface: syslog\n\ facility: local4\n\ log-level: info\n\ "; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(input, strlen(input)); ConfNode *outputs; outputs = ConfGetNode("logging.output"); if (outputs == NULL) return 0; ConfNode *output; ConfNode *output_param; output = TAILQ_FIRST(&outputs->head); if (output == NULL) return 0; if (strcmp(output->name, "0") != 0) return 0; output_param = TAILQ_FIRST(&output->head); if (output_param == NULL) return 0; if (strcmp(output_param->name, "interface") != 0) return 0; if (strcmp(output_param->val, "console") != 0) return 0; output_param = TAILQ_NEXT(output_param, next); if (strcmp(output_param->name, "log-level") != 0) return 0; if (strcmp(output_param->val, "error") != 0) return 0; output = TAILQ_NEXT(output, next); if (output == NULL) return 0; if (strcmp(output->name, "1") != 0) return 0; output_param = TAILQ_FIRST(&output->head); if (output_param == NULL) return 0; if (strcmp(output_param->name, "interface") != 0) return 0; if (strcmp(output_param->val, "syslog") != 0) return 0; output_param = TAILQ_NEXT(output_param, next); if (strcmp(output_param->name, "facility") != 0) return 0; if (strcmp(output_param->val, "local4") != 0) return 0; output_param = TAILQ_NEXT(output_param, next); if (strcmp(output_param->name, "log-level") != 0) return 0; if (strcmp(output_param->val, "info") != 0) return 0; ConfDeInit(); ConfRestoreContextBackup(); return 1; } /** * Try to load something that is not a valid YAML file. */ static int ConfYamlNonYamlFileTest(void) { ConfCreateContextBackup(); ConfInit(); if (ConfYamlLoadFile("/etc/passwd") != -1) return 0; ConfDeInit(); ConfRestoreContextBackup(); return 1; } static int ConfYamlBadYamlVersionTest(void) { char input[] = "\ %YAML 9.9\n\ ---\n\ logging:\n\ output:\n\ - interface: console\n\ log-level: error\n\ - interface: syslog\n\ facility: local4\n\ log-level: info\n\ "; ConfCreateContextBackup(); ConfInit(); if (ConfYamlLoadString(input, strlen(input)) != -1) return 0; ConfDeInit(); ConfRestoreContextBackup(); return 1; } static int ConfYamlSecondLevelSequenceTest(void) { char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ server-config:\n\ - apache-php:\n\ address: [\"192.168.1.0/24\"]\n\ personality: [\"Apache_2_2\", \"PHP_5_3\"]\n\ path-parsing: [\"compress_separators\", \"lowercase\"]\n\ - iis-php:\n\ address:\n\ - 192.168.0.0/24\n\ \n\ personality:\n\ - IIS_7_0\n\ - PHP_5_3\n\ \n\ path-parsing:\n\ - compress_separators\n\ "; ConfCreateContextBackup(); ConfInit(); if (ConfYamlLoadString(input, strlen(input)) != 0) return 0; ConfNode *outputs; outputs = ConfGetNode("libhtp.server-config"); if (outputs == NULL) return 0; ConfNode *node; node = TAILQ_FIRST(&outputs->head); if (node == NULL) return 0; if (strcmp(node->name, "0") != 0) return 0; node = TAILQ_FIRST(&node->head); if (node == NULL) return 0; if (strcmp(node->name, "apache-php") != 0) return 0; node = ConfNodeLookupChild(node, "address"); if (node == NULL) return 0; node = TAILQ_FIRST(&node->head); if (node == NULL) return 0; if (strcmp(node->name, "0") != 0) return 0; if (strcmp(node->val, "192.168.1.0/24") != 0) return 0; ConfDeInit(); ConfRestoreContextBackup(); return 1; } #endif /* UNITTESTS */ void ConfYamlRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("ConfYamlRuleFileTest", ConfYamlRuleFileTest, 1); UtRegisterTest("ConfYamlLoggingOutputTest", ConfYamlLoggingOutputTest, 1); UtRegisterTest("ConfYamlNonYamlFileTest", ConfYamlNonYamlFileTest, 1); UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest, 1); UtRegisterTest("ConfYamlSecondLevelSequenceTest", ConfYamlSecondLevelSequenceTest, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/app-layer-ssl.c0000644000000000000000000040012412253546156013663 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * \author Pierre Chifflier * */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-ssl.h" #include "app-layer-tls-handshake.h" #include "conf.h" #include "decode-events.h" #include "util-spm.h" #include "util-unittest.h" #include "util-debug.h" #include "flow-util.h" #include "flow-private.h" #include "util-byte.h" SCEnumCharMap tls_decoder_event_table[ ] = { /* TLS protocol messages */ { "INVALID_SSLV2_HEADER", TLS_DECODER_EVENT_INVALID_SSLV2_HEADER }, { "INVALID_TLS_HEADER", TLS_DECODER_EVENT_INVALID_TLS_HEADER }, { "INVALID_RECORD_TYPE", TLS_DECODER_EVENT_INVALID_RECORD_TYPE }, { "INVALID_HANDSHAKE_MESSAGE", TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE }, /* Certificates decoding messages */ { "INVALID_CERTIFICATE", TLS_DECODER_EVENT_INVALID_CERTIFICATE }, { "CERTIFICATE_MISSING_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT }, { "CERTIFICATE_UNKNOWN_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT }, { "CERTIFICATE_INVALID_LENGTH", TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH }, { "CERTIFICATE_INVALID_STRING", TLS_DECODER_EVENT_CERTIFICATE_INVALID_STRING }, { "ERROR_MESSAGE_ENCOUNTERED", TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED }, /* used as a generic error event */ { "INVALID_SSL_RECORD", TLS_DECODER_EVENT_INVALID_SSL_RECORD }, { NULL, -1 }, }; typedef struct SslConfig_ { int no_reassemble; } SslConfig; SslConfig ssl_config; /* SSLv3 record types */ #define SSLV3_CHANGE_CIPHER_SPEC 20 #define SSLV3_ALERT_PROTOCOL 21 #define SSLV3_HANDSHAKE_PROTOCOL 22 #define SSLV3_APPLICATION_PROTOCOL 23 /* SSLv3 handshake protocol types */ #define SSLV3_HS_HELLO_REQUEST 0 #define SSLV3_HS_CLIENT_HELLO 1 #define SSLV3_HS_SERVER_HELLO 2 #define SSLV3_HS_CERTIFICATE 11 #define SSLV3_HS_SERVER_KEY_EXCHANGE 12 #define SSLV3_HS_CERTIFICATE_REQUEST 13 #define SSLV3_HS_SERVER_HELLO_DONE 14 #define SSLV3_HS_CERTIFICATE_VERIFY 15 #define SSLV3_HS_CLIENT_KEY_EXCHANGE 16 #define SSLV3_HS_FINISHED 20 #define SSLV3_HS_CERTIFICATE_URL 21 #define SSLV3_HS_CERTIFICATE_STATUS 22 /* SSLv2 protocol message types */ #define SSLV2_MT_ERROR 0 #define SSLV2_MT_CLIENT_HELLO 1 #define SSLV2_MT_CLIENT_MASTER_KEY 2 #define SSLV2_MT_CLIENT_FINISHED 3 #define SSLV2_MT_SERVER_HELLO 4 #define SSLV2_MT_SERVER_VERIFY 5 #define SSLV2_MT_SERVER_FINISHED 6 #define SSLV2_MT_REQUEST_CERTIFICATE 7 #define SSLV2_MT_CLIENT_CERTIFICATE 8 #define SSLV3_RECORD_HDR_LEN 5 #define SSLV3_MESSAGE_HDR_LEN 4 static void SSLParserReset(SSLState *ssl_state) { ssl_state->curr_connp->bytes_processed = 0; } static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, uint32_t input_len) { uint8_t *initial_input = input; uint32_t parsed = 0; int rc; if (input_len == 0) { return 0; } switch (ssl_state->curr_connp->handshake_type) { case SSLV3_HS_CLIENT_HELLO: ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO; break; case SSLV3_HS_SERVER_HELLO: ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO; break; case SSLV3_HS_SERVER_KEY_EXCHANGE: ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_KEYX; break; case SSLV3_HS_CLIENT_KEY_EXCHANGE: ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_KEYX; break; case SSLV3_HS_CERTIFICATE: if (ssl_state->curr_connp->trec == NULL) { ssl_state->curr_connp->trec_len = 2 * ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN + 1; ssl_state->curr_connp->trec = SCMalloc( ssl_state->curr_connp->trec_len ); } if (ssl_state->curr_connp->trec_pos + input_len >= ssl_state->curr_connp->trec_len) { ssl_state->curr_connp->trec_len = ssl_state->curr_connp->trec_len + 2 * input_len + 1; ssl_state->curr_connp->trec = SCRealloc( ssl_state->curr_connp->trec, ssl_state->curr_connp->trec_len ); } if (ssl_state->curr_connp->trec == NULL) { ssl_state->curr_connp->trec_len = 0; /* error, skip packet */ parsed += input_len; ssl_state->curr_connp->bytes_processed += input_len; return -1; } uint32_t write_len = 0; if ((ssl_state->curr_connp->bytes_processed + input_len) > ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } write_len = (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) - ssl_state->curr_connp->bytes_processed; } else { write_len = input_len; } memcpy(ssl_state->curr_connp->trec + ssl_state->curr_connp->trec_pos, initial_input, write_len); ssl_state->curr_connp->trec_pos += write_len; rc = DecodeTLSHandshakeServerCertificate(ssl_state, ssl_state->curr_connp->trec, ssl_state->curr_connp->trec_pos); if (rc > 0) { /* do not return normally if the packet was fragmented: * we would return the size of the *entire* message, * while we expect only the number of bytes parsed bytes * from the *current* fragment */ if (write_len < (ssl_state->curr_connp->trec_pos - rc)) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } uint32_t diff = write_len - (ssl_state->curr_connp->trec_pos - rc); ssl_state->curr_connp->bytes_processed += diff; ssl_state->curr_connp->trec_pos = 0; ssl_state->curr_connp->handshake_type = 0; ssl_state->curr_connp->hs_bytes_processed = 0; ssl_state->curr_connp->message_length = 0; return diff; } else { ssl_state->curr_connp->bytes_processed += write_len; parsed += write_len; return parsed; } break; case SSLV3_HS_HELLO_REQUEST: case SSLV3_HS_CERTIFICATE_REQUEST: case SSLV3_HS_CERTIFICATE_VERIFY: case SSLV3_HS_FINISHED: case SSLV3_HS_CERTIFICATE_URL: case SSLV3_HS_CERTIFICATE_STATUS: break; default: AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } uint32_t write_len = 0; if ((ssl_state->curr_connp->bytes_processed + input_len) >= ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } write_len = (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) - ssl_state->curr_connp->bytes_processed; } else { write_len = input_len; } if ((ssl_state->curr_connp->trec_pos + write_len) >= ssl_state->curr_connp->message_length) { if (ssl_state->curr_connp->message_length < ssl_state->curr_connp->trec_pos) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } parsed += ssl_state->curr_connp->message_length - ssl_state->curr_connp->trec_pos; ssl_state->curr_connp->bytes_processed += ssl_state->curr_connp->message_length - ssl_state->curr_connp->trec_pos; ssl_state->curr_connp->handshake_type = 0; ssl_state->curr_connp->hs_bytes_processed = 0; ssl_state->curr_connp->message_length = 0; ssl_state->curr_connp->trec_pos = 0; return parsed; } else { ssl_state->curr_connp->trec_pos += write_len; ssl_state->curr_connp->bytes_processed += write_len; parsed += write_len; return parsed; } } static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, uint32_t input_len) { uint8_t *initial_input = input; int retval; if (input_len == 0 || ssl_state->curr_connp->bytes_processed == (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) { return 0; } switch (ssl_state->curr_connp->hs_bytes_processed) { case 0: ssl_state->curr_connp->handshake_type = *(input++); ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } case 1: ssl_state->curr_connp->message_length = *(input++) << 16; ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } case 2: ssl_state->curr_connp->message_length |= *(input++) << 8; ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } case 3: ssl_state->curr_connp->message_length |= *(input++); ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; --input_len; } retval = SSLv3ParseHandshakeType(ssl_state, input, input_len); if (retval < 0) { return retval; } input += retval; return (input - initial_input); } static int SSLv3ParseRecord(uint8_t direction, SSLState *ssl_state, uint8_t *input, uint32_t input_len) { uint8_t *initial_input = input; if (input_len == 0) { return 0; } switch (ssl_state->curr_connp->bytes_processed) { case 0: if (input_len >= 5) { ssl_state->curr_connp->content_type = input[0]; ssl_state->curr_connp->version = input[1] << 8; ssl_state->curr_connp->version |= input[2]; ssl_state->curr_connp->record_length = input[3] << 8; ssl_state->curr_connp->record_length |= input[4]; ssl_state->curr_connp->bytes_processed += SSLV3_RECORD_HDR_LEN; return SSLV3_RECORD_HDR_LEN; } else { ssl_state->curr_connp->content_type = *(input++); if (--input_len == 0) break; } case 1: ssl_state->curr_connp->version = *(input++) << 8; if (--input_len == 0) break; case 2: ssl_state->curr_connp->version |= *(input++); if (--input_len == 0) break; case 3: ssl_state->curr_connp->record_length = *(input++) << 8; if (--input_len == 0) break; case 4: ssl_state->curr_connp->record_length |= *(input++); if (--input_len == 0) break; } /* switch (ssl_state->curr_connp->bytes_processed) */ ssl_state->curr_connp->bytes_processed += (input - initial_input); return (input - initial_input); } static int SSLv2ParseRecord(uint8_t direction, SSLState *ssl_state, uint8_t *input, uint32_t input_len) { uint8_t *initial_input = input; if (input_len == 0) { return 0; } if (ssl_state->curr_connp->record_lengths_length == 2) { switch (ssl_state->curr_connp->bytes_processed) { case 0: if (input_len >= ssl_state->curr_connp->record_lengths_length + 1) { ssl_state->curr_connp->record_length = (0x7f & input[0]) << 8 | input[1]; ssl_state->curr_connp->content_type = input[2]; ssl_state->curr_connp->version = SSL_VERSION_2; ssl_state->curr_connp->bytes_processed += 3; return 3; } else { ssl_state->curr_connp->record_length = (0x7f & *(input++)) << 8; if (--input_len == 0) break; } case 1: ssl_state->curr_connp->record_length |= *(input++); if (--input_len == 0) break; case 2: ssl_state->curr_connp->content_type = *(input++); ssl_state->curr_connp->version = SSL_VERSION_2; if (--input_len == 0) break; } /* switch (ssl_state->curr_connp->bytes_processed) */ } else { switch (ssl_state->curr_connp->bytes_processed) { case 0: if (input_len >= ssl_state->curr_connp->record_lengths_length + 1) { ssl_state->curr_connp->record_length = (0x3f & input[0]) << 8 | input[1]; ssl_state->curr_connp->content_type = input[3]; ssl_state->curr_connp->version = SSL_VERSION_2; ssl_state->curr_connp->bytes_processed += 4; return 4; } else { ssl_state->curr_connp->record_length = (0x3f & *(input++)) << 8; if (--input_len == 0) break; } case 1: ssl_state->curr_connp->record_length |= *(input++); if (--input_len == 0) break; case 2: /* padding */ input++; if (--input_len == 0) break; case 3: ssl_state->curr_connp->content_type = *(input++); ssl_state->curr_connp->version = SSL_VERSION_2; if (--input_len == 0) break; } /* switch (ssl_state->curr_connp->bytes_processed) */ } ssl_state->curr_connp->bytes_processed += (input - initial_input); return (input - initial_input); } static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len) { int retval = 0; uint8_t *initial_input = input; if (ssl_state->curr_connp->bytes_processed == 0) { if (input[0] & 0x80) { ssl_state->curr_connp->record_lengths_length = 2; } else { ssl_state->curr_connp->record_lengths_length = 3; } } /* the + 1 because, we also read one extra byte inside SSLv2ParseRecord * to read the msg_type */ if (ssl_state->curr_connp->bytes_processed < (ssl_state->curr_connp->record_lengths_length + 1)) { retval = SSLv2ParseRecord(direction, ssl_state, input, input_len); if (retval == -1) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); return -1; } else { input += retval; input_len -= retval; } } if (input_len == 0) { return (input - initial_input); } switch (ssl_state->curr_connp->content_type) { case SSLV2_MT_ERROR: SCLogDebug("SSLV2_MT_ERROR msg_type received. " "Error encountered in establishing the sslv2 " "session, may be version"); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); break; case SSLV2_MT_CLIENT_HELLO: ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO; ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_HS; if (ssl_state->curr_connp->record_lengths_length == 3) { switch (ssl_state->curr_connp->bytes_processed) { case 4: if (input_len >= 6) { ssl_state->curr_connp->session_id_length = input[4] << 8; ssl_state->curr_connp->session_id_length |= input[5]; input += 6; input_len -= 6; ssl_state->curr_connp->bytes_processed += 6; if (ssl_state->curr_connp->session_id_length == 0) { ssl_state->flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; } break; } else { input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; } case 5: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; case 6: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; case 7: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; case 8: ssl_state->curr_connp->session_id_length = *(input++) << 8; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; case 9: ssl_state->curr_connp->session_id_length |= *(input++); ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; } /* switch (ssl_state->curr_connp->bytes_processed) */ /* ssl_state->curr_connp->record_lengths_length is 3 */ } else { switch (ssl_state->curr_connp->bytes_processed) { case 3: if (input_len >= 6) { ssl_state->curr_connp->session_id_length = input[4] << 8; ssl_state->curr_connp->session_id_length |= input[5]; input += 6; input_len -= 6; ssl_state->curr_connp->bytes_processed += 6; if (ssl_state->curr_connp->session_id_length == 0) { ssl_state->flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; } break; } else { input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; } case 4: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; case 5: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; case 6: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; case 7: ssl_state->curr_connp->session_id_length = *(input++) << 8; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; case 8: ssl_state->curr_connp->session_id_length |= *(input++); ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; } /* switch (ssl_state->curr_connp->bytes_processed) */ } /* else - if (ssl_state->curr_connp->record_lengths_length == 3) */ break; case SSLV2_MT_CLIENT_MASTER_KEY: if ( !(ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS)) { SCLogDebug("Client hello is not seen before master key " "message!!"); } ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY; break; case SSLV2_MT_CLIENT_CERTIFICATE: if (direction == 1) { SCLogDebug("Incorrect SSL Record type sent in the toclient " "direction!"); } else { ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_KEYX; } case SSLV2_MT_SERVER_VERIFY: case SSLV2_MT_SERVER_FINISHED: if (direction == 0 && !(ssl_state->curr_connp->content_type & SSLV2_MT_CLIENT_CERTIFICATE)) { SCLogDebug("Incorrect SSL Record type sent in the toserver " "direction!"); } case SSLV2_MT_CLIENT_FINISHED: case SSLV2_MT_REQUEST_CERTIFICATE: /* both ways hello seen */ if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) && (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_HS)) { if (direction == 0) { if (ssl_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) { ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; SCLogDebug("SSLv2 client side has started the encryption"); } else if (ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY) { ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; SCLogDebug("SSLv2 client side has started the encryption"); } } else { ssl_state->flags |= SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED; SCLogDebug("SSLv2 Server side has started the encryption"); } if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED) && (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED)) { pstate->flags |= APP_LAYER_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION; if (ssl_config.no_reassemble == 1) pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY; SCLogDebug("SSLv2 No reassembly & inspection has been set"); } } break; case SSLV2_MT_SERVER_HELLO: ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO; ssl_state->flags |= SSL_AL_FLAG_SSL_SERVER_HS; break; } if (input_len + ssl_state->curr_connp->bytes_processed >= (ssl_state->curr_connp->record_length + ssl_state->curr_connp->record_lengths_length)) { /* looks like we have another record after this*/ uint32_t diff = ssl_state->curr_connp->record_length + ssl_state->curr_connp->record_lengths_length + - ssl_state->curr_connp->bytes_processed; input += diff; SSLParserReset(ssl_state); return (input - initial_input); /* we still don't have the entire record for the one we are * currently parsing */ } else { input += input_len; ssl_state->curr_connp->bytes_processed += input_len; return (input - initial_input); } } static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len) { int retval = 0; uint32_t parsed = 0; if (ssl_state->curr_connp->bytes_processed < SSLV3_RECORD_HDR_LEN) { retval = SSLv3ParseRecord(direction, ssl_state, input, input_len); if (retval < 0) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_TLS_HEADER); return -1; } else { parsed += retval; input_len -= retval; } } if (input_len == 0) { return parsed; } switch (ssl_state->curr_connp->content_type) { /* we don't need any data from these types */ case SSLV3_CHANGE_CIPHER_SPEC: ssl_state->flags |= SSL_AL_FLAG_CHANGE_CIPHER_SPEC; if (direction) ssl_state->flags |= SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC; else ssl_state->flags |= SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC; break; case SSLV3_ALERT_PROTOCOL: break; case SSLV3_APPLICATION_PROTOCOL: if ((ssl_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) && (ssl_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC)) { /* set flags */ pstate->flags |= APP_LAYER_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION; if (ssl_config.no_reassemble == 1) pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY; } break; case SSLV3_HANDSHAKE_PROTOCOL: if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) break; if (ssl_state->curr_connp->record_length < 4) { SSLParserReset(ssl_state); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } retval = SSLv3ParseHandshakeProtocol(ssl_state, input + parsed, input_len); if (retval < 0) { AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { if ((uint32_t)retval > input_len) { SCLogDebug("Error parsing SSLv3.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } parsed += retval; input_len -= retval; if (ssl_state->curr_connp->bytes_processed == ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { SSLParserReset(ssl_state); } return parsed; } break; default: /* \todo fix the event from invalid rule to unknown rule */ AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } if (input_len + ssl_state->curr_connp->bytes_processed >= ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { /* defensive checks. Something's wrong. */ AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } /* looks like we have another record */ uint32_t diff = ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN - ssl_state->curr_connp->bytes_processed; parsed += diff; SSLParserReset(ssl_state); return parsed; /* we still don't have the entire record for the one we are * currently parsing */ } else { parsed += input_len; ssl_state->curr_connp->bytes_processed += input_len; return parsed; } } /** * \internal * \brief SSLv2, SSLv23, SSLv3, TLSv1.1, TLSv1.2, TLSv1.3 parser. * * On parsing error, this should be the only function that should reset * the parser state, to avoid multiple functions in the chain reseting * the parser state. * * \param direction 0 for toserver, 1 for toclient. * \param alstate Pointer to the state. * \param pstate Application layer parser state for this session. * \param input Pointer the received input data. * \param input_len Length in bytes of the received data. * \param output Pointer to the list of parsed output elements. * * \todo On reaching an inconsistent state, check if the input has * another new record, instead of just returning after the reset * * \retval >=0 On success. */ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserState *pstate, uint8_t *input, uint32_t ilen) { SSLState *ssl_state = (SSLState *)alstate; int retval = 0; uint8_t counter = 0; int32_t input_len = (int32_t)ilen; ssl_state->f = f; if (direction == 0) ssl_state->curr_connp = &ssl_state->client_connp; else ssl_state->curr_connp = &ssl_state->server_connp; /* if we have more than one record */ while (input_len > 0) { if (counter++ == 30) { SCLogDebug("Looks like we have looped quite a bit. Reset state " "and get out of here"); SSLParserReset(ssl_state); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } /* ssl_state->bytes_processed is 0 for a * fresh record or positive to indicate a record currently being * parsed */ switch (ssl_state->curr_connp->bytes_processed) { /* fresh record */ case 0: /* only SSLv2, has one of the top 2 bits set */ if ((input[0] & 0x80) || (input[0] & 0x40)) { SCLogDebug("SSLv2 detected"); ssl_state->curr_connp->version = SSL_VERSION_2; retval = SSLv2Decode(direction, ssl_state, pstate, input, input_len); if (retval < 0) { SCLogDebug("Error parsing SSLv2.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { input_len -= retval; input += retval; } } else { SCLogDebug("SSLv3.x detected"); /* we will keep it this way till our record parser tells * us what exact version it is */ ssl_state->curr_connp->version = TLS_VERSION_UNKNOWN; retval = SSLv3Decode(direction, ssl_state, pstate, input, input_len); if (retval < 0) { SCLogDebug("Error parsing SSLv3.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { input_len -= retval; input += retval; if (ssl_state->curr_connp->bytes_processed == SSLV3_RECORD_HDR_LEN && ssl_state->curr_connp->record_length == 0) { /* empty record */ SSLParserReset(ssl_state); } } } break; default: /* we would have established by now if we are dealing with * SSLv2 or above */ if (ssl_state->curr_connp->version == SSL_VERSION_2) { SCLogDebug("Continuing parsing SSLv2 record from where we " "previously left off"); retval = SSLv2Decode(direction, ssl_state, pstate, input, input_len); if (retval == -1) { SCLogDebug("Error parsing SSLv2.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); return 0; } else { input_len -= retval; input += retval; } } else { SCLogDebug("Continuing parsing SSLv3.x record from where we " "previously left off"); retval = SSLv3Decode(direction, ssl_state, pstate, input, input_len); if (retval < 0) { SCLogDebug("Error parsing SSLv3.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); return 0; } else { if (retval > input_len) { SCLogDebug("Error parsing SSLv3.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); } input_len -= retval; input += retval; if (ssl_state->curr_connp->bytes_processed == SSLV3_RECORD_HDR_LEN && ssl_state->curr_connp->record_length == 0) { /* empty record */ SSLParserReset(ssl_state); } } } break; } /* switch (ssl_state->curr_connp->bytes_processed) */ } /* while (input_len) */ return 1; } int SSLParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { return SSLDecode(f, 0 /* toserver */, alstate, pstate, input, input_len); } int SSLParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { return SSLDecode(f, 1 /* toclient */, alstate, pstate, input, input_len); } /** * \internal * \brief Function to allocate the SSL state memory. */ void *SSLStateAlloc(void) { void *ssl_state = SCMalloc(sizeof(SSLState)); if (unlikely(ssl_state == NULL)) return NULL; memset(ssl_state, 0, sizeof(SSLState)); ((SSLState*)ssl_state)->client_connp.cert_log_flag = 0; ((SSLState*)ssl_state)->server_connp.cert_log_flag = 0; TAILQ_INIT(&((SSLState*)ssl_state)->server_connp.certs); return ssl_state; } /** * \internal * \brief Function to free the SSL state memory. */ void SSLStateFree(void *p) { SSLState *ssl_state = (SSLState *)p; SSLCertsChain *item; if (ssl_state->client_connp.trec) SCFree(ssl_state->client_connp.trec); if (ssl_state->client_connp.cert0_subject) SCFree(ssl_state->client_connp.cert0_subject); if (ssl_state->client_connp.cert0_issuerdn) SCFree(ssl_state->client_connp.cert0_issuerdn); if (ssl_state->client_connp.cert0_fingerprint) SCFree(ssl_state->client_connp.cert0_fingerprint); if (ssl_state->server_connp.trec) SCFree(ssl_state->server_connp.trec); if (ssl_state->server_connp.cert0_subject) SCFree(ssl_state->server_connp.cert0_subject); if (ssl_state->server_connp.cert0_issuerdn) SCFree(ssl_state->server_connp.cert0_issuerdn); if (ssl_state->server_connp.cert0_fingerprint) SCFree(ssl_state->server_connp.cert0_fingerprint); /* Free certificate chain */ while ((item = TAILQ_FIRST(&ssl_state->server_connp.certs))) { TAILQ_REMOVE(&ssl_state->server_connp.certs, item, next); SCFree(item); } TAILQ_INIT(&ssl_state->server_connp.certs); SCFree(ssl_state); return; } static uint16_t SSLProbingParser(uint8_t *input, uint32_t ilen) { /* probably a rst/fin sending an eof */ if (ilen == 0) return ALPROTO_UNKNOWN; /* for now just the 3 byte header ones */ /* \todo Detect the 2 byte ones */ if ((input[0] & 0x80) && (input[2] == 0x01)) { return ALPROTO_TLS; } return ALPROTO_FAILED; } /** * \brief Function to register the SSL protocol parser and other functions */ void RegisterSSLParsers(void) { char *proto_name = "tls"; /** SSLv2 and SSLv23*/ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|01 00 02|", 5, 2, STREAM_TOSERVER); /* subsection - SSLv2 style record by client, but informing the server the max * version it supports */ /* Updated by Anoop Saldanha. Disabled it for now. We'll get back to it * after some tests */ //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|01 03 00|", 5, 2, STREAM_TOSERVER); //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|00 02|", 7, 5, STREAM_TOCLIENT); /** SSLv3 */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|01 03 00|", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|16 03 00|", 3, 0, STREAM_TOSERVER); /* client hello */ /** TLSv1 */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|01 03 01|", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|16 03 01|", 3, 0, STREAM_TOSERVER); /* client hello */ /** TLSv1.1 */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|01 03 02|", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|16 03 02|", 3, 0, STREAM_TOSERVER); /* client hello */ /** TLSv1.2 */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|01 03 03|", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_TLS, "|16 03 03|", 3, 0, STREAM_TOSERVER); /* client hello */ AppLayerRegisterProto(proto_name, ALPROTO_TLS, STREAM_TOSERVER, SSLParseClientRecord); AppLayerRegisterProto(proto_name, ALPROTO_TLS, STREAM_TOCLIENT, SSLParseServerRecord); AppLayerDecoderEventsModuleRegister(ALPROTO_TLS, tls_decoder_event_table); AppLayerRegisterStateFuncs(ALPROTO_TLS, SSLStateAlloc, SSLStateFree); AppLayerRegisterProbingParser(&alp_proto_ctx, 443, IPPROTO_TCP, proto_name, ALPROTO_TLS, 0, 3, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, SSLProbingParser); /* Get the value of no reassembly option from the config file */ if (ConfGetBool("tls.no-reassemble", &ssl_config.no_reassemble) != 1) ssl_config.no_reassemble = 1; return; } /***************************************Unittests******************************/ #ifdef UNITTESTS /** *\test Send a get request in one chunk. */ static int SSLParserTest01(void) { int result = 1; Flow f; uint8_t tlsbuf[] = { 0x16, 0x03, 0x01 }; uint32_t tlslen = sizeof(tlsbuf); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a get request in two chunks. */ static int SSLParserTest02(void) { int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); uint8_t tlsbuf2[] = { 0x03, 0x01 }; uint32_t tlslen2 = sizeof(tlsbuf2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a get request in three chunks. */ static int SSLParserTest03(void) { int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); uint8_t tlsbuf2[] = { 0x03 }; uint32_t tlslen2 = sizeof(tlsbuf2); uint8_t tlsbuf3[] = { 0x01 }; uint32_t tlslen3 = sizeof(tlsbuf3); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a get request in three chunks + more data. */ static int SSLParserTest04(void) { int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); uint8_t tlsbuf2[] = { 0x03 }; uint32_t tlslen2 = sizeof(tlsbuf2); uint8_t tlsbuf3[] = { 0x01 }; uint32_t tlslen3 = sizeof(tlsbuf3); uint8_t tlsbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x01 }; uint32_t tlslen4 = sizeof(tlsbuf4); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } #if 0 /** \test Test the setting up of no reassembly and no payload inspection flag * after detection of the TLS handshake completion */ static int SSLParserTest05(void) { int result = 1; Flow f; uint8_t tlsbuf[] = { 0x16, 0x03, 0x01, 0x00, 0x01 }; uint32_t tlslen = sizeof(tlsbuf); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x14; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x14; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x17; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x17) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.client_version); result = 0; goto end; } AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *) ssn.alparser; AppLayerParserState *parser_state = &parser_state_store->to_server; if (!(parser_state->flags & APP_LAYER_PARSER_NO_INSPECTION) && !(ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && !(ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("The flags should be set\n"); result = 0; goto end; } if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION)) { printf("The flags should be set\n"); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } #endif #if 0 /** \test Test the setting up of no reassembly and no payload inspection flag * after detection of the valid TLS handshake completion, the rouge * 0x17 packet will not be considered in the detection process */ static int SSLParserTest06(void) { int result = 1; Flow f; uint8_t tlsbuf[] = { 0x16, 0x03, 0x01, 0x00, 0x01 }; uint32_t tlslen = sizeof(tlsbuf); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x14; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x17; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x17) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp._content_type); result = 0; goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); result = 0; goto end; } AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *) ssn.alparser; AppLayerParserState *parser_state = &parser_state_store->to_server; if ((parser_state->flags & APP_LAYER_PARSER_NO_INSPECTION) || (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("The flags should not be set\n"); result = 0; goto end; } tlsbuf[0] = 0x14; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x17; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } if (!(parser_state->flags & APP_LAYER_PARSER_NO_INSPECTION) && !(ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && !(ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("The flags should be set\n"); result = 0; goto end; } if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION)) { printf("The flags should be set\n"); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } #endif /** \test multimsg test */ static int SSLParserMultimsgTest01(void) { int result = 1; Flow f; /* 3 msgs */ uint8_t tlsbuf1[] = { 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0xd3, 0x6f, 0x1f, 0x63, 0x82, 0x8d, 0x75, 0x77, 0x8c, 0x91, 0xbc, 0xa1, 0x3d, 0xbb, 0xe1, 0xb5, 0xd3, 0x31, 0x92, 0x59, 0x2b, 0x2c, 0x43, 0x96, 0xa3, 0xaa, 0x23, 0x92, 0xd0, 0x91, 0x2a, 0x5e, 0x10, 0x5b, 0xc8, 0xc1, 0xe2, 0xd3, 0x5c, 0x8b, 0x8c, 0x91, 0x9e, 0xc2, 0xf2, 0x9c, 0x3c, 0x4f, 0x37, 0x1e, 0x20, 0x5e, 0x33, 0xd5, 0xf0, 0xd6, 0xaf, 0x89, 0xf5, 0xcc, 0xb2, 0xcf, 0xc1, 0x60, 0x3a, 0x46, 0xd5, 0x4e, 0x2a, 0xb6, 0x6a, 0xb9, 0xfc, 0x32, 0x8b, 0xe0, 0x6e, 0xa0, 0xed, 0x25, 0xa0, 0xa4, 0x82, 0x81, 0x73, 0x90, 0xbf, 0xb5, 0xde, 0xeb, 0x51, 0x8d, 0xde, 0x5b, 0x6f, 0x94, 0xee, 0xba, 0xe5, 0x69, 0xfa, 0x1a, 0x80, 0x30, 0x54, 0xeb, 0x12, 0x01, 0xb9, 0xfe, 0xbf, 0x82, 0x95, 0x01, 0x7b, 0xb0, 0x97, 0x14, 0xc2, 0x06, 0x3c, 0x69, 0xfb, 0x1c, 0x66, 0x47, 0x17, 0xd9, 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xf6, 0xbc, 0x0d, 0x6f, 0xe8, 0xbb, 0xaa, 0xbf, 0x14, 0xeb, 0x7b, 0xcc, 0x6c, 0x28, 0xb0, 0xfc, 0xa6, 0x01, 0x2a, 0x97, 0x96, 0x17, 0x5e, 0xe8, 0xb4, 0x4e, 0x78, 0xc9, 0x04, 0x65, 0x53, 0xb6, 0x93, 0x3d, 0xeb, 0x44, 0xee, 0x86, 0xf9, 0x80, 0x49, 0x45, 0x21, 0x34, 0xd1, 0xee, 0xc8, 0x9c }; uint32_t tlslen1 = sizeof(tlsbuf1); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** \test multimsg test server */ static int SSLParserMultimsgTest02(void) { int result = 1; Flow f; /* 3 msgs */ uint8_t tlsbuf1[] = { 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0xd3, 0x6f, 0x1f, 0x63, 0x82, 0x8d, 0x75, 0x77, 0x8c, 0x91, 0xbc, 0xa1, 0x3d, 0xbb, 0xe1, 0xb5, 0xd3, 0x31, 0x92, 0x59, 0x2b, 0x2c, 0x43, 0x96, 0xa3, 0xaa, 0x23, 0x92, 0xd0, 0x91, 0x2a, 0x5e, 0x10, 0x5b, 0xc8, 0xc1, 0xe2, 0xd3, 0x5c, 0x8b, 0x8c, 0x91, 0x9e, 0xc2, 0xf2, 0x9c, 0x3c, 0x4f, 0x37, 0x1e, 0x20, 0x5e, 0x33, 0xd5, 0xf0, 0xd6, 0xaf, 0x89, 0xf5, 0xcc, 0xb2, 0xcf, 0xc1, 0x60, 0x3a, 0x46, 0xd5, 0x4e, 0x2a, 0xb6, 0x6a, 0xb9, 0xfc, 0x32, 0x8b, 0xe0, 0x6e, 0xa0, 0xed, 0x25, 0xa0, 0xa4, 0x82, 0x81, 0x73, 0x90, 0xbf, 0xb5, 0xde, 0xeb, 0x51, 0x8d, 0xde, 0x5b, 0x6f, 0x94, 0xee, 0xba, 0xe5, 0x69, 0xfa, 0x1a, 0x80, 0x30, 0x54, 0xeb, 0x12, 0x01, 0xb9, 0xfe, 0xbf, 0x82, 0x95, 0x01, 0x7b, 0xb0, 0x97, 0x14, 0xc2, 0x06, 0x3c, 0x69, 0xfb, 0x1c, 0x66, 0x47, 0x17, 0xd9, 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xf6, 0xbc, 0x0d, 0x6f, 0xe8, 0xbb, 0xaa, 0xbf, 0x14, 0xeb, 0x7b, 0xcc, 0x6c, 0x28, 0xb0, 0xfc, 0xa6, 0x01, 0x2a, 0x97, 0x96, 0x17, 0x5e, 0xe8, 0xb4, 0x4e, 0x78, 0xc9, 0x04, 0x65, 0x53, 0xb6, 0x93, 0x3d, 0xeb, 0x44, 0xee, 0x86, 0xf9, 0x80, 0x49, 0x45, 0x21, 0x34, 0xd1, 0xee, 0xc8, 0x9c }; uint32_t tlslen1 = sizeof(tlsbuf1); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf1, tlslen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->server_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->server_connp.content_type); result = 0; goto end; } if (ssl_state->server_connp.version != 0x0301) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", 0x0301, ssl_state->server_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Test the detection of SSLv3 protocol from the given packet */ static int SSLParserTest07(void) { int result = 1; Flow f; uint8_t tlsbuf[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; uint32_t tlslen = sizeof(tlsbuf); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } #if 0 /** \test Test the setting up of no reassembly and no payload inspection flag * after detection of the SSLv3 handshake completion */ static int SSLParserTest08(void) { int result = 1; Flow f; uint8_t tlsbuf[] = { 0x16, 0x03, 0x00, 0x00, 0x01 }; uint32_t tlslen = sizeof(tlsbuf); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x14; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x14; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } tlsbuf[0] = 0x17; r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x17) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, ssl_state->client_connp.version); result = 0; goto end; } AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *) ssn.alparser; AppLayerParserState *parser_state = &parser_state_store->to_server; if (!(parser_state->flags & APP_LAYER_PARSER_NO_INSPECTION) && !(ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && !(ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("The flags should be set\n"); result = 0; goto end; } if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION)) { printf("The flags should be set\n"); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } #endif /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest09(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { 0x03, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest10(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest11(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest12(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { 0x00, 0x00, 0x6b, }; uint32_t buf2_len = sizeof(buf2); uint8_t buf3[] = { 0x03, 0x00, 0x4b, 0x2f, 0xdc, 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; uint32_t buf3_len = sizeof(buf2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest13(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { 0x00, 0x00, 0x6b, }; uint32_t buf2_len = sizeof(buf2); uint8_t buf3[] = { 0x03, 0x00, 0x4b, 0x2f, 0xdc, 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, }; uint32_t buf3_len = sizeof(buf3); uint8_t buf4[] = { 0xcf, 0x8e, 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; uint32_t buf4_len = sizeof(buf4); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf4, buf4_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest14(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x00, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { 0x16, 0x03, 0x00, 0x00, 0x00, }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest15(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x01, 0x01, }; uint32_t buf1_len = sizeof(buf1); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest16(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x02, 0x01, 0x00 }; uint32_t buf1_len = sizeof(buf1); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest17(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00 }; uint32_t buf1_len = sizeof(buf1); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest18(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x6b, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { 0x16, 0x03, 0x00, 0x00, 0x00, }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest19(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x6b, 0x16, 0x03, 0x00, 0x00, 0x00, }; uint32_t buf1_len = sizeof(buf1); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest20(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x16, 0x03, 0x00, 0x00, 0x00, }; uint32_t buf1_len = sizeof(buf1); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test SSLv2 Record parsing. */ static int SSLParserTest21(void) { int result = 0; Flow f; uint8_t buf[] = { 0x80, 0x31, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, }; uint32_t buf_len = sizeof(buf); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, buf, buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } SSLState *app_state = f.alstate; if (app_state == NULL) { printf("no ssl state: "); goto end; } if (app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", SSLV2_MT_SERVER_HELLO, app_state->client_connp.content_type); goto end; } if (app_state->client_connp.version != SSL_VERSION_2) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_2, app_state->client_connp.version); goto end; } result = 1; end: FLOW_DESTROY(&f); return result; } /** * \test SSLv2 Record parsing. */ static int SSLParserTest22(void) { int result = 1; Flow f; uint8_t buf[] = { 0x80, 0x31, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x07, 0x00, 0xc0, 0x05, 0x00, 0x80, 0x03, 0x00, 0x80, 0x01, 0x00, 0x80, 0x08, 0x00, 0x80, 0x06, 0x00, 0x40, 0x04, 0x00, 0x80, 0x02, 0x00, 0x80, 0x76, 0x64, 0x75, 0x2d, 0xa7, 0x98, 0xfe, 0xc9, 0x12, 0x92, 0xc1, 0x2f, 0x34, 0x84, 0x20, 0xc5}; uint32_t buf_len = sizeof(buf); TcpSession ssn; //AppLayerDetectProtoThreadInit(); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT | STREAM_EOF, buf, buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *app_state = f.alstate; if (app_state == NULL) { printf("no ssl state: "); result = 0; goto end; } if (app_state->server_connp.content_type != SSLV2_MT_SERVER_HELLO) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", SSLV2_MT_SERVER_HELLO, app_state->server_connp.content_type); result = 0; goto end; } if (app_state->server_connp.version != SSL_VERSION_2) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_2, app_state->server_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test SSLv2 Record parsing. */ static int SSLParserTest23(void) { int result = 1; Flow f; uint8_t chello_buf[] = { 0x80, 0x67, 0x01, 0x03, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, 0x00, 0x00, 0x39, 0x00, 0x00, 0x38, 0x00, 0x00, 0x35, 0x00, 0x00, 0x33, 0x00, 0x00, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x15, 0x00, 0x00, 0x12, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, 0xa8, 0xb8, 0x93, 0xbb, 0x90, 0xe9, 0x2a, 0xa2, 0x4d, 0x6d, 0xcc, 0x1c, 0xe7, 0x2a, 0x80, 0x21 }; uint32_t chello_buf_len = sizeof(chello_buf); uint8_t shello_buf[] = { 0x16, 0x03, 0x00, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x46, 0x03, 0x00, 0x44, 0x4c, 0x94, 0x8f, 0xfe, 0x81, 0xed, 0x93, 0x65, 0x02, 0x88, 0xa3, 0xf8, 0xeb, 0x63, 0x86, 0x0e, 0x2c, 0xf6, 0x8d, 0xd0, 0x0f, 0x2c, 0x2a, 0xd6, 0x4f, 0xcd, 0x2d, 0x3c, 0x16, 0xd7, 0xd6, 0x20, 0xa0, 0xfb, 0x60, 0x86, 0x3d, 0x1e, 0x76, 0xf3, 0x30, 0xfe, 0x0b, 0x01, 0xfd, 0x1a, 0x01, 0xed, 0x95, 0xf6, 0x7b, 0x8e, 0xc0, 0xd4, 0x27, 0xbf, 0xf0, 0x6e, 0xc7, 0x56, 0xb1, 0x47, 0xce, 0x98, 0x00, 0x35, 0x00, 0x16, 0x03, 0x00, 0x03, 0x44, 0x0b, 0x00, 0x03, 0x40, 0x00, 0x03, 0x3d, 0x00, 0x03, 0x3a, 0x30, 0x82, 0x03, 0x36, 0x30, 0x82, 0x02, 0x9f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x81, 0xa9, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x58, 0x59, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0c, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x44, 0x65, 0x73, 0x65, 0x72, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x54, 0x6f, 0x77, 0x6e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x4f, 0x69, 0x6c, 0x2c, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0c, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x4f, 0x69, 0x6c, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0f, 0x63, 0x61, 0x40, 0x73, 0x6e, 0x61, 0x6b, 0x65, 0x6f, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x33, 0x30, 0x33, 0x30, 0x35, 0x31, 0x36, 0x34, 0x37, 0x34, 0x35, 0x5a, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x30, 0x33, 0x31, 0x36, 0x34, 0x37, 0x34, 0x35, 0x5a, 0x30, 0x81, 0xa7, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x58, 0x59, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0c, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x44, 0x65, 0x73, 0x65, 0x72, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x54, 0x6f, 0x77, 0x6e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x53, 0x6e, 0x61, 0x6b, 0x65, 0x20, 0x4f, 0x69, 0x6c, 0x2c, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0e, 0x57, 0x65, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x6e, 0x61, 0x6b, 0x65, 0x6f, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x77, 0x77, 0x77, 0x40, 0x73, 0x6e, 0x61, 0x6b, 0x65, 0x6f, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa4, 0x6e, 0x53, 0x14, 0x0a, 0xde, 0x2c, 0xe3, 0x60, 0x55, 0x9a, 0xf2, 0x42, 0xa6, 0xaf, 0x47, 0x12, 0x2f, 0x17, 0xce, 0xfa, 0xba, 0xdc, 0x4e, 0x63, 0x56, 0x34, 0xb9, 0xba, 0x73, 0x4b, 0x78, 0x44, 0x3d, 0xc6, 0x6c, 0x69, 0xa4, 0x25, 0xb3, 0x61, 0x02, 0x9d, 0x09, 0x04, 0x3f, 0x72, 0x3d, 0xd8, 0x27, 0xd3, 0xb0, 0x5a, 0x45, 0x77, 0xb7, 0x36, 0xe4, 0x26, 0x23, 0xcc, 0x12, 0xb8, 0xae, 0xde, 0xa7, 0xb6, 0x3a, 0x82, 0x3c, 0x7c, 0x24, 0x59, 0x0a, 0xf8, 0x96, 0x43, 0x8b, 0xa3, 0x29, 0x36, 0x3f, 0x91, 0x7f, 0x5d, 0xc7, 0x23, 0x94, 0x29, 0x7f, 0x0a, 0xce, 0x0a, 0xbd, 0x8d, 0x9b, 0x2f, 0x19, 0x17, 0xaa, 0xd5, 0x8e, 0xec, 0x66, 0xa2, 0x37, 0xeb, 0x3f, 0x57, 0x53, 0x3c, 0xf2, 0xaa, 0xbb, 0x79, 0x19, 0x4b, 0x90, 0x7e, 0xa7, 0xa3, 0x99, 0xfe, 0x84, 0x4c, 0x89, 0xf0, 0x3d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x6e, 0x30, 0x6c, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x14, 0x30, 0x12, 0x81, 0x10, 0x77, 0x77, 0x77, 0x40, 0x73, 0x6e, 0x61, 0x6b, 0x65, 0x6f, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x30, 0x3a, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x2d, 0x16, 0x2b, 0x6d, 0x6f, 0x64, 0x5f, 0x73, 0x73, 0x6c, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x06, 0x40, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xae, 0x79, 0x79, 0x22, 0x90, 0x75, 0xfd, 0xa6, 0xd5, 0xc4, 0xb8, 0xc4, 0x99, 0x4e, 0x1c, 0x05, 0x7c, 0x91, 0x59, 0xbe, 0x89, 0x0d, 0x3d, 0xc6, 0x8c, 0xa3, 0xcf, 0xf6, 0xba, 0x23, 0xdf, 0xb8, 0xae, 0x44, 0x68, 0x8a, 0x8f, 0xb9, 0x8b, 0xcb, 0x12, 0xda, 0xe6, 0xa2, 0xca, 0xa5, 0xa6, 0x55, 0xd9, 0xd2, 0xa1, 0xad, 0xba, 0x9b, 0x2c, 0x44, 0x95, 0x1d, 0x4a, 0x90, 0x59, 0x7f, 0x83, 0xae, 0x81, 0x5e, 0x3f, 0x92, 0xe0, 0x14, 0x41, 0x82, 0x4e, 0x7f, 0x53, 0xfd, 0x10, 0x23, 0xeb, 0x8a, 0xeb, 0xe9, 0x92, 0xea, 0x61, 0xf2, 0x8e, 0x19, 0xa1, 0xd3, 0x49, 0xc0, 0x84, 0x34, 0x1e, 0x2e, 0x6e, 0xf6, 0x98, 0xe2, 0x87, 0x53, 0xd6, 0x55, 0xd9, 0x1a, 0x8a, 0x92, 0x5c, 0xad, 0xdc, 0x1e, 0x1c, 0x30, 0xa7, 0x65, 0x9d, 0xc2, 0x4f, 0x60, 0xd2, 0x6f, 0xdb, 0xe0, 0x9f, 0x9e, 0xbc, 0x41, 0x16, 0x03, 0x00, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00 }; uint32_t shello_buf_len = sizeof(shello_buf); uint8_t client_change_cipher_spec_buf[] = { 0x16, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00, 0x80, 0x65, 0x51, 0x2d, 0xa6, 0xd4, 0xa7, 0x38, 0xdf, 0xac, 0x79, 0x1f, 0x0b, 0xd9, 0xb2, 0x61, 0x7d, 0x73, 0x88, 0x32, 0xd9, 0xf2, 0x62, 0x3a, 0x8b, 0x11, 0x04, 0x75, 0xca, 0x42, 0xff, 0x4e, 0xd9, 0xcc, 0xb9, 0xfa, 0x86, 0xf3, 0x16, 0x2f, 0x09, 0x73, 0x51, 0x66, 0xaa, 0x29, 0xcd, 0x80, 0x61, 0x0f, 0xe8, 0x13, 0xce, 0x5b, 0x8e, 0x0a, 0x23, 0xf8, 0x91, 0x5e, 0x5f, 0x54, 0x70, 0x80, 0x8e, 0x7b, 0x28, 0xef, 0xb6, 0x69, 0xb2, 0x59, 0x85, 0x74, 0x98, 0xe2, 0x7e, 0xd8, 0xcc, 0x76, 0x80, 0xe1, 0xb6, 0x45, 0x4d, 0xc7, 0xcd, 0x84, 0xce, 0xb4, 0x52, 0x79, 0x74, 0xcd, 0xe6, 0xd7, 0xd1, 0x9c, 0xad, 0xef, 0x63, 0x6c, 0x0f, 0xf7, 0x05, 0xe4, 0x4d, 0x1a, 0xd3, 0xcb, 0x9c, 0xd2, 0x51, 0xb5, 0x61, 0xcb, 0xff, 0x7c, 0xee, 0xc7, 0xbc, 0x5e, 0x15, 0xa3, 0xf2, 0x52, 0x0f, 0xbb, 0x32, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03, 0x00, 0x00, 0x40, 0xa9, 0xd8, 0xd7, 0x35, 0xbc, 0x39, 0x56, 0x98, 0xad, 0x87, 0x61, 0x2a, 0xc4, 0x8f, 0xcc, 0x03, 0xcb, 0x93, 0x80, 0x81, 0xb0, 0x4a, 0xc4, 0xd2, 0x09, 0x71, 0x3e, 0x90, 0x3c, 0x8d, 0xe0, 0x95, 0x44, 0xfe, 0x56, 0xd1, 0x7e, 0x88, 0xe2, 0x48, 0xfd, 0x76, 0x70, 0x76, 0xe2, 0xcd, 0x06, 0xd0, 0xf3, 0x9d, 0x13, 0x79, 0x67, 0x1e, 0x37, 0xf6, 0x98, 0xbe, 0x59, 0x18, 0x4c, 0xfc, 0x75, 0x56 }; uint32_t client_change_cipher_spec_buf_len = sizeof(client_change_cipher_spec_buf); uint8_t server_change_cipher_spec_buf[] = { 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03, 0x00, 0x00, 0x40, 0xce, 0x7c, 0x92, 0x43, 0x59, 0xcc, 0x3d, 0x90, 0x91, 0x9c, 0x58, 0xf0, 0x7a, 0xce, 0xae, 0x0d, 0x08, 0xe0, 0x76, 0xb4, 0x86, 0xb1, 0x15, 0x5b, 0x32, 0xb8, 0x77, 0x53, 0xe7, 0xa6, 0xf9, 0xd0, 0x95, 0x5f, 0xaa, 0x07, 0xc3, 0x96, 0x7c, 0xc9, 0x88, 0xc2, 0x7a, 0x20, 0x89, 0x4f, 0xeb, 0xeb, 0xb6, 0x19, 0xef, 0xaa, 0x27, 0x73, 0x9d, 0xa6, 0xb4, 0x9f, 0xeb, 0x34, 0xe2, 0x4d, 0x9f, 0x6b }; uint32_t server_change_cipher_spec_buf_len = sizeof(server_change_cipher_spec_buf); uint8_t toserver_app_data_buf[] = { 0x17, 0x03, 0x00, 0x01, 0xb0, 0x4a, 0xc3, 0x3e, 0x9d, 0x77, 0x78, 0x01, 0x2c, 0xb4, 0xbc, 0x4c, 0x9a, 0x84, 0xd7, 0xb9, 0x90, 0x0c, 0x21, 0x10, 0xf0, 0xfa, 0x00, 0x7c, 0x16, 0xbb, 0x77, 0xfb, 0x72, 0x42, 0x4f, 0xad, 0x50, 0x4a, 0xd0, 0xaa, 0x6f, 0xaa, 0x44, 0x6c, 0x62, 0x94, 0x1b, 0xc5, 0xfe, 0xe9, 0x1c, 0x5e, 0xde, 0x85, 0x0b, 0x0e, 0x05, 0xe4, 0x18, 0x6e, 0xd2, 0xd3, 0xb5, 0x20, 0xab, 0x81, 0xfd, 0x18, 0x9a, 0x73, 0xb8, 0xd7, 0xef, 0xc3, 0xdd, 0x74, 0xd7, 0x9c, 0x1e, 0x6f, 0x21, 0x6d, 0xf8, 0x24, 0xca, 0x3c, 0x70, 0x78, 0x36, 0x12, 0x7a, 0x8a, 0x9c, 0xac, 0x4e, 0x1c, 0xa8, 0xfb, 0x27, 0x30, 0xba, 0x9a, 0xf4, 0x2f, 0x0a, 0xab, 0x80, 0x6a, 0xa1, 0x60, 0x74, 0xf0, 0xe3, 0x91, 0x84, 0xe7, 0x90, 0x88, 0xcc, 0xf0, 0x95, 0x7b, 0x0a, 0x22, 0xf2, 0xf9, 0x27, 0xe0, 0xdd, 0x38, 0x0c, 0xfd, 0xe9, 0x03, 0x71, 0xdc, 0x70, 0xa4, 0x6e, 0xdf, 0xe3, 0x72, 0x9e, 0xa1, 0xf0, 0xc9, 0x00, 0xd6, 0x03, 0x55, 0x6a, 0x67, 0x5d, 0x9c, 0xb8, 0x75, 0x01, 0xb0, 0x01, 0x9f, 0xe6, 0xd2, 0x44, 0x18, 0xbc, 0xca, 0x7a, 0x10, 0x39, 0xa6, 0xcf, 0x15, 0xc7, 0xf5, 0x35, 0xd4, 0xb3, 0x6d, 0x91, 0x23, 0x84, 0x99, 0xba, 0xb0, 0x7e, 0xd0, 0xc9, 0x4c, 0xbf, 0x3f, 0x33, 0x68, 0x37, 0xb7, 0x7d, 0x44, 0xb0, 0x0b, 0x2c, 0x0f, 0xd0, 0x75, 0xa2, 0x6b, 0x5b, 0xe1, 0x9f, 0xd4, 0x69, 0x9a, 0x14, 0xc8, 0x29, 0xb7, 0xd9, 0x10, 0xbb, 0x99, 0x30, 0x9a, 0xfb, 0xcc, 0x13, 0x1f, 0x76, 0x4e, 0xe6, 0xdf, 0x14, 0xaa, 0xd5, 0x60, 0xbf, 0x91, 0x49, 0x0d, 0x64, 0x42, 0x29, 0xa8, 0x64, 0x27, 0xd4, 0x5e, 0x1b, 0x18, 0x03, 0xa8, 0x73, 0xd6, 0x05, 0x6e, 0xf7, 0x50, 0xb0, 0x09, 0x6b, 0x69, 0x7a, 0x12, 0x28, 0x58, 0xef, 0x5a, 0x86, 0x11, 0xde, 0x71, 0x71, 0x9f, 0xca, 0xbd, 0x79, 0x2a, 0xc2, 0xe5, 0x9b, 0x5e, 0x32, 0xe7, 0xcb, 0x97, 0x6e, 0xa0, 0xea, 0xa4, 0xa4, 0x6a, 0x32, 0xf9, 0x37, 0x39, 0xd8, 0x37, 0x6d, 0x63, 0xf3, 0x08, 0x1c, 0xdd, 0x06, 0xdd, 0x2c, 0x2b, 0x9f, 0x04, 0x88, 0x5f, 0x36, 0x42, 0xc1, 0xb1, 0xc7, 0xe8, 0x2d, 0x5d, 0xa4, 0x6c, 0xe5, 0x60, 0x94, 0xae, 0xd0, 0x90, 0x1e, 0x88, 0xa0, 0x87, 0x52, 0xfb, 0xed, 0x97, 0xa5, 0x25, 0x5a, 0xb7, 0x55, 0xc5, 0x13, 0x07, 0x85, 0x27, 0x40, 0xed, 0xb8, 0xa0, 0x26, 0x13, 0x44, 0x0c, 0xfc, 0xcc, 0x5a, 0x09, 0xe5, 0x44, 0xb5, 0x63, 0xa1, 0x43, 0x51, 0x23, 0x4f, 0x17, 0x21, 0x89, 0x2e, 0x58, 0xfd, 0xf9, 0x63, 0x74, 0x04, 0x70, 0x1e, 0x7d, 0xd0, 0x66, 0xba, 0x40, 0x5e, 0x45, 0xdc, 0x39, 0x7c, 0x53, 0x0f, 0xa8, 0x38, 0xb2, 0x13, 0x99, 0x27, 0xd9, 0x4a, 0x51, 0xe9, 0x9f, 0x2a, 0x92, 0xbb, 0x9c, 0x90, 0xab, 0xfd, 0xf1, 0xb7, 0x40, 0x05, 0xa9, 0x7a, 0x20, 0x63, 0x36, 0xc1, 0xef, 0xb9, 0xad, 0xa2, 0xe0, 0x1d, 0x20, 0x4f, 0xb2, 0x34, 0xbd, 0xea, 0x07, 0xac, 0x21, 0xce, 0xf6, 0x8a, 0xa2, 0x9e, 0xcd, 0xfa }; uint32_t toserver_app_data_buf_len = sizeof(toserver_app_data_buf); TcpSession ssn; //AppLayerDetectProtoThreadInit(); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *app_state = f.alstate; if (app_state == NULL) { printf("no ssl state: "); result = 0; goto end; } if (app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", SSLV2_MT_CLIENT_HELLO, app_state->client_connp.content_type); result = 0; goto end; } if (app_state->client_connp.version != SSL_VERSION_2) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_2, app_state->client_connp.version); result = 0; goto end; } if (app_state->flags != (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | SSL_AL_FLAG_SSL_NO_SESSION_ID)) { printf("flags not set\n"); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, shello_buf_len); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } if (app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", SSLV3_HANDSHAKE_PROTOCOL, app_state->server_connp.content_type); result = 0; goto end; } if (app_state->server_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, app_state->server_connp.version); result = 0; goto end; } if (app_state->flags != (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO)) { printf("flags not set\n"); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* with multiple records the client content type hold the type from the last * record */ if (app_state->client_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", SSLV3_HANDSHAKE_PROTOCOL, app_state->client_connp.content_type); result = 0; goto end; } if (app_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, app_state->client_connp.version); result = 0; goto end; } if (app_state->flags != (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { printf("flags not set\n"); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* with multiple records the serve content type hold the type from the last * record */ if (app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", SSLV3_HANDSHAKE_PROTOCOL, app_state->server_connp.content_type); result = 0; goto end; } if (app_state->server_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, app_state->server_connp.version); result = 0; goto end; } if (app_state->flags != (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { printf("flags not set\n"); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, toserver_app_data_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } if (app_state->client_connp.content_type != SSLV3_APPLICATION_PROTOCOL) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", SSLV3_APPLICATION_PROTOCOL, app_state->client_connp.content_type); result = 0; goto end; } if (app_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, app_state->client_connp.version); result = 0; goto end; } if (app_state->flags != (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { printf("flags not set\n"); result = 0; goto end; } AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f.alparser; AppLayerParserState *parser_state = &parser_state_store->to_server; if (!(parser_state->flags & APP_LAYER_PARSER_NO_INSPECTION) && !(ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && !(ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("The flags should be set\n"); result = 0; goto end; } if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION)) { printf("The flags should be set\n"); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test Tests the parser for handling fragmented records. */ static int SSLParserTest24(void) { int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x6b, 0x03, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { 0x00, 0x4b, 0x2f, 0xdc, 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); result = 0; goto end; } if (ssl_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, ssl_state->client_connp.content_type); result = 0; goto end; } if (ssl_state->client_connp.version != SSL_VERSION_3) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", SSL_VERSION_3, ssl_state->client_connp.version); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Test for bug #955 and CVE-2013-5919. The data is from the * pcap that was used to report this issue. */ static int SSLParserTest25(void) { int result = 0; Flow f; uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xd3, 0x01, 0x00, 0x00, 0xcf, 0x03, 0x01, 0x51, 0x60, 0xc2, 0x15, 0x36, 0x73, 0xf5, 0xb8, 0x58, 0x55, 0x3b, 0x68, 0x12, 0x7d, 0xe3, 0x28, 0xa3, 0xe1, 0x02, 0x79, 0x2d, 0x12, 0xe1, 0xf4, 0x24, 0x12, 0xa2, 0x9e, 0xf1, 0x08, 0x49, 0x68, 0x20, 0x0e, 0x96, 0x46, 0x3d, 0x84, 0x5a, 0xc6, 0x55, 0xeb, 0x3b, 0x53, 0x77, 0xf4, 0x8e, 0xf4, 0xd2, 0x8b, 0xec, 0xd6, 0x99, 0x63, 0x64, 0x62, 0xf8, 0x3f, 0x3b, 0xd5, 0x35, 0x45, 0x1b, 0x16, 0xac, 0x00, 0x46, 0x00, 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x35, 0xc0, 0x02, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x0c, 0xc0, 0x0e, 0xc0, 0x0f, 0xc0, 0x07, 0xc0, 0x09, 0xc0, 0x0a, 0xc0, 0x11, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x32, 0x00, 0x38, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x16, 0x00, 0x13, 0x00, 0x09, 0x00, 0x15, 0x00, 0x12, 0x00, 0x03, 0x00, 0x08, 0x00, 0x14, 0x00, 0x11, 0x00, 0xff, 0x01, 0x00, 0x00, 0x40, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11 }; uint32_t client_hello_len = sizeof(client_hello); uint8_t server_hello_certificate_done[] = { 0x16, 0x03, 0x01, 0x00, 0x51, 0x02, 0x00, 0x00, 0x4d, 0x03, 0x01, 0x51, 0x60, 0xc2, 0x17, 0xb7, 0x81, 0xaa, 0x27, 0xa1, 0xd5, 0xfa, 0x14, 0xc1, 0xe0, 0x05, 0xab, 0x75, 0xf2, 0x51, 0xe7, 0x6e, 0xe6, 0xf9, 0xc4, 0x8f, 0x16, 0x08, 0x26, 0x6c, 0x1b, 0x86, 0x90, 0x20, 0x0a, 0x38, 0x90, 0x2d, 0x17, 0x7d, 0xb7, 0x6b, 0x6b, 0xe5, 0xeb, 0x61, 0x90, 0x35, 0xf8, 0xcd, 0xb1, 0x2a, 0x69, 0x6e, 0x0e, 0x3e, 0x5f, 0x90, 0xdc, 0x2f, 0x51, 0x45, 0x68, 0x63, 0xe3, 0xb3, 0x00, 0x05, 0x00, 0x00, 0x05, 0xff, 0x01, 0x00, 0x01, 0x00, 0x16, 0x03, 0x01, 0x07, 0x60, 0x0b, 0x00, 0x07, 0x5c, 0x00, 0x07, 0x59, 0x00, 0x03, 0xcc, 0x30, 0x82, 0x03, 0xc8, 0x30, 0x82, 0x03, 0x31, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 0x7f, 0x77, 0xde, 0xb3, 0xbc, 0xbb, 0x23, 0x5d, 0x44, 0xcc, 0xc7, 0xdb, 0xa6, 0x2e, 0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0xba, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x31, 0x49, 0x30, 0x47, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x40, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x49, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x62, 0x79, 0x20, 0x52, 0x65, 0x66, 0x2e, 0x20, 0x4c, 0x49, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x20, 0x4c, 0x54, 0x44, 0x2e, 0x28, 0x63, 0x29, 0x39, 0x37, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x36, 0x32, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x50, 0x61, 0x6c, 0x6f, 0x20, 0x41, 0x6c, 0x74, 0x6f, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x46, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x02, 0x14, 0x0e, 0x2a, 0x2e, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xae, 0x94, 0xb1, 0x71, 0xe2, 0xde, 0xcc, 0xc1, 0x69, 0x3e, 0x05, 0x10, 0x63, 0x24, 0x01, 0x02, 0xe0, 0x68, 0x9a, 0xe8, 0x3c, 0x39, 0xb6, 0xb3, 0xe7, 0x4b, 0x97, 0xd4, 0x8d, 0x7b, 0x23, 0x68, 0x91, 0x00, 0xb0, 0xb4, 0x96, 0xee, 0x62, 0xf0, 0xe6, 0xd3, 0x56, 0xbc, 0xf4, 0xaa, 0x0f, 0x50, 0x64, 0x34, 0x02, 0xf5, 0xd1, 0x76, 0x6a, 0xa9, 0x72, 0x83, 0x5a, 0x75, 0x64, 0x72, 0x3f, 0x39, 0xbb, 0xef, 0x52, 0x90, 0xde, 0xd9, 0xbc, 0xdb, 0xf9, 0xd3, 0xd5, 0x5d, 0xfa, 0xd2, 0x3a, 0xa0, 0x3d, 0xc6, 0x04, 0xc5, 0x4d, 0x29, 0xcf, 0x1d, 0x4b, 0x3b, 0xdb, 0xd1, 0xa8, 0x09, 0xcf, 0xae, 0x47, 0xb4, 0x4c, 0x7e, 0xae, 0x17, 0xc5, 0x10, 0x9b, 0xee, 0x24, 0xa9, 0xcf, 0x4a, 0x8d, 0x91, 0x1b, 0xb0, 0xfd, 0x04, 0x15, 0xae, 0x4c, 0x3f, 0x43, 0x0a, 0xa1, 0x2a, 0x55, 0x7e, 0x2a, 0xe1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1e, 0x30, 0x82, 0x01, 0x1a, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x17, 0x03, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x00, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x61, 0x30, 0x3c, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x35, 0x30, 0x33, 0x30, 0x31, 0xa0, 0x2f, 0xa0, 0x2d, 0x86, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x53, 0x56, 0x52, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x56, 0x52, 0x49, 0x6e, 0x74, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x27, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x20, 0x30, 0x1e, 0x82, 0x0e, 0x2a, 0x2e, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x0c, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x5b, 0x6c, 0x2b, 0x75, 0xf8, 0xed, 0x30, 0xaa, 0x51, 0xaa, 0xd3, 0x6a, 0xba, 0x59, 0x5e, 0x55, 0x51, 0x41, 0x95, 0x1f, 0x81, 0xa5, 0x3b, 0x44, 0x79, 0x10, 0xac, 0x1f, 0x76, 0xff, 0x78, 0xfc, 0x27, 0x81, 0x61, 0x6b, 0x58, 0xf3, 0x12, 0x2a, 0xfc, 0x1c, 0x87, 0x01, 0x04, 0x25, 0xe9, 0xed, 0x43, 0xdf, 0x1a, 0x7b, 0xa6, 0x49, 0x80, 0x60, 0x67, 0xe2, 0x68, 0x8a, 0xf0, 0x3d, 0xb5, 0x8c, 0x7d, 0xf4, 0xee, 0x03, 0x30, 0x9a, 0x6a, 0xfc, 0x24, 0x7c, 0xcb, 0x13, 0x4d, 0xc3, 0x3e, 0x54, 0xc6, 0xbc, 0x1d, 0x51, 0x33, 0xa5, 0x32, 0xa7, 0x32, 0x73, 0xb1, 0xd7, 0x9c, 0xad, 0xc0, 0x8e, 0x7e, 0x1a, 0x83, 0x11, 0x6d, 0x34, 0x52, 0x33, 0x40, 0xb0, 0x30, 0x54, 0x27, 0xa2, 0x17, 0x42, 0x82, 0x7c, 0x98, 0x91, 0x66, 0x98, 0xee, 0x7e, 0xaf, 0x8c, 0x3b, 0xdd, 0x71, 0x70, 0x08, 0x17, 0x00, 0x03, 0x87, 0x30, 0x82, 0x03, 0x83, 0x30, 0x82, 0x02, 0xec, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x46, 0xfc, 0xeb, 0xba, 0xb4, 0xd0, 0x2f, 0x0f, 0x92, 0x60, 0x98, 0x23, 0x3f, 0x93, 0x07, 0x8f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x64, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x39, 0x37, 0x30, 0x34, 0x31, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x32, 0x34, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xba, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x31, 0x49, 0x30, 0x47, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x40, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x49, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x62, 0x79, 0x20, 0x52, 0x65, 0x66, 0x2e, 0x20, 0x4c, 0x49, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x20, 0x4c, 0x54, 0x44, 0x2e, 0x28, 0x63, 0x29, 0x39, 0x37, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xd8, 0x82, 0x80, 0xe8, 0xd6, 0x19, 0x02, 0x7d, 0x1f, 0x85, 0x18, 0x39, 0x25, 0xa2, 0x65, 0x2b, 0xe1, 0xbf, 0xd4, 0x05, 0xd3, 0xbc, 0xe6, 0x36, 0x3b, 0xaa, 0xf0, 0x4c, 0x6c, 0x5b, 0xb6, 0xe7, 0xaa, 0x3c, 0x73, 0x45, 0x55, 0xb2, 0xf1, 0xbd, 0xea, 0x97, 0x42, 0xed, 0x9a, 0x34, 0x0a, 0x15, 0xd4, 0xa9, 0x5c, 0xf5, 0x40, 0x25, 0xdd, 0xd9, 0x07, 0xc1, 0x32, 0xb2, 0x75, 0x6c, 0xc4, 0xca, 0xbb, 0xa3, 0xfe, 0x56, 0x27, 0x71, 0x43, 0xaa, 0x63, 0xf5, 0x30, 0x3e, 0x93, 0x28, 0xe5, 0xfa, 0xf1, 0x09, 0x3b, 0xf3, 0xb7, 0x4d, 0x4e, 0x39, 0xf7, 0x5c, 0x49, 0x5a, 0xb8, 0xc1, 0x1d, 0xd3, 0xb2, 0x8a, 0xfe, 0x70, 0x30, 0x95, 0x42, 0xcb, 0xfe, 0x2b, 0x51, 0x8b, 0x5a, 0x3c, 0x3a, 0xf9, 0x22, 0x4f, 0x90, 0xb2, 0x02, 0xa7, 0x53, 0x9c, 0x4f, 0x34, 0xe7, 0xab, 0x04, 0xb2, 0x7b, 0x6f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xe3, 0x30, 0x81, 0xe0, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x01, 0x01, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x2d, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x08, 0x01, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2a, 0x30, 0x28, 0x30, 0x26, 0xa0, 0x24, 0xa0, 0x22, 0x86, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, 0x61, 0x33, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40, 0x8e, 0x49, 0x97, 0x96, 0x8a, 0x73, 0xdd, 0x8e, 0x4d, 0xef, 0x3e, 0x61, 0xb7, 0xca, 0xa0, 0x62, 0xad, 0xf4, 0x0e, 0x0a, 0xbb, 0x75, 0x3d, 0xe2, 0x6e, 0xd8, 0x2c, 0xc7, 0xbf, 0xf4, 0xb9, 0x8c, 0x36, 0x9b, 0xca, 0xa2, 0xd0, 0x9c, 0x72, 0x46, 0x39, 0xf6, 0xa6, 0x82, 0x03, 0x65, 0x11, 0xc4, 0xbc, 0xbf, 0x2d, 0xa6, 0xf5, 0xd9, 0x3b, 0x0a, 0xb5, 0x98, 0xfa, 0xb3, 0x78, 0xb9, 0x1e, 0xf2, 0x2b, 0x4c, 0x62, 0xd5, 0xfd, 0xb2, 0x7a, 0x1d, 0xdf, 0x33, 0xfd, 0x73, 0xf9, 0xa5, 0xd8, 0x2d, 0x8c, 0x2a, 0xea, 0xd1, 0xfc, 0xb0, 0x28, 0xb6, 0xe9, 0x49, 0x48, 0x13, 0x4b, 0x83, 0x8a, 0x1b, 0x48, 0x7b, 0x24, 0xf7, 0x38, 0xde, 0x6f, 0x41, 0x54, 0xb8, 0xab, 0x57, 0x6b, 0x06, 0xdf, 0xc7, 0xa2, 0xd4, 0xa9, 0xf6, 0xf1, 0x36, 0x62, 0x80, 0x88, 0xf2, 0x8b, 0x75, 0xd6, 0x80, 0x75, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00 }; uint32_t server_hello_certificate_done_len = sizeof(server_hello_certificate_done); uint8_t client_key_exchange_cipher_enc_hs[] = { 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, 0x80, 0x00, 0x80, 0x14, 0x2b, 0x2f, 0x9f, 0x02, 0x1d, 0x4e, 0x0d, 0xa7, 0x41, 0x0f, 0x99, 0xc5, 0xe9, 0x49, 0x22, 0x14, 0xa0, 0x42, 0x7b, 0xb4, 0x6d, 0x4f, 0x82, 0x3c, 0x3a, 0x6e, 0xed, 0xd5, 0x6e, 0x72, 0x71, 0xae, 0x00, 0x4a, 0x9a, 0xc9, 0x0e, 0x2d, 0x08, 0xa2, 0xd3, 0x3a, 0xb0, 0xb2, 0x1a, 0x56, 0x01, 0x7c, 0x9a, 0xfa, 0xfb, 0x1a, 0xd7, 0x7e, 0x20, 0x68, 0x51, 0xd0, 0xfe, 0xd9, 0xdc, 0xa7, 0x0b, 0xeb, 0x1a, 0xb6, 0xd3, 0xc7, 0x17, 0x1f, 0xf3, 0x6e, 0x91, 0xdd, 0x06, 0x0d, 0x48, 0xde, 0xcd, 0x0c, 0x36, 0x8c, 0x83, 0x29, 0x9a, 0x40, 0x03, 0xcd, 0xf3, 0x1b, 0xdb, 0xd8, 0x44, 0x6b, 0x75, 0xf3, 0x5a, 0x9f, 0x26, 0x1a, 0xc4, 0x16, 0x35, 0x8f, 0xc1, 0x15, 0x19, 0xa9, 0xdf, 0x07, 0xa9, 0xe5, 0x56, 0x45, 0x6d, 0xca, 0x20, 0x3c, 0xcf, 0x8e, 0xbe, 0x44, 0x68, 0x73, 0xc8, 0x0b, 0xc7, 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xf9, 0x7e, 0x28, 0x77, 0xa9, 0x9a, 0x08, 0x0c, 0x2e, 0xa9, 0x09, 0x15, 0x27, 0xcd, 0x93, 0x5f, 0xc0, 0x32, 0x0a, 0x8d, 0x62, 0xd3, 0x54, 0x79, 0x6b, 0x51, 0xd7, 0xba, 0x02, 0xd6, 0xdb, 0x66, 0xe8, 0x97, 0x5d, 0x7a }; uint32_t client_key_exchange_cipher_enc_hs_len = sizeof(client_key_exchange_cipher_enc_hs); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); SCMutexLock(&f.m); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, client_hello_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); SCMutexUnlock(&f.m); goto end; } SCMutexUnlock(&f.m); SSLState *ssl_state = f.alstate; if (ssl_state == NULL) { printf("no tls state: "); goto end; } if (ssl_state->client_connp.bytes_processed != 0 || ssl_state->client_connp.hs_bytes_processed != 0) { printf("client_hello error\n"); goto end; } SCMutexLock(&f.m); r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello_certificate_done, server_hello_certificate_done_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); SCMutexUnlock(&f.m); goto end; } SCMutexUnlock(&f.m); if (ssl_state->client_connp.bytes_processed != 0 || ssl_state->client_connp.hs_bytes_processed != 0) { printf("server_hello_certificate_done error\n"); goto end; } SCMutexLock(&f.m); r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, client_key_exchange_cipher_enc_hs, client_key_exchange_cipher_enc_hs_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); SCMutexUnlock(&f.m); goto end; } SCMutexUnlock(&f.m); /* The reason hs_bytes_processed is 2 is because, the record * immediately after the client key exchange is 2 bytes long, * and next time we see a new handshake, it is after we have * seen a change cipher spec. Hence when we process the * handshake, we immediately break and don't parse the pdu from * where we left off, and leave the hs_bytes_processed var * isn't reset. */ if (ssl_state->client_connp.bytes_processed != 0 || ssl_state->client_connp.hs_bytes_processed != 2) { printf("client_key_exchange_cipher_enc_hs error\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } #endif /* UNITTESTS */ void SSLParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SSLParserTest01", SSLParserTest01, 1); UtRegisterTest("SSLParserTest02", SSLParserTest02, 1); UtRegisterTest("SSLParserTest03", SSLParserTest03, 1); UtRegisterTest("SSLParserTest04", SSLParserTest04, 1); /* Updated by Anoop Saldanha. Faulty tests. Disable it for now */ //UtRegisterTest("SSLParserTest05", SSLParserTest05, 1); //UtRegisterTest("SSLParserTest06", SSLParserTest06, 1); UtRegisterTest("SSLParserTest07", SSLParserTest07, 1); //UtRegisterTest("SSLParserTest08", SSLParserTest08, 1); UtRegisterTest("SSLParserTest09", SSLParserTest09, 1); UtRegisterTest("SSLParserTest10", SSLParserTest10, 1); UtRegisterTest("SSLParserTest11", SSLParserTest11, 1); UtRegisterTest("SSLParserTest12", SSLParserTest12, 1); UtRegisterTest("SSLParserTest13", SSLParserTest13, 1); UtRegisterTest("SSLParserTest14", SSLParserTest14, 1); UtRegisterTest("SSLParserTest15", SSLParserTest15, 1); UtRegisterTest("SSLParserTest16", SSLParserTest16, 1); UtRegisterTest("SSLParserTest17", SSLParserTest17, 1); UtRegisterTest("SSLParserTest18", SSLParserTest18, 1); UtRegisterTest("SSLParserTest19", SSLParserTest19, 1); UtRegisterTest("SSLParserTest20", SSLParserTest20, 1); UtRegisterTest("SSLParserTest21", SSLParserTest21, 1); UtRegisterTest("SSLParserTest22", SSLParserTest22, 1); UtRegisterTest("SSLParserTest23", SSLParserTest23, 1); UtRegisterTest("SSLParserTest24", SSLParserTest24, 1); UtRegisterTest("SSLParserTest25", SSLParserTest25, 1); UtRegisterTest("SSLParserMultimsgTest01", SSLParserMultimsgTest01, 1); UtRegisterTest("SSLParserMultimsgTest02", SSLParserMultimsgTest02, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/util-rule-vars.c0000644000000000000000000003517112253546156014073 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Rule variable utility functions */ #include "suricata-common.h" #include "conf.h" #include "conf-yaml-loader.h" #include "detect.h" #include "detect-content.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "util-rule-vars.h" #include "util-enum.h" #include "util-debug.h" #include "util-unittest.h" /** An enum-string map, that maps the different vars type in the yaml conf * type with the mapping path in the yaml conf file */ SCEnumCharMap sc_rule_vars_type_map[ ] = { { "vars.address-groups", SC_RULE_VARS_ADDRESS_GROUPS }, { "vars.port-groups", SC_RULE_VARS_PORT_GROUPS } }; /** * \internal * \brief Retrieves a value for a yaml mapping. The sequence from the yaml * conf file, from which the conf value has to be retrieved can be * specified by supplying a SCRuleVarsType enum. The string mapping * for each of the SCRuleVarsType is present in sc_rule_vars_type_map. * * \param conf_var_name Pointer to a character string containing the conf var * name, whose value has to be retrieved from the yaml * conf file. * \param conf_vars_type Holds an enum value that indicates the kind of yaml * mapping that has to be retrieved. Can be one of the * values in SCRuleVarsType. * * \retval conf_var_name_value Pointer to the string containing the conf value * on success; NULL on failure. */ char *SCRuleVarsGetConfVar(const char *conf_var_name, SCRuleVarsType conf_vars_type) { SCEnter(); const char *conf_var_type_name = NULL; char *conf_var_full_name = NULL; char *conf_var_full_name_value = NULL; if (conf_var_name == NULL) goto end; (conf_var_name[0] == '$') ? conf_var_name++ : conf_var_name; conf_var_type_name = SCMapEnumValueToName(conf_vars_type, sc_rule_vars_type_map); if (conf_var_type_name == NULL) goto end; /* the + 2 is for the '.' and the string termination character '\0' */ conf_var_full_name = (char *)SCMalloc(strlen(conf_var_type_name) + strlen(conf_var_name) + 2); if (conf_var_full_name == NULL) goto end; if (snprintf(conf_var_full_name, strlen(conf_var_type_name) + strlen(conf_var_name) + 2, "%s.%s", conf_var_type_name, conf_var_name) < 0) { goto end; } if (ConfGet(conf_var_full_name, &conf_var_full_name_value) != 1) { SCLogError(SC_ERR_UNDEFINED_VAR, "Variable \"%s\" is not defined in " "configuration file", conf_var_name); goto end; } SCLogDebug("Value obtained from the yaml conf file, for the var " "\"%s\" is \"%s\"", conf_var_name, conf_var_full_name_value); end: if (conf_var_full_name != NULL) SCFree(conf_var_full_name); SCReturnCharPtr(conf_var_full_name_value); } /**********************************Unittests***********************************/ static const char *dummy_conf_string = "%YAML 1.1\n" "---\n" "\n" "default-log-dir: /var/log/suricata\n" "\n" "logging:\n" "\n" " default-log-level: debug\n" "\n" " default-format: \"<%t> - <%l>\"\n" "\n" " default-startup-message: Your IDS has started.\n" "\n" " default-output-filter:\n" "\n" " output:\n" "\n" " - interface: console\n" " log-level: info\n" "\n" " - interface: file\n" " filename: /var/log/suricata.log\n" "\n" " - interface: syslog\n" " facility: local5\n" " format: \"%l\"\n" "\n" "pfring:\n" "\n" " interface: eth0\n" "\n" " clusterid: 99\n" "\n" "vars:\n" "\n" " address-groups:\n" "\n" " HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:" "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n" "\n" " EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n" "\n" " HTTP_SERVERS: \"!192.168.0.0/16\"\n" "\n" " SMTP_SERVERS: \"!192.168.0.0/16\"\n" "\n" " SQL_SERVERS: \"!192.168.0.0/16\"\n" "\n" " DNS_SERVERS: any\n" "\n" " TELNET_SERVERS: any\n" "\n" " AIM_SERVERS: any\n" "\n" " port-groups:\n" "\n" " HTTP_PORTS: \"80:81,88\"\n" "\n" " SHELLCODE_PORTS: 80\n" "\n" " ORACLE_PORTS: 1521\n" "\n" " SSH_PORTS: 22\n" "\n"; /** * \test Check that valid address and port group vars are correctly retrieved * from the configuration. */ int SCRuleVarsPositiveTest01(void) { int result = 1; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); /* check for address-groups */ result &= (SCRuleVarsGetConfVar("$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), "[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:13c5:" "5AFE::/64,2001:888:13c5:CAFE::/64]") == 0); result &= (SCRuleVarsGetConfVar("$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS), "[!192.168.0.0/16,2000::/3]") == 0); result &= (SCRuleVarsGetConfVar("$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); result &= (SCRuleVarsGetConfVar("$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); result &= (SCRuleVarsGetConfVar("$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); result &= (SCRuleVarsGetConfVar("$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); result &= (SCRuleVarsGetConfVar("$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); result &= (SCRuleVarsGetConfVar("$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); /* check for port-groups */ result &= (SCRuleVarsGetConfVar("$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), "80:81,88") == 0); result &= (SCRuleVarsGetConfVar("$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS), "80") == 0); result &= (SCRuleVarsGetConfVar("$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS), "1521") == 0); result &= (SCRuleVarsGetConfVar("$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && strcmp(SCRuleVarsGetConfVar("$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), "22") == 0); ConfDeInit(); ConfRestoreContextBackup(); return result; } /** * \test Check that invalid address and port groups are properly handled by the * API. */ int SCRuleVarsNegativeTest02(void) { int result = 1; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); result &= (SCRuleVarsGetConfVar("$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); result &= (SCRuleVarsGetConfVar("$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); result &= (SCRuleVarsGetConfVar("$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL); result &= (SCRuleVarsGetConfVar("$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL); ConfDeInit(); ConfRestoreContextBackup(); return result; } /** * \test Check that Signatures with valid address and port groups are parsed * without any errors by the Signature parsing API. */ int SCRuleVarsPositiveTest03(void) { int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = NULL; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; /* s = SigInit(de_ctx, "alert tcp $HTTP_SERVERS any -> any any (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp $SMTP_SERVERS any -> $HTTP_SERVERS any (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp $AIM_SERVERS any -> $AIM_SERVERS any (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp $TELNET_SERVERS any -> any $SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp $TELNET_SERVERS any -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp $TELNET_SERVERS 80 -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp $TELNET_SERVERS !80 -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp !$HTTP_SERVERS !80 -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp 192.168.1.2 any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp !192.168.1.2 any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp !192.168.1.2 any -> any !$HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp !192.168.1.2 any -> !$HTTP_SERVERS !$HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp !192.168.1.2 $HTTP_PORTS -> !$HTTP_SERVERS !$HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp [!192.168.24.0/23,!167.12.0.0/24] any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp ![192.168.24.0/23,!167.12.0.0/24] any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp [$HOME_NET,!192.168.1.2] $HTTP_PORTS -> !$HTTP_SERVERS !$HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp [[192.168.1.3,$EXTERNAL_NET],192.168.2.5] $HTTP_PORTS -> !$HTTP_SERVERS !$HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp [[192.168.1.3,$EXTERNAL_NET],192.168.2.5] $HTTP_PORTS -> !$HTTP_SERVERS [80,[!$HTTP_PORTS,$ORACLE_PORTS]] (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); */ s = SigInit(de_ctx, "alert tcp [![192.168.1.3,$EXTERNAL_NET],[$HTTP_SERVERS,!$HOME_NET],192.168.2.5] $HTTP_PORTS -> !$HTTP_SERVERS [80,[!$HTTP_PORTS,$ORACLE_PORTS]] (msg:\"Rule Vars Test\"; sid:1;)"); if (s == NULL) goto end; SigFree(s); result = 1; end: ConfDeInit(); ConfRestoreContextBackup(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Check that Signatures with invalid address and port groups, are * are invalidated by the Singature parsing API. */ int SCRuleVarsNegativeTest04(void) { int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = NULL; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx, "alert tcp $HTTP_SERVER any -> any any (msg:\"Rule Vars Test\"; sid:1;)"); if (s != NULL) goto end; s = SigInit(de_ctx, "alert tcp $http_servers any -> any any (msg:\"Rule Vars Test\"; sid:1;)"); if (s != NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp $http_servers any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s != NULL) goto end; SigFree(s); s = SigInit(de_ctx, "alert tcp !$TELNET_SERVERS !80 -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); if (s != NULL) goto end; SigFree(s); result = 1; end: ConfDeInit(); ConfRestoreContextBackup(); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } void SCRuleVarsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01, 1); UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02, 1); UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03, 1); UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04, 1); #endif return; } suricata-1.4.7/src/detect-http-hh.h0000644000000000000000000000162412253546156014023 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_HTTP_HH_H__ #define __DETECT_HTTP_HH_H__ void DetectHttpHHRegister(void); #endif /* __DETECT_HTTP_HH_H__ */ suricata-1.4.7/src/flow-var.c0000644000000000000000000001030312253546156012723 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon * * Flow level variable support for complex detection rules * Supported types atm are String and Integers */ #include "suricata-common.h" #include "threads.h" #include "flow-var.h" #include "flow.h" #include "detect.h" #include "util-debug.h" /* puts a new value into a flowvar */ void FlowVarUpdateStr(FlowVar *fv, uint8_t *value, uint16_t size) { if (fv->data.fv_str.value) SCFree(fv->data.fv_str.value); fv->data.fv_str.value = value; fv->data.fv_str.value_len = size; } /* puts a new value into a flowvar */ void FlowVarUpdateInt(FlowVar *fv, uint32_t value) { fv->data.fv_int.value = value; } /* get the flowvar with name 'name' from the flow * * name is a normal string*/ FlowVar *FlowVarGet(Flow *f, uint16_t idx) { GenericVar *gv = f->flowvar; for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWVAR && gv->idx == idx) return (FlowVar *)gv; } return NULL; } /* add a flowvar to the flow, or update it */ void FlowVarAddStr(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) { FLOWLOCK_WRLOCK(f); FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { fv = SCMalloc(sizeof(FlowVar)); if (unlikely(fv == NULL)) goto out; fv->type = DETECT_FLOWVAR; fv->datatype = FLOWVAR_TYPE_STR; fv->idx = idx; fv->data.fv_str.value = value; fv->data.fv_str.value_len = size; fv->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fv); } else { FlowVarUpdateStr(fv, value, size); } out: FLOWLOCK_UNLOCK(f); } /* add a flowvar to the flow, or update it */ void FlowVarAddInt(Flow *f, uint16_t idx, uint32_t value) { FLOWLOCK_WRLOCK(f); FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { fv = SCMalloc(sizeof(FlowVar)); if (unlikely(fv == NULL)) goto out; fv->type = DETECT_FLOWVAR; fv->datatype = FLOWVAR_TYPE_INT; fv->idx = idx; fv->data.fv_int.value= value; fv->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fv); } else { FlowVarUpdateInt(fv, value); } out: FLOWLOCK_UNLOCK(f); } void FlowVarFree(FlowVar *fv) { if (fv == NULL) return; if (fv->datatype == FLOWVAR_TYPE_STR) { if (fv->data.fv_str.value != NULL) SCFree(fv->data.fv_str.value); } SCFree(fv); } void FlowVarPrint(GenericVar *gv) { uint16_t u; if (!SCLogDebugEnabled()) return; if (gv == NULL) return; if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { FlowVar *fv = (FlowVar *)gv; if (fv->datatype == FLOWVAR_TYPE_STR) { SCLogDebug("Name idx \"%" PRIu16 "\", Value \"", fv->idx); for (u = 0; u < fv->data.fv_str.value_len; u++) { if (isprint(fv->data.fv_str.value[u])) SCLogDebug("%c", fv->data.fv_str.value[u]); else SCLogDebug("\\%02X", fv->data.fv_str.value[u]); } SCLogDebug("\", Len \"%" PRIu16 "\"\n", fv->data.fv_str.value_len); } else if (fv->datatype == FLOWVAR_TYPE_INT) { SCLogDebug("Name idx \"%" PRIu16 "\", Value \"%" PRIu16 "\"", fv->idx, fv->data.fv_int.value); } else { SCLogDebug("Unknown data type at flowvars\n"); } } FlowVarPrint(gv->next); } suricata-1.4.7/src/detect-dsize.c0000644000000000000000000005024112253546156013557 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the dsize keyword */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "flow-var.h" #include "detect-dsize.h" #include "util-unittest.h" #include "util-debug.h" #include "util-byte.h" /** * dsize:[<>]<0-65535>[<><0-65535>]; */ #define PARSE_REGEX "^\\s*(<|>)?\\s*([0-9]{1,5})\\s*(?:(<>)\\s*([0-9]{1,5}))?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectDsizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, char *str); void DsizeRegisterTests(void); static void DetectDsizeFree(void *); /** * \brief Registration function for dsize: keyword */ void DetectDsizeRegister (void) { sigmatch_table[DETECT_DSIZE].name = "dsize"; sigmatch_table[DETECT_DSIZE].desc = "match on the size of the packet payload"; sigmatch_table[DETECT_DSIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Dsize"; sigmatch_table[DETECT_DSIZE].Match = DetectDsizeMatch; sigmatch_table[DETECT_DSIZE].Setup = DetectDsizeSetup; sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree; 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) { SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /** * \internal * \brief This function is used to match flags on a packet with those passed via dsize: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param s pointer to the Signature * \param m pointer to the sigmatch * * \retval 0 no match * \retval 1 match */ int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; if (PKT_IS_PSEUDOPKT(p)) { SCReturnInt(0); } DetectDsizeData *dd = (DetectDsizeData *)m->ctx; SCLogDebug("p->payload_len %"PRIu16"", p->payload_len); if (dd->mode == DETECTDSIZE_EQ && dd->dsize == p->payload_len) ret = 1; else if (dd->mode == DETECTDSIZE_LT && p->payload_len < dd->dsize) ret = 1; else if (dd->mode == DETECTDSIZE_GT && p->payload_len > dd->dsize) ret = 1; else if (dd->mode == DETECTDSIZE_RA && p->payload_len > dd->dsize && p->payload_len < dd->dsize2) ret = 1; SCReturnInt(ret); } /** * \internal * \brief This function is used to parse dsize options passed via dsize: keyword * * \param rawstr Pointer to the user provided dsize options * * \retval dd pointer to DetectDsizeData on success * \retval NULL on failure */ 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) { SCLogError(SC_ERR_PCRE_MATCH,"Parse error %s", rawstr); goto error; } const char *str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed"); goto error; } mode = (char *)str_ptr; SCLogDebug("mode \"%s\"", mode); res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed"); goto error; } value1 = (char *)str_ptr; SCLogDebug("value1 \"%s\"", value1); if (ret > 3) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed"); goto error; } range = (char *)str_ptr; SCLogDebug("range \"%s\"", range); if (ret > 4) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed"); goto error; } value2 = (char *)str_ptr; SCLogDebug("value2 \"%s\"", value2); } } dd = SCMalloc(sizeof(DetectDsizeData)); if (unlikely(dd == NULL)) goto error; dd->dsize = 0; dd->dsize2 = 0; dd->mode = DETECTDSIZE_EQ; // default if (mode != NULL) { if (mode[0] == '<') dd->mode = DETECTDSIZE_LT; else if (mode[0] == '>') dd->mode = DETECTDSIZE_GT; else dd->mode = DETECTDSIZE_EQ; } if (range != NULL && strcmp("<>", range) == 0) { if (mode != NULL && strlen(mode) != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Range specified but mode also set"); goto error; } dd->mode = DETECTDSIZE_RA; } /** set the first dsize value */ if (ByteExtractStringUint16(&dd->dsize,10,strlen(value1),value1) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size value1:\"%s\"", value1); goto error; } /** set the second dsize value if specified */ if (value2 != NULL && strlen(value2) > 0) { if (dd->mode != DETECTDSIZE_RA) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Multiple dsize values specified but mode is not range"); goto error; } if (ByteExtractStringUint16(&dd->dsize2,10,strlen(value2),value2) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size value2:\"%s\"",value2); goto error; } if (dd->dsize2 <= dd->dsize) { SCLogError(SC_ERR_INVALID_ARGUMENT,"dsize2:%"PRIu16" <= dsize:%"PRIu16"",dd->dsize2,dd->dsize); goto error; } } SCLogDebug("dsize parsed successfully dsize: %"PRIu16" dsize2: %"PRIu16"",dd->dsize,dd->dsize2); SCFree(value1); SCFree(mode); if (value2) SCFree(value2); if (range) SCFree(range); return dd; error: if (dd) SCFree(dd); if (value1) SCFree(value1); if (value2) SCFree(value2); if (mode) SCFree(mode); if (range) SCFree(range); return NULL; } /** * \internal * \brief this function is used to add the parsed dsize into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param rawstr pointer to the user provided flags options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectDsizeData *dd = NULL; SigMatch *sm = NULL; if (SigMatchGetLastSMFromLists(s, 2, DETECT_DSIZE, s->sm_lists_tail[DETECT_SM_LIST_MATCH]) != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use 2 or more dsizes in " "the same sig. Invalidating signature."); goto error; } SCLogDebug("\'%s\'", rawstr); dd = DetectDsizeParse(rawstr); if (dd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Parsing \'%s\' failed", rawstr); goto error; } /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ sm = SigMatchAlloc(); if (sm == NULL){ SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for SigMatch"); SCFree(dd); goto error; } sm->type = DETECT_DSIZE; sm->ctx = (void *)dd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); SCLogDebug("dd->dsize %"PRIu16", dd->dsize2 %"PRIu16", dd->mode %"PRIu8"", dd->dsize, dd->dsize2, dd->mode); /* tell the sig it has a dsize to speed up engine init */ s->flags |= SIG_FLAG_REQUIRE_PACKET; s->flags |= SIG_FLAG_DSIZE; if (s->dsize_sm == NULL) { s->dsize_sm = sm; } return 0; error: return -1; } /** * \internal * \brief this function will free memory associated with DetectDsizeData * * \param de pointer to DetectDsizeData */ void DetectDsizeFree(void *de_ptr) { DetectDsizeData *dd = (DetectDsizeData *)de_ptr; if(dd) SCFree(dd); } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS #include "detect.h" #include "detect-engine.h" /** * \test this is a test for a valid dsize value 1 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse01 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse("1"); if (dd) { DetectDsizeFree(dd); return 1; } return 0; } /** * \test this is a test for a valid dsize value >10 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse02 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse(">10"); if (dd) { DetectDsizeFree(dd); return 1; } return 0; } /** * \test this is a test for a valid dsize value <100 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse03 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse("<100"); if (dd) { DetectDsizeFree(dd); return 1; } return 0; } /** * \test this is a test for a valid dsize value 1<>2 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse04 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse("1<>2"); if (dd) { DetectDsizeFree(dd); return 1; } return 0; } /** * \test this is a test for a valid dsize value 1 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse05 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse("1"); if (dd) { if (dd->dsize == 1) result = 1; DetectDsizeFree(dd); } return result; } /** * \test this is a test for a valid dsize value >10 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse06 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse(">10"); if (dd) { if (dd->dsize == 10 && dd->mode == DETECTDSIZE_GT) result = 1; DetectDsizeFree(dd); } return result; } /** * \test this is a test for a valid dsize value <100 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse07 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse("<100"); if (dd) { if (dd->dsize == 100 && dd->mode == DETECTDSIZE_LT) result = 1; DetectDsizeFree(dd); } return result; } /** * \test this is a test for a valid dsize value 1<>2 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse08 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse("1<>2"); if (dd) { if (dd->dsize == 1 && dd->dsize2 == 2 && dd->mode == DETECTDSIZE_RA) result = 1; DetectDsizeFree(dd); } return result; } /** * \test this is a test for a invalid dsize value A * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse09 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse("A"); if (dd) { DetectDsizeFree(dd); return 0; } return 1; } /** * \test this is a test for a invalid dsize value >10<>10 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse10 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse(">10<>10"); if (dd) { DetectDsizeFree(dd); return 0; } return 1; } /** * \test this is a test for a invalid dsize value <>10 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse11 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse("<>10"); if (dd) { DetectDsizeFree(dd); return 0; } return 1; } /** * \test this is a test for a invalid dsize value 1<> * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse12 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse("1<>"); if (dd) { DetectDsizeFree(dd); return 0; } return 1; } /** * \test this is a test for a valid dsize value 1 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse13 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse("1"); if (dd) { if (dd->dsize2 == 0) result = 1; DetectDsizeFree(dd); } return result; } /** * \test this is a test for a invalid dsize value "" * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse14 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse(""); if (dd) { DetectDsizeFree(dd); return 0; } return 1; } /** * \test this is a test for a invalid dsize value " " * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse15 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse(" "); if (dd) { DetectDsizeFree(dd); return 0; } return 1; } /** * \test this is a test for a invalid dsize value 2<>1 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse16 (void) { DetectDsizeData *dd = NULL; dd = DetectDsizeParse("2<>1"); if (dd) { DetectDsizeFree(dd); return 0; } return 1; } /** * \test this is a test for a valid dsize value 1 <> 2 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse17 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse(" 1 <> 2 "); if (dd) { if (dd->dsize == 1 && dd->dsize2 == 2 && dd->mode == DETECTDSIZE_RA) result = 1; DetectDsizeFree(dd); } return result; } /** * \test this is test for a valid dsize value > 2 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse18 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse("> 2 "); if (dd) { if (dd->dsize == 2 && dd->mode == DETECTDSIZE_GT) result = 1; DetectDsizeFree(dd); } return result; } /** * \test test for a valid dsize value < 12 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse19 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse("< 12 "); if (dd) { if (dd->dsize == 12 && dd->mode == DETECTDSIZE_LT) result = 1; DetectDsizeFree(dd); } return result; } /** * \test test for a valid dsize value 12 * * \retval 1 on succces * \retval 0 on failure */ int DsizeTestParse20 (void) { int result = 0; DetectDsizeData *dd = NULL; dd = DetectDsizeParse(" 12 "); if (dd) { if (dd->dsize == 12 && dd->mode == DETECTDSIZE_EQ) result = 1; DetectDsizeFree(dd); } return result; } /** * \test DetectDsizeIcmpv6Test01 is a test for checking the working of * dsize keyword by creating 2 rules and matching a crafted packet * against them. Only the first one shall trigger. */ int DetectDsizeIcmpv6Test01 (void) { int result = 0; static uint8_t raw_icmpv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x7b, 0x85, 0x00, 0x00, 0x00, 0x00, 0x60, 0x4b, 0xe8, 0xbd, 0x00, 0x00, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&ip6h, 0, sizeof(IPV6Hdr)); memset(&th_v, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET6; p->dst.family = AF_INET6; p->ip6h = &ip6h; DecodeIPV6(&tv, &dtv, p, raw_icmpv6, sizeof(raw_icmpv6), NULL); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"ICMP Large ICMP Packet\"; dsize:>8; sid:1; rev:4;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"ICMP Large ICMP Packet\"; dsize:>800; sid:2; rev:4;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { printf("sid 1 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 2)) { printf("sid 2 alerted, but should not have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); end: SCFree(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for dsize */ void DsizeRegisterTests(void) { #ifdef UNITTESTS 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); UtRegisterTest("DsizeTestParse17", DsizeTestParse17, 1); UtRegisterTest("DsizeTestParse18", DsizeTestParse18, 1); UtRegisterTest("DsizeTestParse19", DsizeTestParse19, 1); UtRegisterTest("DsizeTestParse20", DsizeTestParse20, 1); UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-csum.c0000644000000000000000000015315112253546156013414 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implements checksum keyword. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-csum.h" #include "util-unittest.h" #include "util-debug.h" /* prototypes for the "ipv4-csum" rule keyword */ int DetectIPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectIPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectIPV4CsumFree(void *); /* prototypes for the "tcpv4-csum" rule keyword */ int DetectTCPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectTCPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectTCPV4CsumFree(void *); /* prototypes for the "tcpv6-csum" rule keyword */ int DetectTCPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectTCPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectTCPV6CsumFree(void *); /* prototypes for the "udpv4-csum" rule keyword */ int DetectUDPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectUDPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectUDPV4CsumFree(void *); /* prototypes for the "udpv6-csum" rule keyword */ int DetectUDPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectUDPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectUDPV6CsumFree(void *); /* prototypes for the "icmpv4-csum" rule keyword */ int DetectICMPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectICMPV4CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectICMPV4CsumFree(void *); /* prototypes for the "icmpv6-csum" rule keyword */ int DetectICMPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectICMPV6CsumSetup(DetectEngineCtx *, Signature *, char *); void DetectICMPV6CsumFree(void *); void DetectCsumRegisterTests(void); /** * \brief Registers handlers for all the checksum keywords. The checksum * keywords that are registered are ipv4-sum, tcpv4-csum, tcpv6-csum, * udpv4-csum, udpv6-csum, icmpv4-csum and icmpv6-csum. * * Each of the checksum keywords implemented here takes 2 arguments - * "valid" or "invalid". If the rule keyword in the signature is * specified as "valid", the Match function would return TRUE if the * checksum for that particular packet and protocol is valid. Similarly * for "invalid". * * The Setup functions takes 4 arguments - * * DetectEngineCtx * (de_ctx) - A pointer to the detection engine context * Signature *(s) - Pointer to signature for the current Signature being * parsed from the rules * SigMatch * (m) - Pointer to the head of the SigMatchs added to the * current Signature being parsed * char * (csum_str) - Pointer to a string holding the keyword value * * The Setup function returns 0 if it successfully parses the keyword * value, and -1 otherwise. * * The Match function takes 5 arguments - * * ThreadVars * (t) - Pointer to the tv for the detection module instance * DetectEngineThreadCtx * (det_ctx) - Pointer to the detection engine * thread context * Packet * (p) - Pointer to the Packet currently being handled * Signature * (s) - Pointer to the Signature, the packet is being * currently matched with * SigMatch * (m) - Pointer to the keyword structure from the above * Signature, the Packet is being currently matched * with * * The Match function returns 1 if the Packet contents match the keyword, * and 0 otherwise * * The Free function takes a single argument - * * void * (ptr) - Pointer to the DetectCsumData for a keyword */ void DetectCsumRegister (void) { sigmatch_table[DETECT_IPV4_CSUM].name = "ipv4-csum"; sigmatch_table[DETECT_IPV4_CSUM].Match = DetectIPV4CsumMatch; sigmatch_table[DETECT_IPV4_CSUM].Setup = DetectIPV4CsumSetup; sigmatch_table[DETECT_IPV4_CSUM].Free = DetectIPV4CsumFree; sigmatch_table[DETECT_IPV4_CSUM].RegisterTests = DetectCsumRegisterTests; sigmatch_table[DETECT_TCPV4_CSUM].name = "tcpv4-csum"; sigmatch_table[DETECT_TCPV4_CSUM].Match = DetectTCPV4CsumMatch; sigmatch_table[DETECT_TCPV4_CSUM].Setup = DetectTCPV4CsumSetup; sigmatch_table[DETECT_TCPV4_CSUM].Free = DetectTCPV4CsumFree; sigmatch_table[DETECT_TCPV4_CSUM].RegisterTests = NULL; sigmatch_table[DETECT_TCPV6_CSUM].name = "tcpv6-csum"; sigmatch_table[DETECT_TCPV6_CSUM].Match = DetectTCPV6CsumMatch; sigmatch_table[DETECT_TCPV6_CSUM].Setup = DetectTCPV6CsumSetup; sigmatch_table[DETECT_TCPV6_CSUM].Free = DetectTCPV6CsumFree; sigmatch_table[DETECT_TCPV6_CSUM].RegisterTests = NULL; sigmatch_table[DETECT_UDPV4_CSUM].name = "udpv4-csum"; sigmatch_table[DETECT_UDPV4_CSUM].Match = DetectUDPV4CsumMatch; sigmatch_table[DETECT_UDPV4_CSUM].Setup = DetectUDPV4CsumSetup; sigmatch_table[DETECT_UDPV4_CSUM].Free = DetectUDPV4CsumFree; sigmatch_table[DETECT_UDPV4_CSUM].RegisterTests = NULL; sigmatch_table[DETECT_UDPV6_CSUM].name = "udpv6-csum"; sigmatch_table[DETECT_UDPV6_CSUM].Match = DetectUDPV6CsumMatch; sigmatch_table[DETECT_UDPV6_CSUM].Setup = DetectUDPV6CsumSetup; sigmatch_table[DETECT_UDPV6_CSUM].Free = DetectUDPV6CsumFree; sigmatch_table[DETECT_UDPV6_CSUM].RegisterTests = NULL; sigmatch_table[DETECT_ICMPV4_CSUM].name = "icmpv4-csum"; sigmatch_table[DETECT_ICMPV4_CSUM].Match = DetectICMPV4CsumMatch; sigmatch_table[DETECT_ICMPV4_CSUM].Setup = DetectICMPV4CsumSetup; sigmatch_table[DETECT_ICMPV4_CSUM].Free = DetectICMPV4CsumFree; sigmatch_table[DETECT_ICMPV4_CSUM].RegisterTests = NULL; sigmatch_table[DETECT_ICMPV6_CSUM].name = "icmpv6-csum"; sigmatch_table[DETECT_ICMPV6_CSUM].Match = DetectICMPV6CsumMatch; sigmatch_table[DETECT_ICMPV6_CSUM].Setup = DetectICMPV6CsumSetup; sigmatch_table[DETECT_ICMPV6_CSUM].Free = DetectICMPV6CsumFree; sigmatch_table[DETECT_ICMPV6_CSUM].RegisterTests = NULL; return; } /** * \brief Validates and parses the argument supplied with the checksum keyword. * Accepts strings both with and without quotes, i.e. valid, \"valid\", * invalid and \"invalid\" * * \param key Pointer to a const character string holding the csum keyword value * \param cd Pointer to the DetectCsumData structure that holds the keyword * value sent as argument * * \retval 1 the keyvalue has been parsed successfully * \retval 0 error */ static int DetectCsumParseArg(const char *key, DetectCsumData *cd) { char *str; if (key[0] == '\"' && key[strlen(key) - 1] == '\"') { str = SCStrdup(key + 1); if (unlikely(str == NULL)) { goto error; } str[strlen(key) - 2] = '\0'; } else { str = SCStrdup(key); if (unlikely(str == NULL)) { goto error; } } if (strcasecmp(str, DETECT_CSUM_VALID) == 0 || strcasecmp(str, DETECT_CSUM_INVALID) == 0) { cd->valid = (strcasecmp(key, DETECT_CSUM_VALID) == 0); SCFree(str); return 1; } error: if (str != NULL) SCFree(str); return 0; } /** * \brief Checks if the packet sent as the argument, has a valid or invalid * ipv4 checksum, based on whether ipv4-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectIPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectCsumData *cd = (DetectCsumData *)m->ctx; if (p->ip4h == NULL || PKT_IS_PSEUDOPKT(p)) return 0; if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->ip4vars.comp_csum == -1) p->ip4vars.comp_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, IPV4_GET_HLEN(p)); if (p->ip4vars.comp_csum == p->ip4h->ip_csum && cd->valid == 1) return 1; else if (p->ip4vars.comp_csum != p->ip4h->ip_csum && cd->valid == 0) return 1; else return 0; } /** * \brief Creates a SigMatch for the ipv4-csum keyword being sent as argument, * and appends it to the Signature(s). Accepts 2 values for the * keyword - "valid" and "invalid", both with and without quotes * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param csum_str Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ static int DetectIPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum_str) { DetectCsumData *cd = NULL; SigMatch *sm = NULL; //printf("DetectCsumSetup: \'%s\'\n", csum_str); sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_IPV4_CSUM; if ( (cd = SCMalloc(sizeof(DetectCsumData))) == NULL) goto error; memset(cd, 0, sizeof(DetectCsumData)); if (DetectCsumParseArg(csum_str, cd) == 0) goto error; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (cd != NULL) DetectIPV4CsumFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectIPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; if (cd != NULL) SCFree(cd); return; } /** * \brief Checks if the packet sent as the argument, has a valid or invalid * tcpv4 checksum, based on whether tcpv4-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectCsumData *cd = (DetectCsumData *)m->ctx; if (p->ip4h == NULL || p->tcph == NULL || p->proto != IPPROTO_TCP || PKT_IS_PSEUDOPKT(p)) return 0; if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->tcpvars.comp_csum == -1) p->tcpvars.comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); if (p->tcpvars.comp_csum == p->tcph->th_sum && cd->valid == 1) return 1; else if (p->tcpvars.comp_csum != p->tcph->th_sum && cd->valid == 0) return 1; else return 0; } /** * \brief Creates a SigMatch for the tcpv4-csum keyword being sent as argument, * and appends it to the Signature(s). Accepts 2 values for the * keyword - "valid" and "invalid", both with and without quotes * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param csum_str Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ static int DetectTCPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum_str) { DetectCsumData *cd = NULL; SigMatch *sm = NULL; //printf("DetectCsumSetup: \'%s\'\n", csum_str); sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_TCPV4_CSUM; if ( (cd = SCMalloc(sizeof(DetectCsumData))) == NULL) goto error; memset(cd, 0, sizeof(DetectCsumData)); if (DetectCsumParseArg(csum_str, cd) == 0) goto error; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (cd != NULL) DetectTCPV4CsumFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectTCPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; if (cd != NULL) SCFree(cd); return; } /** * \brief Checks if the packet sent as the argument, has a valid or invalid * tcpv6 checksum, based on whether tcpv6-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectCsumData *cd = (DetectCsumData *)m->ctx; if (p->ip6h == NULL || p->tcph == NULL || p->proto != IPPROTO_TCP || PKT_IS_PSEUDOPKT(p)) return 0; if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->tcpvars.comp_csum == -1) p->tcpvars.comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); if (p->tcpvars.comp_csum == p->tcph->th_sum && cd->valid == 1) return 1; else if (p->tcpvars.comp_csum != p->tcph->th_sum && cd->valid == 0) return 1; else return 0; } /** * \brief Creates a SigMatch for the tcpv6-csum keyword being sent as argument, * and appends it to the Signature(s). Accepts 2 values for the * keyword - "valid" and "invalid", both with and without quotes * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param csum_str Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ static int DetectTCPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum_str) { DetectCsumData *cd = NULL; SigMatch *sm = NULL; //printf("DetectCsumSetup: \'%s\'\n", csum_str); sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_TCPV6_CSUM; if ( (cd = SCMalloc(sizeof(DetectCsumData))) == NULL) goto error; memset(cd, 0, sizeof(DetectCsumData)); if (DetectCsumParseArg(csum_str, cd) == 0) goto error; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (cd != NULL) DetectTCPV6CsumFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectTCPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; if (cd != NULL) SCFree(cd); return; } /** * \brief Checks if the packet sent as the argument, has a valid or invalid * udpv4 checksum, based on whether udpv4-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectCsumData *cd = (DetectCsumData *)m->ctx; if (p->ip4h == NULL || p->udph == NULL || p->proto != IPPROTO_UDP || PKT_IS_PSEUDOPKT(p) || p->udph->uh_sum == 0) return 0; if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->udpvars.comp_csum == -1) p->udpvars.comp_csum = UDPV4CalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN) ); if (p->udpvars.comp_csum == p->udph->uh_sum && cd->valid == 1) return 1; else if (p->udpvars.comp_csum != p->udph->uh_sum && cd->valid == 0) return 1; else return 0; } /** * \brief Creates a SigMatch for the udpv4-csum keyword being sent as argument, * and appends it to the Signature(s). Accepts 2 values for the * keyword - "valid" and "invalid", both with and without quotes * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param csum_str Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ static int DetectUDPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum_str) { DetectCsumData *cd = NULL; SigMatch *sm = NULL; //printf("DetectCsumSetup: \'%s\'\n", csum_str); sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_UDPV4_CSUM; if ( (cd = SCMalloc(sizeof(DetectCsumData))) == NULL) goto error; memset(cd, 0, sizeof(DetectCsumData)); if (DetectCsumParseArg(csum_str, cd) == 0) goto error; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (cd != NULL) DetectUDPV4CsumFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectUDPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; if (cd != NULL) SCFree(cd); return; } /** * \brief Checks if the packet sent as the argument, has a valid or invalid * udpv6 checksum, based on whether udpv6-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectCsumData *cd = (DetectCsumData *)m->ctx; if (p->ip6h == NULL || p->udph == NULL || p->proto != IPPROTO_UDP || PKT_IS_PSEUDOPKT(p)) return 0; if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->udpvars.comp_csum == -1) p->udpvars.comp_csum = UDPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN) ); if (p->udpvars.comp_csum == p->udph->uh_sum && cd->valid == 1) return 1; else if (p->udpvars.comp_csum != p->udph->uh_sum && cd->valid == 0) return 1; else return 0; } /** * \brief Creates a SigMatch for the udpv6-csum keyword being sent as argument, * and appends it to the Signature(s). Accepts 2 values for the * keyword - "valid" and "invalid", both with and without quotes * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param csum_str Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ static int DetectUDPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum_str) { DetectCsumData *cd = NULL; SigMatch *sm = NULL; //printf("DetectCsumSetup: \'%s\'\n", csum_str); sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_UDPV6_CSUM; if ( (cd = SCMalloc(sizeof(DetectCsumData))) == NULL) goto error; memset(cd, 0, sizeof(DetectCsumData)); if (DetectCsumParseArg(csum_str, cd) == 0) goto error; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (cd != NULL) DetectUDPV6CsumFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectUDPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; if (cd != NULL) SCFree(cd); return; } /** * \brief Checks if the packet sent as the argument, has a valid or invalid * icmpv4 checksum, based on whether icmpv4-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectICMPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectCsumData *cd = (DetectCsumData *)m->ctx; if (p->ip4h == NULL || p->icmpv4h == NULL || p->proto != IPPROTO_ICMP || PKT_IS_PSEUDOPKT(p)) return 0; if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->icmpv4vars.comp_csum == -1) p->icmpv4vars.comp_csum = ICMPV4CalculateChecksum((uint16_t *)p->icmpv4h, ntohs(IPV4_GET_RAW_IPLEN(p->ip4h)) - IPV4_GET_RAW_HLEN(p->ip4h) * 4); if (p->icmpv4vars.comp_csum == p->icmpv4h->checksum && cd->valid == 1) return 1; else if (p->icmpv4vars.comp_csum != p->icmpv4h->checksum && cd->valid == 0) return 1; else return 0; } /** * \brief Creates a SigMatch for the icmpv4-csum keyword being sent as argument, * and appends it to the Signature(s). Accepts 2 values for the * keyword - "valid" and "invalid", both with and without quotes * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param csum_str Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ static int DetectICMPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum_str) { DetectCsumData *cd = NULL; SigMatch *sm = NULL; //printf("DetectCsumSetup: \'%s\'\n", csum_str); sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ICMPV4_CSUM; if ( (cd = SCMalloc(sizeof(DetectCsumData))) == NULL) goto error; memset(cd, 0, sizeof(DetectCsumData)); if (DetectCsumParseArg(csum_str, cd) == 0) goto error; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (cd != NULL) DetectICMPV4CsumFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectICMPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; if (cd != NULL) SCFree(cd); return; } /** * \brief Checks if the packet sent as the argument, has a valid or invalid * icmpv6 checksum, based on whether icmpv6-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectCsumData *cd = (DetectCsumData *)m->ctx; if (p->ip6h == NULL || p->icmpv6h == NULL || p->proto != IPPROTO_ICMPV6 || PKT_IS_PSEUDOPKT(p) || (GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))) <= 0) { return 0; } if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->icmpv6vars.comp_csum == -1) p->icmpv6vars.comp_csum = ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->icmpv6h, GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))); if (p->icmpv6vars.comp_csum == p->icmpv6h->csum && cd->valid == 1) return 1; else if (p->icmpv6vars.comp_csum != p->icmpv6h->csum && cd->valid == 0) return 1; else return 0; } /** * \brief Creates a SigMatch for the icmpv6-csum keyword being sent as argument, * and appends it to the Signature(s). Accepts 2 values for the * keyword - "valid" and "invalid", both with and without quotes * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param csum_str Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ static int DetectICMPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum_str) { DetectCsumData *cd = NULL; SigMatch *sm = NULL; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ICMPV6_CSUM; if ( (cd = SCMalloc(sizeof(DetectCsumData))) == NULL) goto error; memset(cd, 0, sizeof(DetectCsumData)); if (DetectCsumParseArg(csum_str, cd) == 0) goto error; sm->ctx = (void *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (cd != NULL) DetectICMPV6CsumFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectICMPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; if (cd != NULL) SCFree(cd); return; } /* ---------------------------------- Unit Tests --------------------------- */ #ifdef UNITTESTS int DetectCsumIPV4ValidArgsTestParse01(void) { Signature s; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectIPV4CsumSetup(NULL, &s, "\"valid\"") == 0); result &= (DetectIPV4CsumSetup(NULL, &s, "\"invalid\"") == 0); result &= (DetectIPV4CsumSetup(NULL, &s, "\"vaLid\"") == 0); result &= (DetectIPV4CsumSetup(NULL, &s, "\"VALID\"") == 0); result &= (DetectIPV4CsumSetup(NULL, &s, "\"iNvaLid\"") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumIPV4InValidArgsTestParse02(void) { Signature s; int result = -1; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectIPV4CsumSetup(NULL, &s, "vaid") == -1); result &= (DetectIPV4CsumSetup(NULL, &s, "invaalid") == -1); result &= (DetectIPV4CsumSetup(NULL, &s, "vaLiid") == -1); result &= (DetectIPV4CsumSetup(NULL, &s, "VALieD") == -1); result &= (DetectIPV4CsumSetup(NULL, &s, "iNvamid") == -1); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumIPV4ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectIPV4CsumSetup(NULL, &s, "valid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 1); } DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; result &= (DetectIPV4CsumSetup(NULL, &s, "INVALID") == 0); if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 0); } DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumICMPV4ValidArgsTestParse01(void) { Signature s; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectICMPV4CsumSetup(NULL, &s, "valid") == 0); result &= (DetectICMPV4CsumSetup(NULL, &s, "invalid") == 0); result &= (DetectICMPV4CsumSetup(NULL, &s, "vaLid") == 0); result &= (DetectICMPV4CsumSetup(NULL, &s, "VALID") == 0); result &= (DetectICMPV4CsumSetup(NULL, &s, "iNvaLid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumICMPV4InValidArgsTestParse02(void) { Signature s; int result = -1; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectICMPV4CsumSetup(NULL, &s, "vaid") == -1); result &= (DetectICMPV4CsumSetup(NULL, &s, "invaalid") == -1); result &= (DetectICMPV4CsumSetup(NULL, &s, "vaLiid") == -1); result &= (DetectICMPV4CsumSetup(NULL, &s, "VALieD") == -1); result &= (DetectICMPV4CsumSetup(NULL, &s, "iNvamid") == -1); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumICMPV4ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectICMPV4CsumSetup(NULL, &s, "valid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 1); } DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; result &= (DetectICMPV4CsumSetup(NULL, &s, "INVALID") == 0); if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 0); } DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumTCPV4ValidArgsTestParse01(void) { Signature s; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectTCPV4CsumSetup(NULL, &s, "valid") == 0); result &= (DetectTCPV4CsumSetup(NULL, &s, "invalid") == 0); result &= (DetectTCPV4CsumSetup(NULL, &s, "vaLid") == 0); result &= (DetectTCPV4CsumSetup(NULL, &s, "VALID") == 0); result &= (DetectTCPV4CsumSetup(NULL, &s, "iNvaLid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumTCPV4InValidArgsTestParse02(void) { Signature s; int result = -1; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectTCPV4CsumSetup(NULL, &s, "vaid") == -1); result &= (DetectTCPV4CsumSetup(NULL, &s, "invaalid") == -1); result &= (DetectTCPV4CsumSetup(NULL, &s, "vaLiid") == -1); result &= (DetectTCPV4CsumSetup(NULL, &s, "VALieD") == -1); result &= (DetectTCPV4CsumSetup(NULL, &s, "iNvamid") == -1); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumTCPV4ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectTCPV4CsumSetup(NULL, &s, "valid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 1); } DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; result &= (DetectTCPV4CsumSetup(NULL, &s, "INVALID") == 0); if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 0); } DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumUDPV4ValidArgsTestParse01(void) { Signature s; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectUDPV4CsumSetup(NULL, &s, "valid") == 0); result &= (DetectUDPV4CsumSetup(NULL, &s, "invalid") == 0); result &= (DetectUDPV4CsumSetup(NULL, &s, "vaLid") == 0); result &= (DetectUDPV4CsumSetup(NULL, &s, "VALID") == 0); result &= (DetectUDPV4CsumSetup(NULL, &s, "iNvaLid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumUDPV4InValidArgsTestParse02(void) { Signature s; int result = -1; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectUDPV4CsumSetup(NULL, &s, "vaid") == -1); result &= (DetectUDPV4CsumSetup(NULL, &s, "invaalid") == -1); result &= (DetectUDPV4CsumSetup(NULL, &s, "vaLiid") == -1); result &= (DetectUDPV4CsumSetup(NULL, &s, "VALieD") == -1); result &= (DetectUDPV4CsumSetup(NULL, &s, "iNvamid") == -1); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumUDPV4ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectUDPV4CsumSetup(NULL, &s, "valid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 1); } DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; result &= (DetectUDPV4CsumSetup(NULL, &s, "INVALID") == 0); if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 0); } DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumTCPV6ValidArgsTestParse01(void) { Signature s; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectTCPV6CsumSetup(NULL, &s, "valid") == 0); result &= (DetectTCPV6CsumSetup(NULL, &s, "invalid") == 0); result &= (DetectTCPV6CsumSetup(NULL, &s, "vaLid") == 0); result &= (DetectTCPV6CsumSetup(NULL, &s, "VALID") == 0); result &= (DetectTCPV6CsumSetup(NULL, &s, "iNvaLid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumTCPV6InValidArgsTestParse02(void) { Signature s; int result = -1; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectTCPV6CsumSetup(NULL, &s, "vaid") == -1); result &= (DetectTCPV6CsumSetup(NULL, &s, "invaalid") == -1); result &= (DetectTCPV6CsumSetup(NULL, &s, "vaLiid") == -1); result &= (DetectTCPV6CsumSetup(NULL, &s, "VALieD") == -1); result &= (DetectTCPV6CsumSetup(NULL, &s, "iNvamid") == -1); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumTCPV6ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectTCPV6CsumSetup(NULL, &s, "valid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 1); } DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; result &= (DetectTCPV6CsumSetup(NULL, &s, "INVALID") == 0); if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 0); } DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumUDPV6ValidArgsTestParse01(void) { Signature s; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectUDPV6CsumSetup(NULL, &s, "valid") == 0); result &= (DetectUDPV6CsumSetup(NULL, &s, "invalid") == 0); result &= (DetectUDPV6CsumSetup(NULL, &s, "vaLid") == 0); result &= (DetectUDPV6CsumSetup(NULL, &s, "VALID") == 0); result &= (DetectUDPV6CsumSetup(NULL, &s, "iNvaLid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumUDPV6InValidArgsTestParse02(void) { Signature s; int result = -1; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectUDPV6CsumSetup(NULL, &s, "vaid") == -1); result &= (DetectUDPV6CsumSetup(NULL, &s, "invaalid") == -1); result &= (DetectUDPV6CsumSetup(NULL, &s, "vaLiid") == -1); result &= (DetectUDPV6CsumSetup(NULL, &s, "VALieD") == -1); result &= (DetectUDPV6CsumSetup(NULL, &s, "iNvamid") == -1); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumUDPV6ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectUDPV6CsumSetup(NULL, &s, "valid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 1); } DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; result &= (DetectUDPV6CsumSetup(NULL, &s, "INVALID") == 0); if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 0); } DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumICMPV6ValidArgsTestParse01(void) { Signature s; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectICMPV6CsumSetup(NULL, &s, "valid") == 0); result &= (DetectICMPV6CsumSetup(NULL, &s, "invalid") == 0); result &= (DetectICMPV6CsumSetup(NULL, &s, "vaLid") == 0); result &= (DetectICMPV6CsumSetup(NULL, &s, "VALID") == 0); result &= (DetectICMPV6CsumSetup(NULL, &s, "iNvaLid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumICMPV6InValidArgsTestParse02(void) { Signature s; int result = -1; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectICMPV6CsumSetup(NULL, &s, "vaid") == -1); result &= (DetectICMPV6CsumSetup(NULL, &s, "invaalid") == -1); result &= (DetectICMPV6CsumSetup(NULL, &s, "vaLiid") == -1); result &= (DetectICMPV6CsumSetup(NULL, &s, "VALieD") == -1); result &= (DetectICMPV6CsumSetup(NULL, &s, "iNvamid") == -1); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } int DetectCsumICMPV6ValidArgsTestParse03(void) { Signature s; DetectCsumData *cd = NULL; int result = 0; SigMatch *temp = NULL; memset(&s, 0, sizeof(Signature)); result = (DetectICMPV6CsumSetup(NULL, &s, "valid") == 0); while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 1); } DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; result &= (DetectICMPV6CsumSetup(NULL, &s, "INVALID") == 0); if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; result &= (cd->valid == 0); } DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); temp = s.sm_lists[DETECT_SM_LIST_MATCH]; s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; SCFree(temp); } return result; } #include "detect-engine.h" #include "stream-tcp.h" int DetectCsumICMPV6Test01(void) { int result = 0; DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; DecodeThreadVars dtv; Packet *p = PacketGetFromAlloc(); if (p == NULL) { printf("failure PacketGetFromAlloc\n"); goto end; } uint8_t pkt[] = { 0x00, 0x30, 0x18, 0xa8, 0x7c, 0x23, 0x2c, 0x41, 0x38, 0xa7, 0xea, 0xeb, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3c, 0x40, 0xad, 0xa1, 0x09, 0x80, 0x00, 0x01, 0xd6, 0xf3, 0x20, 0x01, 0xf4, 0xbe, 0xea, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x32, 0xb2, 0x00, 0x01, 0x32, 0xb2, 0x09, 0x80, 0x20, 0x01, 0x00, 0x00, 0x3c, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x63, 0xc2, 0x00, 0x00, 0x00, 0x00 }; PacketCopyData(p, pkt, sizeof(pkt)); memset(&tv, 0, sizeof(tv)); memset(&dtv, 0, sizeof(dtv)); StreamTcpInitConfig(TRUE); FlowInitConfig(FLOW_QUIET); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("DetectEngineCtxInit failure\n"); goto end; } de_ctx->mpm_matcher = MPM_AC; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " "(icmpv6-csum:valid; sid:1;)"); if (s == NULL) { printf("SigInit failed\n"); goto end; } SigGroupBuild(de_ctx); DecodeEthernet(&tv, &dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), NULL); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert on p, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FlowShutdown(); SCFree(p); return result; } #endif /* UNITTESTS */ void DetectCsumRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectCsumIPV4ValidArgsTestParse01", DetectCsumIPV4ValidArgsTestParse01, 1); UtRegisterTest("DetectCsumIPV4InValidArgsTestParse02", DetectCsumIPV4InValidArgsTestParse02, 1); UtRegisterTest("DetectCsumIPV4ValidArgsTestParse03", DetectCsumIPV4ValidArgsTestParse03, 1); UtRegisterTest("DetectCsumICMPV4ValidArgsTestParse01", DetectCsumICMPV4ValidArgsTestParse01, 1); UtRegisterTest("DetectCsumICMPV4InValidArgsTestParse02", DetectCsumICMPV4InValidArgsTestParse02, 1); UtRegisterTest("DetectCsumICMPV4ValidArgsTestParse03", DetectCsumICMPV4ValidArgsTestParse03, 1); UtRegisterTest("DetectCsumTCPV4ValidArgsTestParse01", DetectCsumTCPV4ValidArgsTestParse01, 1); UtRegisterTest("DetectCsumTCPV4InValidArgsTestParse02", DetectCsumTCPV4InValidArgsTestParse02, 1); UtRegisterTest("DetectCsumTCPV4ValidArgsTestParse03", DetectCsumTCPV4ValidArgsTestParse03, 1); UtRegisterTest("DetectCsumUDPV4ValidArgsTestParse01", DetectCsumUDPV4ValidArgsTestParse01, 1); UtRegisterTest("DetectCsumUDPV4InValidArgsTestParse02", DetectCsumUDPV4InValidArgsTestParse02, 1); UtRegisterTest("DetectCsumUDPV4ValidArgsTestParse03", DetectCsumUDPV4ValidArgsTestParse03, 1); UtRegisterTest("DetectCsumUDPV6ValidArgsTestParse01", DetectCsumUDPV6ValidArgsTestParse01, 1); UtRegisterTest("DetectCsumUDPV6InValidArgsTestParse02", DetectCsumUDPV6InValidArgsTestParse02, 1); UtRegisterTest("DetectCsumUDPV6ValidArgsTestParse03", DetectCsumUDPV6ValidArgsTestParse03, 1); UtRegisterTest("DetectCsumTCPV6ValidArgsTestParse01", DetectCsumTCPV6ValidArgsTestParse01, 1); UtRegisterTest("DetectCsumTCPV6InValidArgsTestParse02", DetectCsumTCPV6InValidArgsTestParse02, 1); UtRegisterTest("DetectCsumTCPV6ValidArgsTestParse03", DetectCsumTCPV6ValidArgsTestParse03, 1); UtRegisterTest("DetectCsumICMPV6ValidArgsTestParse01", DetectCsumICMPV6ValidArgsTestParse01, 1); UtRegisterTest("DetectCsumICMPV6InValidArgsTestParse02", DetectCsumICMPV6InValidArgsTestParse02, 1); UtRegisterTest("DetectCsumICMPV6ValidArgsTestParse03", DetectCsumICMPV6ValidArgsTestParse03, 1); UtRegisterTest("DetectCsumICMPV6Test01", DetectCsumICMPV6Test01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-http-stat-msg.h0000644000000000000000000000211712253546156015161 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh */ #ifndef _DETECT_HTTP_STAT_MSG_H #define _DETECT_HTTP_STAT_MSG_H /* prototypes */ int DetectHttpStatMsgMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t , void *, Signature *, SigMatch *); void DetectHttpStatMsgRegister(void); #endif /* _DETECT_HTTP_STAT_MSG_H */ suricata-1.4.7/src/detect-engine-hmd.h0000644000000000000000000000235312253546156014462 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HMD_H__ #define __DETECT_ENGINE_HMD_H__ #include "app-layer-htp.h" int DetectEngineInspectHttpMethod(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *, Flow *, HtpState *, uint8_t); void DetectEngineHttpMethodRegisterTests(void); #endif /* __DETECT_ENGINE_HMD_H__ */ suricata-1.4.7/src/util-unittest-helper.c0000644000000000000000000007437412253546156015317 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * This file provide a set of helper functions for reducing the complexity * when constructing unittests */ #include "suricata-common.h" #include "decode.h" #include "flow-private.h" #include "flow-util.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-sigorder.h" #include "util-debug.h" #include "util-time.h" #include "util-error.h" #include "util-unittest.h" #include "util-unittest-helper.h" #ifdef UNITTESTS /** * \brief return the uint32_t for a ipv4 address string * * \param str Valid ipaddress in string form (e.g. 1.2.3.4) * * \retval uint the uin32_t representation */ uint32_t UTHSetIPv4Address(char *str) { struct in_addr in; if (inet_pton(AF_INET, str, &in) != 1) { printf("invalid IPv6 address %s\n", str); exit(EXIT_FAILURE); } return (uint32_t)in.s_addr; } /** * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests * specifying ip and port sources and destinations (IPV6) * * \param payload pointer to the payloadd buffer * \param payload_len pointer to the length of the payload * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP * \param src pointer to a string containing the ip source * \param dst pointer to a string containing the ip destination * \param sport pointer to a string containing the port source * \param dport pointer to a string containing the port destination * * \retval Packet pointer to the built in packet */ Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len, uint16_t ipproto, char *src, char *dst, uint16_t sport, uint16_t dport) { uint32_t in[4]; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return NULL; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); TimeSet(&p->ts); p->src.family = AF_INET6; p->dst.family = AF_INET6; p->payload = payload; p->payload_len = payload_len; p->proto = ipproto; p->ip6h = SCMalloc(sizeof(IPV6Hdr)); if (p->ip6h == NULL) goto error; memset(p->ip6h, 0, sizeof(IPV6Hdr)); p->ip6h->s_ip6_nxt = ipproto; p->ip6h->s_ip6_plen = htons(payload_len + sizeof(TCPHdr)); if (inet_pton(AF_INET6, src, &in) != 1) goto error; p->src.addr_data32[0] = in[0]; p->src.addr_data32[1] = in[1]; p->src.addr_data32[2] = in[2]; p->src.addr_data32[3] = in[3]; p->sp = sport; p->ip6h->s_ip6_src[0] = in[0]; p->ip6h->s_ip6_src[1] = in[1]; p->ip6h->s_ip6_src[2] = in[2]; p->ip6h->s_ip6_src[3] = in[3]; if (inet_pton(AF_INET6, dst, &in) != 1) goto error; p->dst.addr_data32[0] = in[0]; p->dst.addr_data32[1] = in[1]; p->dst.addr_data32[2] = in[2]; p->dst.addr_data32[3] = in[3]; p->dp = dport; p->ip6h->s_ip6_dst[0] = in[0]; p->ip6h->s_ip6_dst[1] = in[1]; p->ip6h->s_ip6_dst[2] = in[2]; p->ip6h->s_ip6_dst[3] = in[3]; p->tcph = SCMalloc(sizeof(TCPHdr)); if (p->tcph == NULL) goto error; memset(p->tcph, 0, sizeof(TCPHdr)); p->tcph->th_sport = htons(sport); p->tcph->th_dport = htons(dport); SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len); return p; error: if (p != NULL) { if (p->ip6h != NULL) { SCFree(p->ip6h); } if (p->tcph != NULL) { SCFree(p->tcph); } SCFree(p); } return NULL; } /** * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests * specifying ip and port sources and destinations * * \param payload pointer to the payloadd buffer * \param payload_len pointer to the length of the payload * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP * \param src pointer to a string containing the ip source * \param dst pointer to a string containing the ip destination * \param sport pointer to a string containing the port source * \param dport pointer to a string containing the port destination * * \retval Packet pointer to the built in packet */ Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, uint16_t ipproto, char *src, char *dst, uint16_t sport, uint16_t dport) { struct in_addr in; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return NULL; memset(p, 0, SIZE_OF_PACKET); p->pkt = ((uint8_t *)p) + sizeof(*p); struct timeval tv; TimeGet(&tv); COPY_TIMESTAMP(&tv, &p->ts); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = payload; p->payload_len = payload_len; p->proto = ipproto; if (inet_pton(AF_INET, src, &in) != 1) goto error; p->src.addr_data32[0] = in.s_addr; p->sp = sport; if (inet_pton(AF_INET, dst, &in) != 1) goto error; p->dst.addr_data32[0] = in.s_addr; p->dp = dport; p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); if (p->ip4h == NULL) goto error; p->ip4h->s_ip_src.s_addr = p->src.addr_data32[0]; p->ip4h->s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h->ip_proto = ipproto; p->ip4h->ip_verhl = sizeof(IPV4Hdr); p->proto = ipproto; int hdr_offset = sizeof(IPV4Hdr); switch (ipproto) { case IPPROTO_UDP: p->udph = (UDPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); if (p->udph == NULL) goto error; p->udph->uh_sport = sport; p->udph->uh_dport = dport; hdr_offset += sizeof(UDPHdr); break; case IPPROTO_TCP: p->tcph = (TCPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); if (p->tcph == NULL) goto error; p->tcph->th_sport = htons(sport); p->tcph->th_dport = htons(dport); hdr_offset += sizeof(TCPHdr); break; case IPPROTO_ICMP: p->icmpv4h = (ICMPV4Hdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); if (p->icmpv4h == NULL) goto error; hdr_offset += sizeof(ICMPV4Hdr); break; default: break; /* TODO: Add more protocols */ } PacketCopyDataOffset(p, hdr_offset, payload, payload_len); SET_PKT_LEN(p, hdr_offset + payload_len); p->payload = GET_PKT_DATA(p)+hdr_offset; return p; error: SCFree(p); return NULL; } /** * \brief UTHBuildPacket is a wrapper that build packets with default ip * and port fields * * \param payload pointer to the payloadd buffer * \param payload_len pointer to the length of the payload * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP * * \retval Packet pointer to the built in packet */ Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint16_t ipproto) { return UTHBuildPacketReal(payload, payload_len, ipproto, "192.168.1.5", "192.168.1.1", 41424, 80); } /** * \brief UTHBuildPacketArrayFromEth is a wrapper that build a packets from an array of * packets in ethernet rawbytes. Hint: It also share the flows. * * \param raw_eth pointer to the array of ethernet packets in rawbytes * \param pktsize pointer to the array of sizes corresponding to each buffer pointed * from pktsize. * \param numpkts number of packets in the array * * \retval Packet pointer to the array of built in packets; NULL if something fail */ Packet **UTHBuildPacketArrayFromEth(uint8_t *raw_eth[], int *pktsize, int numpkts) { DecodeThreadVars dtv; ThreadVars th_v; if (raw_eth == NULL || pktsize == NULL || numpkts <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "The arrays cant be null, and the number" " of packets should be grater thatn zero"); return NULL; } Packet **p = NULL; p = SCMalloc(sizeof(Packet *) * numpkts); if (unlikely(p == NULL)) return NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); int i = 0; for (; i < numpkts; i++) { p[i] = SCMalloc(SIZE_OF_PACKET); if (p[i] == NULL) { SCFree(p); return NULL; } memset(p[i], 0, SIZE_OF_PACKET); p[i]->pkt = (uint8_t *)(p[i] + 1); DecodeEthernet(&th_v, &dtv, p[i], raw_eth[i], pktsize[i], NULL); } return p; } /** * \brief UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes * * \param raw_eth pointer to the rawbytes containing an ethernet packet * (and any other headers inside) * \param pktsize pointer to the length of the payload * * \retval Packet pointer to the built in packet; NULL if something fail */ Packet *UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize) { DecodeThreadVars dtv; ThreadVars th_v; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return NULL; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); DecodeEthernet(&th_v, &dtv, p, raw_eth, pktsize, NULL); return p; } /** * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs * and defaulting ports * * \param payload pointer to the payloadd buffer * \param payload_len pointer to the length of the payload * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP * * \retval Packet pointer to the built in packet */ Packet *UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len, uint16_t ipproto, char *src, char *dst) { return UTHBuildPacketReal(payload, payload_len, ipproto, src, dst, 41424, 80); } /** * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs * and defaulting ports (IPV6) * * \param payload pointer to the payloadd buffer * \param payload_len pointer to the length of the payload * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP * * \retval Packet pointer to the built in packet */ Packet *UTHBuildPacketIPV6SrcDst(uint8_t *payload, uint16_t payload_len, uint16_t ipproto, char *src, char *dst) { return UTHBuildPacketIPV6Real(payload, payload_len, ipproto, src, dst, 41424, 80); } /** * \brief UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying * src and dst ports and defaulting IPs * * \param payload pointer to the payloadd buffer * \param payload_len pointer to the length of the payload * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP * * \retval Packet pointer to the built in packet */ Packet *UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len, uint16_t ipproto, uint16_t sport, uint16_t dport) { return UTHBuildPacketReal(payload, payload_len, ipproto, "192.168.1.5", "192.168.1.1", sport, dport); } /** * \brief UTHFreePackets: function to release the allocated data * from UTHBuildPacket and the packet itself * * \param p pointer to the Packet */ void UTHFreePackets(Packet **p, int numpkts) { if (p == NULL) return; int i = 0; for (; i < numpkts; i++) { UTHFreePacket(p[i]); } } /** * \brief UTHFreePacket: function to release the allocated data * from UTHBuildPacket and the packet itself * * \param p pointer to the Packet */ void UTHFreePacket(Packet *p) { if (p == NULL) return; #if 0 // VJ we now use one buffer switch (p->proto) { case IPPROTO_UDP: if (p->udph != NULL) SCFree(p->udph); if (p->ip4h != NULL) SCFree(p->ip4h); break; case IPPROTO_TCP: if (p->tcph != NULL) SCFree(p->tcph); if (p->ip4h != NULL) SCFree(p->ip4h); break; case IPPROTO_ICMP: if (p->ip4h != NULL) SCFree(p->ip4h); break; /* TODO: Add more protocols */ } #endif SCFree(p); } Flow *UTHBuildFlow(int family, char *src, char *dst, Port sp, Port dp) { struct in_addr in; Flow *f = SCMalloc(sizeof(Flow)); if (unlikely(f == NULL)) { printf("FlowAlloc failed\n"); ; return NULL; } memset(f, 0x00, sizeof(Flow)); FLOW_INITIALIZE(f); if (family == AF_INET) { f->flags |= FLOW_IPV4; } else if (family == AF_INET6) { f->flags |= FLOW_IPV6; } if (src != NULL) { if (family == AF_INET) { if (inet_pton(AF_INET, src, &in) != 1) { printf("invalid address %s\n", src); SCFree(f); return NULL; } f->src.addr_data32[0] = in.s_addr; } else { BUG_ON(1); } } if (dst != NULL) { if (family == AF_INET) { if (inet_pton(AF_INET, dst, &in) != 1) { printf("invalid address %s\n", dst); SCFree(f); return NULL; } f->dst.addr_data32[0] = in.s_addr; } else { BUG_ON(1); } } f->sp = sp; f->dp = dp; return f; } void UTHFreeFlow(Flow *flow) { if (flow != NULL) { FlowFree(flow); } } /** * \brief UTHGenericTest: function that perfom a generic check taking care of * as maximum common unittest elements as possible. * It will create a detection engine, append an array * of signatures an check the spected results for each * of them, it check matches for an array of packets * * \param pkt pointer to the array of packets * \param numpkts number of packets to match * \param sigs array of char* pointing to signatures to load * \param numsigs number of signatures to load and check * \param results pointer to arrays of numbers, each of them foreach packet * to check if sids matches that packet as expected with * that number of times or not. The size of results should be * numpkts * numsigs * sizeof(uint16_t *) * * Example: * result[1][3] would mean the number of times the pkt[1] * match the sid[3] * * \retval int 1 if the match of all the sids is the specified has the * specified results; 0 if not */ int UTHGenericTest(Packet **pkt, int numpkts, char *sigs[], uint32_t sids[], uint32_t *results, int numsigs) { int result = 0; if (pkt == NULL || sigs == NULL || numpkts == 0 || sids == NULL || results == NULL || numsigs == 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, that the pointer/arrays are not NULL, and the number of signatures and packets is > 0"); goto end; } DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0) goto cleanup; result = UTHMatchPacketsWithResults(de_ctx, pkt, numpkts, sids, results, numsigs); cleanup: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return result; } /** * \brief UTHCheckPacketMatches: function to check if a packet match some sids * * * \param p pointer to the Packet * \param sigs array of char* pointing to signatures to load * \param numsigs number of signatures to load from the array * \param results pointer to an array of numbers to check if sids matches * that number of times or not. * * \retval int 1 if the match of all the sids is the specified has the * specified results; 0 if not */ int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsids) { if (p == NULL || sids == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, check if the " "packet is NULL, and if the array contain sids is set"); return 0; } int i = 0; int res = 1; for (; i < numsids; i++) { uint16_t r = PacketAlertCheck(p, sids[i]); if (r != results[i]) { SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, and not %"PRIu16 " as expected", sids[i], r, results[i]); res = 0; } else { SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, as expected", sids[i], r); } } return res; } /** * \brief UTHAppendSigs: Add sigs to the detection_engine checking for errors * * \param de_ctx pointer to the DetectEngineCtx used * \param sigs array of char* pointing to signatures to load * \param numsigs number of signatures to load from the array * (size of the array) * * \retval int 0 if we have errors; 1 if all the signatures loaded succesfuly */ int UTHAppendSigs(DetectEngineCtx *de_ctx, char *sigs[], int numsigs) { if (de_ctx == NULL || numsigs <= 0 || sigs == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, check if sigs or de_ctx are NULL, and if the array contain sigs"); return 0; } //SCLogDebug("Adding %d signatures for the current unittest", numsigs); Signature *s; int i = 0; for ( ; i < numsigs; i++) { if (sigs[i] == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Check the signature" " at position %d", i); return 0; } s = DetectEngineAppendSig(de_ctx, sigs[i]); if (s == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Check the signature at" " position %d (%s)", i, sigs[i]); return 0; } } //SCLogDebug("Added %d signatures to the de_ctx of the unittest", i); return 1; } /** * \test UTHMatchPacketsWithResults Match a packet or a array of packets against sigs * of a de_ctx, checking that each signature match match X times for certain packets * * \param de_ctx pointer with the signatures loaded * \param p pointer to the array of packets * \param num_packets number of packets in the array * * \retval return 1 if all goes well * \retval return 0 if something fail */ int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, uint32_t sids[], uint32_t *results, int numsigs) { int result = 0; if (de_ctx == NULL || p == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "packet or de_ctx was null"); result = 0; goto end; } DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); //de_ctx->flags |= DE_QUIET; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int i = 0; for (; i < num_packets; i++) { SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); if (UTHCheckPacketMatchResults(p[i], sids, &results[(i * numsigs)], numsigs) == 0) goto cleanup; } /* so far, so good ;) */ result = 1; cleanup: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: return result; } /** * \test UTHMatchPackets Match a packet or a array of packets against sigs * of a de_ctx, but note that the return value doesn't mean that we have a * match, we have to check it later with PacketAlertCheck() * * \param de_ctx pointer with the signatures loaded * \param p pointer to the array of packets * \param num_packets number of packets in the array * * \retval return 1 if all goes well * \retval return 0 if something fail */ int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets) { int result = 1; if (de_ctx == NULL || p == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "packet or de_ctx was null"); result = 0; goto end; } DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); //de_ctx->flags |= DE_QUIET; SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int i = 0; for (; i < num_packets; i++) SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); /* Here we don't check if the packet matched or not, because * the de_ctx can have multiple signatures, and some of them may match * and others may not. That check will be outside */ if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); return result; } /** * \test Test if a packet match a signature given as string and a mpm_type * Hint: Useful for unittests with only one packet and one signature * * \param sig pointer to the string signature to test * \param sid sid number of the signature * * \retval return 1 if match * \retval return 0 if not */ int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type) { SCEnter(); int result = 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("de_ctx == NULL: "); goto end; } de_ctx->flags |= DE_QUIET; de_ctx->mpm_matcher = mpm_type; de_ctx->sig_list = SigInit(de_ctx, sig); if (de_ctx->sig_list == NULL) { printf("signature == NULL: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) { printf("signature didn't alert: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); SCReturnInt(result); } /** * \test Test if a packet match a signature given as string * Hint: Useful for unittests with only one packet and one signature * * \param sig pointer to the string signature to test * \param sid sid number of the signature * * \retval return 1 if match * \retval return 0 if not */ int UTHPacketMatchSig(Packet *p, char *sig) { int result = 1; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { result=0; goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) { result = 0; goto end; } end: if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir) { uint32_t i = start; uint8_t payload[] = "Payload"; for (; i < end; i++) { Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); if (dir == 0) { p->src.addr_data32[0] = i; p->dst.addr_data32[0] = i + 1; } else { p->src.addr_data32[0] = i + 1; p->dst.addr_data32[0] = i; } FlowHandlePacket(NULL, p); if (p->flow != NULL) SC_ATOMIC_RESET(p->flow->use_cnt); /* Now the queues shoul be updated */ UTHFreePacket(p); } return i; } /* * unittests for the unittest helpers */ /** * \brief CheckUTHTestPacket wrapper to check packets for unittests */ int CheckUTHTestPacket(Packet *p, uint16_t ipproto) { uint16_t sport = 41424; uint16_t dport = 80; uint8_t payload[] = "Payload"; uint8_t len = sizeof(payload); if (p == NULL) return 0; if (p->payload_len != len) return 0; if (strncmp((char *)payload, (char *)p->payload, len) != 0) return 0; if (p->src.family != AF_INET) return 0; if (p->dst.family != AF_INET) return 0; if (p->proto != ipproto) return 0; switch(ipproto) { case IPPROTO_UDP: if (p->udph == NULL) return 0; if (p->udph->uh_sport != sport) return 0; if (p->udph->uh_dport != dport) return 0; break; case IPPROTO_TCP: if (p->tcph == NULL) return 0; if (ntohs(p->tcph->th_sport) != sport) return 0; if (ntohs(p->tcph->th_dport) != dport) return 0; break; } return 1; } /** * \brief UTHBuildPacketRealTest01 wrapper to check packets for unittests */ int UTHBuildPacketRealTest01(void) { uint8_t payload[] = "Payload"; Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); int ret = CheckUTHTestPacket(p, IPPROTO_TCP); UTHFreePacket(p); return ret; } /** * \brief UTHBuildPacketRealTest02 wrapper to check packets for unittests */ int UTHBuildPacketRealTest02(void) { uint8_t payload[] = "Payload"; Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 80); int ret = CheckUTHTestPacket(p, IPPROTO_UDP); UTHFreePacket(p); return ret; } /** * \brief UTHBuildPacketTest01 wrapper to check packets for unittests */ int UTHBuildPacketTest01(void) { uint8_t payload[] = "Payload"; Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); int ret = CheckUTHTestPacket(p, IPPROTO_TCP); UTHFreePacket(p); return ret; } /** * \brief UTHBuildPacketTest02 wrapper to check packets for unittests */ int UTHBuildPacketTest02(void) { uint8_t payload[] = "Payload"; Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_UDP); int ret = CheckUTHTestPacket(p, IPPROTO_UDP); UTHFreePacket(p); return ret; } /** * \brief UTHBuildPacketOfFlowsTest01 wrapper to check packets for unittests */ int UTHBuildPacketOfFlowsTest01(void) { int result = 0; FlowInitConfig(FLOW_QUIET); uint32_t flow_spare_q_len = flow_spare_q.len; UTHBuildPacketOfFlows(0, 100, 0); if (flow_spare_q.len != flow_spare_q_len - 100) result = 0; else result = 1; FlowShutdown(); return result; } /** * \brief UTHBuildPacketSrcDstTest01 wrapper to check packets for unittests */ int UTHBuildPacketSrcDstTest01(void) { uint8_t payload[] = "Payload"; Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_TCP, "192.168.1.5", "192.168.1.1"); int ret = CheckUTHTestPacket(p, IPPROTO_TCP); UTHFreePacket(p); return ret; } /** * \brief UTHBuildPacketSrcDstTest02 wrapper to check packets for unittests */ int UTHBuildPacketSrcDstTest02(void) { uint8_t payload[] = "Payload"; Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_UDP, "192.168.1.5", "192.168.1.1"); int ret = CheckUTHTestPacket(p, IPPROTO_UDP); UTHFreePacket(p); return ret; } /** * \brief UTHBuildPacketSrcDstPortsTest01 wrapper to check packets for unittests */ int UTHBuildPacketSrcDstPortsTest01(void) { uint8_t payload[] = "Payload"; Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_TCP, 41424, 80); int ret = CheckUTHTestPacket(p, IPPROTO_TCP); UTHFreePacket(p); return ret; } /** * \brief UTHBuildPacketSrcDstPortsTest02 wrapper to check packets for unittests */ int UTHBuildPacketSrcDstPortsTest02(void) { uint8_t payload[] = "Payload"; Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_UDP, 41424, 80); int ret = CheckUTHTestPacket(p, IPPROTO_UDP); UTHFreePacket(p); return ret; } #endif /* UNITTESTS */ void UTHRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01, 1); UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02, 1); UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01, 1); UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02, 1); UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01, 1); UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02, 1); UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", UTHBuildPacketSrcDstPortsTest01, 1); UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", UTHBuildPacketSrcDstPortsTest02, 1); UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/decode.h0000644000000000000000000007765212253546156012442 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DECODE_H__ #define __DECODE_H__ //#define DBG_THREADS #define COUNTERS #include "suricata-common.h" #include "threadvars.h" typedef enum { CHECKSUM_VALIDATION_DISABLE, CHECKSUM_VALIDATION_ENABLE, CHECKSUM_VALIDATION_AUTO, CHECKSUM_VALIDATION_RXONLY, CHECKSUM_VALIDATION_KERNEL, } ChecksumValidationMode; enum { PKT_SRC_WIRE = 1, PKT_SRC_DECODER_GRE, PKT_SRC_DECODER_IPV4, PKT_SRC_DECODER_IPV6, PKT_SRC_DECODER_TEREDO, PKT_SRC_DEFRAG, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO, PKT_SRC_FFR_V2, PKT_SRC_FFR_SHUTDOWN, }; #include "source-nfq.h" #include "source-ipfw.h" #include "source-pcap.h" #include "source-af-packet.h" #include "action-globals.h" #include "decode-ethernet.h" #include "decode-gre.h" #include "decode-ppp.h" #include "decode-pppoe.h" #include "decode-sll.h" #include "decode-ipv4.h" #include "decode-ipv6.h" #include "decode-icmpv4.h" #include "decode-icmpv6.h" #include "decode-tcp.h" #include "decode-udp.h" #include "decode-sctp.h" #include "decode-raw.h" #include "decode-vlan.h" #include "detect-reference.h" #include "app-layer-protos.h" #ifdef __SC_CUDA_SUPPORT__ #define CUDA_MAX_PAYLOAD_SIZE 1500 #endif /* forward declaration */ struct DetectionEngineThreadCtx_; /* Address */ typedef struct Address_ { char family; union { uint32_t address_un_data32[4]; /* type-specific field */ uint16_t address_un_data16[8]; /* type-specific field */ uint8_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 #define COPY_ADDRESS(a, b) do { \ (b)->family = (a)->family; \ (b)->addr_data32[0] = (a)->addr_data32[0]; \ (b)->addr_data32[1] = (a)->addr_data32[1]; \ (b)->addr_data32[2] = (a)->addr_data32[2]; \ (b)->addr_data32[3] = (a)->addr_data32[3]; \ } while (0) /* 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) do { \ (a)->family = AF_INET; \ (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \ (a)->addr_data32[1] = 0; \ (a)->addr_data32[2] = 0; \ (a)->addr_data32[3] = 0; \ } while (0) #define SET_IPV4_DST_ADDR(p, a) do { \ (a)->family = AF_INET; \ (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \ (a)->addr_data32[1] = 0; \ (a)->addr_data32[2] = 0; \ (a)->addr_data32[3] = 0; \ } while (0) /* clear the address structure by setting all fields to 0 */ #define CLEAR_ADDR(a) do { \ (a)->family = 0; \ (a)->addr_data32[0] = 0; \ (a)->addr_data32[1] = 0; \ (a)->addr_data32[2] = 0; \ (a)->addr_data32[3] = 0; \ } while (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) do { \ (a)->family = AF_INET6; \ (a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \ (a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \ (a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \ (a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \ } while (0) #define SET_IPV6_DST_ADDR(p, a) do { \ (a)->family = AF_INET6; \ (a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \ (a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \ (a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \ (a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \ } while (0) /* 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) do { \ SET_PORT(TCP_GET_SRC_PORT((pkt)), *(prt)); \ } while (0) #define SET_TCP_DST_PORT(pkt, prt) do { \ SET_PORT(TCP_GET_DST_PORT((pkt)), *(prt)); \ } while (0) /* Set the UDP ports into the Ports of the Packet. * Make sure p->udph is initialized and validated. */ #define SET_UDP_SRC_PORT(pkt, prt) do { \ SET_PORT(UDP_GET_SRC_PORT((pkt)), *(prt)); \ } while (0) #define SET_UDP_DST_PORT(pkt, prt) do { \ SET_PORT(UDP_GET_DST_PORT((pkt)), *(prt)); \ } while (0) /* Set the SCTP ports into the Ports of the Packet. * Make sure p->sctph is initialized and validated. */ #define SET_SCTP_SRC_PORT(pkt, prt) do { \ SET_PORT(SCTP_GET_SRC_PORT((pkt)), *(prt)); \ } while (0) #define SET_SCTP_DST_PORT(pkt, prt) do { \ SET_PORT(SCTP_GET_DST_PORT((pkt)), *(prt)); \ } while (0) #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) #define GET_PKT_LEN(p) ((p)->pktlen) #define GET_PKT_DATA(p) ((((p)->ext_pkt) == NULL ) ? (p)->pkt : (p)->ext_pkt) #define GET_PKT_DIRECT_DATA(p) ((p)->pkt) #define GET_PKT_DIRECT_MAX_SIZE(p) (default_packet_size) #define SET_PKT_LEN(p, len) do { \ (p)->pktlen = (len); \ } while (0) /* Port is just a uint16_t */ typedef uint16_t Port; #define SET_PORT(v, p) ((p) = (v)) #define COPY_PORT(a,b) ((b) = (a)) #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)) /*Given a packet pkt offset to the start of the ip header in a packet *We determine the ip version. */ #define IP_GET_RAW_VER(pkt) ((((pkt)[0] & 0xf0) >> 4)) #define PKT_IS_IPV4(p) (((p)->ip4h != NULL)) #define PKT_IS_IPV6(p) (((p)->ip6h != NULL)) #define PKT_IS_TCP(p) (((p)->tcph != NULL)) #define PKT_IS_UDP(p) (((p)->udph != NULL)) #define PKT_IS_ICMPV4(p) (((p)->icmpv4h != NULL)) #define PKT_IS_ICMPV6(p) (((p)->icmpv6h != NULL)) #define PKT_IS_TOSERVER(p) (((p)->flowflags & FLOW_PKT_TOSERVER)) #define PKT_IS_TOCLIENT(p) (((p)->flowflags & FLOW_PKT_TOCLIENT)) #define IPH_IS_VALID(p) (PKT_IS_IPV4((p)) || PKT_IS_IPV6((p))) /* Retrieve proto regardless of IP version */ #define IP_GET_IPPROTO(p) \ (p->proto ? p->proto : \ (PKT_IS_IPV4((p))? IPV4_GET_IPPROTO((p)) : (PKT_IS_IPV6((p))? IPV6_GET_L4PROTO((p)) : 0))) /* structure to store the sids/gids/etc the detection engine * found in this packet */ typedef struct PacketAlert_ { SigIntId num; /* Internal num, used for sorting */ SigIntId order_id; /* Internal num, used for sorting */ uint8_t action; /* Internal num, used for sorting */ uint8_t flags; struct Signature_ *s; } PacketAlert; /** After processing an alert by the thresholding module, if at * last it gets triggered, we might want to stick the drop action to * the flow on IPS mode */ #define PACKET_ALERT_FLAG_DROP_FLOW 0x01 /** alert was generated based on state */ #define PACKET_ALERT_FLAG_STATE_MATCH 0x02 /** alert was generated based on stream */ #define PACKET_ALERT_FLAG_STREAM_MATCH 0x04 #define PACKET_ALERT_MAX 15 typedef struct PacketAlerts_ { uint16_t cnt; PacketAlert alerts[PACKET_ALERT_MAX]; } PacketAlerts; /** number of decoder events we support per packet. Power of 2 minus 1 * for memory layout */ #define PACKET_ENGINE_EVENT_MAX 15 /** data structure to store decoder, defrag and stream events */ typedef struct PacketEngineEvents_ { uint8_t cnt; /**< number of events */ uint8_t events[PACKET_ENGINE_EVENT_MAX]; /**< array of events */ } PacketEngineEvents; typedef struct PktVar_ { char *name; struct PktVar_ *next; /* right now just implement this as a list, * in the long run we have thing of something * faster. */ uint8_t *value; uint16_t value_len; } PktVar; #ifdef PROFILING /** \brief Per TMM stats storage */ typedef struct PktProfilingTmmData_ { uint64_t ticks_start; uint64_t ticks_end; #ifdef PROFILE_LOCKING uint64_t mutex_lock_cnt; uint64_t mutex_lock_wait_ticks; uint64_t mutex_lock_contention; uint64_t spin_lock_cnt; uint64_t spin_lock_wait_ticks; uint64_t spin_lock_contention; uint64_t rww_lock_cnt; uint64_t rww_lock_wait_ticks; uint64_t rww_lock_contention; uint64_t rwr_lock_cnt; uint64_t rwr_lock_wait_ticks; uint64_t rwr_lock_contention; #endif } PktProfilingTmmData; typedef struct PktProfilingDetectData_ { uint64_t ticks_start; uint64_t ticks_end; uint64_t ticks_spent; } PktProfilingDetectData; typedef struct PktProfilingAppData_ { uint64_t ticks_spent; } PktProfilingAppData; /** \brief Per pkt stats storage */ typedef struct PktProfiling_ { uint64_t ticks_start; uint64_t ticks_end; PktProfilingTmmData tmm[TMM_SIZE]; PktProfilingAppData app[ALPROTO_MAX]; PktProfilingDetectData detect[PROF_DETECT_SIZE]; uint64_t proto_detect; } PktProfiling; #endif /* PROFILING */ /* forward declartion since Packet struct definition requires this */ struct PacketQueue_; /* sizes of the members: * src: 17 bytes * dst: 17 bytes * sp/type: 1 byte * dp/code: 1 byte * proto: 1 byte * recurs: 1 byte * * sum of above: 38 bytes * * flow ptr: 4/8 bytes * flags: 1 byte * flowflags: 1 byte * * sum of above 44/48 bytes */ 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; union { Port sp; uint8_t type; }; union { Port dp; uint8_t code; }; uint8_t proto; /* make sure we can't be attacked on when the tunneled packet * has the exact same tuple as the lower levels */ uint8_t recursion_level; /* Pkt Flags */ uint32_t flags; /* flow */ uint8_t flowflags; uint8_t pkt_src; struct Flow_ *flow; struct timeval ts; union { /* nfq stuff */ #ifdef NFQ NFQPacketVars nfq_v; #endif /* NFQ */ #ifdef IPFW IPFWPacketVars ipfw_v; #endif /* IPFW */ #ifdef AF_PACKET AFPPacketVars afp_v; #endif /** libpcap vars: shared by Pcap Live mode and Pcap File mode */ PcapPacketVars pcap_v; }; /** data linktype in host order */ int datalink; /* IPS action to take */ uint8_t action; /* used to hold flowbits only if debuglog is enabled */ int debuglog_flowbits_names_len; const char **debuglog_flowbits_names; /** The release function for packet data */ TmEcode (*ReleaseData)(ThreadVars *, struct Packet_ *); /* pkt vars */ PktVar *pktvar; /* header pointers */ EthernetHdr *ethh; IPV4Hdr *ip4h; IPV4Vars ip4vars; IPV6Hdr *ip6h; IPV6Vars ip6vars; IPV6ExtHdrs ip6eh; TCPHdr *tcph; TCPVars tcpvars; UDPHdr *udph; UDPVars udpvars; SCTPHdr *sctph; ICMPV4Hdr *icmpv4h; ICMPV4Vars icmpv4vars; ICMPV6Hdr *icmpv6h; ICMPV6Vars icmpv6vars; PPPHdr *ppph; PPPOESessionHdr *pppoesh; PPPOEDiscoveryHdr *pppoedh; GREHdr *greh; VLANHdr *vlanh; /* ptr to the payload of the packet * with it's length. */ uint8_t *payload; uint16_t payload_len; /* storage: set to pointer to heap and extended via allocation if necessary */ uint8_t *pkt; uint8_t *ext_pkt; uint32_t pktlen; /* Incoming interface */ struct LiveDevice_ *livedev; PacketAlerts alerts; struct Host_ *host_src; struct Host_ *host_dst; /** packet number in the pcap file, matches wireshark */ uint64_t pcap_cnt; /** mutex to protect access to: * - tunnel_rtv_cnt * - tunnel_tpr_cnt */ SCMutex tunnel_mutex; /* ready to set verdict counter, only set in root */ uint16_t tunnel_rtv_cnt; /* tunnel packet ref count */ uint16_t tunnel_tpr_cnt; /* engine events */ PacketEngineEvents events; /* 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 */ /* required for cuda support */ #ifdef __SC_CUDA_SUPPORT__ /* indicates if the cuda mpm would be conducted or a normal cpu mpm would * be conduced on this packet. If it is set to 0, the cpu mpm; else cuda mpm */ uint8_t cuda_mpm_enabled; /* indicates if the cuda mpm has finished running the mpm and processed the * results for this packet, assuming if cuda_mpm_enabled has been set for this * packet */ uint16_t cuda_done; /* used by the detect thread and the cuda mpm dispatcher thread. The detect * thread would wait on this cond var, if the cuda mpm dispatcher thread * still hasn't processed the packet. The dispatcher would use this cond * to inform the detect thread(in case it is waiting on this packet), once * the dispatcher is done processing the packet results */ SCMutex cuda_mutex; SCCondT cuda_cond; /* the extra 1 in the 1481, is to hold the no_of_matches from the mpm run */ uint16_t mpm_offsets[CUDA_MAX_PAYLOAD_SIZE + 1]; #endif #ifdef PROFILING PktProfiling profile; #endif } Packet; #define DEFAULT_PACKET_SIZE (1500 + ETHERNET_HEADER_LEN) /* storage: maximum ip packet size + link header */ #define MAX_PAYLOAD_SIZE (IPV6_HEADER_LEN + 65536 + 28) uint32_t default_packet_size; #define SIZE_OF_PACKET (default_packet_size + sizeof(Packet)) typedef struct PacketQueue_ { Packet *top; Packet *bot; uint32_t len; #ifdef DBG_PERF uint32_t dbg_maxlen; #endif /* DBG_PERF */ SCMutex mutex_q; SCCondT cond_q; } PacketQueue; /** \brief Specific ctx for AL proto detection */ typedef struct AlpProtoDetectDirectionThread_ { MpmThreadCtx mpm_ctx; PatternMatcherQueue pmq; } AlpProtoDetectDirectionThread; /** \brief Specific ctx for AL proto detection */ typedef struct AlpProtoDetectThreadCtx_ { AlpProtoDetectDirectionThread toserver; AlpProtoDetectDirectionThread toclient; void *alproto_local_storage[ALPROTO_MAX]; #ifdef PROFILING uint64_t ticks_start; uint64_t ticks_end; uint64_t ticks_spent; uint16_t alproto; uint64_t proto_detect_ticks_start; uint64_t proto_detect_ticks_end; uint64_t proto_detect_ticks_spent; #endif } AlpProtoDetectThreadCtx; /** \brief Structure to hold thread specific data for all decode modules */ typedef struct DecodeThreadVars_ { /** Specific context for udp protocol detection (here atm) */ AlpProtoDetectThreadCtx udp_dp_ctx; /** stats/counters */ uint16_t counter_pkts; uint16_t counter_pkts_per_sec; uint16_t counter_bytes; uint16_t counter_bytes_per_sec; uint16_t counter_mbit_per_sec; uint16_t counter_ipv4; uint16_t counter_ipv6; uint16_t counter_eth; uint16_t counter_sll; uint16_t counter_raw; uint16_t counter_tcp; uint16_t counter_udp; uint16_t counter_sctp; uint16_t counter_icmpv4; uint16_t counter_icmpv6; uint16_t counter_ppp; uint16_t counter_gre; uint16_t counter_vlan; uint16_t counter_pppoe; uint16_t counter_teredo; uint16_t counter_ipv4inipv6; uint16_t counter_ipv6inipv6; uint16_t counter_avg_pkt_size; uint16_t counter_max_pkt_size; /** frag stats - defrag runs in the context of the decoder. */ uint16_t counter_defrag_ipv4_fragments; uint16_t counter_defrag_ipv4_reassembled; uint16_t counter_defrag_ipv4_timeouts; uint16_t counter_defrag_ipv6_fragments; uint16_t counter_defrag_ipv6_reassembled; uint16_t counter_defrag_ipv6_timeouts; uint16_t counter_defrag_max_hit; } DecodeThreadVars; /** * \brief reset these to -1(indicates that the packet is fresh from the queue) */ #define PACKET_RESET_CHECKSUMS(p) do { \ (p)->ip4vars.comp_csum = -1; \ (p)->tcpvars.comp_csum = -1; \ (p)->udpvars.comp_csum = -1; \ (p)->icmpv4vars.comp_csum = -1; \ (p)->icmpv6vars.comp_csum = -1; \ } while (0) /** * \brief Initialize a packet structure for use. */ #ifndef __SC_CUDA_SUPPORT__ #define PACKET_INITIALIZE(p) { \ memset((p), 0x00, SIZE_OF_PACKET); \ SCMutexInit(&(p)->tunnel_mutex, NULL); \ PACKET_RESET_CHECKSUMS((p)); \ (p)->pkt = ((uint8_t *)(p)) + sizeof(Packet); \ (p)->livedev = NULL; \ } #else #define PACKET_INITIALIZE(p) { \ memset((p), 0x00, SIZE_OF_PACKET); \ SCMutexInit(&(p)->tunnel_mutex, NULL); \ PACKET_RESET_CHECKSUMS((p)); \ SCMutexInit(&(p)->cuda_mutex, NULL); \ SCCondInit(&(p)->cuda_cond, NULL); \ (p)->pkt = ((uint8_t *)(p)) + sizeof(Packet); \ (p)->livedev = NULL; \ } #endif /** * \brief Recycle a packet structure for reuse. * \todo the mutex destroy & init is necessary because of the memset, reconsider */ #define PACKET_DO_RECYCLE(p) do { \ CLEAR_ADDR(&(p)->src); \ CLEAR_ADDR(&(p)->dst); \ (p)->sp = 0; \ (p)->dp = 0; \ (p)->proto = 0; \ (p)->recursion_level = 0; \ (p)->flags = 0; \ (p)->flowflags = 0; \ (p)->pkt_src = 0; \ FlowDeReference(&((p)->flow)); \ (p)->ts.tv_sec = 0; \ (p)->ts.tv_usec = 0; \ (p)->datalink = 0; \ (p)->action = 0; \ if ((p)->pktvar != NULL) { \ PktVarFree((p)->pktvar); \ (p)->pktvar = NULL; \ } \ (p)->ethh = NULL; \ if ((p)->ip4h != NULL) { \ CLEAR_IPV4_PACKET((p)); \ } \ if ((p)->ip6h != NULL) { \ CLEAR_IPV6_PACKET((p)); \ } \ if ((p)->tcph != NULL) { \ CLEAR_TCP_PACKET((p)); \ } \ if ((p)->udph != NULL) { \ CLEAR_UDP_PACKET((p)); \ } \ if ((p)->sctph != NULL) { \ CLEAR_SCTP_PACKET((p)); \ } \ if ((p)->icmpv4h != NULL) { \ CLEAR_ICMPV4_PACKET((p)); \ } \ if ((p)->icmpv6h != NULL) { \ CLEAR_ICMPV6_PACKET((p)); \ } \ (p)->ppph = NULL; \ (p)->pppoesh = NULL; \ (p)->pppoedh = NULL; \ (p)->greh = NULL; \ (p)->vlanh = NULL; \ (p)->payload = NULL; \ (p)->payload_len = 0; \ (p)->pktlen = 0; \ (p)->alerts.cnt = 0; \ HostDeReference(&((p)->host_src)); \ HostDeReference(&((p)->host_dst)); \ (p)->pcap_cnt = 0; \ (p)->tunnel_rtv_cnt = 0; \ (p)->tunnel_tpr_cnt = 0; \ SCMutexDestroy(&(p)->tunnel_mutex); \ SCMutexInit(&(p)->tunnel_mutex, NULL); \ (p)->events.cnt = 0; \ (p)->next = NULL; \ (p)->prev = NULL; \ (p)->root = NULL; \ (p)->livedev = NULL; \ (p)->ReleaseData = NULL; \ PACKET_RESET_CHECKSUMS((p)); \ PACKET_PROFILING_RESET((p)); \ } while (0) #ifndef __SC_CUDA_SUPPORT__ #define PACKET_RECYCLE(p) PACKET_DO_RECYCLE((p)) #else #define PACKET_RECYCLE(p) do { \ PACKET_DO_RECYCLE((p)); \ SCMutexDestroy(&(p)->cuda_mutex); \ SCCondDestroy(&(p)->cuda_cond); \ SCMutexInit(&(p)->cuda_mutex, NULL); \ SCCondInit(&(p)->cuda_cond, NULL); \ PACKET_RESET_CHECKSUMS((p)); \ } while(0) #endif /** * \brief Cleanup a packet so that we can free it. No memset needed.. */ #ifndef __SC_CUDA_SUPPORT__ #define PACKET_CLEANUP(p) do { \ if ((p)->pktvar != NULL) { \ PktVarFree((p)->pktvar); \ } \ SCMutexDestroy(&(p)->tunnel_mutex); \ } while (0) #else #define PACKET_CLEANUP(p) do { \ if ((p)->pktvar != NULL) { \ PktVarFree((p)->pktvar); \ } \ SCMutexDestroy(&(p)->tunnel_mutex); \ SCMutexDestroy(&(p)->cuda_mutex); \ SCCondDestroy(&(p)->cuda_cond); \ } while(0) #endif /* macro's for setting the action * handle the case of a root packet * for tunnels */ #define ALERT_PACKET(p) do { \ ((p)->root ? \ ((p)->root->action = ACTION_ALERT) : \ ((p)->action = ACTION_ALERT)); \ } while (0) #define ACCEPT_PACKET(p) do { \ ((p)->root ? \ ((p)->root->action = ACTION_ACCEPT) : \ ((p)->action = ACTION_ACCEPT)); \ } while (0) #define DROP_PACKET(p) do { \ ((p)->root ? \ ((p)->root->action = ACTION_DROP) : \ ((p)->action = ACTION_DROP)); \ } while (0) #define REJECT_PACKET(p) do { \ ((p)->root ? \ ((p)->root->action = (ACTION_REJECT|ACTION_DROP)) : \ ((p)->action = (ACTION_REJECT|ACTION_DROP))); \ } while (0) #define REJECT_PACKET_DST(p) do { \ ((p)->root ? \ ((p)->root->action = (ACTION_REJECT_DST|ACTION_DROP)) : \ ((p)->action = (ACTION_REJECT_DST|ACTION_DROP))); \ } while (0) #define REJECT_PACKET_BOTH(p) do { \ ((p)->root ? \ ((p)->root->action = (ACTION_REJECT_BOTH|ACTION_DROP)) : \ ((p)->action = (ACTION_REJECT_BOTH|ACTION_DROP))); \ } while (0) #define PASS_PACKET(p) do { \ ((p)->root ? \ ((p)->root->action = ACTION_PASS) : \ ((p)->action = ACTION_PASS)); \ } while (0) #define UPDATE_PACKET_ACTION(p, a) do { \ ((p)->root ? \ ((p)->root->action |= a) : \ ((p)->action |= a)); \ } while (0) #define PACKET_TEST_ACTION(p, a) \ ((p)->root ? \ ((p)->root->action & a) : \ ((p)->action & a)) #define TUNNEL_INCR_PKT_RTV(p) do { \ SCMutexLock((p)->root ? &(p)->root->tunnel_mutex : &(p)->tunnel_mutex); \ ((p)->root ? (p)->root->tunnel_rtv_cnt++ : (p)->tunnel_rtv_cnt++); \ SCMutexUnlock((p)->root ? &(p)->root->tunnel_mutex : &(p)->tunnel_mutex); \ } while (0) #define TUNNEL_INCR_PKT_TPR(p) do { \ SCMutexLock((p)->root ? &(p)->root->tunnel_mutex : &(p)->tunnel_mutex); \ ((p)->root ? (p)->root->tunnel_tpr_cnt++ : (p)->tunnel_tpr_cnt++); \ SCMutexUnlock((p)->root ? &(p)->root->tunnel_mutex : &(p)->tunnel_mutex); \ } while (0) #define TUNNEL_DECR_PKT_TPR(p) do { \ SCMutexLock((p)->root ? &(p)->root->tunnel_mutex : &(p)->tunnel_mutex); \ ((p)->root ? (p)->root->tunnel_tpr_cnt-- : (p)->tunnel_tpr_cnt--); \ SCMutexUnlock((p)->root ? &(p)->root->tunnel_mutex : &(p)->tunnel_mutex); \ } while (0) #define TUNNEL_DECR_PKT_TPR_NOLOCK(p) do { \ ((p)->root ? (p)->root->tunnel_tpr_cnt-- : (p)->tunnel_tpr_cnt--); \ } while (0) #define TUNNEL_PKT_RTV(p) ((p)->root ? (p)->root->tunnel_rtv_cnt : (p)->tunnel_rtv_cnt) #define TUNNEL_PKT_TPR(p) ((p)->root ? (p)->root->tunnel_tpr_cnt : (p)->tunnel_tpr_cnt) #define IS_TUNNEL_PKT(p) (((p)->flags & PKT_TUNNEL)) #define SET_TUNNEL_PKT(p) ((p)->flags |= PKT_TUNNEL) #define IS_TUNNEL_ROOT_PKT(p) (IS_TUNNEL_PKT(p) && (p)->root == NULL) #define IS_TUNNEL_PKT_VERDICTED(p) (((p)->flags & PKT_TUNNEL_VERDICTED)) #define SET_TUNNEL_PKT_VERDICTED(p) ((p)->flags |= PKT_TUNNEL_VERDICTED) void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *); Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto); Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto); Packet *PacketGetFromQueueOrAlloc(void); Packet *PacketGetFromAlloc(void); int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen); int PacketSetData(Packet *p, uint8_t *pktdata, int pktlen); int PacketCopyDataOffset(Packet *p, int offset, uint8_t *data, int datalen); DecodeThreadVars *DecodeThreadVarsAlloc(); /* decoder functions */ void DecodeEthernet(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeSll(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodePPP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodePPPOESession(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodePPPOEDiscovery(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *, uint8_t); void DecodeRaw(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeIPV4(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeIPV6(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeICMPV4(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeICMPV6(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeTCP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeUDP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeSCTP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeGRE(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeVLAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void AddressDebugPrint(Address *); /** \brief Set the No payload inspection Flag for the packet. * * \param p Packet to set the flag in */ #define DecodeSetNoPayloadInspectionFlag(p) do { \ (p)->flags |= PKT_NOPAYLOAD_INSPECTION; \ } while (0) /** \brief Set the No packet inspection Flag for the packet. * * \param p Packet to set the flag in */ #define DecodeSetNoPacketInspectionFlag(p) do { \ (p)->flags |= PKT_NOPACKET_INSPECTION; \ } while (0) #define ENGINE_SET_EVENT(p, e) do { \ SCLogDebug("p %p event %d", (p), e); \ if ((p)->events.cnt < PACKET_ENGINE_EVENT_MAX) { \ (p)->events.events[(p)->events.cnt] = e; \ (p)->events.cnt++; \ } \ } while(0) #define ENGINE_ISSET_EVENT(p, e) ({ \ int r = 0; \ uint8_t u; \ for (u = 0; u < (p)->events.cnt; u++) { \ if ((p)->events.events[u] == (e)) { \ r = 1; \ break; \ } \ } \ r; \ }) /* older libcs don't contain a def for IPPROTO_DCCP * inside of * if it isn't defined let's define it here. */ #ifndef IPPROTO_DCCP #define IPPROTO_DCCP 33 #endif /* older libcs don't contain a def for IPPROTO_SCTP * inside of * if it isn't defined let's define it here. */ #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif /* pcap provides this, but we don't want to depend on libpcap */ #ifndef DLT_EN10MB #define DLT_EN10MB 1 #endif /* taken from pcap's bpf.h */ #ifndef DLT_RAW #ifdef __OpenBSD__ #define DLT_RAW 14 /* raw IP */ #else #define DLT_RAW 12 /* raw IP */ #endif #endif /** libpcap shows us the way to linktype codes * \todo we need more & maybe put them in a separate file? */ #define LINKTYPE_ETHERNET DLT_EN10MB #define LINKTYPE_LINUX_SLL 113 #define LINKTYPE_PPP 9 #define LINKTYPE_RAW DLT_RAW #define PPP_OVER_GRE 11 #define VLAN_OVER_GRE 13 /*Packet Flags*/ #define PKT_NOPACKET_INSPECTION (1) /**< Flag to indicate that packet header or contents should not be inspected*/ #define PKT_NOPAYLOAD_INSPECTION (1<<2) /**< Flag to indicate that packet contents should not be inspected*/ #define PKT_ALLOC (1<<3) /**< Packet was alloc'd this run, needs to be freed */ #define PKT_HAS_TAG (1<<4) /**< Packet has matched a tag */ #define PKT_STREAM_ADD (1<<5) /**< Packet payload was added to reassembled stream */ #define PKT_STREAM_EST (1<<6) /**< Packet is part of establised stream */ #define PKT_STREAM_EOF (1<<7) /**< Stream is in eof state */ #define PKT_HAS_FLOW (1<<8) #define PKT_PSEUDO_STREAM_END (1<<9) /**< Pseudo packet to end the stream */ #define PKT_STREAM_MODIFIED (1<<10) /**< Packet is modified by the stream engine, we need to recalc the csum and reinject/replace */ #define PKT_MARK_MODIFIED (1<<11) /**< Packet mark is modified */ #define PKT_STREAM_NOPCAPLOG (1<<12) /**< Exclude packet from pcap logging as it's part of a stream that has reassembly depth reached. */ #define PKT_TUNNEL (1<<13) #define PKT_TUNNEL_VERDICTED (1<<14) #define PKT_IGNORE_CHECKSUM (1<<15) /**< Packet checksum is not computed (TX packet for example) */ #define PKT_ZERO_COPY (1<<16) /**< Packet comes from zero copy (ext_pkt must not be freed) */ #define PKT_HOST_SRC_LOOKED_UP (1<<17) #define PKT_HOST_DST_LOOKED_UP (1<<18) #define PKT_IS_FRAGMENT (1<<19) /**< Packet is a fragment */ /** \brief return 1 if the packet is a pseudo packet */ #define PKT_IS_PSEUDOPKT(p) ((p)->flags & PKT_PSEUDO_STREAM_END) #define PKT_SET_SRC(p, src_val) ((p)->pkt_src = src_val) #endif /* __DECODE_H__ */ suricata-1.4.7/src/detect-engine-iponly.c0000644000000000000000000023454312253546156015227 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon Crespo * * Signatures that only inspect IP addresses are processed here * We use radix trees for src dst ipv4 and ipv6 adresses * This radix trees hold information for subnets and hosts in a * hierarchical distribution */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "decode.h" #include "flow.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-siggroup.h" #include "detect-engine-address.h" #include "detect-engine-proto.h" #include "detect-engine-port.h" #include "detect-engine-mpm.h" #include "detect-engine-threshold.h" #include "detect-engine-iponly.h" #include "detect-threshold.h" #include "util-classification-config.h" #include "util-rule-vars.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-print.h" #ifdef OS_WIN32 #include #else #include #endif /* OS_WIN32 */ /** * \brief This function creates a new IPOnlyCIDRItem * * \retval IPOnlyCIDRItem address of the new instance */ static IPOnlyCIDRItem *IPOnlyCIDRItemNew() { SCEnter(); IPOnlyCIDRItem *item = NULL; item = SCMalloc(sizeof(IPOnlyCIDRItem)); if (unlikely(item == NULL)) SCReturnPtr(NULL, "NULL"); memset(item, 0, sizeof(IPOnlyCIDRItem)); SCReturnPtr(item, "IPOnlyCIDRItem"); } static uint8_t IPOnlyCIDRItemCompare(IPOnlyCIDRItem *head, IPOnlyCIDRItem *item) { uint8_t i = 0; for (; i < head->netmask / 32 || i < 1; i++) { if (item->ip[i] < head->ip[i]) //if (*(uint8_t *)(item->ip + i) < *(uint8_t *)(head->ip + i)) return 1; } return 0; } /** * \internal * \brief Parses an ipv4/ipv6 address string and updates the result into the * IPOnlyCIDRItem instance sent as the argument. * * \param dd Pointer to the IPOnlyCIDRItem instance which should be updated with * the address (in cidr) details from the parsed ip string. * \param str Pointer to address string that has to be parsed. * * \retval 0 On successfully parsing the address string. * \retval -1 On failure. */ static int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem *dd, char *str) { char *ip = NULL; char *ip2 = NULL; char *mask = NULL; int r = 0; while (*str != '\0' && *str == ' ') str++; char *ipdup = SCStrdup(str); if (unlikely(ipdup == NULL)) return -1; SCLogDebug("str %s", str); /* first handle 'any' */ if (strcasecmp(str, "any") == 0) { /* if any, insert 0.0.0.0/0 and ::/0 as well */ SCLogDebug("adding 0.0.0.0/0 and ::/0 as we\'re handling \'any\'"); IPOnlyCIDRItemParseSingle(dd, "0.0.0.0/0"); BUG_ON(dd->family == 0); dd->next = IPOnlyCIDRItemNew(); if (dd->next == NULL) goto error; IPOnlyCIDRItemParseSingle(dd->next, "::/0"); BUG_ON(dd->family == 0); SCFree(ipdup); SCLogDebug("address is \'any\'"); return 0; } /* we dup so we can put a nul-termination in it later */ ip = ipdup; /* handle the negation case */ if (ip[0] == '!') { dd->negated = (dd->negated)? 0 : 1; ip++; } /* see if the address is an ipv4 or ipv6 address */ if ((strchr(str, ':')) == NULL) { /* IPv4 Address */ struct in_addr in; dd->family = AF_INET; if ((mask = strchr(ip, '/')) != NULL) { /* 1.2.3.4/xxx format (either dotted or cidr notation */ ip[mask - ip] = '\0'; mask++; uint32_t netmask = 0; size_t u = 0; if ((strchr (mask, '.')) == NULL) { /* 1.2.3.4/24 format */ for (u = 0; u < strlen(mask); u++) { if(!isdigit((unsigned char)mask[u])) goto error; } int cidr = atoi(mask); if (cidr < 0 || cidr > 32) goto error; dd->netmask = cidr; } else { /* 1.2.3.4/255.255.255.0 format */ r = inet_pton(AF_INET, mask, &in); if (r <= 0) goto error; netmask = in.s_addr; /* Extract cidr netmask */ while ((0x01 & netmask) == 0) { dd->netmask++; netmask = netmask >> 1; } dd->netmask = 32 - dd->netmask; } r = inet_pton(AF_INET, ip, &in); if (r <= 0) goto error; dd->ip[0] = in.s_addr; } else if ((ip2 = strchr(ip, '-')) != NULL) { /* 1.2.3.4-1.2.3.6 range format */ ip[ip2 - ip] = '\0'; ip2++; uint32_t tmp_ip[4]; uint32_t tmp_ip2[4]; uint32_t first, last; r = inet_pton(AF_INET, ip, &in); if (r <= 0) goto error; tmp_ip[0] = in.s_addr; r = inet_pton(AF_INET, ip2, &in); if (r <= 0) goto error; tmp_ip2[0] = in.s_addr; /* a > b is illegal, a = b is ok */ if (ntohl(tmp_ip[0]) > ntohl(tmp_ip2[0])) goto error; first = ntohl(tmp_ip[0]); last = ntohl(tmp_ip2[0]); dd->netmask = 32; dd->ip[0] =htonl(first); if (first < last) { for (first++; first <= last; first++) { IPOnlyCIDRItem *new = IPOnlyCIDRItemNew(); if (new == NULL) goto error; dd->next = new; new->negated = dd->negated; new->family= dd->family; new->netmask = dd->netmask; new->ip[0] = htonl(first); dd = dd->next; } } } else { /* 1.2.3.4 format */ r = inet_pton(AF_INET, ip, &in); if (r <= 0) goto error; /* single host */ dd->ip[0] = in.s_addr; dd->netmask = 32; } } else { /* IPv6 Address */ struct in6_addr in6; uint32_t ip6addr[4]; dd->family = AF_INET6; if ((mask = strchr(ip, '/')) != NULL) { mask[0] = '\0'; mask++; r = inet_pton(AF_INET6, ip, &in6); if (r <= 0) goto error; /* Format is cidr val */ dd->netmask = atoi(mask); memcpy(dd->ip, &in6.s6_addr, sizeof(ip6addr)); } else { r = inet_pton(AF_INET6, ip, &in6); if (r <= 0) goto error; memcpy(dd->ip, &in6.s6_addr, sizeof(dd->ip)); dd->netmask = 128; } } SCFree(ipdup); BUG_ON(dd->family == 0); return 0; error: if (ipdup) SCFree(ipdup); return -1; } /** * \brief Setup a single address string, parse it and add the resulting * Address items in cidr format to the list of gh * * \param gh Pointer to the IPOnlyCIDRItem list Head to which the * resulting Address-Range(s) from the parsed ip string has to * be added. * \param s Pointer to the ip address string to be parsed. * * \retval 0 On success. * \retval -1 On failure. */ static int IPOnlyCIDRItemSetup(IPOnlyCIDRItem *gh, char *s) { SCLogDebug("gh %p, s %s", gh, s); /* parse the address */ if (IPOnlyCIDRItemParseSingle(gh, s) == -1) { SCLogError(SC_ERR_ADDRESS_ENGINE_GENERIC, "DetectAddressParse error \"%s\"", s); goto error; } return 0; error: return -1; } /** * \brief This function insert a IPOnlyCIDRItem * to a list of IPOnlyCIDRItems sorted by netmask * ascending * \param head Pointer to the head of IPOnlyCIDRItems list * \param item Pointer to the item to insert in the list * * \retval IPOnlyCIDRItem address of the new head if apply */ static IPOnlyCIDRItem *IPOnlyCIDRItemInsertReal(IPOnlyCIDRItem *head, IPOnlyCIDRItem *item) { IPOnlyCIDRItem *it, *prev = NULL; if (item == NULL) return head; /* Compare with the head */ if (item->netmask < head->netmask || (item->netmask == head->netmask && IPOnlyCIDRItemCompare(head, item))) { item->next = head; return item; } if (item->netmask == head->netmask && !IPOnlyCIDRItemCompare(head, item)) { item->next = head->next; head->next = item; return head; } for (prev = it = head; it != NULL && it->netmask < item->netmask; it = it->next) prev = it; if (it == NULL) { prev->next = item; item->next = NULL; } else { item->next = it; prev->next = item; } return head; } /** * \brief This function insert a IPOnlyCIDRItem list * to a list of IPOnlyCIDRItems sorted by netmask * ascending * \param head Pointer to the head of IPOnlyCIDRItems list * \param item Pointer to the list of items to insert in the list * * \retval IPOnlyCIDRItem address of the new head if apply */ static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head, IPOnlyCIDRItem *item) { IPOnlyCIDRItem *it, *prev = NULL; /* The first element */ if (head == NULL) { SCLogDebug("Head is NULL to insert item (%p)",item); return item; } if (item == NULL) { SCLogDebug("Item is NULL"); return head; } SCLogDebug("Inserting item(%p)->netmask %u head %p", item, item->netmask, head); prev = item; while (prev != NULL) { it = prev->next; /* Separate from the item list */ prev->next = NULL; //SCLogDebug("Before:"); //IPOnlyCIDRListPrint(head); head = IPOnlyCIDRItemInsertReal(head, prev); //SCLogDebug("After:"); //IPOnlyCIDRListPrint(head); prev = it; } return head; } /** * \brief This function free a IPOnlyCIDRItem list * \param tmphead Pointer to the list */ void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead) { SCEnter(); uint32_t i = 0; IPOnlyCIDRItem *it, *next = NULL; if (tmphead == NULL) { SCLogDebug("temphead is NULL"); return; } it = tmphead; next = it->next; while (it != NULL) { i++; SCFree(it); SCLogDebug("Item(%p) %"PRIu32" removed\n", it, i); it = next; if (next != NULL) next = next->next; } SCReturn; } /** * \brief This function update a list of IPOnlyCIDRItems * setting the signature internal id (signum) to "i" * * \param tmphead Pointer to the list * \param i number of signature internal id */ static void IPOnlyCIDRListSetSigNum(IPOnlyCIDRItem *tmphead, SigIntId i) { while (tmphead != NULL) { tmphead->signum = i; tmphead = tmphead->next; } } #ifdef UNITTESTS /** * \brief This function print a IPOnlyCIDRItem list * \param tmphead Pointer to the head of IPOnlyCIDRItems list */ static void IPOnlyCIDRListPrint(IPOnlyCIDRItem *tmphead) { uint32_t i = 0; while (tmphead != NULL) { i++; SCLogDebug("Item %"PRIu32" has netmask %"PRIu16" negated:" " %s; IP: %s; signum: %"PRIu16, i, tmphead->netmask, (tmphead->negated) ? "yes":"no", inet_ntoa(*(struct in_addr*)&tmphead->ip[0]), tmphead->signum); tmphead = tmphead->next; } } #endif /** * \brief This function print a SigNumArray, it's used with the * radix tree print function to help debugging * \param tmp Pointer to the head of SigNumArray */ static void SigNumArrayPrint(void *tmp) { SigNumArray *sna = (SigNumArray *)tmp; uint32_t u; for (u = 0; u < sna->size; u++) { uint8_t bitarray = sna->array[u]; uint8_t i = 0; for (; i < 8; i++) { if (bitarray & 0x01) printf(", %"PRIu16"", u * 8 + i); else printf(", "); bitarray = bitarray >> 1; } } } /** * \brief This function creates a new SigNumArray with the * size fixed to the io_ctx->max_idx * \param de_ctx Pointer to the current detection context * \param io_ctx Pointer to the current ip only context * * \retval SigNumArray address of the new instance */ static SigNumArray *SigNumArrayNew(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) { SigNumArray *new = SCMalloc(sizeof(SigNumArray)); if (unlikely(new == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigNumArrayNew. Exiting..."); exit(EXIT_FAILURE); } memset(new, 0, sizeof(SigNumArray)); new->array = SCMalloc(io_ctx->max_idx / 8 + 1); if (new->array == NULL) { exit(EXIT_FAILURE); } memset(new->array, 0, io_ctx->max_idx / 8 + 1); new->size = io_ctx->max_idx / 8 + 1; SCLogDebug("max idx= %u", io_ctx->max_idx); return new; } /** * \brief This function creates a new SigNumArray with the * same data as the argument * * \param orig Pointer to the original SigNumArray to copy * * \retval SigNumArray address of the new instance */ static SigNumArray *SigNumArrayCopy(SigNumArray *orig) { SigNumArray *new = SCMalloc(sizeof(SigNumArray)); if (unlikely(new == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SigNumArrayCopy. Exiting..."); exit(EXIT_FAILURE); } memset(new, 0, sizeof(SigNumArray)); new->size = orig->size; new->array = SCMalloc(orig->size); if (new->array == NULL) { exit(EXIT_FAILURE); } memcpy(new->array, orig->array, orig->size); return new; } /** * \brief This function free() a SigNumArray * \param orig Pointer to the original SigNumArray to copy */ static void SigNumArrayFree(void *tmp) { SigNumArray *sna = (SigNumArray *)tmp; if (sna == NULL) return; if (sna->array != NULL) SCFree(sna->array); SCFree(sna); } /** * \brief This function parses and return a list of IPOnlyCIDRItem * * \param s Pointer to the string of the addresses * (in the format of signatures) * \param negate flag to indicate if all this string is negated or not * * \retval 0 if success * \retval -1 if fails */ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) { size_t x = 0; size_t u = 0; int o_set = 0, n_set = 0, d_set = 0; int depth = 0; size_t size = strlen(s); char address[8196] = ""; char *rule_var_address = NULL; char *temp_rule_var_address = NULL; IPOnlyCIDRItem *head; IPOnlyCIDRItem *subhead; head = subhead = NULL; SCLogDebug("s %s negate %s", s, negate ? "true" : "false"); for (u = 0, x = 0; u < size && x < sizeof(address); u++) { address[x] = s[u]; x++; if (!o_set && s[u] == '!') { n_set = 1; x--; } else if (s[u] == '[') { if (!o_set) { o_set = 1; x = 0; } depth++; } else if (s[u] == ']') { if (depth == 1) { address[x - 1] = '\0'; x = 0; if ( (subhead = IPOnlyCIDRListParse2(address, (negate + n_set) % 2)) == NULL) goto error; head = IPOnlyCIDRItemInsert(head, subhead); n_set = 0; } depth--; } else if (depth == 0 && s[u] == ',') { if (o_set == 1) { o_set = 0; } else if (d_set == 1) { address[x - 1] = '\0'; rule_var_address = SCRuleVarsGetConfVar(address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; temp_rule_var_address = rule_var_address; if ((negate + n_set) % 2) { temp_rule_var_address = SCMalloc(strlen(rule_var_address) + 3); if (unlikely(temp_rule_var_address == NULL)) { goto error; } snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } subhead = IPOnlyCIDRListParse2(temp_rule_var_address, (negate + n_set) % 2); head = IPOnlyCIDRItemInsert(head, subhead); d_set = 0; n_set = 0; if (temp_rule_var_address != rule_var_address) SCFree(temp_rule_var_address); } else { address[x - 1] = '\0'; subhead = IPOnlyCIDRItemNew(); if (subhead == NULL) goto error; if (!((negate + n_set) % 2)) subhead->negated = 0; else subhead->negated = 1; if (IPOnlyCIDRItemSetup(subhead, address) < 0) { IPOnlyCIDRListFree(subhead); subhead = NULL; goto error; } head = IPOnlyCIDRItemInsert(head, subhead); n_set = 0; } x = 0; } else if (depth == 0 && s[u] == '$') { d_set = 1; } else if (depth == 0 && u == size - 1) { if (x == sizeof(address)) { address[x - 1] = '\0'; } else { address[x] = '\0'; } x = 0; if (d_set == 1) { rule_var_address = SCRuleVarsGetConfVar(address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; temp_rule_var_address = rule_var_address; if ((negate + n_set) % 2) { temp_rule_var_address = SCMalloc(strlen(rule_var_address) + 3); if (unlikely(temp_rule_var_address == NULL)) { goto error; } snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } subhead = IPOnlyCIDRListParse2(temp_rule_var_address, (negate + n_set) % 2); head = IPOnlyCIDRItemInsert(head, subhead); d_set = 0; if (temp_rule_var_address != rule_var_address) SCFree(temp_rule_var_address); } else { subhead = IPOnlyCIDRItemNew(); if (subhead == NULL) goto error; if (!((negate + n_set) % 2)) subhead->negated = 0; else subhead->negated = 1; if (IPOnlyCIDRItemSetup(subhead, address) < 0) { IPOnlyCIDRListFree(subhead); subhead = NULL; goto error; } head = IPOnlyCIDRItemInsert(head, subhead); } n_set = 0; } } return head; error: SCLogError(SC_ERR_ADDRESS_ENGINE_GENERIC,"Error parsing addresses"); return head; } /** * \brief Parses an address group sent as a character string and updates the * IPOnlyCIDRItem list * * \param gh Pointer to the IPOnlyCIDRItem list * \param str Pointer to the character string containing the address group * that has to be parsed. * * \retval 0 On success. * \retval -1 On failure. */ static int IPOnlyCIDRListParse(IPOnlyCIDRItem **gh, char *str) { SCLogDebug("gh %p, str %s", gh, str); if (gh == NULL) goto error; *gh = IPOnlyCIDRListParse2(str, 0); if (*gh == NULL) { SCLogDebug("DetectAddressParse2 returned null"); goto error; } return 0; error: return -1; } /** * \brief Parses an address group sent as a character string and updates the * IPOnlyCIDRItem lists src and dst of the Signature *s * * \param s Pointer to the signature structure * \param addrstr Pointer to the character string containing the address group * that has to be parsed. * \param flag to indicate if we are parsing the src string or the dst string * * \retval 0 On success. * \retval -1 On failure. */ int IPOnlySigParseAddress(Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); IPOnlyCIDRItem *tmp = NULL; /* pass on to the address(list) parser */ if (flag == 0) { if (strcasecmp(addrstr, "any") == 0) { s->flags |= SIG_FLAG_SRC_ANY; if (IPOnlyCIDRListParse(&s->CidrSrc, (char *)"0.0.0.0/0") < 0) goto error; if (IPOnlyCIDRListParse(&tmp, (char *)"::/0") < 0) goto error; s->CidrSrc = IPOnlyCIDRItemInsert(s->CidrSrc, tmp); } else if (IPOnlyCIDRListParse(&s->CidrSrc, (char *)addrstr) < 0) { goto error; } /* IPOnlyCIDRListPrint(s->CidrSrc); */ } else { if (strcasecmp(addrstr, "any") == 0) { s->flags |= SIG_FLAG_DST_ANY; if (IPOnlyCIDRListParse(&tmp, (char *)"0.0.0.0/0") < 0) goto error; if (IPOnlyCIDRListParse(&s->CidrDst, (char *)"::/0") < 0) goto error; s->CidrDst = IPOnlyCIDRItemInsert(s->CidrDst, tmp); } else if (IPOnlyCIDRListParse(&s->CidrDst, (char *)addrstr) < 0) { goto error; } /* IPOnlyCIDRListPrint(s->CidrDst); */ } return 0; error: SCLogError(SC_ERR_ADDRESS_ENGINE_GENERIC, "failed to parse addresses"); return -1; } /** * \brief Setup the IP Only detection engine context * * \param de_ctx Pointer to the current detection engine * \param io_ctx Pointer to the current ip only detection engine */ void IPOnlyInit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) { io_ctx->sig_init_size = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; if ( (io_ctx->sig_init_array = SCMalloc(io_ctx->sig_init_size)) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in IPOnlyInit. Exiting..."); exit(EXIT_FAILURE); } memset(io_ctx->sig_init_array, 0, io_ctx->sig_init_size); io_ctx->tree_ipv4src = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); io_ctx->tree_ipv4dst = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); io_ctx->tree_ipv6src = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); io_ctx->tree_ipv6dst = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint); } /** * \brief Setup the IP Only thread detection engine context * * \param de_ctx Pointer to the current detection engine * \param io_ctx Pointer to the current ip only thread detection engine */ void DetectEngineIPOnlyThreadInit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyThreadCtx *io_tctx) { /* initialize the signature bitarray */ io_tctx->sig_match_size = de_ctx->io_ctx.max_idx / 8 + 1; io_tctx->sig_match_array = SCMalloc(io_tctx->sig_match_size); if (io_tctx->sig_match_array == NULL) { exit(EXIT_FAILURE); } memset(io_tctx->sig_match_array, 0, io_tctx->sig_match_size); } /** * \brief Print stats of the IP Only engine * * \param de_ctx Pointer to the current detection engine * \param io_ctx Pointer to the current ip only detection engine */ void IPOnlyPrint(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) { /* XXX: how are we going to print the stats now? */ } /** * \brief Deinitialize the IP Only detection engine context * * \param de_ctx Pointer to the current detection engine * \param io_ctx Pointer to the current ip only detection engine */ void IPOnlyDeinit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) { if (io_ctx == NULL) return; if (io_ctx->tree_ipv4src != NULL) SCRadixReleaseRadixTree(io_ctx->tree_ipv4src); if (io_ctx->tree_ipv4dst != NULL) SCRadixReleaseRadixTree(io_ctx->tree_ipv4dst); if (io_ctx->tree_ipv6src != NULL) SCRadixReleaseRadixTree(io_ctx->tree_ipv6src); if (io_ctx->tree_ipv6dst != NULL) SCRadixReleaseRadixTree(io_ctx->tree_ipv6dst); if (io_ctx->sig_init_array) SCFree(io_ctx->sig_init_array); io_ctx->sig_init_array = NULL; } /** * \brief Deinitialize the IP Only thread detection engine context * * \param de_ctx Pointer to the current detection engine * \param io_ctx Pointer to the current ip only detection engine */ void DetectEngineIPOnlyThreadDeinit(DetectEngineIPOnlyThreadCtx *io_tctx) { SCFree(io_tctx->sig_match_array); } static inline int IPOnlyMatchCompatSMs(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p) { SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { BUG_ON(!(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)); if (sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm) > 0) { sm = sm->next; continue; } return 0; } return 1; } /** * \brief Match a packet against the IP Only detection engine contexts * * \param de_ctx Pointer to the current detection engine * \param io_ctx Pointer to the current ip only detection engine * \param io_ctx Pointer to the current ip only thread detection engine * \param p Pointer to the Packet to match against */ void IPOnlyMatchPacket(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, DetectEngineIPOnlyCtx *io_ctx, DetectEngineIPOnlyThreadCtx *io_tctx, Packet *p) { SCRadixNode *srcnode = NULL, *dstnode = NULL; SigNumArray *src = NULL; SigNumArray *dst = NULL; if (p->src.family == AF_INET) { srcnode = SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), io_ctx->tree_ipv4src); } else if (p->src.family == AF_INET6) { srcnode = SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_SRC_ADDR(p), io_ctx->tree_ipv6src); } if (p->dst.family == AF_INET) { dstnode = SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_DST_ADDR_U32(p), io_ctx->tree_ipv4dst); } else if (p->dst.family == AF_INET6) { dstnode = SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_DST_ADDR(p), io_ctx->tree_ipv6dst); } /* The radix trees are printed without our logging format comment this out if you need to debug printf("Src: \n"); SCRadixPrintNodeInfo(srcnode, 4, SigNumArrayPrint); printf("Dst: \n"); SCRadixPrintNodeInfo(dstnode, 4, SigNumArrayPrint); */ if (srcnode != NULL && srcnode->prefix != NULL && srcnode->prefix->user_data_result != NULL) { src = srcnode->prefix->user_data_result; } else { //SCLogError(SC_ERR_IPONLY_RADIX, "Error, no userdata found at the radix" // " on src node!"); return; } if (dstnode != NULL && dstnode->prefix != NULL && dstnode->prefix->user_data_result != NULL) { dst = dstnode->prefix->user_data_result; } else { //SCLogError(SC_ERR_IPONLY_RADIX, "Error, no userdata found at the radix" // " on dst node!"); return; } uint32_t u; for (u = 0; u < src->size; u++) { SCLogDebug("And %"PRIu8" & %"PRIu8, src->array[u], dst->array[u]); /* The final results will be at io_tctx */ io_tctx->sig_match_array[u] = dst->array[u] & src->array[u]; /* We have to move the logic of the signature checking * to the main detect loop, in order to apply the * priority of actions (pass, drop, reject, alert) */ if (io_tctx->sig_match_array[u] != 0) { /* We have a match :) Let's see from which signum's */ uint8_t bitarray = io_tctx->sig_match_array[u]; uint8_t i = 0; for (; i < 8; i++, bitarray = bitarray >> 1) { if (bitarray & 0x01) { Signature *s = de_ctx->sig_array[u * 8 + i]; if ((s->proto.flags & DETECT_PROTO_IPV4) && !PKT_IS_IPV4(p)) { SCLogDebug("ip version didn't match"); continue; } if ((s->proto.flags & DETECT_PROTO_IPV6) && !PKT_IS_IPV6(p)) { SCLogDebug("ip version didn't match"); continue; } if (DetectProtoContainsProto(&s->proto, IP_GET_IPPROTO(p)) == 0) { SCLogDebug("proto didn't match"); continue; } /* check the source & dst port in the sig */ if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { if (!(s->flags & SIG_FLAG_DP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) continue; DetectPort *dport = DetectPortLookupGroup(s->dp,p->dp); if (dport == NULL) { SCLogDebug("dport didn't match."); continue; } } if (!(s->flags & SIG_FLAG_SP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) continue; DetectPort *sport = DetectPortLookupGroup(s->sp,p->sp); if (sport == NULL) { SCLogDebug("sport didn't match."); continue; } } } if (!IPOnlyMatchCompatSMs(tv, det_ctx, s, p)) { continue; } SCLogDebug("Signum %"PRIu16" match (sid: %"PRIu16", msg: %s)", u * 8 + i, s->id, s->msg); if (s->sm_lists[DETECT_SM_LIST_POSTMATCH] != NULL) { SigMatch *sm = s->sm_lists[DETECT_SM_LIST_POSTMATCH]; SCLogDebug("running match functions, sm %p", sm); for ( ; sm != NULL; sm = sm->next) { (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm); } } if (!(s->flags & SIG_FLAG_NOALERT)) { if (s->action & ACTION_DROP) PacketAlertAppend(det_ctx, s, p, PACKET_ALERT_FLAG_DROP_FLOW); else PacketAlertAppend(det_ctx, s, p, 0); } else { /* apply actions for noalert/rule suppressed as well */ UPDATE_PACKET_ACTION(p, s->action); } } } } } } /** * \brief Build the radix trees from the lists of parsed adresses in CIDR format * the result should be 4 radix trees: src/dst ipv4 and src/dst ipv6 * holding SigNumArrays, each of them with a hierarchical relation * of subnets and hosts * * \param de_ctx Pointer to the current detection engine */ void IPOnlyPrepare(DetectEngineCtx *de_ctx) { SCLogDebug("Preparing Final Lists"); /* IPOnlyCIDRListPrint((de_ctx->io_ctx).ip_src); IPOnlyCIDRListPrint((de_ctx->io_ctx).ip_dst); */ IPOnlyCIDRItem *src, *dst; SCRadixNode *node = NULL; /* Prepare Src radix trees */ for (src = (de_ctx->io_ctx).ip_src; src != NULL; ) { if (src->family == AF_INET) { /* SCLogDebug("To IPv4"); SCLogDebug("Item has netmask %"PRIu16" negated: %s; IP: %s; " "signum: %"PRIu16, src->netmask, (src->negated) ? "yes":"no", inet_ntoa( *(struct in_addr*)&src->ip[0]), src->signum); */ if (src->netmask == 32) node = SCRadixFindKeyIPV4ExactMatch((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src); else node = SCRadixFindKeyIPV4Netblock((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, src->netmask); if (node == NULL) { SCLogDebug("Exact match not found"); /** Not found, look if there's a subnet of this range with * bigger netmask */ node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src); if (node == NULL) { SCLogDebug("best match not found"); /* Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); /* Update the sig */ uint8_t tmp = 1 << (src->signum % 8); if (src->negated > 0) /* Unset it */ sna->array[src->signum / 8] &= ~tmp; else /* Set it */ sna->array[src->signum / 8] |= tmp; if (src->netmask == 32) node = SCRadixAddKeyIPV4((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, sna); else node = SCRadixAddKeyIPV4Netblock((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, sna, src->netmask); if (node == NULL) SCLogError(SC_ERR_IPONLY_RADIX, "Error inserting in the " "src ipv4 radix tree"); } else { SCLogDebug("Best match found"); /* Found, copy the sig num table, add this signum and insert */ SigNumArray *sna = NULL; sna = SigNumArrayCopy((SigNumArray *) node->prefix->user_data_result); /* Update the sig */ uint8_t tmp = 1 << (src->signum % 8); if (src->negated > 0) /* Unset it */ sna->array[src->signum / 8] &= ~tmp; else /* Set it */ sna->array[src->signum / 8] |= tmp; if (src->netmask == 32) node = SCRadixAddKeyIPV4((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, sna); else node = SCRadixAddKeyIPV4Netblock((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, sna, src->netmask); if (node == NULL) { char tmpstr[64]; PrintInet(src->family, &src->ip[0], tmpstr, sizeof(tmpstr)); SCLogError(SC_ERR_IPONLY_RADIX, "Error inserting in the" " src ipv4 radix tree ip %s netmask %"PRIu8, tmpstr, src->netmask); //SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4src); exit(-1); } } } else { SCLogDebug("Exact match found"); /* it's already inserted. Update it */ SigNumArray *sna = (SigNumArray *)node->prefix->user_data_result; /* Update the sig */ uint8_t tmp = 1 << (src->signum % 8); if (src->negated > 0) /* Unset it */ sna->array[src->signum / 8] &= ~tmp; else /* Set it */ sna->array[src->signum / 8] |= tmp; } } else if (src->family == AF_INET6) { SCLogDebug("To IPv6"); if (src->netmask == 128) node = SCRadixFindKeyIPV6ExactMatch((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src); else node = SCRadixFindKeyIPV6Netblock((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, src->netmask); if (node == NULL) { /* Not found, look if there's a subnet of this range with bigger netmask */ node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src); if (node == NULL) { /* Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); /* Update the sig */ uint8_t tmp = 1 << (src->signum % 8); if (src->negated > 0) /* Unset it */ sna->array[src->signum / 8] &= ~tmp; else /* Set it */ sna->array[src->signum / 8] |= tmp; if (src->netmask == 128) node = SCRadixAddKeyIPV6((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, sna); else node = SCRadixAddKeyIPV6Netblock((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, sna, src->netmask); if (node == NULL) SCLogError(SC_ERR_IPONLY_RADIX, "Error inserting in the src " "ipv6 radix tree"); } else { /* Found, copy the sig num table, add this signum and insert */ SigNumArray *sna = NULL; sna = SigNumArrayCopy((SigNumArray *)node->prefix->user_data_result); /* Update the sig */ uint8_t tmp = 1 << (src->signum % 8); if (src->negated > 0) /* Unset it */ sna->array[src->signum / 8] &= ~tmp; else /* Set it */ sna->array[src->signum / 8] |= tmp; if (src->netmask == 128) node = SCRadixAddKeyIPV6((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, sna); else node = SCRadixAddKeyIPV6Netblock((uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, sna, src->netmask); if (node == NULL) SCLogError(SC_ERR_IPONLY_RADIX, "Error inserting in the src " "ipv6 radix tree"); } } else { /* it's already inserted. Update it */ SigNumArray *sna = (SigNumArray *)node->prefix->user_data_result; /* Update the sig */ uint8_t tmp = 1 << (src->signum % 8); if (src->negated > 0) /* Unset it */ sna->array[src->signum / 8] &= ~tmp; else /* Set it */ sna->array[src->signum / 8] |= tmp; } } IPOnlyCIDRItem *tmpaux = src; src = src->next; SCFree(tmpaux); } SCLogDebug("dsts:"); /* Prepare Dst radix trees */ for (dst = (de_ctx->io_ctx).ip_dst; dst != NULL; ) { if (dst->family == AF_INET) { SCLogDebug("To IPv4"); SCLogDebug("Item has netmask %"PRIu16" negated: %s; IP: %s; signum:" " %"PRIu16"", dst->netmask, (dst->negated)?"yes":"no", inet_ntoa(*(struct in_addr*)&dst->ip[0]), dst->signum); if (dst->netmask == 32) node = SCRadixFindKeyIPV4ExactMatch((uint8_t *) &dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst); else node = SCRadixFindKeyIPV4Netblock((uint8_t *) &dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, dst->netmask); if (node == NULL) { SCLogDebug("Exact match not found"); /** * Not found, look if there's a subnet of this range * with bigger netmask */ node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst); if (node == NULL) { SCLogDebug("Best match not found"); /** Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); /** Update the sig */ uint8_t tmp = 1 << (dst->signum % 8); if (dst->negated > 0) /** Unset it */ sna->array[dst->signum / 8] &= ~tmp; else /** Set it */ sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 32) node = SCRadixAddKeyIPV4((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, sna); else node = SCRadixAddKeyIPV4Netblock((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, sna, dst->netmask); if (node == NULL) SCLogError(SC_ERR_IPONLY_RADIX, "Error inserting in the dst " "ipv4 radix tree"); } else { SCLogDebug("Best match found"); /* Found, copy the sig num table, add this signum and insert */ SigNumArray *sna = NULL; sna = SigNumArrayCopy((SigNumArray *)node->prefix->user_data_result); /* Update the sig */ uint8_t tmp = 1 << (dst->signum % 8); if (dst->negated > 0) /* Unset it */ sna->array[dst->signum / 8] &= ~tmp; else /* Set it */ sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 32) node = SCRadixAddKeyIPV4((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, sna); else node = SCRadixAddKeyIPV4Netblock((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, sna, dst->netmask); if (node == NULL) SCLogError(SC_ERR_IPONLY_RADIX, "Error inserting in the dst " "ipv4 radix tree"); } } else { SCLogDebug("Exact match found"); /* it's already inserted. Update it */ SigNumArray *sna = (SigNumArray *)node->prefix->user_data_result; /* Update the sig */ uint8_t tmp = 1 << (dst->signum % 8); if (dst->negated > 0) /* Unset it */ sna->array[dst->signum / 8] &= ~tmp; else /* Set it */ sna->array[dst->signum / 8] |= tmp; } } else if (dst->family == AF_INET6) { SCLogDebug("To IPv6"); if (dst->netmask == 128) node = SCRadixFindKeyIPV6ExactMatch((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst); else node = SCRadixFindKeyIPV6Netblock((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, dst->netmask); if (node == NULL) { /** Not found, look if there's a subnet of this range with * bigger netmask */ node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst); if (node == NULL) { /* Not found, insert a new one */ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx); /* Update the sig */ uint8_t tmp = 1 << (dst->signum % 8); if (dst->negated > 0) /* Unset it */ sna->array[dst->signum / 8] &= ~tmp; else /* Set it */ sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 128) node = SCRadixAddKeyIPV6((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, sna); else node = SCRadixAddKeyIPV6Netblock((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, sna, dst->netmask); if (node == NULL) SCLogError(SC_ERR_IPONLY_RADIX, "Error inserting in the dst " "ipv6 radix tree"); } else { /* Found, copy the sig num table, add this signum and insert */ SigNumArray *sna = NULL; sna = SigNumArrayCopy((SigNumArray *)node->prefix->user_data_result); /* Update the sig */ uint8_t tmp = 1 << (dst->signum % 8); if (dst->negated > 0) /* Unset it */ sna->array[dst->signum / 8] &= ~tmp; else /* Set it */ sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 128) node = SCRadixAddKeyIPV6((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, sna); else node = SCRadixAddKeyIPV6Netblock((uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, sna, dst->netmask); if (node == NULL) SCLogError(SC_ERR_IPONLY_RADIX, "Error inserting in the dst " "ipv6 radix tree"); } } else { /* it's already inserted. Update it */ SigNumArray *sna = (SigNumArray *)node->prefix->user_data_result; /* Update the sig */ uint8_t tmp = 1 << (dst->signum % 8); if (dst->negated > 0) /* Unset it */ sna->array[dst->signum / 8] &= ~tmp; else /* Set it */ sna->array[dst->signum / 8] |= tmp; } } IPOnlyCIDRItem *tmpaux = dst; dst = dst->next; SCFree(tmpaux); } /* print all the trees: for debuggin it might print too much info SCLogDebug("Radix tree src ipv4:"); SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4src); SCLogDebug("Radix tree src ipv6:"); SCRadixPrintTree((de_ctx->io_ctx).tree_ipv6src); SCLogDebug("__________________"); SCLogDebug("Radix tree dst ipv4:"); SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4dst); SCLogDebug("Radix tree dst ipv6:"); SCRadixPrintTree((de_ctx->io_ctx).tree_ipv6dst); SCLogDebug("__________________"); */ } /** * \brief Add a signature to the lists of Adrresses in CIDR format (sorted) * this step is necesary to build the radix tree with a hierarchical * relation between nodes * \param de_ctx Pointer to the current detection engine context * \param de_ctx Pointer to the current ip only detection engine contest * \param s Pointer to the current signature */ void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx, Signature *s) { if (!(s->flags & SIG_FLAG_IPONLY)) return; /* Set the internal signum to the list before merging */ IPOnlyCIDRListSetSigNum(s->CidrSrc, s->num); IPOnlyCIDRListSetSigNum(s->CidrDst, s->num); /** * ipv4 and ipv6 are mixed, but later we will separate them into * different trees */ io_ctx->ip_src = IPOnlyCIDRItemInsert(io_ctx->ip_src, s->CidrSrc); io_ctx->ip_dst = IPOnlyCIDRItemInsert(io_ctx->ip_dst, s->CidrDst); if (s->num > io_ctx->max_idx) io_ctx->max_idx = s->num; /* enable the sig in the bitarray */ io_ctx->sig_init_array[(s->num/8)] |= 1 << (s->num % 8); /** no longer ref to this, it's in the table now */ s->CidrSrc = NULL; s->CidrDst = NULL; } #ifdef UNITTESTS /** * \test check that we set a Signature as IPOnly because it has no rule * option appending a SigMatch and no port is fixed */ static int IPOnlyTestSig01(void) { int result = 0; DetectEngineCtx de_ctx; memset(&de_ctx, 0, sizeof(DetectEngineCtx)); de_ctx.flags |= DE_QUIET; Signature *s = SigInit(&de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-01 sig is IPOnly \"; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(&de_ctx, s)) result = 1; else printf("expected a IPOnly signature: "); SigFree(s); end: return result; } /** * \test check that we dont set a Signature as IPOnly because it has no rule * option appending a SigMatch but a port is fixed */ static int IPOnlyTestSig02 (void) { int result = 0; DetectEngineCtx de_ctx; memset (&de_ctx, 0, sizeof(DetectEngineCtx)); memset(&de_ctx, 0, sizeof(DetectEngineCtx)); de_ctx.flags |= DE_QUIET; Signature *s = SigInit(&de_ctx,"alert tcp any any -> any 80 (msg:\"SigTest40-02 sig is not IPOnly \"; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if ((SignatureIsIPOnly(&de_ctx, s))) result = 1; else printf("got a non-IPOnly signature: "); SigFree(s); end: return result; } /** * \test check that we set dont set a Signature as IPOnly * because it has rule options appending a SigMatch like content, and pcre */ static int IPOnlyTestSig03 (void) { int result = 1; DetectEngineCtx *de_ctx; Signature *s=NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; /* combination of pcre and content */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre and content) \"; content:\"php\"; pcre:\"/require(_once)?/i\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (content): "); result=0; } SigFree(s); /* content */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (content) \"; content:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (content): "); result=0; } SigFree(s); /* uricontent */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (uricontent) \"; uricontent:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (uricontent): "); result=0; } SigFree(s); /* pcre */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre) \"; pcre:\"/e?idps rule[sz]/i\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (pcre): "); result=0; } SigFree(s); /* flow */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flow) \"; flow:to_server; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (flow): "); result=0; } SigFree(s); /* dsize */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (dsize) \"; dsize:100; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (dsize): "); result=0; } SigFree(s); /* flowbits */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowbits) \"; flowbits:unset; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (flowbits): "); result=0; } SigFree(s); /* flowvar */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowvar) \"; pcre:\"/(?.*)/i\"; flowvar:var,\"str\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (flowvar): "); result=0; } SigFree(s); /* pktvar */ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pktvar) \"; pcre:\"/(?.*)/i\"; pktvar:var,\"str\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } if(SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (pktvar): "); result=0; } SigFree(s); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test */ static int IPOnlyTestSig04 (void) { int result = 1; IPOnlyCIDRItem *head = NULL; IPOnlyCIDRItem *new; new = IPOnlyCIDRItemNew(); new->netmask= 10; head = IPOnlyCIDRItemInsert(head, new); new = IPOnlyCIDRItemNew(); new->netmask= 11; head = IPOnlyCIDRItemInsert(head, new); new = IPOnlyCIDRItemNew(); new->netmask= 9; head = IPOnlyCIDRItemInsert(head, new); new = IPOnlyCIDRItemNew(); new->netmask= 10; head = IPOnlyCIDRItemInsert(head, new); new = IPOnlyCIDRItemNew(); new->netmask= 10; head = IPOnlyCIDRItemInsert(head, new); IPOnlyCIDRListPrint(head); new = head; if (new->netmask != 9) { result = 0; goto end; } new = new->next; if (new->netmask != 10) { result = 0; goto end; } new = new->next; if (new->netmask != 10) { result = 0; goto end; } new = new->next; if (new->netmask != 10) { result = 0; goto end; } new = new->next; if (new->netmask != 11) { result = 0; goto end; } end: IPOnlyCIDRListFree(head); return result; } /** * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ int IPOnlyTestSig05(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 1; uint8_t numsigs = 7; Packet *p[1]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); char *sigs[numsigs]; sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } /** * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ int IPOnlyTestSig06(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 1; uint8_t numsigs = 7; Packet *p[1]; p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "80.58.0.33", "195.235.113.3"); char *sigs[numsigs]; sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } /* \todo fix it. We have disabled this unittest because 599 exposes 608, * which is why these unittests fail. When we fix 608, we need to renable * these sigs */ #if 0 /** * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ int IPOnlyTestSig07(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 1; uint8_t numsigs = 7; Packet *p[1]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); char *sigs[numsigs]; sigs[0]= "alert tcp 192.168.1.5 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp [192.168.1.2,192.168.1.5,192.168.1.4] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)"; sigs[2]= "alert tcp [192.168.1.0/24,!192.168.1.1] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; sigs[3]= "alert tcp [192.0.0.0/8,!192.168.0.0/16,192.168.1.0/24,!192.168.1.1] any -> [192.168.1.0/24,!192.168.1.5] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; sigs[4]= "alert tcp any any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; sigs[5]= "alert tcp any any -> [192.168.0.0/16,!192.168.1.0/24,192.168.1.1] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; sigs[6]= "alert tcp [78.129.202.0/24,192.168.1.5,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> 192.168.1.1 any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */ /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } #endif /** * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ int IPOnlyTestSig08(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 1; uint8_t numsigs = 7; Packet *p[1]; p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"192.168.1.1","192.168.1.5"); char *sigs[numsigs]; sigs[0]= "alert tcp 192.168.1.5 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp [192.168.1.2,192.168.1.5,192.168.1.4] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)"; sigs[2]= "alert tcp [192.168.1.0/24,!192.168.1.1] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; sigs[3]= "alert tcp [192.0.0.0/8,!192.168.0.0/16,192.168.1.0/24,!192.168.1.1] any -> [192.168.1.0/24,!192.168.1.5] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; sigs[4]= "alert tcp any any -> !192.168.1.5 any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; sigs[5]= "alert tcp any any -> [192.168.0.0/16,!192.168.1.0/24,192.168.1.1] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; sigs[6]= "alert tcp [78.129.202.0/24,192.168.1.5,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> 192.168.1.1 any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */ /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } /** * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ int IPOnlyTestSig09(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 1; uint8_t numsigs = 7; Packet *p[1]; p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562"); char *sigs[numsigs]; sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; sigs[2]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; sigs[3]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:0/96 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; sigs[4]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; sigs[5]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; sigs[6]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } /** * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ int IPOnlyTestSig10(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 1; uint8_t numsigs = 7; Packet *p[1]; p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565"); char *sigs[numsigs]; sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; sigs[2]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; sigs[3]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> !3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562/96 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; sigs[4]= "alert tcp !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; sigs[5]= "alert tcp any any -> !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; sigs[6]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDB:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } /* \todo fix it. We have disabled this unittest because 599 exposes 608, * which is why these unittests fail. When we fix 608, we need to renable * these sigs */ #if 0 /** * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) with ipv4 and ipv6 mixed */ int IPOnlyTestSig11(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 2; uint8_t numsigs = 7; Packet *p[2]; p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562"); p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"192.168.1.1","192.168.1.5"); char *sigs[numsigs]; sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.5 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp [192.168.1.1,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.4,192.168.1.5,!192.168.1.0/24] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.0/24] any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)"; sigs[2]= "alert tcp [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; sigs[3]= "alert tcp [3FFE:FFFF:0:0:0:0:0:0/32,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.0/24,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; sigs[4]= "alert tcp any any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; sigs[5]= "alert tcp any any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; sigs[6]= "alert tcp [78.129.202.0/24,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.0.0.0/8] any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */ /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[2][7] = {{ 1, 1, 1, 1, 1, 1, 1}, { 1, 1, 1, 1, 1, 1, 1}}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } #endif /** * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) with ipv4 and ipv6 mixed */ int IPOnlyTestSig12(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 2; uint8_t numsigs = 7; Packet *p[2]; p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"3FBE:FFFF:7654:FEDA:1245:BA98:3210:4562","3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565"); p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"195.85.1.1","80.198.1.5"); char *sigs[numsigs]; sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.5 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp [192.168.1.1,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.4,192.168.1.5,!192.168.1.0/24] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.0/24] any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)"; sigs[2]= "alert tcp [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; sigs[3]= "alert tcp [3FFE:FFFF:0:0:0:0:0:0/32,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.0/24,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; sigs[4]= "alert tcp any any -> [!3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565,!80.198.1.5] any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; sigs[5]= "alert tcp any any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; sigs[6]= "alert tcp [78.129.202.0/24,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.0.0.0/8] any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */ /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[2][7] = {{ 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } static int IPOnlyTestSig13(void) { int result = 0; DetectEngineCtx de_ctx; memset(&de_ctx, 0, sizeof(DetectEngineCtx)); de_ctx.flags |= DE_QUIET; Signature *s = SigInit(&de_ctx, "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " "flowbits:set,myflow1; sid:1; rev:1;)"); if (s == NULL) { goto end; } if (SignatureIsIPOnly(&de_ctx, s)) result = 1; else printf("expected a IPOnly signature: "); SigFree(s); end: return result; } static int IPOnlyTestSig14(void) { int result = 0; DetectEngineCtx de_ctx; memset(&de_ctx, 0, sizeof(DetectEngineCtx)); de_ctx.flags |= DE_QUIET; Signature *s = SigInit(&de_ctx, "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " "flowbits:set,myflow1; flowbits:isset,myflow2; sid:1; rev:1;)"); if (s == NULL) { goto end; } if (SignatureIsIPOnly(&de_ctx, s)) printf("expected a IPOnly signature: "); else result = 1; SigFree(s); end: return result; } int IPOnlyTestSig15(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 1; uint8_t numsigs = 7; Packet *p[1]; Flow f; GenericVar flowvar; memset(&f, 0, sizeof(Flow)); memset(&flowvar, 0, sizeof(GenericVar)); FLOW_INITIALIZE(&f); p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[0]->flow = &f; p[0]->flow->flowvar = &flowvar; p[0]->flags |= PKT_HAS_FLOW; p[0]->flowflags |= FLOW_PKT_TOSERVER; char *sigs[numsigs]; sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; " "flowbits:set,one; sid:1;)"; sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; " "flowbits:set,two; sid:2;)"; sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; " "flowbits:set,three; sid:3;)"; sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; " "flowbits:set,four; sid:4;)"; sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; " "flowbits:set,five; sid:5;)"; sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; " "flowbits:set,six; sid:6;)"; sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; " "flowbits:set,seven; content:\"Hi all\"; sid:7;)"; /* Sid numbers (we could extract them from the sig) */ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); FLOW_DESTROY(&f); return result; } /** * \brief Unittest to show #599. We fail to match if we have negated addresses. */ int IPOnlyTestSig16(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); uint8_t numpkts = 1; uint8_t numsigs = 2; Packet *p[1]; p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "100.100.0.0", "50.0.0.0"); char *sigs[numsigs]; sigs[0]= "alert tcp !100.100.0.1 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; sigs[1]= "alert tcp any any -> !50.0.0.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; /* Sid numbers (we could extract them from the sig) */ uint32_t sid[2] = { 1, 2}; uint32_t results[2] = { 1, 1}; result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); UTHFreePackets(p, numpkts); return result; } #endif /* UNITTESTS */ void IPOnlyRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("IPOnlyTestSig01", IPOnlyTestSig01, 1); UtRegisterTest("IPOnlyTestSig02", IPOnlyTestSig02, 1); UtRegisterTest("IPOnlyTestSig03", IPOnlyTestSig03, 1); UtRegisterTest("IPOnlyTestSig04", IPOnlyTestSig04, 1); UtRegisterTest("IPOnlyTestSig05", IPOnlyTestSig05, 1); UtRegisterTest("IPOnlyTestSig06", IPOnlyTestSig06, 1); /* \todo fix it. We have disabled this unittest because 599 exposes 608, * which is why these unittests fail. When we fix 608, we need to renable * these sigs */ #if 0 UtRegisterTest("IPOnlyTestSig07", IPOnlyTestSig07, 1); #endif UtRegisterTest("IPOnlyTestSig08", IPOnlyTestSig08, 1); UtRegisterTest("IPOnlyTestSig09", IPOnlyTestSig09, 1); UtRegisterTest("IPOnlyTestSig10", IPOnlyTestSig10, 1); /* \todo fix it. We have disabled this unittest because 599 exposes 608, * which is why these unittests fail. When we fix 608, we need to renable * these sigs */ #if 0 UtRegisterTest("IPOnlyTestSig11", IPOnlyTestSig11, 1); #endif UtRegisterTest("IPOnlyTestSig12", IPOnlyTestSig12, 1); UtRegisterTest("IPOnlyTestSig13", IPOnlyTestSig13, 1); UtRegisterTest("IPOnlyTestSig14", IPOnlyTestSig14, 1); UtRegisterTest("IPOnlyTestSig15", IPOnlyTestSig15, 1); UtRegisterTest("IPOnlyTestSig16", IPOnlyTestSig16, 1); #endif return; } suricata-1.4.7/src/util-cuda-handlers.h0000644000000000000000000000750712253546156014674 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file Provides cuda utility functions. * * \author Anoop Saldanha */ /* macros decides if cuda is enabled for the platform or not */ #ifdef __SC_CUDA_SUPPORT__ #include #ifndef __UTIL_MPM_CUDA_HANDLERS_H__ #define __UTIL_MPM_CUDA_HANDLERS_H__ typedef enum { SC_CUDA_HL_MTYPE_RULE_NONE = -1, SC_CUDA_HL_MTYPE_RULE_CONTENTS = 0, SC_CUDA_HL_MTYPE_RULE_URICONTENTS, SC_CUDA_HL_MTYPE_APP_LAYER, SC_CUDA_HL_MTYPE_RULE_CUSTOM, SC_CUDA_HL_MTYPE_MAX, } SCCudaHlModuleType; typedef struct SCCudaHlModuleDevicePointer_ { /* device pointer name. This is a primary key. For the same module you * can't register different device pointers */ char *name; CUdeviceptr d_ptr; struct SCCudaHlModuleDevicePointer_ *next; } SCCudaHlModuleDevicePointer; typedef struct SCCudaHlModuleCUmodule_ { /* Handle for this CUmodule. This has to be first obtained from the * call to SCCudaHlGetCudaModule() or SCCudaHlGetCudaModuleFromFile() */ int cuda_module_handle; CUmodule cuda_module; SCCudaHlModuleDevicePointer *device_ptrs; struct SCCudaHlModuleCUmodule_ *next; } SCCudaHlModuleCUmodule; typedef struct SCCudaHlModuleData_ { /* The unique module handle. This has to be first obtained from the * call to SCCudaHlGetUniqueHandle() */ const char *name; int handle; CUcontext cuda_context; SCCudaHlModuleCUmodule *cuda_modules; void *(*SCCudaHlDispFunc)(void *); struct SCCudaHlModuleData_ *next; } SCCudaHlModuleData; /** * \brief Used to hold the cuda configuration from our conf yaml file */ typedef struct SCCudaHlCudaProfile_ { /* profile name. Should be unique */ char *name; /* the data associated with this profile */ void *data; struct SCCudaHlCudaProfile_ *next; } SCCudaHlCudaProfile; void SCCudaHlGetYamlConf(void); void *SCCudaHlGetProfile(char *); void SCCudaHlCleanProfiles(void); void SCCudaHlBackupRegisteredProfiles(void); void SCCudaHlRestoreBackupRegisteredProfiles(void); int SCCudaHlGetCudaContext(CUcontext *, char *, int); int SCCudaHlGetCudaModule(CUmodule *, const char *, int); int SCCudaHlGetCudaModuleFromFile(CUmodule *, const char *, int); int SCCudaHlGetCudaDevicePtr(CUdeviceptr *, const char *, size_t, void *, int, int); int SCCudaHlFreeCudaDevicePtr(const char *, int, int); int SCCudaHlRegisterDispatcherFunc(void *(*SCCudaHlDispFunc)(void *), int); SCCudaHlModuleData *SCCudaHlGetModuleData(uint8_t); const char *SCCudaHlGetModuleName(int); int SCCudaHlGetModuleHandle(const char *); int SCCudaHlRegisterModule(const char *); int SCCudaHlDeRegisterModule(const char *); void SCCudaHlDeRegisterAllRegisteredModules(void); int SCCudaHlPushCudaContextFromModule(const char *); int SCCudaHlTestEnvCudaContextInit(void); int SCCudaHlTestEnvCudaContextDeInit(void); void SCCudaHlProcessPacketWithDispatcher(Packet *, DetectEngineThreadCtx *, void *); void SCCudaHlProcessUriWithDispatcher(uint8_t *, uint16_t, DetectEngineThreadCtx *, void *); #endif /* __UTIL_CUDA_HANDLERS__ */ #endif /* __SC_CUDA_SUPPORT__ */ suricata-1.4.7/src/decode-ipv6.c0000644000000000000000000010757212253546156013312 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Victor Julien * * Decode IPv6 */ #include "suricata-common.h" #include "packet-queue.h" #include "decode.h" #include "decode-ipv6.h" #include "decode-icmpv6.h" #include "decode-events.h" #include "defrag.h" #include "pkt-var.h" #include "util-debug.h" #include "util-print.h" #include "util-unittest.h" #define IPV6_EXTHDRS ip6eh.ip6_exthdrs #define IPV6_EH_CNT ip6eh.ip6_exthdrs_cnt /** * \brief Function to decode IPv4 in IPv6 packets * */ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t plen, PacketQueue *pq) { if (unlikely(plen < IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p, IPV4_IN_IPV6_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 4) { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt, plen, IPPROTO_IP); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IP); PacketEnqueue(pq,tp); SCPerfCounterIncr(dtv->counter_ipv4inipv6, tv->sc_perf_pca); return; } } } else { ENGINE_SET_EVENT(p, IPV4_IN_IPV6_WRONG_IP_VER); } return; } /** * \brief Function to decode IPv4 in IPv6 packets * */ static void DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t plen, PacketQueue *pq) { if (unlikely(plen < IPV6_HEADER_LEN)) { ENGINE_SET_EVENT(p, IPV6_IN_IPV6_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 6) { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt, plen, IPPROTO_IPV6); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IPV6); PacketEnqueue(pq,tp); SCPerfCounterIncr(dtv->counter_ipv6inipv6, tv->sc_perf_pca); return; } } } else { ENGINE_SET_EVENT(p, IPV6_IN_IPV6_WRONG_IP_VER); } return; } static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCEnter(); uint8_t *orig_pkt = pkt; uint8_t nh; uint16_t hdrextlen; uint16_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 */ SCReturn; } switch(nh) { case IPPROTO_TCP: IPV6_SET_L4PROTO(p,nh); DecodeTCP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_UDP: IPV6_SET_L4PROTO(p,nh); DecodeUDP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_ICMPV6: IPV6_SET_L4PROTO(p,nh); DecodeICMPV6(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_SCTP: IPV6_SET_L4PROTO(p,nh); DecodeSCTP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_ROUTING: IPV6_SET_L4PROTO(p,nh); hdrextlen = 8 + (*(pkt+1) * 8); /* 8 bytes + length in 8 octet units */ SCLogDebug("hdrextlen %"PRIu8, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } 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)) { ENGINE_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; /** \todo move into own function and load on demand */ if (IPV6_EXTHDR_RH(p)->ip6rh_type == 0) { uint8_t i; uint8_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 */ /** \todo 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; uint8_t optslen = 0; IPV6_SET_L4PROTO(p,nh); hdrextlen = (*(pkt+1) + 1) << 3; if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } 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++; } uint8_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)) { ENGINE_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 { ENGINE_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. */ ENGINE_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; } /** \todo move into own function to loaded on demand */ uint16_t padn_cnt = 0; uint16_t other_cnt = 0; uint16_t offset = 0; while(offset < optslen) { if (*ptr == IPV6OPT_PADN) /* PadN */ { //printf("PadN option\n"); padn_cnt++; } 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 %" PRIu32 " len %" PRIu32 " value %" PRIu32 "\n", // ra->ip6ra_type, ra->ip6ra_len, ra->ip6ra_value); other_cnt++; } 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 %" PRIu32 " len %" PRIu32 " payload len %" PRIu32 "\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 %" PRIu32 " len %" PRIu32 " ", // hao->ip6hao_type, hao->ip6hao_len); //char addr_buf[46]; //PrintInet(AF_INET6, (char *)&(hao->ip6hao_hoa), // addr_buf,sizeof(addr_buf)); //printf("home addr %s\n", addr_buf); other_cnt++; } else { if (nh == IPPROTO_HOPOPTS) ENGINE_SET_EVENT(p, IPV6_HOPOPTS_UNKNOWN_OPT); else ENGINE_SET_EVENT(p, IPV6_DSTOPTS_UNKNOWN_OPT); other_cnt++; } uint16_t optlen = (*(ptr + 1) + 2); ptr += optlen; /* +2 for opt type and opt len fields */ offset += optlen; } /* flag packets that have only padding */ if (padn_cnt > 0 && other_cnt == 0) { if (nh == IPPROTO_HOPOPTS) ENGINE_SET_EVENT(p, IPV6_HOPOPTS_ONLY_PADDING); else ENGINE_SET_EVENT(p, IPV6_DSTOPTS_ONLY_PADDING); } nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_FRAGMENT: IPV6_SET_L4PROTO(p,nh); /* 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) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if(p->IPV6_EH_CNTIPV6_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)) { ENGINE_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); /* if FH has offset 0 and no more fragments are coming, we * parse this packet further right away, no defrag will be * needed. It is a useless FH then though, so we do set an * decoder event. */ if (IPV6_EXTHDR_GET_FH_FLAG(p) == 0 && IPV6_EXTHDR_GET_FH_OFFSET(p) == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /* the rest is parsed upon reassembly */ p->flags |= PKT_IS_FRAGMENT; SCReturn; case IPPROTO_ESP: { IPV6_SET_L4PROTO(p,nh); hdrextlen = sizeof(IPV6EspHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if(p->IPV6_EH_CNTIPV6_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)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH); SCReturn; } IPV6_EXTHDR_SET_EH(p, pkt); nh = IPPROTO_NONE; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_AH: { IPV6_SET_L4PROTO(p,nh); /* we need the header as a minimum */ hdrextlen = sizeof(IPV6AuthHdr); /* the payload len field is the number of extra 4 byte fields, * IPV6AuthHdr already contains the first */ if (*(pkt+1) > 0) hdrextlen += ((*(pkt+1) - 1) * 4); SCLogDebug("hdrextlen %"PRIu8, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } IPV6AuthHdr *ahhdr = (IPV6AuthHdr *)pkt; if (ahhdr->ip6ah_reserved != 0x0000) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_AH_RES_NOT_NULL); } 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)) { ENGINE_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_IPIP: IPV6_SET_L4PROTO(p,nh); DecodeIPv4inIPv6(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_NONE: IPV6_SET_L4PROTO(p,nh); SCReturn; case IPPROTO_ICMP: ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4); SCReturn; default: IPV6_SET_L4PROTO(p,nh); SCReturn; } } SCReturn; } static int DecodeIPV6Packet (ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len) { if (len < IPV6_HEADER_LEN) { return -1; } if (IP_GET_RAW_VER(pkt) != 6) { SCLogDebug("wrong ip version %" PRIu8 "",IP_GET_RAW_VER(pkt)); ENGINE_SET_EVENT(p,IPV6_WRONG_IP_VER); return -1; } p->ip6h = (IPV6Hdr *)pkt; if (len < (IPV6_HEADER_LEN + IPV6_GET_PLEN(p))) { ENGINE_SET_EVENT(p,IPV6_TRUNC_PKT); return -1; } SET_IPV6_SRC_ADDR(p,&p->src); SET_IPV6_DST_ADDR(p,&p->dst); return 0; } void DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int ret; SCPerfCounterIncr(dtv->counter_ipv6, tv->sc_perf_pca); /* do the actual decoding */ ret = DecodeIPV6Packet (tv, dtv, p, pkt, len); if (ret < 0) { p->ip6h = NULL; return; } #ifdef DEBUG if (SCLogDebugEnabled()) { /* only convert the addresses if debug is really enabled */ /* debug print */ char s[46], d[46]; PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), s, sizeof(s)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), d, sizeof(d)); SCLogDebug("IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: %" PRIu32 " NH: %" PRIu32 " PLEN: %" PRIu32 " HLIM: %" PRIu32 "", s,d, IPV6_GET_CLASS(p), IPV6_GET_FLOW(p), IPV6_GET_NH(p), IPV6_GET_PLEN(p), IPV6_GET_HLIM(p)); } #endif /* DEBUG */ /* now process the Ext headers and/or the L4 Layer */ switch(IPV6_GET_NH(p)) { case IPPROTO_TCP: IPV6_SET_L4PROTO (p, IPPROTO_TCP); DecodeTCP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return; case IPPROTO_UDP: IPV6_SET_L4PROTO (p, IPPROTO_UDP); DecodeUDP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return; break; case IPPROTO_ICMPV6: IPV6_SET_L4PROTO (p, IPPROTO_ICMPV6); DecodeICMPV6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return; case IPPROTO_SCTP: IPV6_SET_L4PROTO (p, IPPROTO_SCTP); DecodeSCTP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return; case IPPROTO_IPIP: IPV6_SET_L4PROTO(p, IPPROTO_IPIP); DecodeIPv4inIPv6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return; case IPPROTO_IPV6: DecodeIP6inIP6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return; case IPPROTO_FRAGMENT: case IPPROTO_HOPOPTS: case IPPROTO_ROUTING: case IPPROTO_NONE: case IPPROTO_DSTOPTS: case IPPROTO_AH: case IPPROTO_ESP: DecodeIPV6ExtHdrs(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); break; case IPPROTO_ICMP: ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4); break; default: IPV6_SET_L4PROTO (p, IPV6_GET_NH(p)); break; } p->proto = IPV6_GET_L4PROTO (p); /* Pass to defragger if a fragment. */ if (IPV6_EXTHDR_ISSET_FH(p)) { Packet *rp = Defrag(tv, dtv, p); if (rp != NULL) { DecodeIPV6(tv, dtv, rp, (uint8_t *)rp->ip6h, IPV6_GET_PLEN(rp) + IPV6_HEADER_LEN, pq); PacketEnqueue(pq, rp); /* Not really a tunnel packet, but we're piggybacking that * functionality for now. */ SET_TUNNEL_PKT(p); } } #ifdef DEBUG if (IPV6_EXTHDR_ISSET_FH(p)) { SCLogDebug("IPV6 FRAG - HDRLEN: %" PRIuMAX " NH: %" PRIu32 " OFFSET: %" PRIu32 " ID: %" PRIu32 "", (uintmax_t)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)) { SCLogDebug("IPV6 ROUTE - HDRLEN: %" PRIu32 " NH: %" PRIu32 " TYPE: %" PRIu32 "", IPV6_EXTHDR_GET_RH_HDRLEN(p), IPV6_EXTHDR_GET_RH_NH(p), IPV6_EXTHDR_GET_RH_TYPE(p)); } if (IPV6_EXTHDR_ISSET_HH(p)) { SCLogDebug("IPV6 HOPOPT - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", IPV6_EXTHDR_GET_HH_HDRLEN(p), IPV6_EXTHDR_GET_HH_NH(p)); } if (IPV6_EXTHDR_ISSET_DH1(p)) { SCLogDebug("IPV6 DSTOPT1 - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", IPV6_EXTHDR_GET_DH1_HDRLEN(p), IPV6_EXTHDR_GET_DH1_NH(p)); } if (IPV6_EXTHDR_ISSET_DH2(p)) { SCLogDebug("IPV6 DSTOPT2 - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", IPV6_EXTHDR_GET_DH2_HDRLEN(p), IPV6_EXTHDR_GET_DH2_NH(p)); } #endif return; } #ifdef UNITTESTS /** * \test fragment decoding */ static int DecodeIPV6FragTest01 (void) { uint8_t raw_frag1[] = { 0x60, 0x0f, 0x1a, 0xcf, 0x05, 0xa8, 0x2c, 0x36, 0x20, 0x01, 0x04, 0x70, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x09, 0x80, 0x32, 0xb2, 0x00, 0x01, 0x2e, 0x41, 0x38, 0xff, 0xfe, 0xa7, 0xea, 0xeb, 0x06, 0x00, 0x00, 0x01, 0xdf, 0xf8, 0x11, 0xd7, 0x00, 0x50, 0xa6, 0x5c, 0xcc, 0xd7, 0x28, 0x9f, 0xc3, 0x34, 0xc6, 0x58, 0x80, 0x10, 0x20, 0x13, 0x18, 0x1f, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0xcd, 0xf9, 0x3a, 0x41, 0x00, 0x1a, 0x91, 0x8a, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x30, 0x32, 0x20, 0x44, 0x65, 0x63, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20, 0x30, 0x38, 0x3a, 0x33, 0x32, 0x3a, 0x35, 0x37, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x0d, 0x0a, 0x50, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x3a, 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x0d, 0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x3a, 0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30, 0x31, 0x20, 0x4a, 0x61, 0x6e, 0x20, 0x31, 0x39, 0x37, 0x31, 0x20, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x31, 0x35, 0x39, 0x39, 0x0d, 0x0a, 0x4b, 0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x3a, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x3d, 0x35, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x3d, 0x39, 0x39, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, 0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x61, 0x73, 0x63, 0x69, 0x69, 0x0d, 0x0a, 0x0d, 0x0a, 0x5f, 0x6a, 0x71, 0x6a, 0x73, 0x70, 0x28, 0x7b, 0x22, 0x69, 0x70, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x30, 0x31, 0x3a, 0x39, 0x38, 0x30, 0x3a, 0x33, 0x32, 0x62, 0x32, 0x3a, 0x31, 0x3a, 0x32, 0x65, 0x34, 0x31, 0x3a, 0x33, 0x38, 0x66, 0x66, 0x3a, 0x66, 0x65, 0x61, 0x37, 0x3a, 0x65, 0x61, 0x65, 0x62, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x70, 0x76, 0x36, 0x22, 0x2c, 0x22, 0x73, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x76, 0x69, 0x61, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, }; uint8_t raw_frag2[] = { 0x60, 0x0f, 0x1a, 0xcf, 0x00, 0x1c, 0x2c, 0x36, 0x20, 0x01, 0x04, 0x70, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x09, 0x80, 0x32, 0xb2, 0x00, 0x01, 0x2e, 0x41, 0x38, 0xff, 0xfe, 0xa7, 0xea, 0xeb, 0x06, 0x00, 0x05, 0xa0, 0xdf, 0xf8, 0x11, 0xd7, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, }; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars tv; DecodeThreadVars dtv; int result = 0; PacketQueue pq; FlowInitConfig(FLOW_QUIET); DefragInit(); memset(&pq, 0, sizeof(PacketQueue)); memset(&tv, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); PACKET_INITIALIZE(p1); PACKET_INITIALIZE(p2); PacketCopyData(p1, raw_frag1, sizeof(raw_frag1)); PacketCopyData(p2, raw_frag2, sizeof(raw_frag2)); DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1), &pq); if (!(IPV6_EXTHDR_ISSET_FH(p1))) { printf("ipv6 frag header not detected: "); goto end; } DecodeIPV6(&tv, &dtv, p2, GET_PKT_DATA(p2), GET_PKT_LEN(p2), &pq); if (!(IPV6_EXTHDR_ISSET_FH(p2))) { printf("ipv6 frag header not detected: "); goto end; } if (pq.len != 1) { printf("no reassembled packet: "); goto end; } result = 1; end: PACKET_CLEANUP(p1); PACKET_CLEANUP(p2); SCFree(p1); SCFree(p2); DefragDestroy(); FlowShutdown(); return result; } /** * \test routing header decode */ static int DecodeIPV6RouteTest01 (void) { uint8_t raw_pkt1[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x2b, 0x40, 0x20, 0x01, 0xaa, 0xaa, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xaa, 0xaa, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xed, 0x00, 0x50, 0x1b, 0xc7, 0x6a, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x20, 0x00, 0xfa, 0x87, 0x00, 0x00, }; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int result = 0; PacketQueue pq; FlowInitConfig(FLOW_QUIET); memset(&pq, 0, sizeof(PacketQueue)); memset(&tv, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); PACKET_INITIALIZE(p1); PacketCopyData(p1, raw_pkt1, sizeof(raw_pkt1)); DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1), &pq); if (!(IPV6_EXTHDR_ISSET_RH(p1))) { printf("ipv6 routing header not detected: "); goto end; } if (p1->ip6eh.ip6_exthdrs[0].len != 8) { printf("ipv6 routing length incorrect: "); goto end; } result = 1; end: PACKET_CLEANUP(p1); SCFree(p1); FlowShutdown(); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for IPV6 decoder */ void DecodeIPV6RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeIPV6FragTest01", DecodeIPV6FragTest01, 1); UtRegisterTest("DecodeIPV6RouteTest01", DecodeIPV6RouteTest01, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/util-rohash.c0000644000000000000000000001572612253546156013443 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Chained read only hash table implementation, meaning that * after the initial fill no changes are allowed. * * Loading takes 2 stages. * - stage1 maps data * - stage2 fills blob * * \todo a bloomfilter in the ROHashTableOffsets could possibly prevent * a lot of cache misses when validating a potential match * * \todo maybe add a user ctx to be returned instead, something like a * 4/8 byte ptr or simply a flag */ #include "suricata-common.h" #include "util-hash.h" #include "util-unittest.h" #include "util-memcmp.h" #include "util-hash-lookup3.h" #include "queue.h" #include "util-rohash.h" /** item_size data beyond this header */ typedef struct ROHashTableItem_ { uint32_t pos; /**< position relative to other values with same hash */ TAILQ_ENTRY(ROHashTableItem_) next; } ROHashTableItem; /** offset table */ typedef struct ROHashTableOffsets_ { uint32_t cnt; /**< number of items for this hash */ uint32_t offset; /**< position in the blob of the first item */ } ROHashTableOffsets; /** \brief initialize a new rohash * * \param hash_bits hash size as 2^hash_bits, so power of 2 * \param item_size size of the data to store * * \retval table ptr or NULL on error */ ROHashTable *ROHashInit(uint8_t hash_bits, uint16_t item_size) { if (item_size % 4 != 0 || item_size == 0) { SCLogError(SC_ERR_HASH_TABLE_INIT, "data size must be multiple of 4"); return NULL; } if (hash_bits < 4 || hash_bits > 32) { SCLogError(SC_ERR_HASH_TABLE_INIT, "invalid hash_bits setting, valid range is 4-32"); return NULL; } uint32_t size = hashsize(hash_bits) * sizeof(ROHashTableOffsets); ROHashTable *table = SCMalloc(sizeof(ROHashTable) + size); if (unlikely(table == NULL)) { SCLogError(SC_ERR_HASH_TABLE_INIT, "failed to alloc memory"); return NULL; } memset(table, 0, sizeof(ROHashTable) + size); table->items = 0; table->item_size = item_size; table->hash_bits = hash_bits; TAILQ_INIT(&table->head); return table; } void ROHashFree(ROHashTable *table) { if (table != NULL) { if (table->data != NULL) { SCFree(table->data); } SCFree(table); } } uint32_t ROHashMemorySize(ROHashTable *table) { return (uint32_t)(hashsize(table->hash_bits) * sizeof(ROHashTableOffsets) + table->items * table->item_size + sizeof(ROHashTable)); } /** * \retval NULL not found * \retval ptr found */ void *ROHashLookup(ROHashTable *table, void *data, uint16_t size) { if (data == NULL || size != table->item_size) { SCReturnPtr(NULL, "void"); } uint32_t hash = hashword(data, table->item_size/4, 0) & hashmask(table->hash_bits); /* get offsets start */ ROHashTableOffsets *os = (void *)table + sizeof(ROHashTable); ROHashTableOffsets *o = &os[hash]; /* no matches */ if (o->cnt == 0) { SCReturnPtr(NULL, "void"); } uint32_t u; for (u = 0; u < o->cnt; u++) { uint32_t offset = (o->offset + u) * table->item_size; if (SCMemcmp(table->data + offset, data, table->item_size) == 0) { SCReturnPtr(table->data + offset, "void"); } } SCReturnPtr(NULL, "void"); } /** \brief Add a new value to the hash * * \note can only be done when table isn't in a locked state yet * * \param table the hash table * \param value value to add * \param size value size. *MUST* match table item_size * * \retval 0 error * \retval 1 ok */ int ROHashInitQueueValue(ROHashTable *table, void *value, uint16_t size) { if (table->locked) { SCLogError(SC_ERR_HASH_TABLE_INIT, "can't add value to locked table"); return 0; } if (table->item_size != size) { SCLogError(SC_ERR_HASH_TABLE_INIT, "wrong size for data %u != %u", size, table->item_size); return 0; } ROHashTableItem *item = SCMalloc(sizeof(ROHashTableItem) + table->item_size); if (item != NULL) { memset(item, 0x00, sizeof(ROHashTableItem)); memcpy((void *)item + sizeof(ROHashTableItem), value, table->item_size); TAILQ_INSERT_TAIL(&table->head, item, next); return 1; } return 0; } /** \brief create final hash data structure * * \param table the hash table * * \retval 0 error * \retval 1 ok * * \note after this call the nothing can be added to the hash anymore. */ int ROHashInitFinalize(ROHashTable *table) { if (table->locked) { SCLogError(SC_ERR_HASH_TABLE_INIT, "table already locked"); return 0; } ROHashTableItem *item = NULL; ROHashTableOffsets *os = (void *)table + sizeof(ROHashTable); /* count items per hash value */ TAILQ_FOREACH(item, &table->head, next) { uint32_t hash = hashword((void *)item + sizeof(*item), table->item_size/4, 0) & hashmask(table->hash_bits); ROHashTableOffsets *o = &os[hash]; item->pos = o->cnt; o->cnt++; table->items++; } if (table->items == 0) { SCLogError(SC_ERR_HASH_TABLE_INIT, "no items"); return 0; } /* get the data block */ uint32_t newsize = table->items * table->item_size; table->data = SCMalloc(newsize); if (table->data == NULL) { SCLogError(SC_ERR_HASH_TABLE_INIT, "failed to alloc memory"); return 0; } memset(table->data, 0x00, newsize); /* calc offsets into the block per hash value */ uint32_t total = 0; uint32_t x; for (x = 0; x < hashsize(table->hash_bits); x++) { ROHashTableOffsets *o = &os[x]; if (o->cnt == 0) continue; o->offset = total; total += o->cnt; } /* copy each value into the data block */ TAILQ_FOREACH(item, &table->head, next) { uint32_t hash = hashword((void *)item + sizeof(*item), table->item_size/4, 0) & hashmask(table->hash_bits); ROHashTableOffsets *o = &os[hash]; uint32_t offset = (o->offset + item->pos) * table->item_size; memcpy(table->data + offset, (void *)item + sizeof(*item), table->item_size); } /* clean up temp items */ while ((item = TAILQ_FIRST(&table->head))) { TAILQ_REMOVE(&table->head, item, next); SCFree(item); } table->locked = 1; return 1; } suricata-1.4.7/src/detect-l3proto.c0000644000000000000000000002506312253546156014047 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond * * * Implements the l3_proto keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-ipproto.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-siggroup.h" #include "detect-engine-address.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" static int DetectL3ProtoSetup(DetectEngineCtx *, Signature *, char *); void DetectL3protoRegisterTests(void); void DetectL3ProtoRegister(void) { sigmatch_table[DETECT_L3PROTO].name = "l3_proto"; sigmatch_table[DETECT_L3PROTO].Match = NULL; sigmatch_table[DETECT_L3PROTO].Setup = DetectL3ProtoSetup; sigmatch_table[DETECT_L3PROTO].Free = NULL; sigmatch_table[DETECT_L3PROTO].RegisterTests = DetectL3protoRegisterTests; return; } /** * \internal * \brief Setup l3_proto keyword. * * \param de_ctx Detection engine context * \param s Signature * \param optstr Options string * * \return Non-zero on error */ static int DetectL3ProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { char *str = optstr; char dubbed = 0; /* strip "'s */ if (optstr[0] == '\"' && optstr[strlen(optstr) - 1] == '\"') { str = SCStrdup(optstr + 1); if (unlikely(str == NULL)) goto error; str[strlen(optstr) - 2] = '\0'; dubbed = 1; } /* reset possible any value */ if (s->proto.flags & DETECT_PROTO_ANY) { s->proto.flags &= ~DETECT_PROTO_ANY; } /* authorized value, ip, any, ip4, ipv4, ip6, ipv6 */ if (strcasecmp(str,"ipv4") == 0 || strcasecmp(str,"ip4") == 0 ) { if (s->proto.flags & DETECT_PROTO_IPV6) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Conflicting l3 proto specified"); goto error; } s->proto.flags |= DETECT_PROTO_IPV4; SCLogDebug("IPv4 protocol detected"); } else if (strcasecmp(str,"ipv6") == 0 || strcasecmp(str,"ip6") == 0 ) { if (s->proto.flags & DETECT_PROTO_IPV6) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Conflicting l3 proto specified"); goto error; } s->proto.flags |= DETECT_PROTO_IPV6; SCLogDebug("IPv6 protocol detected"); } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid l3 proto: \"%s\"", str); goto error; } if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; } #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" /** * \test DetectL3protoTestSig01 is a test for checking the working of ttl keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. */ static int DetectL3protoTestSig1(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; IPV4Hdr ip4h; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->ip4h = &ip4h; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv4\"; l3_proto:ipv4; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv6\"; l3_proto:ipv6; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip4\"; l3_proto:ip4; sid:3;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip6\"; l3_proto:ip6; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { printf("sid 1 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 2)) { printf("sid 2 alerted, but should not have: "); goto cleanup; } else if (PacketAlertCheck(p, 3) == 0) { printf("sid 3 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 4)) { printf("sid 4 alerted, but should not have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p); return result; } /** * \test DetectL3protoTestSig02 is a test for checking the working of l3proto keyword * by setting up the signature and later testing its working by matching * the received IPv6 packet against the sig. */ static int DetectL3protoTestSig2(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; IPV6Hdr ip6h; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET6; p->dst.family = AF_INET6; p->proto = IPPROTO_TCP; p->ip6h = &ip6h; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv4\"; l3_proto:ipv4; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv6\"; l3_proto:ipv6; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip4\"; l3_proto:ip4; sid:3;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip6\"; l3_proto:ip6; sid:4;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 alerted, but should not have: "); goto cleanup; } else if (PacketAlertCheck(p, 2) == 0) { printf("sid 2 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 3)) { printf("sid 3 alerted, but should not have: "); goto cleanup; } else if (PacketAlertCheck(p, 4) == 0) { printf("sid 4 did not alert, but should have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p); return result; } /** * \test DetectL3protoTestSig03 is a test for checking the working of l3proto keyword * in conjonction with ip_proto keyword. */ static int DetectL3protoTestSig3(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; IPV6Hdr ip6h; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET6; p->dst.family = AF_INET6; p->proto = IPPROTO_TCP; p->ip6h = &ip6h; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv4 and ip_proto udp\"; l3_proto:ipv4; ip_proto:17; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv6 and ip_proto udp\"; l3_proto:ipv6; ip_proto:17; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip4 and ip_proto tcp\"; l3_proto:ipv4; ip_proto:6; sid:3;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv6 and ip_proto tcp\"; l3_proto:ipv6; ip_proto:6; sid:4;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 alerted, but should not have: "); goto cleanup; } else if (PacketAlertCheck(p, 2)) { printf("sid 2 alerted, but should not have: "); goto cleanup; } else if (PacketAlertCheck(p, 3)) { printf("sid 3 alerted, but should not have: "); goto cleanup; } else if (PacketAlertCheck(p, 4) == 0) { printf("sid 4 did not alert, but should have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectL3proto */ void DetectL3protoRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectL3protoTestSig1", DetectL3protoTestSig1, 1); UtRegisterTest("DetectL3protoTestSig2", DetectL3protoTestSig2, 1); UtRegisterTest("DetectL3protoTestSig3", DetectL3protoTestSig3, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-nocase.h0000644000000000000000000000163712253546156013723 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_NOCASE_H__ #define __DETECT_NOCASE_H__ /* prototypes */ void DetectNocaseRegister (void); #endif /* __DETECT_NOCASE_H__ */ suricata-1.4.7/src/util-bloomfilter.h0000644000000000000000000000365612253546156014501 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __BLOOMFILTER_H__ #define __BLOOMFILTER_H__ /* Bloom Filter structure */ typedef struct BloomFilter_ { uint8_t hash_iterations; uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t); uint32_t bitarray_size; uint8_t *bitarray; } BloomFilter; /* prototypes */ BloomFilter *BloomFilterInit(uint32_t, uint8_t, uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t)); void BloomFilterFree(BloomFilter *); void BloomFilterPrint(BloomFilter *); int BloomFilterAdd(BloomFilter *, void *, uint16_t); uint32_t BloomFilterMemoryCnt(BloomFilter *); uint32_t BloomFilterMemorySize(BloomFilter *); void BloomFilterRegisterTests(void); /** ----- Inline functions ---- */ static inline int BloomFilterTest(BloomFilter *, void *, uint16_t); static inline int BloomFilterTest(BloomFilter *bf, void *data, uint16_t datalen) { uint8_t iter = 0; uint32_t hash = 0; int hit = 1; for (iter = 0; iter < bf->hash_iterations; iter++) { hash = bf->Hash(data, datalen, iter, bf->bitarray_size); if (!(bf->bitarray[hash/8] & (1< */ #ifndef __DETECT_FRAGBITS_H__ #define __DETECT_FRAGBITS_H__ #include "decode-events.h" #include "decode-ipv4.h" #include "decode-tcp.h" /** * \struct DetectFragBitsData_ * DetectFragBitsData_ is used to store fragbits: input value */ /** * \typedef DetectFragBitsData * A typedef for DetectFragBitsData_ */ typedef struct DetectFragBitsData_ { uint16_t fragbits; /**< TCP fragbits */ uint8_t modifier; /**< !(1) +(2) *(3) modifiers */ } DetectFragBitsData; /** * Registration function for fragbits: keyword */ void DetectFragBitsRegister (void); /** * This function registers unit tests for FragBits */ void FragBitsRegisterTests(void); #endif /*__DETECT_FRAGBITS_H__ */ suricata-1.4.7/src/app-layer-parser.h0000644000000000000000000002673312253546156014375 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __APP_LAYER_PARSER_H__ #define __APP_LAYER_PARSER_H__ #include "decode-events.h" #include "util-file.h" /** Mapping between local parser id's (e.g. HTTP_FIELD_REQUEST_URI) and * the dynamically assigned (at registration) global parser id. */ typedef struct AppLayerLocalMap_ { uint16_t parser_id; } AppLayerLocalMap; /** \brief Mapping between ALPROTO_* and L7Parsers * * Map the proto to the parsers for the to_client and to_server directions. */ typedef struct AppLayerProto_ { char *name; /**< name of the registered proto */ uint16_t to_server; uint16_t to_client; uint16_t map_size; char logger; /**< does this proto have a logger enabled? */ AppLayerLocalMap **map; void *(*StateAlloc)(void); void (*StateFree)(void *); void (*StateUpdateTransactionId)(void *, uint16_t *); void (*StateTransactionFree)(void *, uint16_t); void *(*LocalStorageAlloc)(void); void (*LocalStorageFree)(void *); /** truncate state after a gap/depth event */ void (*Truncate)(void *, uint8_t); FileContainer *(*StateGetFiles)(void *, uint8_t); } AppLayerProto; /** flags for the result elmts */ #define ALP_RESULT_ELMT_ALLOC 0x01 /** \brief Result elements for the parser */ typedef struct AppLayerParserResultElmt_ { uint16_t flags; /* flags. E.g. local alloc */ uint16_t name_idx; /* idx for names like "http.request_line.uri" */ uint32_t data_len; /* length of the data from the ptr */ uint8_t *data_ptr; /* point to the position in the "input" data * or ptr to new mem if local alloc flag set */ struct AppLayerParserResultElmt_ *next; } AppLayerParserResultElmt; /** \brief List head for parser result elmts */ typedef struct AppLayerParserResult_ { AppLayerParserResultElmt *head; AppLayerParserResultElmt *tail; uint32_t cnt; } AppLayerParserResult; #define APP_LAYER_PARSER_USE 0x01 #define APP_LAYER_PARSER_EOF 0x02 #define APP_LAYER_PARSER_DONE 0x04 /**< parser is done, ignore more msgs */ #define APP_LAYER_PARSER_NO_INSPECTION 0x08 /**< Flag to indicate no more packets payload inspection */ #define APP_LAYER_PARSER_NO_REASSEMBLY 0x10 /**< Flag to indicate no more packets reassembly for this session */ #define APP_LAYER_TRANSACTION_EOF 0x01 /**< Session done, last transaction as well */ #define APP_LAYER_TRANSACTION_TOSERVER 0x02 /**< transaction has been inspected in to server direction. */ #define APP_LAYER_TRANSACTION_TOCLIENT 0x04 /**< transaction has been inspected in to server direction. */ typedef struct AppLayerParserState_ { uint8_t flags; uint16_t cur_parser; /**< idx of currently active parser */ uint8_t *store; uint32_t store_len; uint16_t parse_field; } AppLayerParserState; typedef struct AppLayerParserStateStore_ { AppLayerParserState to_client; AppLayerParserState to_server; /** flags related to the id's */ uint8_t id_flags; /** the highest id of inspected state's (i.e. http transactions), updated by * the stateful detection engine code */ uint16_t inspect_id; /** the highest id of logged state's (i.e. http transactions), updated by * a logging module throught the app layer API */ uint16_t logged_id; /** the higest id of available state's, updated by the app layer parser */ uint16_t avail_id; /** the base id signifies the id number of the oldest id we have in our * state. As transactions may be cleaned up before the entire state is * freed, id's may "disappear". */ uint16_t base_id; uint16_t version; /**< state version, incremented for each update, * can wrap around */ /* Used to store decoder events */ AppLayerDecoderEvents *decoder_events; } AppLayerParserStateStore; typedef struct AppLayerParserTableElement_ { int (*AppLayerParser)(Flow *f, void *protocol_state, AppLayerParserState *parser_state, uint8_t *input, uint32_t input_len, void *local_storage, AppLayerParserResult *output); char *name; uint16_t proto; uint16_t parser_local_id; /**< local id of the parser in the parser itself. */ } AppLayerParserTableElement; typedef struct AppLayerProbingParserElement_ { const char *al_proto_name; uint16_t al_proto; uint16_t port; uint16_t ip_proto; uint8_t priority; uint8_t top; uint32_t al_proto_mask; /* the min length of data that has to be supplied to invoke the parser */ uint32_t min_depth; /* the max length of data after which this parser won't be invoked */ uint32_t max_depth; /* the probing parser function */ uint16_t (*ProbingParser)(uint8_t *input, uint32_t input_len); struct AppLayerProbingParserElement_ *next; } AppLayerProbingParserElement; typedef struct AppLayerProbingParser_ { /* the port no for which probing parser(s) are invoked */ uint16_t port; uint32_t toserver_al_proto_mask; uint32_t toclient_al_proto_mask; /* the max depth for all the probing parsers registered for this port */ uint16_t toserver_max_depth; uint16_t toclient_max_depth; AppLayerProbingParserElement *toserver; AppLayerProbingParserElement *toclient; struct AppLayerProbingParser_ *next; } AppLayerProbingParser; typedef struct AppLayerProbingParserInfo_ { const char *al_proto_name; uint16_t ip_proto; uint16_t al_proto; uint16_t (*ProbingParser)(uint8_t *input, uint32_t input_len); struct AppLayerProbingParserInfo_ *next; } AppLayerProbingParserInfo; #define APP_LAYER_PROBING_PARSER_PRIORITY_HIGH 1 #define APP_LAYER_PROBING_PARSER_PRIORITY_MEDIUM 2 #define APP_LAYER_PROBING_PARSER_PRIORITY_LOW 3 extern AppLayerProto al_proto_table[]; static inline AppLayerProbingParser *AppLayerGetProbingParsers(AppLayerProbingParser *probing_parsers, uint16_t ip_proto, uint16_t port) { if (probing_parsers == NULL) return NULL; AppLayerProbingParser *pp = probing_parsers; while (pp != NULL) { if (pp->port == port || pp->port == 0) { break; } pp = pp->next; } return pp; } static inline AppLayerProbingParserInfo *AppLayerGetProbingParserInfo(AppLayerProbingParserInfo *ppi, const char *al_proto_name) { while (ppi != NULL) { if (strcmp(ppi->al_proto_name, al_proto_name) == 0) return ppi; ppi = ppi->next; } return NULL; } struct AlpProtoDetectCtx_; /* prototypes */ void AppLayerParsersInitPostProcess(void); void RegisterAppLayerParsers(void); void AppLayerParserRegisterTests(void); /* registration */ int AppLayerRegisterProto(char *name, uint8_t proto, uint8_t flags, int (*AppLayerParser)(Flow *f, void *protocol_state, AppLayerParserState *parser_state, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output)); int AppLayerRegisterParser(char *name, uint16_t proto, uint16_t parser_id, int (*AppLayerParser)(Flow *f, void *protocol_state, AppLayerParserState *parser_state, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output), char *dependency); void AppLayerRegisterProbingParser(struct AlpProtoDetectCtx_ *, uint16_t, uint16_t, const char *, uint16_t, uint16_t, uint16_t, uint8_t, uint8_t, uint8_t, uint16_t (*ProbingParser)(uint8_t *, uint32_t)); void AppLayerRegisterStateFuncs(uint16_t proto, void *(*StateAlloc)(void), void (*StateFree)(void *)); void AppLayerRegisterTransactionIdFuncs(uint16_t proto, void (*StateTransactionId)(void *, uint16_t *), void (*StateTransactionFree)(void *, uint16_t id)); void AppLayerRegisterLocalStorageFunc(uint16_t proto, void *(*LocalStorageAlloc)(void), void (*LocalStorageFree)(void *)); void *AppLayerGetProtocolParserLocalStorage(uint16_t); void AppLayerRegisterGetFilesFunc(uint16_t proto, FileContainer *(*StateGetFile)(void *, uint8_t)); void AppLayerRegisterLogger(uint16_t proto); uint16_t AppLayerGetProtoByName(const char *); const char *AppLayerGetProtoString(int proto); void AppLayerRegisterTruncateFunc(uint16_t proto, void (*Truncate)(void *, uint8_t)); int AppLayerParse(void *, Flow *, uint8_t, uint8_t, uint8_t *, uint32_t); int AlpParseFieldBySize(AppLayerParserResult *, AppLayerParserState *, uint16_t, uint32_t, uint8_t *, uint32_t, uint32_t *); int AlpParseFieldByEOF(AppLayerParserResult *, AppLayerParserState *, uint16_t, uint8_t *, uint32_t); int AlpParseFieldByDelimiter(AppLayerParserResult *, AppLayerParserState *, uint16_t, const uint8_t *, uint8_t, uint8_t *, uint32_t, uint32_t *); /* transaction handling */ int AppLayerTransactionUpdateInspectId(Flow *, char); void AppLayerTransactionUpdateLoggedId(Flow *); int AppLayerTransactionGetLoggableId(Flow *f); int AppLayerTransactionGetLoggedId(Flow *f); int AppLayerTransactionGetBaseId(Flow *f); int AppLayerTransactionGetInspectId(Flow *f); uint16_t AppLayerTransactionGetAvailId(Flow *f); void AppLayerSetEOF(Flow *); /* cleanup */ void AppLayerParserCleanupState(Flow *); void AppLayerFreeProbingParsers(AppLayerProbingParser *); void AppLayerFreeProbingParsersInfo(AppLayerProbingParserInfo *); void AppLayerPrintProbingParsers(AppLayerProbingParser *); uint16_t AppLayerGetStateVersion(Flow *f); void AppLayerListSupportedProtocols(void); FileContainer *AppLayerGetFilesFromFlow(Flow *, uint8_t); AppLayerDecoderEvents *AppLayerGetDecoderEventsForFlow(Flow *); void AppLayerTriggerRawStreamReassembly(Flow *); #endif /* __APP_LAYER_PARSER_H__ */ suricata-1.4.7/src/alert-pcapinfo.h0000644000000000000000000000167312253546156014111 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #ifndef __ALERT_PCAPINFO_H__ #define __ALERT_PCAPINFO_H__ void TmModuleAlertPcapInfoRegister (void); OutputCtx *AlertPcapInfoInitCtx(ConfNode *); #endif /* __ALERT_PCAPINFO_H__ */ suricata-1.4.7/src/detect-l3proto.h0000644000000000000000000000170712253546156014053 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond * */ #ifndef __DETECT_L3PROTO_H__ #define __DETECT_L3PROTO_H__ /** * \brief Registration function for ip_proto keyword. */ void DetectL3ProtoRegister (void); #endif /* __DETECT_L3PROTO_H__ */ suricata-1.4.7/src/suricata-common.h0000644000000000000000000001346112253546156014304 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Common includes, etc. */ #ifndef __SURICATA_COMMON_H__ #define __SURICATA_COMMON_H__ #ifdef DEBUG #define DBG_PERF #endif #define TRUE 1 #define FALSE 0 #define _GNU_SOURCE #define __USE_GNU #if HAVE_CONFIG_H #include #endif #if HAVE_STDIO_H #include #endif #if HAVE_STDINT_h #include #endif #if HAVE_STDARG_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #if HAVE_ERRNO_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_INTTYPES_H #include #endif #if HAVE_LIMITS_H #include #endif #if HAVE_CTYPE_H #include #endif #if HAVE_STRING_H #include #endif #if HAVE_FCNTL_H #include #endif #ifdef HAVE_TIME_H #include #endif #if HAVE_SYS_SYSCALL_H #include #endif #if HAVE_SYSCALL_H #include #endif #if HAVE_SYS_TYPES_H #include /* for gettid(2) */ #endif #if HAVE_SCHED_H #include /* for sched_setaffinity(2) */ #endif #include #ifdef HAVE_SYSLOG_H #include #else #ifdef OS_WIN32 #include "win32-syslog.h" #endif /* OS_WIN32 */ #endif /* HAVE_SYSLOG_H */ #ifdef OS_WIN32 #include "win32-misc.h" #include "win32-service.h" #endif /* OS_WIN32 */ #if HAVE_SYS_TIME_H #include #endif #if HAVE_POLL_H #include #endif #if HAVE_SYS_SIGNAL_H #include #endif #if HAVE_SIGNAL_H #include #endif #if HAVE_SYS_TYPES_H #include #endif #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_SYS_STAT_H #include #endif #if HAVE_NETINET_IN_H #include #endif #if HAVE_ARPA_INET_H #include #endif #if HAVE_NETDB_H #include #endif #ifdef HAVE_PCAP_H #include #endif #ifdef HAVE_PCAP_PCAP_H #include #endif #ifdef HAVE_PCAP_BPF_H #include #endif #if __CYGWIN__ #if !defined _X86_ && !defined __x86_64 #define _X86_ #endif #endif #ifdef HAVE_WINDOWS_H #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif #include #endif #ifdef HAVE_W32API_WINBASE_H #include #endif #if !__CYGWIN__ #ifdef HAVE_WINSOCK2_H #include #endif #ifdef HAVE_WS2TCPIP_H #include #endif #endif /* !__CYGWIN__ */ #ifdef HAVE_ASSERT_H #include #define BUG_ON(x) assert(!(x)) #else #define BUG_ON(x) #endif /* we need this to stringify the defines which are supplied at compiletime see: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */ #define xstr(s) str(s) #define str(s) #s /** type for the internal signature id. Since it's used in the matching engine * extensively keeping this as small as possible reduces the overall memory * footprint of the engine. Set to uint32_t if the engine needs to support * more than 64k sigs. */ #define SigIntId uint16_t //#define SigIntId uint32_t /** same for pattern id's */ #define PatIntId uint16_t /** FreeBSD does not define __WORDSIZE, but it uses __LONG_BIT */ #ifndef __WORDSIZE #ifdef __LONG_BIT #define __WORDSIZE __LONG_BIT #else #ifdef LONG_BIT #define __WORDSIZE LONG_BIT #endif #endif #endif /** Windows does not define __WORDSIZE, but it uses __X86__ */ #ifndef __WORDSIZE #if defined(__X86__) || defined(_X86_) #define __WORDSIZE 32 #else #if defined(__X86_64__) || defined(_X86_64_) #define __WORDSIZE 64 #endif #endif #ifndef __WORDSIZE #warning Defaulting to __WORDSIZE 32 #define __WORDSIZE 32 #endif #endif /** darwin doesn't defined __BYTE_ORDER and friends, but BYTE_ORDER */ #ifndef __BYTE_ORDER #ifdef BYTE_ORDER #define __BYTE_ORDER BYTE_ORDER #endif #endif #ifndef __LITTLE_ENDIAN #ifdef LITTLE_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN #endif #endif #ifndef __BIG_ENDIAN #ifdef BIG_ENDIAN #define __BIG_ENDIAN BIG_ENDIAN #endif #endif typedef enum PacketProfileDetectId_ { PROF_DETECT_MPM, PROF_DETECT_MPM_PACKET, /* PKT MPM */ PROF_DETECT_MPM_PKT_STREAM, /* PKT inspected with stream MPM */ PROF_DETECT_MPM_STREAM, /* STREAM MPM */ PROF_DETECT_MPM_URI, PROF_DETECT_MPM_HCBD, PROF_DETECT_MPM_HSBD, PROF_DETECT_MPM_HHD, PROF_DETECT_MPM_HRHD, PROF_DETECT_MPM_HMD, PROF_DETECT_MPM_HCD, PROF_DETECT_MPM_HRUD, PROF_DETECT_MPM_HSMD, PROF_DETECT_MPM_HSCD, PROF_DETECT_MPM_HUAD, PROF_DETECT_MPM_HHHD, PROF_DETECT_MPM_HRHHD, PROF_DETECT_IPONLY, PROF_DETECT_RULES, PROF_DETECT_STATEFUL, PROF_DETECT_PREFILTER, PROF_DETECT_ALERT, PROF_DETECT_CLEANUP, PROF_DETECT_GETSGH, PROF_DETECT_SIZE, } PacketProfileDetectId; #include #include "threads.h" #include "tm-threads-common.h" #include "util-debug.h" #include "util-error.h" #include "util-mem.h" #include "detect-engine-alert.h" #include "util-optimize.h" #include "util-path.h" size_t strlcat(char *, const char *src, size_t siz); size_t strlcpy(char *dst, const char *src, size_t siz); #endif /* __SURICATA_COMMON_H__ */ suricata-1.4.7/src/detect-seq.h0000644000000000000000000000210112253546156013226 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus */ #ifndef __DETECT_SEQ_H__ #define __DETECT_SEQ_H__ /** * \brief seq data */ typedef struct DetectSeqData_ { uint32_t seq; /**< seq to match */ } DetectSeqData; /** * \brief Registration function for ack: keyword */ void DetectSeqRegister(void); #endif /* __DETECT_SEQ_H__ */ suricata-1.4.7/src/detect-http-ua.h0000644000000000000000000000162412253546156014031 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_HTTP_UA_H__ #define __DETECT_HTTP_UA_H__ void DetectHttpUARegister(void); #endif /* __DETECT_HTTP_UA_H__ */ suricata-1.4.7/src/app-layer-dcerpc-common.h0000644000000000000000000002067512253546156015626 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Kirby Kuehl */ #ifndef __APP_LAYER_DCERPC_COMMON_H__ #define __APP_LAYER_DCERPC_COMMON_H__ #include "app-layer-protos.h" #include "app-layer-parser.h" #include "flow.h" #include "queue.h" #include "util-byte.h" void RegisterDCERPCParsers(void); void DCERPCParserTests(void); void DCERPCParserRegisterTests(void); // http://www.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06 #define REQUEST 0 #define PING 1 #define RESPONSE 2 #define FAULT 3 #define WORKING 4 #define NOCALL 5 #define REJECT 6 #define ACK 7 #define CL_CANCEL 8 #define FACK 9 #define CANCEL_ACK 10 #define BIND 11 #define BIND_ACK 12 #define BIND_NAK 13 #define ALTER_CONTEXT 14 #define ALTER_CONTEXT_RESP 15 #define SHUTDOWN 17 #define CO_CANCEL 18 #define ORPHANED 19 #if 0 typedef struct { uint8_t rpc_vers; /* 4 RPC protocol major version (4 LSB only)*/ uint8_t ptype; /* Packet type (5 LSB only) */ uint8_t flags1; /* Packet flags */ uint8_t flags2; /* Packet flags */ uint8_t drep[3]; /* Data representation format label */ uint8_t serial_hi; /* High byte of serial number */ uuid_t object; /* Object identifier */ uuid_t if_id; /* Interface identifier */ uuid_t act_id; /* Activity identifier */ unsigned long server_boot;/* Server boot time */ unsigned long if_vers; /* Interface version */ unsigned long seqnum; /* Sequence number */ unsigned short opnum; /* Operation number */ unsigned short ihint; /* Interface hint */ unsigned short ahint; /* Activity hint */ unsigned short len; /* Length of packet body */ unsigned short fragnum; /* Fragment number */ unsigned small auth_proto; /* Authentication protocol identifier*/ unsigned small serial_lo; /* Low byte of serial number */ } dc_rpc_cl_pkt_hdr_t; #endif #define RESERVED_01 0x01 #define LASTFRAG 0x02 #define FRAG 0x04 #define NOFACK 0x08 #define MAYBE 0x10 #define IDEMPOTENT 0x20 #define BROADCAST 0x40 #define RESERVED_80 0x80 #define CANCEL_PENDING 0x02 #define RESERVED_04 0x04 #define RESERVED_10 0x10 #define RESERVED_20 0x20 #define RESERVED_40 0x40 #define RESERVED_80 0x80 typedef struct DCERPCHdr_ { uint8_t rpc_vers; /**< 00:01 RPC version should be 5 */ uint8_t rpc_vers_minor; /**< 01:01 minor version */ uint8_t type; /**< 02:01 packet type */ uint8_t pfc_flags; /**< 03:01 flags (see PFC_... ) */ uint8_t packed_drep[4]; /**< 04:04 NDR data representation format label */ uint16_t frag_length; /**< 08:02 total length of fragment */ uint16_t auth_length; /**< 10:02 length of auth_value */ uint32_t call_id; /**< 12:04 call identifier */ } DCERPCHdr; #define DCERPC_HDR_LEN 16 typedef struct DCERPCHdrUdp_ { uint8_t rpc_vers; /**< 4 RPC protocol major version (4 LSB only)*/ uint8_t type; /**< Packet type (5 LSB only) */ uint8_t flags1; /**< Packet flags */ uint8_t flags2; /**< Packet flags */ uint8_t drep[3]; /**< Data representation format label */ uint8_t serial_hi; /**< High byte of serial number */ uint8_t objectuuid[16]; uint8_t interfaceuuid[16]; uint8_t activityuuid[16]; uint32_t server_boot; /**< Server boot time */ uint32_t if_vers; /**< Interface version */ uint32_t seqnum; /**< Sequence number */ uint16_t opnum; /**< Operation number */ uint16_t ihint; /**< Interface hint */ uint16_t ahint; /**< Activity hint */ uint16_t fraglen; /**< Length of packet body */ uint16_t fragnum; /**< Fragment number */ uint8_t auth_proto; /**< Authentication protocol identifier*/ uint8_t serial_lo; /**< Low byte of serial number */ } DCERPCHdrUdp; #define DCERPC_UDP_HDR_LEN 80 #define DCERPC_UUID_ENTRY_FLAG_FF 0x0001 /**< FIRST flag set on the packet that contained this uuid entry */ typedef struct DCERPCUuidEntry_ { uint16_t ctxid; uint16_t internal_id; uint16_t result; uint8_t uuid[16]; uint16_t version; uint16_t versionminor; uint16_t flags; /**< DCERPC_UUID_ENTRY_FLAG_* flags */ TAILQ_ENTRY(DCERPCUuidEntry_) next; } DCERPCUuidEntry; typedef struct DCERPCBindBindAck_ { uint8_t numctxitems; uint8_t numctxitemsleft; uint8_t ctxbytesprocessed; uint16_t ctxid; uint8_t uuid[16]; uint16_t version; uint16_t versionminor; DCERPCUuidEntry *uuid_entry; TAILQ_HEAD(, DCERPCUuidEntry_) uuid_list; /* the interface uuids that the server has accepted */ TAILQ_HEAD(, DCERPCUuidEntry_) accepted_uuid_list; uint16_t uuid_internal_id; uint16_t secondaryaddrlen; uint16_t secondaryaddrlenleft; uint16_t result; } DCERPCBindBindAck; typedef struct DCERPCRequest_ { uint16_t ctxid; uint16_t opnum; /* holds the stub data for the request */ uint8_t *stub_data_buffer; /* length of the above buffer */ uint32_t stub_data_buffer_len; /* used by the dce preproc to indicate fresh entry in the stub data buffer */ uint8_t stub_data_fresh; uint8_t first_request_seen; } DCERPCRequest; typedef struct DCERPCResponse_ { /* holds the stub data for the response */ uint8_t *stub_data_buffer; /* length of the above buffer */ uint32_t stub_data_buffer_len; /* used by the dce preproc to indicate fresh entry in the stub data buffer */ uint8_t stub_data_fresh; } DCERPCResponse; typedef struct DCERPC_ { DCERPCHdr dcerpchdr; DCERPCBindBindAck dcerpcbindbindack; DCERPCRequest dcerpcrequest; DCERPCResponse dcerpcresponse; uint16_t bytesprocessed; uint8_t pad; uint16_t padleft; uint16_t transaction_id; /* indicates if the dcerpc pdu state is in the middle of processing * a fragmented pdu */ uint8_t pdu_fragged; } DCERPC; typedef struct DCERPCUDP_ { DCERPCHdrUdp dcerpchdrudp; DCERPCBindBindAck dcerpcbindbindack; DCERPCRequest dcerpcrequest; DCERPCResponse dcerpcresponse; uint16_t bytesprocessed; uint16_t fraglenleft; uint8_t *frag_data; DCERPCUuidEntry *uuid_entry; TAILQ_HEAD(, uuid_entry) uuid_list; } DCERPCUDP; /** First fragment */ #define PFC_FIRST_FRAG 0x01 /** Last fragment */ #define PFC_LAST_FRAG 0x02 /** Cancel was pending at sender */ #define PFC_PENDING_CANCEL 0x04 #define PFC_RESERVED_1 0x08 /** supports concurrent multiplexing of a single connection. */ #define PFC_CONC_MPX 0x10 /** only meaningful on `fault' packet; if true, guaranteed * call did not execute. */ #define PFC_DID_NOT_EXECUTE 0x20 /** `maybe' call semantics requested */ #define PFC_MAYBE 0x40 /** if true, a non-nil object UUID was specified in the handle, and * is present in the optional object field. If false, the object field * is omitted. */ #define PFC_OBJECT_UUID 0x80 #define REASON_NOT_SPECIFIED 0 #define TEMPORARY_CONGESTION 1 #define LOCAL_LIMIT_EXCEEDED 2 #define CALLED_PADDR_UNKNOWN 3 /* not used */ #define PROTOCOL_VERSION_NOT_SUPPORTED 4 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */ #define USER_DATA_NOT_READABLE 6 /* not used */ #define NO_PSAP_AVAILABLE 7 /* not used */ int32_t DCERPCParser(DCERPC *, uint8_t *, uint32_t); void hexdump(const void *buf, size_t len); void printUUID(char *type, DCERPCUuidEntry *uuid); #endif /* __APP_LAYER_DCERPC_COMMON_H__ */ suricata-1.4.7/src/util-pidfile.c0000644000000000000000000000720212253546156013561 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * \author Victor Julien * * Utility code for dealing with a pidfile. * Adaptation of Steve Grubbs patch to our coding guidelines * (thanks for the patch Steve ;) */ #include "suricata-common.h" #include "util-pidfile.h" /** * \brief Write a pid file (used at the startup) * This commonly needed by the init scripts * * \param pointer to the name of the pid file to write (optarg) * * \retval 0 if succes * \retval -1 on failure */ int SCPidfileCreate(const char *pidfile) { SCEnter(); int pidfd = 0; char val[16]; size_t len = snprintf(val, sizeof(val), "%"PRIuMAX"\n", (uintmax_t)getpid()); if (len <= 0) { SCLogError(SC_ERR_PIDFILE_SNPRINTF, "Pid error (%s)", strerror(errno)); SCReturnInt(-1); } pidfd = open(pidfile, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644); if (pidfd < 0) { SCLogError(SC_ERR_PIDFILE_OPEN, "unable to set pidfile '%s': %s", pidfile, strerror(errno)); SCReturnInt(-1); } ssize_t r = write(pidfd, val, (unsigned int)len); if (r == -1) { SCLogError(SC_ERR_PIDFILE_WRITE, "unable to write pidfile: %s", strerror(errno)); close(pidfd); SCReturnInt(-1); } else if ((size_t)r != len) { SCLogError(SC_ERR_PIDFILE_WRITE, "unable to write pidfile: wrote" " %"PRIdMAX" of %"PRIuMAX" bytes.", (intmax_t)r, (uintmax_t)len); close(pidfd); SCReturnInt(-1); } close(pidfd); SCReturnInt(0); } /** * \brief Remove the pid file (used at the startup) * * \param pointer to the name of the pid file to write (optarg) */ void SCPidfileRemove(const char *pid_filename) { if (pid_filename != NULL) { /* we ignore the result, the user may have removed the file already. */ (void)unlink(pid_filename); } } /** * \brief Check a pid file (used at the startup) * This commonly needed by the init scripts * * \param pointer to the name of the pid file to write (optarg) * * \retval 0 if succes * \retval -1 on failure */ int SCPidfileTestRunning(const char *pid_filename) { if (access(pid_filename, F_OK) == 0) { /* Check if the existing process is still alive. */ pid_t pidv; FILE *pf; pf = fopen(pid_filename, "r"); if (pf == NULL) { SCLogError(SC_ERR_INITIALIZATION, "pid file '%s' exists and can not be read. Aborting!", pid_filename); return -1; } if (fscanf(pf, "%d", &pidv) == 1 && kill(pidv, 0) == 0) { fclose(pf); SCLogError(SC_ERR_INITIALIZATION, "pid file '%s' exists. Is Suricata already running? Aborting!", pid_filename); return -1; } if (pf != NULL) fclose(pf); } return 0; } suricata-1.4.7/src/util-unittest-helper.h0000644000000000000000000000451412253546156015311 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo */ #ifndef __UTIL_UNITTEST_HELPER__ #define __UTIL_UNITTEST_HELPER__ #ifdef UNITTESTS uint32_t UTHSetIPv4Address(char *); Packet *UTHBuildPacketReal(uint8_t *, uint16_t, uint16_t, char *, char *, uint16_t, uint16_t); Packet *UTHBuildPacket(uint8_t *, uint16_t, uint16_t); Packet *UTHBuildPacketSrcDst(uint8_t *, uint16_t, uint16_t, char *, char *); Packet *UTHBuildPacketSrcDstPorts(uint8_t *, uint16_t, uint16_t, uint16_t, uint16_t); Packet *UTHBuildPacketIPV6SrcDst(uint8_t *, uint16_t, uint16_t, char *, char *); int UTHPacketMatchSigMpm(Packet *, char *, uint16_t); Packet **UTHBuildPacketArrayFromEth(uint8_t **, int *, int); Packet *UTHBuildPacketFromEth(uint8_t *, uint16_t); void UTHFreePacket(Packet *); void UTHFreePackets(Packet **, int); Flow *UTHBuildFlow(int family, char *src, char *dst, Port sp, Port dp); void UTHFreeFlow(Flow *flow); int UTHAppendSigs(DetectEngineCtx *, char **, int); int UTHMatchPackets(DetectEngineCtx *, Packet **, int); int UTHPacketMatchSig(Packet *p, char *); int UTHCheckPacketMatch(Packet *, uint32_t *, uint32_t *, int); int UTHCheckPacketMatchResults(Packet *, uint32_t *, uint32_t *, int); int UTHMatchPacketsWithResults(DetectEngineCtx *, Packet **, int, uint32_t *, uint32_t *, int); int UTHGenericTest(Packet **, int, char **, uint32_t *, uint32_t *, int); uint32_t UTHBuildPacketOfFlows(uint32_t, uint32_t, uint8_t); Packet *UTHBuildPacketIPV6Real(uint8_t *, uint16_t , uint16_t , char *, char *, uint16_t , uint16_t ); #endif void UTHRegisterTests(void); #endif /* __UTIL_UNITTEST_HELPER__ */ suricata-1.4.7/src/util-mpm-ac.h0000644000000000000000000000513612253546156013330 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * */ #define SC_AC_STATE_TYPE_U16 uint16_t #define SC_AC_STATE_TYPE_U32 uint32_t typedef struct SCACPattern_ { /* length of the pattern */ uint16_t len; /* flags decribing the pattern */ uint8_t flags; /* holds the original pattern that was added */ uint8_t *original_pat; /* case sensitive */ uint8_t *cs; /* case INsensitive */ uint8_t *ci; /* pattern id */ uint32_t id; struct SCACPattern_ *next; } SCACPattern; typedef struct SCACPatternList_ { uint8_t *cs; uint16_t patlen; uint16_t case_state; } SCACPatternList; typedef struct SCACOutputTable_ { /* list of pattern sids */ uint32_t *pids; /* no of entries we have in pids */ uint32_t no_of_entries; } SCACOutputTable; typedef struct SCACCtx_ { /* hash used during ctx initialization */ SCACPattern **init_hash; /* pattern arrays. We need this only during the goto table creation phase */ SCACPattern **parray; /* no of states used by ac */ uint32_t state_count; /* the all important memory hungry state_table */ SC_AC_STATE_TYPE_U16 (*state_table_u16)[256]; /* the all important memory hungry state_table */ SC_AC_STATE_TYPE_U32 (*state_table_u32)[256]; /* goto_table, failure table and output table. Needed to create state_table. * Will be freed, once we have created the state_table */ int32_t (*goto_table)[256]; int32_t *failure_table; SCACOutputTable *output_table; SCACPatternList *pid_pat_list; /* the size of each state */ uint16_t single_state_size; uint16_t max_pat_id; } SCACCtx; typedef struct SCACThreadCtx_ { /* the total calls we make to the search function */ uint32_t total_calls; /* the total patterns that we ended up matching against */ uint64_t total_matches; } SCACThreadCtx; void MpmACRegister(void); suricata-1.4.7/src/decode-udp.h0000644000000000000000000001235612253546156013216 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DECODE_UDP_H__ #define __DECODE_UDP_H__ #define UDP_HEADER_LEN 8 /* XXX RAW* needs to be really 'raw', so no ntohs there */ #define UDP_GET_RAW_LEN(udph) ntohs((udph)->uh_len) #define UDP_GET_RAW_SRC_PORT(udph) ntohs((udph)->uh_sport) #define UDP_GET_RAW_DST_PORT(udph) ntohs((udph)->uh_dport) #define UDP_GET_LEN(p) UDP_GET_RAW_LEN(p->udph) #define UDP_GET_SRC_PORT(p) UDP_GET_RAW_SRC_PORT(p->udph) #define UDP_GET_DST_PORT(p) UDP_GET_RAW_DST_PORT(p->udph) /* UDP header structure */ typedef struct UDPHdr_ { uint16_t uh_sport; /* source port */ uint16_t uh_dport; /* destination port */ uint16_t uh_len; /* length */ uint16_t uh_sum; /* checksum */ } UDPHdr; typedef struct UDPVars_ { /* checksum computed over the udp(for both ipv4 and ipv6) packet */ int32_t comp_csum; } UDPVars; #define CLEAR_UDP_PACKET(p) do { \ (p)->udph = NULL; \ (p)->udpvars.comp_csum = -1; \ } while (0) void DecodeUDPV4RegisterTests(void); /** ------ Inline function ------ */ static inline uint16_t UDPV4CalculateChecksum(uint16_t *, uint16_t *, uint16_t); static inline uint16_t UDPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t); /** * \brief Calculates the checksum for the UDP packet * * \param shdr Pointer to source address field from the IP packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the UDP packet * \param hlen Total length of the UDP packet(header + payload) * * \retval csum Checksum for the UDP packet */ static inline uint16_t UDPV4CalculateChecksum(uint16_t *shdr, uint16_t *pkt, uint16_t tlen) { uint16_t pad = 0; uint32_t csum = shdr[0]; csum += shdr[1] + shdr[2] + shdr[3] + htons(17) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2]; tlen -= 8; pkt += 4; while (tlen >= 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } while(tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } while(tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; } while (tlen > 1) { csum += pkt[0]; pkt += 1; tlen -= 2; } if (tlen == 1) { *(uint8_t *)(&pad) = (*(uint8_t *)pkt); csum += pad; } csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); uint16_t csum_u16 = (uint16_t)~csum; if (csum_u16 == 0) return 0xFFFF; else return csum_u16; } /** * \brief Calculates the checksum for the UDP packet * * \param shdr Pointer to source address field from the IPV6 packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the UDP packet * \param tlen Total length of the UDP packet(header + payload) * * \retval csum Checksum for the UDP packet */ static inline uint16_t UDPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, uint16_t tlen) { uint16_t pad = 0; uint32_t csum = shdr[0]; csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(17) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2]; tlen -= 8; pkt += 4; while (tlen >= 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } while(tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } while(tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; } while (tlen > 1) { csum += pkt[0]; pkt += 1; tlen -= 2; } if (tlen == 1) { *(uint8_t *)(&pad) = (*(uint8_t *)pkt); csum += pad; } csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); uint16_t csum_u16 = (uint16_t)~csum; if (csum_u16 == 0) return 0xFFFF; else return csum_u16; } #endif /* __DECODE_UDP_H__ */ suricata-1.4.7/src/detect-asn1.h0000644000000000000000000000301112253546156013301 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file detect-asn1.h * * \author Pablo Rincon Crespo * * Implements "asn1" keyword */ #ifndef __DETECT_ASN1_H__ #define __DETECT_ASN1_H__ /* Function check flags */ #define ASN1_BITSTRING_OVF 0x01 #define ASN1_DOUBLE_OVF 0x02 #define ASN1_OVERSIZE_LEN 0x04 #define ASN1_ABSOLUTE_OFFSET 0x10 #define ASN1_RELATIVE_OFFSET 0x20 typedef struct DetectAsn1Data_ { uint8_t flags; /* flags indicating the checks loaded */ uint32_t oversize_length; /* Length argument if needed */ int32_t absolute_offset; /* Length argument if needed */ int32_t relative_offset; /* Length argument if needed */ } DetectAsn1Data; /* prototypes */ void DetectAsn1Register (void); #endif /* __DETECT_ASN1_H__ */ suricata-1.4.7/src/runmode-erf-file.h0000644000000000000000000000203712253546156014340 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien */ #ifndef __RUNMODE_ERF_FILE_H__ #define __RUNMODE_ERF_FILE_H__ int RunModeErfFileSingle(DetectEngineCtx *); int RunModeErfFileAutoFp(DetectEngineCtx *); void RunModeErfFileRegister(void); const char *RunModeErfFileGetDefaultMode(void); #endif /* __RUNMODE_ERF_FILE_H__ */ suricata-1.4.7/src/detect-ftpbounce.h0000644000000000000000000000166412253546156014440 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_FTPBOUNCE_H__ #define __DETECT_FTPBOUNCE_H__ /* prototypes */ void DetectFtpbounceRegister (void); #endif /* __DETECT_FTPBOUNCE_H__ */ suricata-1.4.7/src/util-profiling.c0000644000000000000000000007113312253546156014142 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited. * \author Victor Julien * * An API for profiling operations. * * Really just a wrapper around the existing perf counters. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "conf.h" #include "tm-threads.h" #include "util-unittest.h" #include "util-byte.h" #include "util-profiling.h" #include "util-profiling-locks.h" #ifdef PROFILING #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #define DEFAULT_LOG_FILENAME "profile.log" #define DEFAULT_LOG_MODE_APPEND "yes" static pthread_mutex_t packet_profile_lock; static FILE *packet_profile_csv_fp = NULL; extern int profiling_locks_enabled; extern int profiling_locks_output_to_file; extern char *profiling_locks_file_name; extern char *profiling_locks_file_mode; typedef struct SCProfilePacketData_ { uint64_t min; uint64_t max; uint64_t tot; uint64_t cnt; #ifdef PROFILE_LOCKING uint64_t lock; uint64_t ticks; uint64_t contention; uint64_t slock; uint64_t sticks; uint64_t scontention; #endif } SCProfilePacketData; SCProfilePacketData packet_profile_data4[257]; /**< all proto's + tunnel */ SCProfilePacketData packet_profile_data6[257]; /**< all proto's + tunnel */ /* each module, each proto */ SCProfilePacketData packet_profile_tmm_data4[TMM_SIZE][257]; SCProfilePacketData packet_profile_tmm_data6[TMM_SIZE][257]; SCProfilePacketData packet_profile_app_data4[TMM_SIZE][257]; SCProfilePacketData packet_profile_app_data6[TMM_SIZE][257]; SCProfilePacketData packet_profile_app_pd_data4[257]; SCProfilePacketData packet_profile_app_pd_data6[257]; SCProfilePacketData packet_profile_detect_data4[PROF_DETECT_SIZE][257]; SCProfilePacketData packet_profile_detect_data6[PROF_DETECT_SIZE][257]; int profiling_packets_enabled = 0; int profiling_packets_csv_enabled = 0; int profiling_output_to_file = 0; int profiling_packets_output_to_file = 0; char *profiling_file_name; char *profiling_packets_file_name; char *profiling_csv_file_name; const char *profiling_packets_file_mode = "a"; /** * Used as a check so we don't double enter a profiling run. */ __thread int profiling_rules_entered = 0; void SCProfilingDumpPacketStats(void); const char * PacketProfileDetectIdToString(PacketProfileDetectId id); /** * \brief Initialize profiling. */ void SCProfilingInit(void) { ConfNode *conf; conf = ConfGetNode("profiling.packets"); if (conf != NULL) { if (ConfNodeChildValueIsTrue(conf, "enabled")) { profiling_packets_enabled = 1; if (pthread_mutex_init(&packet_profile_lock, NULL) != 0) { SCLogError(SC_ERR_MUTEX, "Failed to initialize packet profiling mutex."); exit(EXIT_FAILURE); } memset(&packet_profile_data4, 0, sizeof(packet_profile_data4)); memset(&packet_profile_data6, 0, sizeof(packet_profile_data6)); memset(&packet_profile_tmm_data4, 0, sizeof(packet_profile_tmm_data4)); memset(&packet_profile_tmm_data6, 0, sizeof(packet_profile_tmm_data6)); memset(&packet_profile_app_data4, 0, sizeof(packet_profile_app_data4)); memset(&packet_profile_app_data6, 0, sizeof(packet_profile_app_data6)); memset(&packet_profile_app_pd_data4, 0, sizeof(packet_profile_app_pd_data4)); memset(&packet_profile_app_pd_data6, 0, sizeof(packet_profile_app_pd_data6)); memset(&packet_profile_detect_data4, 0, sizeof(packet_profile_detect_data4)); memset(&packet_profile_detect_data6, 0, sizeof(packet_profile_detect_data6)); const char *filename = ConfNodeLookupChildValue(conf, "filename"); if (filename != NULL) { char *log_dir; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; profiling_packets_file_name = SCMalloc(PATH_MAX); if (unlikely(profiling_packets_file_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); exit(EXIT_FAILURE); } snprintf(profiling_packets_file_name, PATH_MAX, "%s/%s", log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { profiling_packets_file_mode = "a"; } else { profiling_packets_file_mode = "w"; } profiling_packets_output_to_file = 1; } } conf = ConfGetNode("profiling.packets.csv"); if (conf != NULL) { if (ConfNodeChildValueIsTrue(conf, "enabled")) { const char *filename = ConfNodeLookupChildValue(conf, "filename"); if (filename == NULL) { filename = "packet_profile.csv"; } char *log_dir; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; profiling_csv_file_name = SCMalloc(PATH_MAX); if (unlikely(profiling_csv_file_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "out of memory"); exit(EXIT_FAILURE); } snprintf(profiling_csv_file_name, PATH_MAX, "%s/%s", log_dir, filename); packet_profile_csv_fp = fopen(profiling_csv_file_name, "w"); if (packet_profile_csv_fp == NULL) { return; } fprintf(packet_profile_csv_fp, "pcap_cnt,ipver,ipproto,total,"); int i; for (i = 0; i < TMM_SIZE; i++) { fprintf(packet_profile_csv_fp, "%s,", TmModuleTmmIdToString(i)); } fprintf(packet_profile_csv_fp, "threading,"); for (i = 0; i < ALPROTO_MAX; i++) { fprintf(packet_profile_csv_fp, "%s,", TmModuleAlprotoToString(i)); } fprintf(packet_profile_csv_fp, "STREAM (no app),proto detect,"); for (i = 0; i < PROF_DETECT_SIZE; i++) { fprintf(packet_profile_csv_fp, "%s,", PacketProfileDetectIdToString(i)); } fprintf(packet_profile_csv_fp, "\n"); profiling_packets_csv_enabled = 1; } } } conf = ConfGetNode("profiling.locks"); if (conf != NULL) { if (ConfNodeChildValueIsTrue(conf, "enabled")) { #ifndef PROFILE_LOCKING SCLogWarning(SC_WARN_PROFILE, "lock profiling not compiled in. Add --enable-profiling-locks to configure."); #else profiling_locks_enabled = 1; LockRecordInitHash(); const char *filename = ConfNodeLookupChildValue(conf, "filename"); if (filename != NULL) { char *log_dir; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; profiling_locks_file_name = SCMalloc(PATH_MAX); if (unlikely(profiling_locks_file_name == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); exit(EXIT_FAILURE); } snprintf(profiling_locks_file_name, PATH_MAX, "%s/%s", log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { profiling_locks_file_mode = "a"; } else { profiling_locks_file_mode = "w"; } profiling_locks_output_to_file = 1; } #endif } } } /** * \brief Free resources used by profiling. */ void SCProfilingDestroy(void) { if (profiling_packets_enabled) { pthread_mutex_destroy(&packet_profile_lock); } if (profiling_packets_csv_enabled) { if (packet_profile_csv_fp != NULL) fclose(packet_profile_csv_fp); } if (profiling_csv_file_name != NULL) SCFree(profiling_csv_file_name); if (profiling_file_name != NULL) SCFree(profiling_file_name); #ifdef PROFILE_LOCKING LockRecordFreeHash(); #endif } void SCProfilingDump(void) { SCProfilingDumpPacketStats(); SCLogInfo("Done dumping profiling data."); } void SCProfilingDumpPacketStats(void) { int i; FILE *fp; if (profiling_packets_enabled == 0) return; if (profiling_packets_output_to_file == 1) { fp = fopen(profiling_packets_file_name, profiling_packets_file_mode); if (fp == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", profiling_packets_file_name, strerror(errno)); return; } } else { fp = stdout; } fprintf(fp, "\n\nPacket profile dump:\n"); fprintf(fp, "\n%-6s %-5s %-12s %-12s %-12s %-12s\n", "IP ver", "Proto", "cnt", "min", "max", "avg"); fprintf(fp, "%-6s %-5s %-12s %-12s %-12s %-12s\n", "------", "-----", "----------", "------------", "------------", "-----------"); for (i = 0; i < 257; i++) { SCProfilePacketData *pd = &packet_profile_data4[i]; if (pd->cnt == 0) { continue; } fprintf(fp, " IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", i, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } for (i = 0; i < 257; i++) { SCProfilePacketData *pd = &packet_profile_data6[i]; if (pd->cnt == 0) { continue; } fprintf(fp, " IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", i, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } fprintf(fp, "Note: Protocol 256 tracks pseudo/tunnel packets.\n"); fprintf(fp, "\nPer Thread module stats:\n"); fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s", "Thread Module", "IP ver", "Proto", "cnt", "min", "max", "avg"); #ifdef PROFILE_LOCKING fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", "locks", "ticks", "cont.", "cont.avg", "slocks", "sticks", "scont.", "scont.avg"); #else fprintf(fp, "\n"); #endif fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s", "------------------------", "------", "-----", "----------", "------------", "------------", "-----------"); #ifdef PROFILE_LOCKING fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", "--------", "--------", "----------", "-----------", "--------", "--------", "------------", "-----------"); #else fprintf(fp, "\n"); #endif int m; for (m = 0; m < TMM_SIZE; m++) { int p; for (p = 0; p < 257; p++) { SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; if (pd->cnt == 0) { continue; } fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64, TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); #ifdef PROFILE_LOCKING fprintf(fp, " %10.2f %12"PRIu64" %12"PRIu64" %10.2f %10.2f %12"PRIu64" %12"PRIu64" %10.2f\n", (float)pd->lock/pd->cnt, (uint64_t)pd->ticks/pd->cnt, pd->contention, (float)pd->contention/pd->cnt, (float)pd->slock/pd->cnt, (uint64_t)pd->sticks/pd->cnt, pd->scontention, (float)pd->scontention/pd->cnt); #else fprintf(fp, "\n"); #endif } } for (m = 0; m < TMM_SIZE; m++) { int p; for (p = 0; p < 257; p++) { SCProfilePacketData *pd = &packet_profile_tmm_data6[m][p]; if (pd->cnt == 0) { continue; } fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } } fprintf(fp, "Note: TMM_STREAMTCP includes TCP app layer parsers, see below.\n"); fprintf(fp, "\nPer App layer parser stats:\n"); fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", "App Layer", "IP ver", "Proto", "cnt", "min", "max", "avg"); fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", "--------------------", "------", "-----", "----------", "------------", "------------", "-----------"); for (m = 0; m < ALPROTO_MAX; m++) { int p; for (p = 0; p < 257; p++) { SCProfilePacketData *pd = &packet_profile_app_data4[m][p]; if (pd->cnt == 0) { continue; } fprintf(fp, "%-20s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", TmModuleAlprotoToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } } for (m = 0; m < ALPROTO_MAX; m++) { int p; for (p = 0; p < 257; p++) { SCProfilePacketData *pd = &packet_profile_app_data6[m][p]; if (pd->cnt == 0) { continue; } fprintf(fp, "%-20s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", TmModuleAlprotoToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } } /* proto detect output */ { int p; for (p = 0; p < 257; p++) { SCProfilePacketData *pd = &packet_profile_app_pd_data4[p]; if (pd->cnt == 0) { continue; } fprintf(fp, "%-20s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", "Proto detect", p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } for (p = 0; p < 257; p++) { SCProfilePacketData *pd = &packet_profile_app_pd_data6[p]; if (pd->cnt == 0) { continue; } fprintf(fp, "%-20s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", "Proto detect", p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } } fprintf(fp, "\nGeneral detection engine stats:\n"); fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s\n", "Detection phase", "IP ver", "Proto", "cnt", "min", "max", "avg"); fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s\n", "------------------------", "------", "-----", "----------", "------------", "------------", "-----------"); for (m = 0; m < PROF_DETECT_SIZE; m++) { int p; for (p = 0; p < 257; p++) { SCProfilePacketData *pd = &packet_profile_detect_data4[m][p]; if (pd->cnt == 0) { continue; } fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", PacketProfileDetectIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } } for (m = 0; m < PROF_DETECT_SIZE; m++) { int p; for (p = 0; p < 257; p++) { SCProfilePacketData *pd = &packet_profile_detect_data6[m][p]; if (pd->cnt == 0) { continue; } fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", PacketProfileDetectIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt)); } } fclose(fp); } void SCProfilingPrintPacketProfile(Packet *p) { if (profiling_packets_csv_enabled == 0 || p == NULL || packet_profile_csv_fp == NULL) { return; } uint64_t delta = p->profile.ticks_end - p->profile.ticks_start; fprintf(packet_profile_csv_fp, "%"PRIu64",%c,%"PRIu8",%"PRIu64",", p->pcap_cnt, PKT_IS_IPV4(p) ? '4' : (PKT_IS_IPV6(p) ? '6' : '?'), p->proto, delta); int i; uint64_t tmm_total = 0; uint64_t tmm_streamtcp_tcp = 0; for (i = 0; i < TMM_SIZE; i++) { PktProfilingTmmData *pdt = &p->profile.tmm[i]; uint64_t tmm_delta = pdt->ticks_end - pdt->ticks_start; fprintf(packet_profile_csv_fp, "%"PRIu64",", tmm_delta); tmm_total += tmm_delta; if (p->proto == IPPROTO_TCP && i == TMM_STREAMTCP) { tmm_streamtcp_tcp = tmm_delta; } } fprintf(packet_profile_csv_fp, "%"PRIu64",", delta - tmm_total); uint64_t app_total = 0; for (i = 0; i < ALPROTO_MAX; i++) { PktProfilingAppData *pdt = &p->profile.app[i]; fprintf(packet_profile_csv_fp,"%"PRIu64",", pdt->ticks_spent); if (p->proto == IPPROTO_TCP) { app_total += pdt->ticks_spent; } } uint64_t real_tcp = 0; if (tmm_streamtcp_tcp > app_total) real_tcp = tmm_streamtcp_tcp - app_total; fprintf(packet_profile_csv_fp, "%"PRIu64",", real_tcp); fprintf(packet_profile_csv_fp, "%"PRIu64",", p->profile.proto_detect); for (i = 0; i < PROF_DETECT_SIZE; i++) { PktProfilingDetectData *pdt = &p->profile.detect[i]; fprintf(packet_profile_csv_fp,"%"PRIu64",", pdt->ticks_spent); } fprintf(packet_profile_csv_fp,"\n"); } static void SCProfilingUpdatePacketDetectRecord(PacketProfileDetectId id, uint8_t ipproto, PktProfilingDetectData *pdt, int ipver) { if (pdt == NULL) { return; } SCProfilePacketData *pd; if (ipver == 4) pd = &packet_profile_detect_data4[id][ipproto]; else pd = &packet_profile_detect_data6[id][ipproto]; if (pd->min == 0 || pdt->ticks_spent < pd->min) { pd->min = pdt->ticks_spent; } if (pd->max < pdt->ticks_spent) { pd->max = pdt->ticks_spent; } pd->tot += pdt->ticks_spent; pd->cnt ++; } void SCProfilingUpdatePacketDetectRecords(Packet *p) { PacketProfileDetectId i; for (i = 0; i < PROF_DETECT_SIZE; i++) { PktProfilingDetectData *pdt = &p->profile.detect[i]; if (pdt->ticks_spent > 0) { if (PKT_IS_IPV4(p)) { SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 4); } else { SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 6); } } } } static void SCProfilingUpdatePacketAppPdRecord(uint8_t ipproto, uint32_t ticks_spent, int ipver) { SCProfilePacketData *pd; if (ipver == 4) pd = &packet_profile_app_pd_data4[ipproto]; else pd = &packet_profile_app_pd_data6[ipproto]; if (pd->min == 0 || ticks_spent < pd->min) { pd->min = ticks_spent; } if (pd->max < ticks_spent) { pd->max = ticks_spent; } pd->tot += ticks_spent; pd->cnt ++; } static void SCProfilingUpdatePacketAppRecord(int alproto, uint8_t ipproto, PktProfilingAppData *pdt, int ipver) { if (pdt == NULL) { return; } SCProfilePacketData *pd; if (ipver == 4) pd = &packet_profile_app_data4[alproto][ipproto]; else pd = &packet_profile_app_data6[alproto][ipproto]; if (pd->min == 0 || pdt->ticks_spent < pd->min) { pd->min = pdt->ticks_spent; } if (pd->max < pdt->ticks_spent) { pd->max = pdt->ticks_spent; } pd->tot += pdt->ticks_spent; pd->cnt ++; } void SCProfilingUpdatePacketAppRecords(Packet *p) { int i; for (i = 0; i < ALPROTO_MAX; i++) { PktProfilingAppData *pdt = &p->profile.app[i]; if (pdt->ticks_spent > 0) { if (PKT_IS_IPV4(p)) { SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 4); } else { SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 6); } } } if (p->profile.proto_detect > 0) { if (PKT_IS_IPV4(p)) { SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile.proto_detect, 4); } else { SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile.proto_detect, 6); } } } void SCProfilingUpdatePacketTmmRecord(int module, uint8_t proto, PktProfilingTmmData *pdt, int ipver) { if (pdt == NULL) { return; } SCProfilePacketData *pd; if (ipver == 4) pd = &packet_profile_tmm_data4[module][proto]; else pd = &packet_profile_tmm_data6[module][proto]; uint32_t delta = (uint32_t)pdt->ticks_end - pdt->ticks_start; if (pd->min == 0 || delta < pd->min) { pd->min = delta; } if (pd->max < delta) { pd->max = delta; } pd->tot += (uint64_t)delta; pd->cnt ++; #ifdef PROFILE_LOCKING pd->lock += pdt->mutex_lock_cnt; pd->ticks += pdt->mutex_lock_wait_ticks; pd->contention += pdt->mutex_lock_contention; pd->slock += pdt->spin_lock_cnt; pd->sticks += pdt->spin_lock_wait_ticks; pd->scontention += pdt->spin_lock_contention; #endif } void SCProfilingUpdatePacketTmmRecords(Packet *p) { int i; for (i = 0; i < TMM_SIZE; i++) { PktProfilingTmmData *pdt = &p->profile.tmm[i]; if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) { continue; } if (PKT_IS_IPV4(p)) { SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 4); } else { SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 6); } } } void SCProfilingAddPacket(Packet *p) { if (p->profile.ticks_start == 0 || p->profile.ticks_end == 0 || p->profile.ticks_start > p->profile.ticks_end) return; pthread_mutex_lock(&packet_profile_lock); { if (profiling_packets_csv_enabled) SCProfilingPrintPacketProfile(p); if (PKT_IS_IPV4(p)) { SCProfilePacketData *pd = &packet_profile_data4[p->proto]; uint64_t delta = p->profile.ticks_end - p->profile.ticks_start; if (pd->min == 0 || delta < pd->min) { pd->min = delta; } if (pd->max < delta) { pd->max = delta; } pd->tot += delta; pd->cnt ++; if (IS_TUNNEL_PKT(p)) { pd = &packet_profile_data4[256]; if (pd->min == 0 || delta < pd->min) { pd->min = delta; } if (pd->max < delta) { pd->max = delta; } pd->tot += delta; pd->cnt ++; } SCProfilingUpdatePacketTmmRecords(p); SCProfilingUpdatePacketAppRecords(p); SCProfilingUpdatePacketDetectRecords(p); } else if (PKT_IS_IPV6(p)) { SCProfilePacketData *pd = &packet_profile_data6[p->proto]; uint64_t delta = p->profile.ticks_end - p->profile.ticks_start; if (pd->min == 0 || delta < pd->min) { pd->min = delta; } if (pd->max < delta) { pd->max = delta; } pd->tot += delta; pd->cnt ++; if (IS_TUNNEL_PKT(p)) { pd = &packet_profile_data6[256]; if (pd->min == 0 || delta < pd->min) { pd->min = delta; } if (pd->max < delta) { pd->max = delta; } pd->tot += delta; pd->cnt ++; } SCProfilingUpdatePacketTmmRecords(p); SCProfilingUpdatePacketAppRecords(p); SCProfilingUpdatePacketDetectRecords(p); } } pthread_mutex_unlock(&packet_profile_lock); } #define CASE_CODE(E) case E: return #E /** * \brief Maps the PacketProfileDetectId, to its string equivalent * * \param id PacketProfileDetectId id * * \retval string equivalent for the PacketProfileDetectId id */ const char * PacketProfileDetectIdToString(PacketProfileDetectId id) { switch (id) { CASE_CODE (PROF_DETECT_MPM); CASE_CODE (PROF_DETECT_MPM_PACKET); CASE_CODE (PROF_DETECT_MPM_PKT_STREAM); CASE_CODE (PROF_DETECT_MPM_STREAM); CASE_CODE (PROF_DETECT_MPM_URI); CASE_CODE (PROF_DETECT_MPM_HCBD); CASE_CODE (PROF_DETECT_MPM_HSBD); CASE_CODE (PROF_DETECT_MPM_HHD); CASE_CODE (PROF_DETECT_MPM_HRHD); CASE_CODE (PROF_DETECT_MPM_HMD); CASE_CODE (PROF_DETECT_MPM_HCD); CASE_CODE (PROF_DETECT_MPM_HRUD); CASE_CODE (PROF_DETECT_MPM_HSMD); CASE_CODE (PROF_DETECT_MPM_HSCD); CASE_CODE (PROF_DETECT_MPM_HUAD); CASE_CODE (PROF_DETECT_IPONLY); CASE_CODE (PROF_DETECT_RULES); CASE_CODE (PROF_DETECT_PREFILTER); CASE_CODE (PROF_DETECT_STATEFUL); CASE_CODE (PROF_DETECT_ALERT); CASE_CODE (PROF_DETECT_CLEANUP); CASE_CODE (PROF_DETECT_GETSGH); default: return "UNKNOWN"; } } #ifdef UNITTESTS static int ProfilingGenericTicksTest01(void) { #define TEST_RUNS 1024 uint64_t ticks_start = 0; uint64_t ticks_end = 0; void *ptr[TEST_RUNS]; int i; ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { ptr[i] = SCMalloc(1024); } ticks_end = UtilCpuGetTicks(); printf("malloc(1024) %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCFree(ptr[i]); } ticks_end = UtilCpuGetTicks(); printf("SCFree(1024) %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); SCMutex m[TEST_RUNS]; ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCMutexInit(&m[i], NULL); } ticks_end = UtilCpuGetTicks(); printf("SCMutexInit() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCMutexLock(&m[i]); } ticks_end = UtilCpuGetTicks(); printf("SCMutexLock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCMutexUnlock(&m[i]); } ticks_end = UtilCpuGetTicks(); printf("SCMutexUnlock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCMutexDestroy(&m[i]); } ticks_end = UtilCpuGetTicks(); printf("SCMutexDestroy() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); SCSpinlock s[TEST_RUNS]; ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCSpinInit(&s[i], 0); } ticks_end = UtilCpuGetTicks(); printf("SCSpinInit() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCSpinLock(&s[i]); } ticks_end = UtilCpuGetTicks(); printf("SCSpinLock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCSpinUnlock(&s[i]); } ticks_end = UtilCpuGetTicks(); printf("SCSpinUnlock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SCSpinDestroy(&s[i]); } ticks_end = UtilCpuGetTicks(); printf("SCSpinDestroy() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); SC_ATOMIC_DECL_AND_INIT(unsigned int, test); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { (void) SC_ATOMIC_ADD(test,1); } ticks_end = UtilCpuGetTicks(); printf("SC_ATOMIC_ADD %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); ticks_start = UtilCpuGetTicks(); for (i = 0; i < TEST_RUNS; i++) { SC_ATOMIC_CAS(&test,i,i+1); } ticks_end = UtilCpuGetTicks(); printf("SC_ATOMIC_CAS %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); return 1; } #endif /* UNITTESTS */ void SCProfilingRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01, 1); #endif /* UNITTESTS */ } #endif /* PROFILING */ suricata-1.4.7/src/util-unittest.c0000644000000000000000000001571012253546156014027 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Breno Silva * * Unit test framework */ #include "suricata-common.h" #include "runmodes.h" #include "util-unittest.h" #include "util-debug.h" #include "util-time.h" #include "conf.h" #ifdef UNITTESTS static pcre *parse_regex; static pcre_extra *parse_regex_study; static UtTest *ut_list; /** * \brief Allocate UtTest list member * * \retval ut Pointer to UtTest */ static UtTest *UtAllocTest(void) { UtTest *ut = SCMalloc(sizeof(UtTest)); if (unlikely(ut == NULL)) return NULL; memset(ut, 0, sizeof(UtTest)); return ut; } /** * \brief Append test in UtTest list * * \param list Pointer to the start of the IP packet * \param test Pointer to unit test * * \retval 0 Function always returns zero */ static int UtAppendTest(UtTest **list, UtTest *test) { if (*list == NULL) { *list = test; } else { UtTest *tmp = *list; while (tmp->next != NULL) { tmp = tmp->next; } tmp->next = test; } return 0; } /** * \brief Register unit test * * \param name Unit test name * \param TestFn Unit test function * \param evalue Unit test function return value * */ void UtRegisterTest(char *name, int(*TestFn)(void), int evalue) { UtTest *ut = UtAllocTest(); if (ut == NULL) return; ut->name = name; ut->TestFn = TestFn; ut->evalue = evalue; ut->next = NULL; /* append */ UtAppendTest(&ut_list, ut); } /** * \brief Compile a regex to run a specific unit test * * \param regex_arg The regular expression * * \retval 1 Regex compiled * \retval -1 Regex error */ int UtRegex (char *regex_arg) { const char *eb; int eo; int opts = PCRE_CASELESS;; if(regex_arg == NULL) return -1; parse_regex = pcre_compile(regex_arg, opts, &eb, &eo, NULL); if(parse_regex == NULL) { printf("pcre compile of \"%s\" failed at offset %" PRId32 ": %s\n", regex_arg, 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 1; error: return -1; } #define MAX_SUBSTRINGS 30 /** \brief List all registered unit tests. * * \param regex_arg Regular expression to limit listed tests. */ void UtListTests(char *regex_arg) { UtTest *ut; int ret = 0, rcomp = 0; int ov[MAX_SUBSTRINGS]; rcomp = UtRegex(regex_arg); for (ut = ut_list; ut != NULL; ut = ut->next) { if (rcomp == 1) { ret = pcre_exec(parse_regex, parse_regex_study, ut->name, strlen(ut->name), 0, 0, ov, MAX_SUBSTRINGS); if (ret >= 1) { printf("%s\n", ut->name); } } else { printf("%s\n", ut->name); } } } /** \brief Run all registered unittests. * * \param regex_arg The regular expression * * \retval 0 all successful * \retval result number of tests that failed */ uint32_t UtRunTests(char *regex_arg) { UtTest *ut; uint32_t good = 0, bad = 0, matchcnt = 0; int ret = 0, rcomp = 0; int ov[MAX_SUBSTRINGS]; int failure_fatal; if (ConfGetBool("unittests.failure-fatal", &failure_fatal) != 1) { SCLogDebug("ConfGetBool could not load the value."); failure_fatal = 0; } rcomp = UtRegex(regex_arg); if(rcomp == 1){ for (ut = ut_list; ut != NULL; ut = ut->next) { ret = pcre_exec(parse_regex, parse_regex_study, ut->name, strlen(ut->name), 0, 0, ov, MAX_SUBSTRINGS); if( ret >= 1 ) { printf("Test %-60.60s : ", ut->name); matchcnt++; fflush(stdout); /* flush so in case of a segv we see the testname */ /* reset the time */ TimeModeSetOffline(); TimeSetToCurrentTime(); ret = ut->TestFn(); printf("%s\n", (ret == ut->evalue) ? "pass" : "FAILED"); if (ret != ut->evalue) { if (failure_fatal == 1) { fprintf(stderr, "ERROR: unittest failed.\n"); exit(EXIT_FAILURE); } bad++; } else { good++; } } } if(matchcnt > 0){ printf("==== TEST RESULTS ====\n"); printf("PASSED: %" PRIu32 "\n", good); printf("FAILED: %" PRIu32 "\n", bad); printf("======================\n"); } else { SCLogInfo("UtRunTests: regex provided regex_arg: %s did not match any tests",regex_arg); } } else { SCLogInfo("UtRunTests: pcre compilation failed"); } return bad; } /** * \brief Initialize unit test list */ void UtInitialize(void) { ut_list = NULL; } /** * \brief Cleanup unit test list */ void UtCleanup(void) { UtTest *tmp = ut_list, *otmp; while (tmp != NULL) { otmp = tmp->next; SCFree(tmp); tmp = otmp; } ut_list = NULL; } void UtRunModeRegister(void) { RunModeRegisterNewRunMode(RUNMODE_UNITTEST, "unittest", "Unittest mode", NULL); return; } /* * unittests for the unittests code */ /** \brief True test * * \retval 1 True * \retval 0 False */ int UtSelftestTrue(void) { if (1)return 1; else return 0; } /** \brief False test * * \retval 1 False * \retval 0 True */ int UtSelftestFalse(void) { if (0)return 1; else return 0; } #endif /* UNITTESTS */ /** \brief Run self tests * * \param regex_arg The regular expression * * \retval 0 all successful */ int UtRunSelftest (char *regex_arg) { #ifdef UNITTESTS printf("* Running Unittesting subsystem selftests...\n"); UtInitialize(); UtRegisterTest("true", UtSelftestTrue, 1); UtRegisterTest("false", UtSelftestFalse, 0); int ret = UtRunTests(regex_arg); if (ret == 0) printf("* Done running Unittesting subsystem selftests...\n"); else printf("* ERROR running Unittesting subsystem selftests failed...\n"); UtCleanup(); #endif /* UNITTESTS */ return 0; } suricata-1.4.7/src/util-mpm-b3g.h0000644000000000000000000000651412253546156013421 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_MPM_B3G_H__ #define __UTIL_MPM_B3G_H__ #include "util-mpm.h" #include "util-bloomfilter.h" #define B3G_HASHSHIFT_MAX 8 #define B3G_HASHSHIFT_MAX2 5 #define B3G_HASHSHIFT_HIGHER 7 #define B3G_HASHSHIFT_HIGHER2 4 #define B3G_HASHSHIFT_HIGH 6 #define B3G_HASHSHIFT_HIGH2 3 #define B3G_HASHSHIFT_MEDIUM 5 #define B3G_HASHSHIFT_MEDIUM2 2 #define B3G_HASHSHIFT_LOW 4 #define B3G_HASHSHIFT_LOW2 1 #define B3G_HASHSHIFT_LOWEST 3 #define B3G_HASHSHIFT_LOWEST2 1 #define B3G_TYPE uint32_t //#define B3G_TYPE uint16_t //#define B3G_TYPE uint8_t //#define B3G_WORD_SIZE 16 //#define B3G_WORD_SIZE 8 #define B3G_WORD_SIZE 32 #define B3G_Q 3 //#define B3G_SEARCHFUNC B3gSearch #define B3G_SEARCHFUNC B3gSearchBNDMq //#define B3G_COUNTERS typedef struct B3gPattern_ { uint8_t *cs; /* case sensitive */ uint8_t *ci; /* case INsensitive */ uint16_t len; struct B3gPattern_ *next; uint8_t flags; uint32_t id; } B3gPattern; typedef struct B3gHashItem_ { uint8_t flags; uint16_t idx; struct B3gHashItem_ *nxt; } B3gHashItem; typedef struct B3gCtx_ { /* hash used during ctx initialization */ B3gPattern **init_hash; B3G_TYPE m; B3G_TYPE *B3G; uint8_t s0; uint16_t pat_1_cnt; uint16_t pat_2_cnt; uint16_t pat_x_cnt; uint32_t hash_size; B3gHashItem **hash; BloomFilter **bloom; uint8_t *pminlen; /* array containing the minimal length of the patters in a hash bucket. Used for the BloomFilter. */ B3gHashItem hash1[256]; B3gHashItem **hash2; uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* we store our own multi byte search func ptr here for B3gSearch1 */ uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* pattern arrays */ B3gPattern **parray; } B3gCtx; typedef struct B3gThreadCtx_ { #ifdef B3G_COUNTERS uint32_t stat_pminlen_calls; uint32_t stat_pminlen_total; uint32_t stat_bloom_calls; uint32_t stat_bloom_hits; uint32_t stat_calls; uint32_t stat_m_total; uint32_t stat_d0; uint32_t stat_d0_hashloop; uint32_t stat_loop_match; uint32_t stat_loop_no_match; uint32_t stat_num_shift; uint32_t stat_total_shift; #endif /* B3G_COUNTERS */ } B3gThreadCtx; void MpmB3gRegister(void); #endif suricata-1.4.7/src/respond-reject-libnet11.c0000644000000000000000000002261512253546156015540 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author William Metcalf * * RespondRejectLibnet11 used to send out libnet based * TCP resets and ICMP unreachables. * * \todo calculate TTL base on average from stream tracking * \todo come up with a way for users to specify icmp unreachable type * \todo Possibly default to port unreachable for UDP traffic this seems * to be the default in flexresp and iptables * \todo implement ipv6 resets * \todo implement pre-alloc resets for speed */ #include "suricata-common.h" #include "decode.h" #include "decode-ipv4.h" #include "decode-tcp.h" #include "decode-sctp.h" #include "decode-udp.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "action-globals.h" #include "respond-reject.h" #include "respond-reject-libnet11.h" #ifdef HAVE_LIBNET11 /** set to true in main if we're setting caps. We need it here if we're using * reject rules as libnet 1.1 is not compatible with caps. */ extern int sc_set_caps; #include typedef struct Libnet11Packet_ { uint32_t ack, seq; uint16_t window, dsize; uint8_t ttl; uint16_t id; uint32_t flow; uint8_t class; struct in6_addr src6, dst6; uint32_t src4, dst4; uint16_t sp, dp; size_t len; } Libnet11Packet; int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir) { Libnet11Packet lpacket; libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; /* fill in struct defaults */ lpacket.ttl = 0; lpacket.id = 0; lpacket.flow = 0; lpacket.class = 0; if ((c = libnet_init (LIBNET_RAW4, NULL, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf); return 1; } if (p->tcph == NULL) return 1; /* save payload len */ lpacket.dsize = p->payload_len; if (dir == REJECT_DIR_SRC) { SCLogDebug("sending a tcp reset to src"); lpacket.seq = TCP_GET_ACK(p); lpacket.ack = TCP_GET_SEQ(p) + lpacket.dsize; lpacket.sp = TCP_GET_DST_PORT(p); lpacket.dp = TCP_GET_SRC_PORT(p); lpacket.src4 = GET_IPV4_DST_ADDR_U32(p); lpacket.dst4 = GET_IPV4_SRC_ADDR_U32(p); } else if (dir == REJECT_DIR_DST) { SCLogDebug("sending a tcp reset to dst"); lpacket.seq = TCP_GET_SEQ(p); lpacket.ack = TCP_GET_ACK(p); lpacket.sp = TCP_GET_SRC_PORT(p); lpacket.dp = TCP_GET_DST_PORT(p); lpacket.src4 = GET_IPV4_SRC_ADDR_U32(p); lpacket.dst4 = GET_IPV4_DST_ADDR_U32(p); } else { SCLogError(SC_ERR_LIBNET_INVALID_DIR,"reset not src or dst returning"); return 1; } lpacket.window = TCP_GET_WINDOW(p); //lpacket.seq += lpacket.dsize; /* TODO come up with ttl calc function */ lpacket.ttl = 64; /* build the package */ if ((libnet_build_tcp ( lpacket.sp, /* source port */ lpacket.dp, /* dst port */ lpacket.seq, /* seq number */ lpacket.ack+1, /* ack number */ TH_RST|TH_ACK, /* flags */ lpacket.window, /* window size */ 0, /* checksum */ 0, /* urgent flag */ LIBNET_TCP_H, /* header length */ NULL, /* payload */ 0, /* payload length */ c, /* libnet context */ 0)) < 0) /* libnet ptag */ { SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_tcp %s", libnet_geterror(c)); goto cleanup; } if((libnet_build_ipv4( LIBNET_TCP_H + LIBNET_IPV4_H, /* entire packet length */ 0, /* tos */ lpacket.id, /* ID */ 0, /* fragmentation flags and offset */ lpacket.ttl, /* TTL */ IPPROTO_TCP, /* protocol */ 0, /* checksum */ lpacket.src4, /* source address */ lpacket.dst4, /* destination address */ NULL, /* pointer to packet data (or NULL) */ 0, /* payload length */ c, /* libnet context pointer */ 0)) < 0) /* packet id */ { SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ipv4 %s", libnet_geterror(c)); goto cleanup; } result = libnet_write(c); if (result == -1) { SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write failed: %s", libnet_geterror(c)); goto cleanup; } cleanup: libnet_destroy (c); return 0; } int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir) { //printf("going to send a ICMP host unreachable\n"); Libnet11Packet lpacket; libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; /* fill in struct defaults */ lpacket.ttl = 0; lpacket.id = 0; lpacket.flow = 0; lpacket.class = 0; lpacket.len = (IPV4_GET_HLEN(p) + p->payload_len); if ((c = libnet_init (LIBNET_RAW4, NULL, ebuf)) == NULL){ SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf); return 1; } if (dir == REJECT_DIR_SRC) { lpacket.src4 = GET_IPV4_DST_ADDR_U32(p); lpacket.dst4 = GET_IPV4_SRC_ADDR_U32(p); } else if (dir == REJECT_DIR_DST) { lpacket.src4 = GET_IPV4_SRC_ADDR_U32(p); lpacket.dst4 = GET_IPV4_DST_ADDR_U32(p); } else { SCLogError(SC_ERR_LIBNET_INVALID_DIR,"reset not src or dst returning"); return 1; } /* TODO come up with ttl calc function */ lpacket.ttl = 64; /* build the package */ if ((libnet_build_icmpv4_unreach ( ICMP_DEST_UNREACH, /* type */ ICMP_HOST_ANO, /* code */ 0, /* checksum */ (uint8_t *)p->ip4h, /* payload */ lpacket.len, /* payload length */ c, /* libnet context */ 0)) < 0) /* libnet ptag */ { SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_icmpv4_unreach %s", libnet_geterror(c)); goto cleanup; } if((libnet_build_ipv4( LIBNET_ICMPV4_H + LIBNET_IPV4_H + lpacket.len, /* entire packet length */ 0, /* tos */ lpacket.id, /* ID */ 0, /* fragmentation flags and offset */ lpacket.ttl, /* TTL */ IPPROTO_ICMP, /* protocol */ 0, /* checksum */ lpacket.src4, /* source address */ lpacket.dst4, /* destination address */ NULL, /* pointer to packet data (or NULL) */ 0, /* payload length */ c, /* libnet context pointer */ 0)) < 0) /* packet id */ { SCLogError(SC_ERR_LIBNET_BUILD_FAILED,"libnet_build_ipv4 %s", libnet_geterror(c)); goto cleanup; } result = libnet_write(c); if (result == -1) { SCLogError(SC_ERR_LIBNET_WRITE_FAILED,"libnet_write_raw_ipv4 failed: %s", libnet_geterror(c)); goto cleanup; } cleanup: libnet_destroy (c); return 0; } #else int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir) { SCLogError(SC_ERR_LIBNET_NOT_ENABLED,"Libnet based rejects are disabled. Usually this means that you don't have libnet installed, or configure couldn't find it."); return 0; } int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir) { SCLogError(SC_ERR_LIBNET_NOT_ENABLED,"Libnet based rejects are disabled. Usually this means that you don't have libnet installed, or configure couldn't find it."); return 0; } #endif /* HAVE_LIBNET11 */ suricata-1.4.7/src/detect-http-server-body.h0000644000000000000000000000166712253546156015674 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_HTTP_SERVER_BODY_H__ #define __DETECT_HTTP_SERVER_BODY_H__ void DetectHttpServerBodyRegister(void); #endif /* __DETECT_HTTP_SERVER_BODY_H__ */ suricata-1.4.7/src/detect-offset.h0000644000000000000000000000163712253546156013741 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_OFFSET_H__ #define __DETECT_OFFSET_H__ /* prototypes */ void DetectOffsetRegister (void); #endif /* __DETECT_OFFSET_H__ */ suricata-1.4.7/src/host.c0000644000000000000000000004451312253546156012155 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Information about hosts. */ #include "suricata-common.h" #include "conf.h" #include "util-debug.h" #include "host.h" #include "util-random.h" #include "util-misc.h" #include "util-byte.h" #include "host-queue.h" #include "detect-tag.h" #include "detect-engine-threshold.h" #include "util-hash-lookup3.h" static Host *HostGetUsedHost(void); /** queue with spare hosts */ static HostQueue host_spare_q; uint32_t HostSpareQueueGetSize(void) { return HostQueueLen(&host_spare_q); } void HostMoveToSpare(Host *h) { HostEnqueue(&host_spare_q, h); (void) SC_ATOMIC_SUB(host_counter, 1); } Host *HostAlloc(void) { if (!(HOST_CHECK_MEMCAP(sizeof(Host)))) { return NULL; } (void) SC_ATOMIC_ADD(host_memuse, sizeof(Host)); Host *h = SCMalloc(sizeof(Host)); if (unlikely(h == NULL)) goto error; memset(h, 0x00, sizeof(Host)); SCMutexInit(&h->m, NULL); SC_ATOMIC_INIT(h->use_cnt); return h; error: return NULL; } void HostFree(Host *h) { if (h != NULL) { HostClearMemory(h); SC_ATOMIC_DESTROY(h->use_cnt); SCMutexDestroy(&h->m); SCFree(h); (void) SC_ATOMIC_SUB(host_memuse, sizeof(Host)); } } Host *HostNew(Address *a) { Host *h = HostAlloc(); if (h == NULL) goto error; /* copy address */ COPY_ADDRESS(a, &h->a); return h; error: return NULL; } void HostClearMemory(Host *h) { if (h->tag != NULL) { DetectTagDataListFree(h->tag); h->tag = NULL; } if (h->threshold != NULL) { ThresholdListFree(h->threshold); h->threshold = NULL; } if (h->iprep != NULL) { SCFree(h->iprep); h->iprep = NULL; } } #define HOST_DEFAULT_HASHSIZE 4096 #define HOST_DEFAULT_MEMCAP 16777216 #define HOST_DEFAULT_PREALLOC 1000 /** \brief initialize the configuration * \warning Not thread safe */ void HostInitConfig(char quiet) { SCLogDebug("initializing host engine..."); memset(&host_config, 0, sizeof(host_config)); //SC_ATOMIC_INIT(flow_flags); SC_ATOMIC_INIT(host_counter); SC_ATOMIC_INIT(host_memuse); SC_ATOMIC_INIT(host_prune_idx); HostQueueInit(&host_spare_q); unsigned int seed = RandomTimePreseed(); /* set defaults */ host_config.hash_rand = (int)( HOST_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); host_config.hash_size = HOST_DEFAULT_HASHSIZE; host_config.memcap = HOST_DEFAULT_MEMCAP; host_config.prealloc = HOST_DEFAULT_PREALLOC; /* Check if we have memcap and hash_size defined at config */ char *conf_val; uint32_t configval = 0; /** set config values for memcap, prealloc and hash_size */ if ((ConfGet("host.memcap", &conf_val)) == 1) { if (ParseSizeStringU64(conf_val, &host_config.memcap) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing host.memcap " "from conf file - %s. Killing engine", conf_val); exit(EXIT_FAILURE); } } if ((ConfGet("host.hash-size", &conf_val)) == 1) { if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { host_config.hash_size = configval; } } if ((ConfGet("host.prealloc", &conf_val)) == 1) { if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { host_config.prealloc = configval; } } SCLogDebug("Host config from suricata.yaml: memcap: %"PRIu64", hash-size: " "%"PRIu32", prealloc: %"PRIu32, host_config.memcap, host_config.hash_size, host_config.prealloc); /* alloc hash memory */ uint64_t hash_size = host_config.hash_size * sizeof(HostHashRow); if (!(HOST_CHECK_MEMCAP(hash_size))) { SCLogError(SC_ERR_HOST_INIT, "allocating host hash failed: " "max host memcap is smaller than projected hash size. " "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate " "total hash size by multiplying \"host.hash-size\" with %"PRIuMAX", " "which is the hash bucket size.", host_config.memcap, hash_size, (uintmax_t)sizeof(HostHashRow)); exit(EXIT_FAILURE); } host_hash = SCCalloc(host_config.hash_size, sizeof(HostHashRow)); if (unlikely(host_hash == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in HostInitConfig. Exiting..."); exit(EXIT_FAILURE); } memset(host_hash, 0, host_config.hash_size * sizeof(HostHashRow)); uint32_t i = 0; for (i = 0; i < host_config.hash_size; i++) { HRLOCK_INIT(&host_hash[i]); } (void) SC_ATOMIC_ADD(host_memuse, (host_config.hash_size * sizeof(HostHashRow))); if (quiet == FALSE) { SCLogInfo("allocated %llu bytes of memory for the host hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(host_memuse), host_config.hash_size, (uintmax_t)sizeof(HostHashRow)); } /* pre allocate hosts */ for (i = 0; i < host_config.prealloc; i++) { if (!(HOST_CHECK_MEMCAP(sizeof(Host)))) { SCLogError(SC_ERR_HOST_INIT, "preallocating hosts failed: " "max host memcap reached. Memcap %"PRIu64", " "Memuse %"PRIu64".", host_config.memcap, ((uint64_t)SC_ATOMIC_GET(host_memuse) + (uint64_t)sizeof(Host))); exit(EXIT_FAILURE); } Host *h = HostAlloc(); if (h == NULL) { SCLogError(SC_ERR_HOST_INIT, "preallocating host failed: %s", strerror(errno)); exit(EXIT_FAILURE); } HostEnqueue(&host_spare_q,h); } if (quiet == FALSE) { SCLogInfo("preallocated %" PRIu32 " hosts of size %" PRIuMAX "", host_spare_q.len, (uintmax_t)sizeof(Host)); SCLogInfo("host memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); } return; } /** \brief print some host stats * \warning Not thread safe */ void HostPrintStats (void) { #ifdef HOSTBITS_STATS SCLogInfo("hostbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", hostbits_added, hostbits_removed, hostbits_memuse_max); #endif /* HOSTBITS_STATS */ SCLogInfo("host memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); return; } /** \brief shutdown the flow engine * \warning Not thread safe */ void HostShutdown(void) { Host *h; uint32_t u; HostPrintStats(); /* free spare queue */ while((h = HostDequeue(&host_spare_q))) { BUG_ON(SC_ATOMIC_GET(h->use_cnt) > 0); HostFree(h); } /* clear and free the hash */ if (host_hash != NULL) { for (u = 0; u < host_config.hash_size; u++) { Host *h = host_hash[u].head; while (h) { Host *n = h->hnext; HostFree(h); h = n; } HRLOCK_DESTROY(&host_hash[u]); } SCFree(host_hash); host_hash = NULL; } (void) SC_ATOMIC_SUB(host_memuse, host_config.hash_size * sizeof(HostHashRow)); HostQueueDestroy(&host_spare_q); SC_ATOMIC_DESTROY(host_prune_idx); SC_ATOMIC_DESTROY(host_memuse); SC_ATOMIC_DESTROY(host_counter); //SC_ATOMIC_DESTROY(flow_flags); return; } /** \brief Cleanup the host engine * * Cleanup the host engine from tag and threshold. * */ void HostCleanup(void) { Host *h; uint32_t u; if (host_hash != NULL) { for (u = 0; u < host_config.hash_size; u++) { h = host_hash[u].head; HostHashRow *hb = &host_hash[u]; HRLOCK_LOCK(hb); while (h) { if ((SC_ATOMIC_GET(h->use_cnt) > 0) && (h->iprep != NULL)) { /* iprep is attached to host only clear tag and threshold */ if (h->tag != NULL) { DetectTagDataListFree(h->tag); h->tag = NULL; } if (h->threshold != NULL) { ThresholdListFree(h->threshold); h->threshold = NULL; } h = h->hnext; } else { Host *n = h->hnext; /* remove from the hash */ if (h->hprev != NULL) h->hprev->hnext = h->hnext; if (h->hnext != NULL) h->hnext->hprev = h->hprev; if (hb->head == h) hb->head = h->hnext; if (hb->tail == h) hb->tail = h->hprev; h->hnext = NULL; h->hprev = NULL; HostClearMemory(h); HostMoveToSpare(h); h = n; } } HRLOCK_UNLOCK(hb); } } return; } /* calculate the hash key for this packet * * we're using: * hash_rand -- set at init time * source address */ uint32_t HostGetKey(Address *a) { uint32_t key; if (a->family == AF_INET) { uint32_t hash = hashword(&a->addr_data32[0], 1, host_config.hash_rand); key = hash % host_config.hash_size; } else if (a->family == AF_INET6) { uint32_t hash = hashword(a->addr_data32, 4, host_config.hash_rand); key = hash % host_config.hash_size; } else key = 0; return key; } /* Since two or more hosts can have the same hash key, we need to compare * the flow with the current flow key. */ #define CMP_HOST(h,a) \ (CMP_ADDR(&(h)->a, (a))) static inline int HostCompare(Host *h, Address *a) { return CMP_HOST(h, a); } /** * \brief Get a new host * * Get a new host. We're checking memcap first and will try to make room * if the memcap is reached. * * \retval h *LOCKED* host on succes, NULL on error. */ static Host *HostGetNew(Address *a) { Host *h = NULL; /* get a host from the spare queue */ h = HostDequeue(&host_spare_q); if (h == NULL) { /* If we reached the max memcap, we get a used host */ if (!(HOST_CHECK_MEMCAP(sizeof(Host)))) { /* declare state of emergency */ //if (!(SC_ATOMIC_GET(host_flags) & HOST_EMERGENCY)) { // SC_ATOMIC_OR(host_flags, HOST_EMERGENCY); /* under high load, waking up the flow mgr each time leads * to high cpu usage. Flows are not timed out much faster if * we check a 1000 times a second. */ // FlowWakeupFlowManagerThread(); //} h = HostGetUsedHost(); if (h == NULL) { return NULL; } /* freed a host, but it's unlocked */ } else { /* now see if we can alloc a new host */ h = HostNew(a); if (h == NULL) { return NULL; } /* host is initialized but *unlocked* */ } } else { /* host has been recycled before it went into the spare queue */ /* host is initialized (recylced) but *unlocked* */ } (void) SC_ATOMIC_ADD(host_counter, 1); SCMutexLock(&h->m); return h; } void HostInit(Host *h, Address *a) { COPY_ADDRESS(a, &h->a); (void) HostIncrUsecnt(h); } void HostRelease(Host *h) { (void) HostDecrUsecnt(h); SCMutexUnlock(&h->m); } void HostLock(Host *h) { SCMutexLock(&h->m); } /* HostGetHostFromHash * * Hash retrieval function for hosts. Looks up the hash bucket containing the * host pointer. Then compares the packet with the found host to see if it is * the host we need. If it isn't, walk the list until the right host is found. * * returns a *LOCKED* host or NULL */ Host *HostGetHostFromHash (Address *a) { Host *h = NULL; /* get the key to our bucket */ uint32_t key = HostGetKey(a); /* get our hash bucket and lock it */ HostHashRow *hb = &host_hash[key]; HRLOCK_LOCK(hb); /* see if the bucket already has a host */ if (hb->head == NULL) { h = HostGetNew(a); if (h == NULL) { HRLOCK_UNLOCK(hb); return NULL; } /* host is locked */ hb->head = h; hb->tail = h; /* got one, now lock, initialize and return */ HostInit(h,a); HRLOCK_UNLOCK(hb); return h; } /* ok, we have a host in the bucket. Let's find out if it is our host */ h = hb->head; /* see if this is the host we are looking for */ if (HostCompare(h, a) == 0) { Host *ph = NULL; /* previous host */ while (h) { ph = h; h = h->hnext; if (h == NULL) { h = ph->hnext = HostGetNew(a); if (h == NULL) { HRLOCK_UNLOCK(hb); return NULL; } hb->tail = h; /* host is locked */ h->hprev = ph; /* initialize and return */ HostInit(h,a); HRLOCK_UNLOCK(hb); return h; } if (HostCompare(h, a) != 0) { /* we found our host, lets put it on top of the * hash list -- this rewards active hosts */ if (h->hnext) { h->hnext->hprev = h->hprev; } if (h->hprev) { h->hprev->hnext = h->hnext; } if (h == hb->tail) { hb->tail = h->hprev; } h->hnext = hb->head; h->hprev = NULL; hb->head->hprev = h; hb->head = h; /* found our host, lock & return */ SCMutexLock(&h->m); (void) HostIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } } } /* lock & return */ SCMutexLock(&h->m); (void) HostIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } /** \brief look up a host in the hash * * \param a address to look up * * \retval h *LOCKED* host or NULL */ Host *HostLookupHostFromHash (Address *a) { Host *h = NULL; /* get the key to our bucket */ uint32_t key = HostGetKey(a); /* get our hash bucket and lock it */ HostHashRow *hb = &host_hash[key]; HRLOCK_LOCK(hb); /* see if the bucket already has a host */ if (hb->head == NULL) { HRLOCK_UNLOCK(hb); return h; } /* ok, we have a host in the bucket. Let's find out if it is our host */ h = hb->head; /* see if this is the host we are looking for */ if (HostCompare(h, a) == 0) { while (h) { h = h->hnext; if (h == NULL) { HRLOCK_UNLOCK(hb); return h; } if (HostCompare(h, a) != 0) { /* we found our host, lets put it on top of the * hash list -- this rewards active hosts */ if (h->hnext) { h->hnext->hprev = h->hprev; } if (h->hprev) { h->hprev->hnext = h->hnext; } if (h == hb->tail) { hb->tail = h->hprev; } h->hnext = hb->head; h->hprev = NULL; hb->head->hprev = h; hb->head = h; /* found our host, lock & return */ SCMutexLock(&h->m); (void) HostIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } } } /* lock & return */ SCMutexLock(&h->m); (void) HostIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } /** \internal * \brief Get a host from the hash directly. * * Called in conditions where the spare queue is empty and memcap is reached. * * Walks the hash until a host can be freed. "host_prune_idx" atomic int makes * sure we don't start at the top each time since that would clear the top of * the hash leading to longer and longer search times under high pressure (observed). * * \retval h host or NULL */ static Host *HostGetUsedHost(void) { uint32_t idx = SC_ATOMIC_GET(host_prune_idx) % host_config.hash_size; uint32_t cnt = host_config.hash_size; while (cnt--) { if (++idx >= host_config.hash_size) idx = 0; HostHashRow *hb = &host_hash[idx]; if (HRLOCK_TRYLOCK(hb) != 0) continue; Host *h = hb->tail; if (h == NULL) { HRLOCK_UNLOCK(hb); continue; } if (SCMutexTrylock(&h->m) != 0) { HRLOCK_UNLOCK(hb); continue; } /** never prune a host that is used by a packets * we are currently processing in one of the threads */ if (SC_ATOMIC_GET(h->use_cnt) > 0) { HRLOCK_UNLOCK(hb); SCMutexUnlock(&h->m); continue; } /* remove from the hash */ if (h->hprev != NULL) h->hprev->hnext = h->hnext; if (h->hnext != NULL) h->hnext->hprev = h->hprev; if (hb->head == h) hb->head = h->hnext; if (hb->tail == h) hb->tail = h->hprev; h->hnext = NULL; h->hprev = NULL; HRLOCK_UNLOCK(hb); HostClearMemory (h); SCMutexUnlock(&h->m); (void) SC_ATOMIC_ADD(host_prune_idx, (host_config.hash_size - cnt)); return h; } return NULL; } suricata-1.4.7/src/util-bloomfilter.c0000644000000000000000000001535112253546156014467 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Bitwise bloom filter implementation */ #include "suricata-common.h" #include "util-bloomfilter.h" #include "util-unittest.h" BloomFilter *BloomFilterInit(uint32_t size, uint8_t iter, uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t)) { BloomFilter *bf = NULL; if (size == 0 || iter == 0) goto error; if (Hash == NULL) { //printf("ERROR: BloomFilterInit no Hash function\n"); goto error; } /* setup the filter */ bf = SCMalloc(sizeof(BloomFilter)); if (unlikely(bf == NULL)) goto error; memset(bf,0,sizeof(BloomFilter)); bf->bitarray_size = size; bf->hash_iterations = iter; bf->Hash = Hash; /* setup the bitarray */ bf->bitarray = SCMalloc((bf->bitarray_size/8)+1); if (bf->bitarray == NULL) goto error; memset(bf->bitarray,0,(bf->bitarray_size/8)+1); return bf; error: if (bf != NULL) { if (bf->bitarray != NULL) SCFree(bf->bitarray); SCFree(bf); } return NULL; } void BloomFilterFree(BloomFilter *bf) { if (bf != NULL) { if (bf->bitarray != NULL) SCFree(bf->bitarray); SCFree(bf); } } void BloomFilterPrint(BloomFilter *bf) { printf("\n---------- Bloom Filter Stats -----------\n"); printf("Buckets: %" PRIu32 "\n", bf->bitarray_size); printf("Memory size: %" PRIu32 " bytes\n", bf->bitarray_size/8 + 1); printf("Hash function pointer: %p\n", bf->Hash); printf("Hash functions: %" PRIu32 "\n", bf->hash_iterations); printf("-----------------------------------------\n"); } int BloomFilterAdd(BloomFilter *bf, void *data, uint16_t datalen) { uint8_t iter = 0; uint32_t hash = 0; if (bf == NULL || data == NULL || datalen == 0) return -1; for (iter = 0; iter < bf->hash_iterations; iter++) { hash = bf->Hash(data, datalen, iter, bf->bitarray_size); bf->bitarray[hash/8] |= (1<bitarray_size/8) + 1); } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS static uint32_t BloomFilterTestHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint32_t i; uint32_t hash = 0; for (i = 0; i < datalen; i++) { if (i == 0) hash += (((uint32_t)*d++)); else if (i == 1) hash += (((uint32_t)*d++) * datalen); else hash *= (((uint32_t)*d++) * i); } hash *= (iter + datalen); hash %= hash_size; return hash; } static int BloomFilterTestInit01 (void) { BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); if (bf == NULL) return 0; BloomFilterFree(bf); return 1; } /* no hash function, so it should fail */ static int BloomFilterTestInit02 (void) { BloomFilter *bf = BloomFilterInit(1024, 4, NULL); if (bf == NULL) return 1; BloomFilterFree(bf); return 0; } static int BloomFilterTestInit03 (void) { int result = 0; BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); if (bf == NULL) return 0; if (bf->Hash == BloomFilterTestHash) result = 1; BloomFilterFree(bf); return result; } static int BloomFilterTestInit04 (void) { BloomFilter *bf = BloomFilterInit(1024, 0, BloomFilterTestHash); if (bf == NULL) return 1; BloomFilterFree(bf); return 0; } static int BloomFilterTestInit05 (void) { BloomFilter *bf = BloomFilterInit(0, 4, BloomFilterTestHash); if (bf == NULL) return 1; BloomFilterFree(bf); return 0; } static int BloomFilterTestAdd01 (void) { int result = 0; BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); if (bf == NULL) return 0; int r = BloomFilterAdd(bf, "test", 0); if (r == 0) goto end; /* all is good! */ result = 1; end: if (bf != NULL) BloomFilterFree(bf); return result; } static int BloomFilterTestAdd02 (void) { int result = 0; BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); if (bf == NULL) return 0; int r = BloomFilterAdd(bf, NULL, 4); if (r == 0) goto end; /* all is good! */ result = 1; end: if (bf != NULL) BloomFilterFree(bf); return result; } static int BloomFilterTestFull01 (void) { int result = 0; BloomFilter *bf = BloomFilterInit(32, 4, BloomFilterTestHash); if (bf == NULL) goto end; int r = BloomFilterAdd(bf, "test", 4); if (r != 0) goto end; r = BloomFilterTest(bf, "test", 4); if (r != 1) goto end; /* all is good! */ result = 1; end: if (bf != NULL) BloomFilterFree(bf); return result; } static int BloomFilterTestFull02 (void) { int result = 0; BloomFilter *bf = BloomFilterInit(32, 4, BloomFilterTestHash); if (bf == NULL) goto end; int r = BloomFilterTest(bf, "test", 4); if (r != 0) goto end; /* all is good! */ result = 1; end: if (bf != NULL) BloomFilterFree(bf); return result; } #endif /* UNITTESTS */ void BloomFilterRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("BloomFilterTestInit01", BloomFilterTestInit01, 1); UtRegisterTest("BloomFilterTestInit02", BloomFilterTestInit02, 1); UtRegisterTest("BloomFilterTestInit03", BloomFilterTestInit03, 1); UtRegisterTest("BloomFilterTestInit04", BloomFilterTestInit04, 1); UtRegisterTest("BloomFilterTestInit05", BloomFilterTestInit05, 1); UtRegisterTest("BloomFilterTestAdd01", BloomFilterTestAdd01, 1); UtRegisterTest("BloomFilterTestAdd02", BloomFilterTestAdd02, 1); UtRegisterTest("BloomFilterTestFull01", BloomFilterTestFull01, 1); UtRegisterTest("BloomFilterTestFull02", BloomFilterTestFull02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/alert-unified2-alert.h0000644000000000000000000000265012253546156015120 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * \author Breno Silva */ #ifndef __ALERT_UNIFIED2_ALERT_H__ #define __ALERT_UNIFIED2_ALERT_H__ /** Unified2 Option packet action */ #define UNIFIED2_PACKET_FLAG 1 #define UNIFIED2_BLOCKED_FLAG 0x20 /** Unified2 Header Types */ #define UNIFIED2_EVENT_TYPE 1 #define UNIFIED2_PACKET_TYPE 2 #define UNIFIED2_IDS_EVENT_TYPE 7 #define UNIFIED2_EVENT_EXTENDED_TYPE 66 #define UNIFIED2_PERFORMANCE_TYPE 67 #define UNIFIED2_PORTSCAN_TYPE 68 #define UNIFIED2_IDS_EVENT_IPV6_TYPE 72 #define UNIFIED2_IDS_EVENT_MPLS_TYPE 99 #define UNIFIED2_IDS_EVENT_IPV6_MPLS_TYPE 100 void TmModuleUnified2AlertRegister (void); OutputCtx *Unified2AlertInitCtx(ConfNode *); #endif /* __ALERT_UNIFIED2_ALERT_H__ */ suricata-1.4.7/src/detect-parse.h0000644000000000000000000000425212253546156013561 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_PARSE_H__ #define __DETECT_PARSE_H__ /** Flags to indicate if the Signature parsing must be done * switching the source and dest (for ip addresses and ports) * or otherwise as normal */ enum { SIG_DIREC_NORMAL, SIG_DIREC_SWITCHED }; /** Flags to indicate if are referencing the source of the Signature * or the destination (for ip addresses and ports)*/ enum { SIG_DIREC_SRC, SIG_DIREC_DST }; /* prototypes */ int SigParse(DetectEngineCtx *,Signature *, char *, uint8_t); Signature *SigAlloc(void); void SigFree(Signature *s); Signature *SigInit(DetectEngineCtx *,char *sigstr); Signature *SigInitReal(DetectEngineCtx *, char *); SigMatch *SigMatchGetLastSMFromLists(Signature *, int, ...); void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, SigMatch **, SigMatch **s, SigMatch **, SigMatch **); void SigParsePrepare(void); void SigParseRegisterTests(void); Signature *DetectEngineAppendSig(DetectEngineCtx *, char *); void SigMatchAppendSMToList(Signature *, SigMatch *, int); void SigMatchRemoveSMFromList(Signature *, SigMatch *, int); int SigMatchListSMBelongsTo(Signature *, SigMatch *); int DetectParseDupSigHashInit(DetectEngineCtx *); void DetectParseDupSigHashFree(DetectEngineCtx *); int DetectParseContentString (char *, uint8_t **, uint16_t *, uint32_t *); #endif /* __DETECT_PARSE_H__ */ suricata-1.4.7/src/util-spm-bs2bm.c0000644000000000000000000001337612253546156013760 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * Bs2Bm use a simple context array to determine the charactes * that are not present on the pattern. This way on partial matches * broken by a char not present, we can skip to the next character * making less checks */ #include "suricata-common.h" #include "suricata.h" #include "util-spm-bs2bm.h" /** * \brief Array setup function for Bs2Bm of bad characters index (not found at the needle) * * \param neddle pointer to the pattern we ar searching for * \param needle_len length limit of the needle * \param badchars pointer to an empty array of bachars. The array prepared contains * characters that can't be inside the needle_len. So the skips can be * faster */ void Bs2BmBadchars(const uint8_t *needle, uint16_t needle_len, uint8_t *badchars) { uint32_t i; for (i = 0; i < ALPHABET_SIZE; i++) badchars[i] = 1; /* set to 0 the values where index as ascii is present * because they are not badchars */ for (i = 0; i < needle_len; i++) badchars[needle[i]] = 0; } /** * \brief Array setup function for Bs2BmNocase of bad characters index (not found at the needle) * * \param neddle pointer to the pattern we ar searching for * \param needle_len length limit of the needle * \param badchars pointer to an empty array of bachars. The array prepared contains * characters that can't be inside the needle_len. So the skips can be * faster */ void Bs2BmBadcharsNocase(const uint8_t *needle, uint16_t needle_len, uint8_t *badchars) { uint32_t i; for (i = 0; i < ALPHABET_SIZE; i++) badchars[i] = 1; /* set to 0 the values where index as ascii is present * because they are not badchars */ for (i = 0; i < needle_len; i++) { badchars[u8_tolower(needle[i])] = 0; } } /** * \brief Basic search with a bad characters array. The array badchars contains * flags at character's ascii index that can't be inside the needle. So the skips can be * faster * * \param haystack pointer to the buffer to search in * \param haystack_len length limit of the buffer * \param neddle pointer to the pattern we ar searching for * \param needle_len length limit of the needle * \param badchars pointer to an array of bachars prepared by Bs2BmBadchars() * * \retval ptr to start of the match; NULL if no match */ uint8_t * Bs2Bm(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len, uint8_t badchars[]) { const uint8_t *h, *n; const uint8_t *hmax = haystack + haystack_len; const uint8_t *nmax = needle + needle_len; if (needle_len == 0 || needle_len > haystack_len) return NULL; for (n = needle; nmax - n <= hmax - haystack; haystack++) { if (*haystack != *n) { continue; } /* one byte needles */ if (needle_len == 1) return (uint8_t *)haystack; for (h = haystack+1, n++; nmax - n <= hmax - haystack; h++, n++) { if (*h != *n) { if (badchars[*h] == 1) { /* skip it! */ haystack = h; } break; } /* if we run out of needle we fully matched */ if (n == nmax - 1 ) { return (uint8_t *)haystack; } } n = needle; } return NULL; } /** * \brief Basic search case less with a bad characters array. The array badchars contains * flags at character's ascii index that can't be inside the needle. So the skips can be * faster * * \param haystack pointer to the buffer to search in * \param haystack_len length limit of the buffer * \param neddle pointer to the pattern we ar searching for * \param needle_len length limit of the needle * \param badchars pointer to an array of bachars prepared by Bs2BmBadchars() * * \retval ptr to start of the match; NULL if no match */ uint8_t *Bs2BmNocase(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len, uint8_t badchars[]) { const uint8_t *h, *n; const uint8_t *hmax = haystack + haystack_len; const uint8_t *nmax = needle + needle_len; if (needle_len == 0 || needle_len > haystack_len) return NULL; for (n = needle; nmax - n <= hmax - haystack; haystack++) { if (u8_tolower(*haystack) != u8_tolower(*n)) { continue; } /* one byte needles */ if (needle_len == 1) return (uint8_t *)haystack; for (h = haystack+1, n++; nmax - n <= hmax - haystack; h++, n++) { if (u8_tolower(*h) != u8_tolower(*n)) { if (badchars[u8_tolower(*h)] == 1) { /* skip it! */ haystack = h; } break; } /* if we run out of needle we fully matched */ if (n == nmax - 1) { return (uint8_t *)haystack; } } n = needle; } return NULL; } suricata-1.4.7/src/detect-file-data.c0000644000000000000000000000527012253546156014271 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-spm-bm.h" #include "util-unittest.h" #include "util-unittest-helper.h" static int DetectFiledataSetup (DetectEngineCtx *, Signature *, char *); /** * \brief Registration function for keyword: file_data */ void DetectFiledataRegister(void) { sigmatch_table[DETECT_FILE_DATA].name = "file_data"; sigmatch_table[DETECT_FILE_DATA].desc = "make content keywords match on HTTP response body"; sigmatch_table[DETECT_FILE_DATA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#file_data"; sigmatch_table[DETECT_FILE_DATA].Match = NULL; sigmatch_table[DETECT_FILE_DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_FILE_DATA].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILE_DATA].Setup = DetectFiledataSetup; sigmatch_table[DETECT_FILE_DATA].Free = NULL; sigmatch_table[DETECT_FILE_DATA].RegisterTests = NULL; } /** * \brief this function is used to parse filedata options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param str pointer to the user provided "filestore" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); if ((s->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_server or from_client with http."); return -1; } s->init_flags |= SIG_FLAG_INIT_FILE_DATA; return 0; } suricata-1.4.7/src/flow-timeout.c0000644000000000000000000006560712253546156013642 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "conf.h" #include "threadvars.h" #include "tm-threads.h" #include "runmodes.h" #include "util-random.h" #include "util-time.h" #include "flow.h" #include "flow-queue.h" #include "flow-hash.h" #include "flow-util.h" #include "flow-var.h" #include "flow-private.h" #include "flow-manager.h" #include "pkt-var.h" #include "host.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-byte.h" #include "util-debug.h" #include "util-privs.h" #include "detect.h" #include "detect-engine-state.h" #include "stream.h" #include "app-layer-parser.h" #include "util-profiling.h" static TmSlot *stream_pseudo_pkt_stream_tm_slot = NULL; static ThreadVars *stream_pseudo_pkt_stream_TV = NULL; static TmSlot *stream_pseudo_pkt_detect_tm_slot = NULL; static ThreadVars *stream_pseudo_pkt_detect_TV = NULL; static ThreadVars *stream_pseudo_pkt_detect_prev_TV = NULL; static TmSlot *stream_pseudo_pkt_decode_tm_slot = NULL; static ThreadVars *stream_pseudo_pkt_decode_TV = NULL; /** * \internal * \brief Flush out if we have any unattended packets. */ static inline void FlowForceReassemblyFlushPendingPseudoPackets(void) { /* we don't lock the queue, since flow manager is dead */ if (stream_pseudo_pkt_decode_tm_slot->slot_post_pq.len == 0) return; SCMutexLock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); Packet *p = PacketDequeue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq); SCMutexUnlock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); if (TmThreadsSlotProcessPkt(stream_pseudo_pkt_decode_TV, stream_pseudo_pkt_decode_tm_slot, p) != TM_ECODE_OK) { SCLogError(SC_ERR_TM_THREADS_ERROR, "Received error from FFR on " "flushing packets through decode->.. TMs"); } return; } /** * \internal * \brief Pseudo packet setup for flow forced reassembly. * * \param direction Direction of the packet. 0 indicates toserver and 1 * indicates toclient. * \param f Pointer to the flow. * \param ssn Pointer to the tcp session. * \param dummy Indicates to create a dummy pseudo packet. Not all pseudo * packets need to force reassembly, in which case we just * set dummy ack/seq values. */ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, int direction, Flow *f, TcpSession *ssn, int dummy) { p->datalink = DLT_RAW; p->proto = IPPROTO_TCP; FlowReference(&p->flow, f); p->flags |= PKT_STREAM_EST; p->flags |= PKT_STREAM_EOF; p->flags |= PKT_HAS_FLOW; p->flags |= PKT_PSEUDO_STREAM_END; if (direction == 0) p->flowflags |= FLOW_PKT_TOSERVER; else p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->payload = NULL; p->payload_len = 0; if (FLOW_IS_IPV4(f)) { if (direction == 0) { FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &p->src); FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &p->dst); p->sp = f->sp; p->dp = f->dp; } else { FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &p->dst); FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &p->src); p->sp = f->dp; p->dp = f->sp; } /* set the ip header */ p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); /* version 4 and length 20 bytes for the tcp header */ p->ip4h->ip_verhl = 0x45; p->ip4h->ip_tos = 0; p->ip4h->ip_len = htons(40); p->ip4h->ip_id = 0; p->ip4h->ip_off = 0; p->ip4h->ip_ttl = 64; p->ip4h->ip_proto = IPPROTO_TCP; //p->ip4h->ip_csum = if (direction == 0) { p->ip4h->s_ip_src.s_addr = f->src.addr_data32[0]; p->ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0]; } else { p->ip4h->s_ip_src.s_addr = f->dst.addr_data32[0]; p->ip4h->s_ip_dst.s_addr = f->src.addr_data32[0]; } /* set the tcp header */ p->tcph = (TCPHdr *)((uint8_t *)GET_PKT_DATA(p) + 20); SET_PKT_LEN(p, 40); /* ipv4 hdr + tcp hdr */ } else if (FLOW_IS_IPV6(f)) { if (direction == 0) { FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &p->src); FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &p->dst); p->sp = f->sp; p->dp = f->dp; } else { FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &p->dst); FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &p->src); p->sp = f->dp; p->dp = f->sp; } /* set the ip header */ p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p); /* version 6 */ p->ip6h->s_ip6_vfc = 0x60; p->ip6h->s_ip6_flow = 0; p->ip6h->s_ip6_nxt = IPPROTO_TCP; p->ip6h->s_ip6_plen = htons(20); p->ip6h->s_ip6_hlim = 64; if (direction == 0) { p->ip6h->s_ip6_src[0] = f->src.addr_data32[0]; p->ip6h->s_ip6_src[1] = f->src.addr_data32[1]; p->ip6h->s_ip6_src[2] = f->src.addr_data32[2]; p->ip6h->s_ip6_src[3] = f->src.addr_data32[3]; p->ip6h->s_ip6_dst[0] = f->dst.addr_data32[0]; p->ip6h->s_ip6_dst[1] = f->dst.addr_data32[1]; p->ip6h->s_ip6_dst[2] = f->dst.addr_data32[2]; p->ip6h->s_ip6_dst[3] = f->dst.addr_data32[3]; } else { p->ip6h->s_ip6_src[0] = f->dst.addr_data32[0]; p->ip6h->s_ip6_src[1] = f->dst.addr_data32[1]; p->ip6h->s_ip6_src[2] = f->dst.addr_data32[2]; p->ip6h->s_ip6_src[3] = f->dst.addr_data32[3]; p->ip6h->s_ip6_dst[0] = f->src.addr_data32[0]; p->ip6h->s_ip6_dst[1] = f->src.addr_data32[1]; p->ip6h->s_ip6_dst[2] = f->src.addr_data32[2]; p->ip6h->s_ip6_dst[3] = f->src.addr_data32[3]; } /* set the tcp header */ p->tcph = (TCPHdr *)((uint8_t *)GET_PKT_DATA(p) + 40); SET_PKT_LEN(p, 60); /* ipv6 hdr + tcp hdr */ } p->tcph->th_offx2 = 0x50; p->tcph->th_flags |= TH_ACK; p->tcph->th_win = 10; p->tcph->th_urp = 0; /* to server */ if (direction == 0) { p->tcph->th_sport = htons(f->sp); p->tcph->th_dport = htons(f->dp); if (dummy) { p->tcph->th_seq = htonl(ssn->client.next_seq); p->tcph->th_ack = htonl(ssn->server.last_ack); } else { p->tcph->th_seq = htonl(ssn->client.next_seq); p->tcph->th_ack = htonl(ssn->server.seg_list_tail->seq + ssn->server.seg_list_tail->payload_len); } /* to client */ } else { p->tcph->th_sport = htons(f->dp); p->tcph->th_dport = htons(f->sp); if (dummy) { p->tcph->th_seq = htonl(ssn->server.next_seq); p->tcph->th_ack = htonl(ssn->client.last_ack); } else { p->tcph->th_seq = htonl(ssn->server.next_seq); p->tcph->th_ack = htonl(ssn->client.seg_list_tail->seq + ssn->client.seg_list_tail->payload_len); } } if (FLOW_IS_IPV4(f)) { p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, 20); /* calc ipv4 csum as we may log it and barnyard might reject * a wrong checksum */ p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h)); } else if (FLOW_IS_IPV6(f)) { p->tcph->th_sum = TCPCalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, 20); } memset(&p->ts, 0, sizeof(struct timeval)); TimeGet(&p->ts); AppLayerSetEOF(f); return p; } static inline Packet *FlowForceReassemblyPseudoPacketGet(int direction, Flow *f, TcpSession *ssn, int dummy) { Packet *p; p = PacketGetFromAlloc(); if (p == NULL) return NULL; return FlowForceReassemblyPseudoPacketSetup(p, direction, f, ssn, dummy); } /** * \brief Check if a flow needs forced reassembly * * \param f *LOCKED* flow * \param server ptr to int that should be set to 1 or 2 if we return 1 * \param client ptr to int that should be set to 1 or 2 if we return 1 * * \retval 0 no * \retval 1 yes */ int FlowForceReassemblyNeedReassmbly(Flow *f, int *server, int *client) { TcpSession *ssn; /* looks like we have no flows in this queue */ if (f == NULL || (f->flags & FLOW_TIMEOUT_REASSEMBLY_DONE)) { return 0; } /* Get the tcp session for the flow */ ssn = (TcpSession *)f->protoctx; if (ssn == NULL) { return 0; } *client = StreamHasUnprocessedSegments(ssn, 0); *server = StreamHasUnprocessedSegments(ssn, 1); /* if state is not fully closed we assume that we haven't fully * inspected the app layer state yet */ if (ssn->state >= TCP_ESTABLISHED && ssn->state != TCP_CLOSED) { if (*client != 1) *client = 2; if (*server != 1) *server = 2; } /* nothing to do */ if (*client == 0 && *server == 0) { return 0; } return 1; } /** * \internal * \brief Forces reassembly for flow if it needs it. * * The function requires flow to be locked beforehand. * * \param f Pointer to the flow. * \param server action required for server: 1 or 2 * \param client action required for client: 1 or 2 * * \retval 0 This flow doesn't need any reassembly processing; 1 otherwise. */ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; TcpSession *ssn; /* looks like we have no flows in this queue */ if (f == NULL) { return 0; } /* Get the tcp session for the flow */ ssn = (TcpSession *)f->protoctx; if (ssn == NULL) { return 0; } /* The packets we use are based on what segments in what direction are * unprocessed. * p1 if we have client segments for reassembly purpose only. If we * have no server segments p2 can be a toserver packet with dummy * seq/ack, and if we have server segments p2 has to carry out reassembly * for server segment as well, in which case we will also need a p3 in the * toclient which is now dummy since all we need it for is detection */ /* insert a pseudo packet in the toserver direction */ if (client == 1) { p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 0); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); if (server == 1) { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); p3 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p3 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); FlowDeReference(&p2->flow); TmqhOutputPacketpool(NULL, p2); return 1; } PKT_SET_SRC(p3, PKT_SRC_FFR_V2); } else { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); } } else if (client == 2) { if (server == 1) { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); } else { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); if (server == 2) { p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); } } } else { if (server == 1) { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); } else if (server == 2) { p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); } else { /* impossible */ BUG_ON(1); } } f->flags |= FLOW_TIMEOUT_REASSEMBLY_DONE; SCMutexLock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p1); if (p2 != NULL) PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p2); if (p3 != NULL) PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p3); SCMutexUnlock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); if (stream_pseudo_pkt_decode_TV->inq != NULL) { SCCondSignal(&trans_q[stream_pseudo_pkt_decode_TV->inq->id].cond_q); } return 1; } /** * \internal * \brief Forces reassembly for flows that need it. * * When this function is called we're running in virtually dead engine, * so locking the flows is not strictly required. The reasons it is still * done are: * - code consistency * - silence complaining profilers * - allow us to aggressively check using debug valdation assertions * - be robust in case of future changes * - locking overhead if neglectable when no other thread fights us * * \param q The queue to process flows from. */ static inline void FlowForceReassemblyForHash(void) { Flow *f; TcpSession *ssn; int client_ok; int server_ok; int tcp_needs_inspection; uint32_t idx = 0; /* We use this packet just for reassembly purpose */ Packet *reassemble_p = PacketGetFromAlloc(); if (reassemble_p == NULL) return; for (idx = 0; idx < flow_config.hash_size; idx++) { FlowBucket *fb = &flow_hash[idx]; FBLOCK_LOCK(fb); /* get the topmost flow from the QUEUE */ f = fb->head; /* we need to loop through all the flows in the queue */ while (f != NULL) { PACKET_RECYCLE(reassemble_p); FLOWLOCK_WRLOCK(f); /* Get the tcp session for the flow */ ssn = (TcpSession *)f->protoctx; /* \todo Also skip flows that shouldn't be inspected */ if (ssn == NULL) { FLOWLOCK_UNLOCK(f); f = f->hnext; continue; } /* ah ah! We have some unattended toserver segments */ if ((client_ok = StreamHasUnprocessedSegments(ssn, 0)) == 1) { StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); ssn->client.last_ack = (ssn->client.seg_list_tail->seq + ssn->client.seg_list_tail->payload_len); FlowForceReassemblyPseudoPacketSetup(reassemble_p, 1, f, ssn, 1); StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, stt->ra_ctx, ssn, &ssn->server, reassemble_p, NULL); FlowDeReference(&reassemble_p->flow); if (StreamTcpReassembleProcessAppLayer(stt->ra_ctx) < 0) { SCLogDebug("shutdown flow timeout " "StreamTcpReassembleProcessAppLayer() erroring " "over something"); } } /* oh oh! We have some unattended toclient segments */ if ((server_ok = StreamHasUnprocessedSegments(ssn, 1)) == 1) { StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); ssn->server.last_ack = (ssn->server.seg_list_tail->seq + ssn->server.seg_list_tail->payload_len); FlowForceReassemblyPseudoPacketSetup(reassemble_p, 0, f, ssn, 1); StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, stt->ra_ctx, ssn, &ssn->client, reassemble_p, NULL); FlowDeReference(&reassemble_p->flow); if (StreamTcpReassembleProcessAppLayer(stt->ra_ctx) < 0) { SCLogDebug("shutdown flow timeout " "StreamTcpReassembleProcessAppLayer() erroring " "over something"); } } if (ssn->state >= TCP_ESTABLISHED && ssn->state != TCP_CLOSED) tcp_needs_inspection = 1; else tcp_needs_inspection = 0; FLOWLOCK_UNLOCK(f); /* insert a pseudo packet in the toserver direction */ if (client_ok || tcp_needs_inspection) { FLOWLOCK_WRLOCK(f); Packet *p = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); FLOWLOCK_UNLOCK(f); if (p == NULL) { TmqhOutputPacketpool(NULL, reassemble_p); FBLOCK_UNLOCK(fb); return; } PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); if (stream_pseudo_pkt_detect_prev_TV != NULL) { stream_pseudo_pkt_detect_prev_TV-> tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); } else { TmSlot *s = stream_pseudo_pkt_detect_tm_slot; while (s != NULL) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); s = s->slot_next; } if (stream_pseudo_pkt_detect_TV != NULL) { stream_pseudo_pkt_detect_TV-> tmqh_out(stream_pseudo_pkt_detect_TV, p); } else { TmqhOutputPacketpool(NULL, p); } } } /* if (ssn->client.seg_list != NULL) */ if (server_ok || tcp_needs_inspection) { FLOWLOCK_WRLOCK(f); Packet *p = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); FLOWLOCK_UNLOCK(f); if (p == NULL) { TmqhOutputPacketpool(NULL, reassemble_p); FBLOCK_UNLOCK(fb); return; } PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); if (stream_pseudo_pkt_detect_prev_TV != NULL) { stream_pseudo_pkt_detect_prev_TV-> tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); } else { TmSlot *s = stream_pseudo_pkt_detect_tm_slot; while (s != NULL) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); s = s->slot_next; } if (stream_pseudo_pkt_detect_TV != NULL) { stream_pseudo_pkt_detect_TV-> tmqh_out(stream_pseudo_pkt_detect_TV, p); } else { TmqhOutputPacketpool(NULL, p); } } } /* if (ssn->server.seg_list != NULL) */ /* next flow in the queue */ f = f->hnext; } /* while (f != NULL) */ FBLOCK_UNLOCK(fb); } PKT_SET_SRC(reassemble_p, PKT_SRC_FFR_SHUTDOWN); TmqhOutputPacketpool(NULL, reassemble_p); return; } /** * \brief Force reassembly for all the flows that have unprocessed segments. */ void FlowForceReassembly(void) { /* Do remember. We need to have packet acquire disabled by now */ /** ----- Part 1 ------*/ /* Flush out unattended packets */ FlowForceReassemblyFlushPendingPseudoPackets(); /** ----- Part 2 ----- **/ /* Check if all threads are idle. We need this so that we have all * packets freeds. As a consequence, no flows are in use */ SCMutexLock(&tv_root_lock); /* all receive threads are part of packet processing threads */ ThreadVars *tv = tv_root[TVT_PPT]; /* we are doing this in order receive -> decode -> ... -> log */ while (tv != NULL) { if (tv->inq != NULL) { /* we wait till we dry out all the inq packets, before we * kill this thread. Do note that you should have disabled * packet acquire by now using TmThreadDisableReceiveThreads()*/ if (!(strlen(tv->inq->name) == strlen("packetpool") && strcasecmp(tv->inq->name, "packetpool") == 0)) { PacketQueue *q = &trans_q[tv->inq->id]; while (q->len != 0) { usleep(100); } TmThreadsSetFlag(tv, THV_PAUSE); if (tv->inq->q_type == 0) SCCondSignal(&trans_q[tv->inq->id].cond_q); else SCCondSignal(&data_queues[tv->inq->id].cond_q); while (!TmThreadsCheckFlag(tv, THV_PAUSED)) { if (tv->inq->q_type == 0) SCCondSignal(&trans_q[tv->inq->id].cond_q); else SCCondSignal(&data_queues[tv->inq->id].cond_q); usleep(100); } TmThreadsUnsetFlag(tv, THV_PAUSE); } } tv = tv->next; } SCMutexUnlock(&tv_root_lock); /** ----- Part 3 ----- **/ /* Carry out flow reassembly for unattended flows */ FlowForceReassemblyForHash(); return; } void FlowForceReassemblySetup(void) { /* get StreamTCP TM's slot and TV containing this slot */ stream_pseudo_pkt_stream_tm_slot = TmSlotGetSlotForTM(TMM_STREAMTCP); if (stream_pseudo_pkt_stream_tm_slot == NULL) { /* yes, this is fatal! */ SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " "retrieve the slot for STREAMTCP TM"); exit(EXIT_FAILURE); } stream_pseudo_pkt_stream_TV = TmThreadsGetTVContainingSlot(stream_pseudo_pkt_stream_tm_slot); if (stream_pseudo_pkt_stream_TV == NULL) { /* yes, this is fatal! */ SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " "retrieve the TV containing STREAMTCP TM slot"); exit(EXIT_FAILURE); } /* get detect TM's slot and TV containing this slot */ stream_pseudo_pkt_detect_tm_slot = TmSlotGetSlotForTM(TMM_DETECT); if (stream_pseudo_pkt_detect_tm_slot == NULL) { /* yes, this is fatal! */ SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " "retrieve a slot for DETECT TM"); exit(EXIT_FAILURE); } stream_pseudo_pkt_detect_TV = TmThreadsGetTVContainingSlot(stream_pseudo_pkt_detect_tm_slot); if (stream_pseudo_pkt_detect_TV == NULL) { /* yes, this is fatal! */ SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " "retrieve the TV containing the Detect TM slot"); exit(EXIT_FAILURE); } if (stream_pseudo_pkt_detect_TV->tm_slots == stream_pseudo_pkt_detect_tm_slot) { stream_pseudo_pkt_detect_prev_TV = stream_pseudo_pkt_detect_TV->prev; } if (strcasecmp(stream_pseudo_pkt_detect_TV->outqh_name, "packetpool") == 0) { stream_pseudo_pkt_detect_TV = NULL; } SCMutexLock(&tv_root_lock); ThreadVars *tv = tv_root[TVT_PPT]; int done = 0; while (tv) { TmSlot *slots = tv->tm_slots; while (slots) { TmModule *tm = TmModuleGetById(slots->tm_id); if (tm->flags & TM_FLAG_DECODE_TM) { done = 1; stream_pseudo_pkt_decode_tm_slot = slots; break; } slots = slots->slot_next; } if (done) break; tv = tv->next; } SCMutexUnlock(&tv_root_lock); if (stream_pseudo_pkt_decode_tm_slot == NULL) { /* yes, this is fatal! */ SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " "retrieve the slot for DECODE TM"); exit(EXIT_FAILURE); } stream_pseudo_pkt_decode_TV = TmThreadsGetTVContainingSlot(stream_pseudo_pkt_decode_tm_slot); if (stream_pseudo_pkt_decode_TV == NULL) { /* yes, this is fatal! */ SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " "retrieve the TV containing the Decode TM slot"); exit(EXIT_FAILURE); } return; } suricata-1.4.7/src/detect-engine-tag.h0000644000000000000000000000346612253546156014473 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file detect-engine-tag.h * * \author Pablo Rincon Crespo * * Implements a global context to store data related to hosts flagged * tag keyword */ #ifndef __DETECT_ENGINE_TAG_H__ #define __DETECT_ENGINE_TAG_H__ #include "host.h" #include "detect.h" /* This limit should be overwriten/predefined at the config file * to limit the options to prevent possible DOS situations. We should also * create a limit for bytes and a limit for number of packets */ #define TAG_MAX_LAST_TIME_SEEN 600 #define TAG_TIMEOUT_CHECK_INTERVAL 60 /* Used for tagged data (sid and gid of the packets that * follow the one that triggered the rule with tag option) */ #define TAG_SIG_GEN 2 #define TAG_SIG_ID 1 int TagHashAddTag(DetectTagDataEntry *, Packet *); int TagFlowAdd(Packet *, DetectTagDataEntry *); void TagContextDestroy(void); void TagHandlePacket(DetectEngineCtx *, DetectEngineThreadCtx *, Packet *); void TagInitCtx(void); void TagDestroyCtx(void); void TagRestartCtx(void); int TagTimeoutCheck(Host *, struct timeval *); #endif /* __DETECT_ENGINE_TAG_H__ */ suricata-1.4.7/src/detect-engine-analyzer.h0000644000000000000000000000243412253546156015537 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eileen Donlon */ #ifndef __DETECT_ENGINE_ANALYZER_H__ #define __DETECT_ENGINE_ANALYZER_H__ #include int SetupFPAnalyzer(void); void CleanupFPAnalyzer(void); int SetupRuleAnalyzer(void); void CleanupRuleAnalyzer (void); int PerCentEncodingSetup (); int PerCentEncodingMatch (uint8_t *content, uint8_t content_len); void EngineAnalysisFP(Signature *s, char *line); void EngineAnalysisRules(Signature *s, char *line); void EngineAnalysisRulesFailure(char *line, char *file, int lineno); #endif /* __DETECT_ENGINE_ANALYZER_H__ */ suricata-1.4.7/src/detect-http-uri.c0000644000000000000000000006510512253546156014222 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Gerardo Iglesias */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "util-debug.h" #include "util-unittest.h" #include "util-spm.h" #include "util-print.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-uri.h" #include "detect-uricontent.h" #include "stream-tcp.h" static int DetectHttpUriSetup (DetectEngineCtx *, Signature *, char *); void DetectHttpUriRegisterTests(void); /** * \brief Registration function for keyword: http_uri */ void DetectHttpUriRegister (void) { sigmatch_table[DETECT_AL_HTTP_URI].name = "http_uri"; sigmatch_table[DETECT_AL_HTTP_URI].desc = "content modifier to match specifically and only on the HTTP uri-buffer"; sigmatch_table[DETECT_AL_HTTP_URI].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_uri-and-http_raw_uri"; sigmatch_table[DETECT_AL_HTTP_URI].Match = NULL; sigmatch_table[DETECT_AL_HTTP_URI].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_URI].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup; sigmatch_table[DETECT_AL_HTTP_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests; sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_PAYLOAD; } /** * \brief this function setups the http_uri modifier keyword used in the rule * * \param de_ctx Pointer to the Detection Engine Context * \param s Pointer to the Signature to which the current keyword belongs * \param str Should hold an empty string always * * \retval 0 On success * \retval -1 On failure */ static int DetectHttpUriSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (str != NULL && strcmp(str, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_uri shouldn't be supplied with " " an argument"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_uri\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_uri\" keyword"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_uri should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_uri rule can not " "be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "uricontent seen with a " "distance or within without a previous http_uri " "content. Invalidating signature."); goto error; } DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_UMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hcbdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_UMATCH], &s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } /******************************** UNITESTS **********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Checks if a http_uri is registered in a Signature, if content is not * specified in the signature */ int DetectHttpUriTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_uri\"; http_uri;sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_uri is registered in a Signature, if some parameter * is specified with http_uri in the signature */ int DetectHttpUriTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_uri\"; content:\"one\"; " "http_cookie:wrong; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_uri is registered in a Signature */ int DetectHttpUriTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_uri\"; content:\"one\"; " "http_uri; content:\"two\"; http_uri; " "content:\"three\"; http_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; } while (sm != NULL) { if (sm->type == DETECT_CONTENT) { result = 1; } else { printf("expected DETECT_AL_HTTP_URI, got %d: ", sm->type); goto end; } sm = sm->next; } end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_uri is registered in a Signature, when rawbytes is * also specified in the signature */ int DetectHttpUriTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_uri\"; content:\"one\"; " "rawbytes; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_uri is successfully converted to a uricontent * */ int DetectHttpUriTest05(void) { DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; int result = 0; if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_uri\"; " "content:\"we are testing http_uri keyword\"; " "http_uri; sid:1;)"); if (s == NULL) { printf("sig failed to parse\n"); goto end; } if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) goto end; if (s->sm_lists[DETECT_SM_LIST_UMATCH]->type != DETECT_CONTENT) { printf("wrong type\n"); goto end; } char *str = "we are testing http_uri keyword"; int uricomp = memcmp((const char *)((DetectContentData*) s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->content, str, strlen(str)-1); int urilen = ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->content_len; if (uricomp != 0 || urilen != strlen("we are testing http_uri keyword")) { printf("sig failed to parse, content not setup properly\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); return result; } int DetectHttpUriTest06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd->id == ud->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest07(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd->id == ud->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest08(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_uri; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd->id != 0 || ud->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest09(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (cd->id != 1 || ud->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest10(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; " "content:\"one\"; content:\"one\"; http_uri; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (cd->id != 1 || ud1->id != 0 || ud2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest11(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; " "content:\"one\"; content:\"one\"; http_uri; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; if (cd->id != 2 || ud1->id != 0 || ud2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; " "content:\"two\"; distance:0; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || memcmp(ud2->content, "two", ud1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest13(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; " "content:\"two\"; within:5; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || memcmp(ud2->content, "two", ud1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_uri; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (memcmp(cd->content, "one", cd->content_len) != 0 || cd->flags != DETECT_CONTENT_WITHIN) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; " "content:\"two\"; distance:0; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || memcmp(ud2->content, "two", ud1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpUriTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(uricontent:\"one\"; " "content:\"two\"; within:5; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); goto end; } DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || memcmp(ud2->content, "two", ud1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ /** * \brief Register the UNITTESTS for the http_uri keyword */ void DetectHttpUriRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectHttpUriTest01", DetectHttpUriTest01, 1); UtRegisterTest("DetectHttpUriTest02", DetectHttpUriTest02, 1); UtRegisterTest("DetectHttpUriTest03", DetectHttpUriTest03, 1); UtRegisterTest("DetectHttpUriTest04", DetectHttpUriTest04, 1); UtRegisterTest("DetectHttpUriTest05", DetectHttpUriTest05, 1); UtRegisterTest("DetectHttpUriTest06", DetectHttpUriTest06, 1); UtRegisterTest("DetectHttpUriTest07", DetectHttpUriTest07, 1); UtRegisterTest("DetectHttpUriTest08", DetectHttpUriTest08, 1); UtRegisterTest("DetectHttpUriTest09", DetectHttpUriTest09, 1); UtRegisterTest("DetectHttpUriTest10", DetectHttpUriTest10, 1); UtRegisterTest("DetectHttpUriTest11", DetectHttpUriTest11, 1); UtRegisterTest("DetectHttpUriTest12", DetectHttpUriTest12, 1); UtRegisterTest("DetectHttpUriTest13", DetectHttpUriTest13, 1); UtRegisterTest("DetectHttpUriTest14", DetectHttpUriTest14, 1); UtRegisterTest("DetectHttpUriTest15", DetectHttpUriTest15, 1); UtRegisterTest("DetectHttpUriTest16", DetectHttpUriTest16, 1); UtRegisterTest("DetectHttpUriTest17", DetectHttpUriTest17, 1); UtRegisterTest("DetectHttpUriTest18", DetectHttpUriTest18, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/util-hashlist.h0000644000000000000000000000437312253546156013777 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __HASHLIST_H__ #define __HASHLIST_H__ /* hash bucket structure */ typedef struct HashListTableBucket_ { void *data; uint16_t size; struct HashListTableBucket_ *bucknext; struct HashListTableBucket_ *listnext; struct HashListTableBucket_ *listprev; } HashListTableBucket; /* hash table structure */ typedef struct HashListTable_ { HashListTableBucket **array; HashListTableBucket *listhead; HashListTableBucket *listtail; uint32_t array_size; uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t); char (*Compare)(void *, uint16_t, void *, uint16_t); void (*Free)(void *); } HashListTable; #define HASHLIST_NO_SIZE 0 /* prototypes */ HashListTable* HashListTableInit(uint32_t, uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t), char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)); void HashListTableFree(HashListTable *); void HashListTablePrint(HashListTable *); int HashListTableAdd(HashListTable *, void *, uint16_t); int HashListTableRemove(HashListTable *, void *, uint16_t); void *HashListTableLookup(HashListTable *, void *, uint16_t); uint32_t HashListTableGenericHash(HashListTable *, void *, uint16_t); HashListTableBucket *HashListTableGetListHead(HashListTable *); #define HashListTableGetListNext(hb) (hb)->listnext #define HashListTableGetListData(hb) (hb)->data char HashListTableDefaultCompare(void *, uint16_t, void *, uint16_t); void HashListTableRegisterTests(void); #endif /* __HASHLIST_H__ */ suricata-1.4.7/src/detect-http-client-body.h0000644000000000000000000000166712253546156015644 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_HTTP_CLIENT_BODY_H__ #define __DETECT_HTTP_CLIENT_BODY_H__ void DetectHttpClientBodyRegister(void); #endif /* __DETECT_HTTP_CLIENT_BODY_H__ */ suricata-1.4.7/src/stream-tcp-reassemble.h0000644000000000000000000000660212253546156015401 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Gurvinder Singh */ #ifndef __STREAM_TCP_REASSEMBLE_H__ #define __STREAM_TCP_REASSEMBLE_H__ #include "stream-tcp-private.h" #include "stream.h" #include "app-layer-detect-proto.h" #include "stream-tcp-private.h" /** Supported OS list and default OS policy is BSD */ enum { OS_POLICY_NONE = 1, OS_POLICY_BSD, OS_POLICY_BSD_RIGHT, OS_POLICY_OLD_LINUX, OS_POLICY_LINUX, OS_POLICY_OLD_SOLARIS, OS_POLICY_SOLARIS, OS_POLICY_HPUX10, OS_POLICY_HPUX11, OS_POLICY_IRIX, OS_POLICY_MACOS, OS_POLICY_WINDOWS, OS_POLICY_VISTA, OS_POLICY_WINDOWS2K3, OS_POLICY_FIRST, OS_POLICY_LAST }; typedef struct TcpReassemblyThreadCtx_ { StreamMsgQueue *stream_q; AlpProtoDetectThreadCtx dp_ctx; /**< proto detection thread data */ /** TCP segments which are not being reassembled due to memcap was reached */ uint16_t counter_tcp_segment_memcap; /** number of streams that stop reassembly because their depth is reached */ uint16_t counter_tcp_stream_depth; /** account memory usage for the reassembly portion of the stream engine */ uint16_t counter_tcp_reass_memuse; /** count number of streams with a unrecoverable stream gap (missing pkts) */ uint16_t counter_tcp_reass_gap; } TcpReassemblyThreadCtx; #define OS_POLICY_DEFAULT OS_POLICY_BSD int StreamTcpReassembleHandleSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpSession *, TcpStream *, Packet *, PacketQueue *); int StreamTcpReassembleInit(char); void StreamTcpReassembleFree(char); void StreamTcpReassembleRegisterTests(void); TcpReassemblyThreadCtx *StreamTcpReassembleInitThreadCtx(void); void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *); int StreamTcpReassembleProcessAppLayer(TcpReassemblyThreadCtx *); void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t); void StreamTcpSetSessionNoReassemblyFlag (TcpSession *, char ); void StreamTcpSetOSPolicy(TcpStream *, Packet *); void StreamTcpReassemblePause (TcpSession *, char ); void StreamTcpReassembleUnPause (TcpSession *, char ); int StreamTcpCheckStreamContents(uint8_t *, uint16_t , TcpStream *); int StreamTcpReassembleInsertSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, Packet *); TcpSegment* StreamTcpGetSegment(ThreadVars *, TcpReassemblyThreadCtx *, uint16_t); void StreamTcpReturnStreamSegments(TcpStream *); void StreamTcpSegmentReturntoPool(TcpSegment *); void StreamTcpReassembleTriggerRawReassembly(TcpSession *); void StreamTcpPruneSession(Flow *, uint8_t); int StreamTcpReassembleDepthReached(Packet *p); #endif /* __STREAM_TCP_REASSEMBLE_H__ */ suricata-1.4.7/src/detect-fragoffset.c0000644000000000000000000002535112253546156014573 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * * Implements fragoffset keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "decode-ipv4.h" #include "decode-ipv6.h" #include "detect.h" #include "detect-parse.h" #include "detect-fragoffset.h" #include "util-byte.h" #include "util-unittest.h" #include "util-debug.h" #define PARSE_REGEX "^\\s*(?:(<|>))?\\s*([0-9]+)" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectFragOffsetMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectFragOffsetSetup(DetectEngineCtx *, Signature *, char *); void DetectFragOffsetRegisterTests(void); void DetectFragOffsetFree(void *); /** * \brief Registration function for fragoffset */ void DetectFragOffsetRegister (void) { sigmatch_table[DETECT_FRAGOFFSET].name = "fragoffset"; sigmatch_table[DETECT_FRAGOFFSET].desc = "match on specific decimal values of the IP fragment offset field"; sigmatch_table[DETECT_FRAGOFFSET].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Fragoffset"; sigmatch_table[DETECT_FRAGOFFSET].Match = DetectFragOffsetMatch; sigmatch_table[DETECT_FRAGOFFSET].Setup = DetectFragOffsetSetup; sigmatch_table[DETECT_FRAGOFFSET].Free = DetectFragOffsetFree; sigmatch_table[DETECT_FRAGOFFSET].RegisterTests = DetectFragOffsetRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief This function is used to match fragoffset rule option set on a packet * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectFragOffsetData * * \retval 0 no match or frag is not set * \retval 1 match * */ int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { uint16_t frag = 0; DetectFragOffsetData *fragoff = (DetectFragOffsetData *)m->ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; if (PKT_IS_IPV4(p)) { frag = IPV4_GET_IPOFFSET(p); } else if (PKT_IS_IPV6(p)) { if(IPV6_EXTHDR_FH(p)) { frag = IPV6_EXTHDR_GET_FH_OFFSET(p); } else { return 0; } } else { SCLogDebug("No IPv4 or IPv6 packet"); return 0; } switch (fragoff->mode) { case FRAG_LESS: if (frag < fragoff->frag_off) return 1; break; case FRAG_MORE: if (frag > fragoff->frag_off) return 1; break; default: if (frag == fragoff->frag_off) return 1; } return 0; } /** * \brief This function is used to parse fragoffset option passed via fragoffset: keyword * * \param fragoffsetstr Pointer to the user provided fragoffset options * * \retval fragoff pointer to DetectFragOffsetData on success * \retval NULL on failure */ DetectFragOffsetData *DetectFragOffsetParse (char *fragoffsetstr) { DetectFragOffsetData *fragoff = NULL; char *substr[3] = {NULL, NULL, NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int i; const char *str_ptr; char *mode = NULL; ret = pcre_exec(parse_regex, parse_regex_study, fragoffsetstr, strlen(fragoffsetstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH,"Parse error %s", fragoffsetstr); goto error; } for (i = 1; i < ret; i++) { res = pcre_get_substring((char *)fragoffsetstr, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed"); goto error; } substr[i-1] = (char *)str_ptr; } fragoff = SCMalloc(sizeof(DetectFragOffsetData)); if (unlikely(fragoff == NULL)) goto error; fragoff->frag_off = 0; fragoff->mode = 0; mode = substr[0]; if(mode != NULL) { while(*mode != '\0') { switch(*mode) { case '>': fragoff->mode = FRAG_MORE; break; case '<': fragoff->mode = FRAG_LESS; break; } mode++; } } if (ByteExtractStringUint16(&fragoff->frag_off, 10, 0, substr[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified frag offset %s is not " "valid", substr[1]); goto error; } for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } return fragoff; error: for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } if (fragoff != NULL) DetectFragOffsetFree(fragoff); return NULL; } /** * \brief this function is used to add the parsed fragoffset data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param fragoffsetstr pointer to the user provided fragoffset option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFragOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *fragoffsetstr) { DetectFragOffsetData *fragoff = NULL; SigMatch *sm = NULL; fragoff = DetectFragOffsetParse(fragoffsetstr); if (fragoff == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FRAGOFFSET; sm->ctx = (void *)fragoff; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (fragoff != NULL) DetectFragOffsetFree(fragoff); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectFragOffsetData * * \param ptr pointer to DetectFragOffsetData */ void DetectFragOffsetFree (void *ptr) { DetectFragOffsetData *fragoff = (DetectFragOffsetData *)ptr; SCFree(fragoff); } #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" /** * \test DetectFragOffsetParseTest01 is a test for setting a valid fragoffset value */ int DetectFragOffsetParseTest01 (void) { DetectFragOffsetData *fragoff = NULL; fragoff = DetectFragOffsetParse("300"); if (fragoff != NULL && fragoff->frag_off == 300) { DetectFragOffsetFree(fragoff); return 1; } return 0; } /** * \test DetectFragOffsetParseTest02 is a test for setting a valid fragoffset value * with spaces all around */ int DetectFragOffsetParseTest02 (void) { DetectFragOffsetData *fragoff = NULL; fragoff = DetectFragOffsetParse(">300"); if (fragoff != NULL && fragoff->frag_off == 300 && fragoff->mode == FRAG_MORE) { DetectFragOffsetFree(fragoff); return 1; } return 0; } /** * \test DetectFragOffsetParseTest03 is a test for setting an invalid fragoffset value */ int DetectFragOffsetParseTest03 (void) { DetectFragOffsetData *fragoff = NULL; fragoff = DetectFragOffsetParse("badc"); if (fragoff != NULL) { DetectFragOffsetFree(fragoff); return 1; } return 0; } /** * \test DetectFragOffsetMatchTest01 is a test for checking the working of * fragoffset keyword by creating 2 rules and matching a crafted packet * against them. Only the first one shall trigger. */ int DetectFragOffsetMatchTest01 (void) { int result = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; IPV4Hdr ip4h; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = 0x01020304; p->dst.addr_data32[0] = 0x04030201; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; ip4h.ip_off = 0x2222; p->ip4h = &ip4h; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (fragoffset:546; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx, "alert ip any any -> any any (fragoffset:5000; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { printf("sid 1 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 2)) { printf("sid 2 alerted, but should not have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); end: SCFree(p); return result; } #endif /* UNITTESTS */ void DetectFragOffsetRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("DetectFragOffsetParseTest01", DetectFragOffsetParseTest01, 1); UtRegisterTest("DetectFragOffsetParseTest02", DetectFragOffsetParseTest02, 1); UtRegisterTest("DetectFragOffsetParseTest03", DetectFragOffsetParseTest03, 0); UtRegisterTest("DetectFragOffsetMatchTest01", DetectFragOffsetMatchTest01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-hash.c0000644000000000000000000002361012253546156013071 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Chained hash table implementation * * The 'Free' pointer can be used to have the API free your * hashed data. If it's NULL it's the callers responsebility */ #include "suricata-common.h" #include "util-hash.h" #include "util-unittest.h" #include "util-memcmp.h" HashTable* HashTableInit(uint32_t size, uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)) { HashTable *ht = NULL; if (size == 0) { goto error; } if (Hash == NULL) { //printf("ERROR: HashTableInit no Hash function\n"); goto error; } /* setup the filter */ ht = SCMalloc(sizeof(HashTable)); if (unlikely(ht == NULL)) goto error; memset(ht,0,sizeof(HashTable)); ht->array_size = size; ht->Hash = Hash; ht->Free = Free; if (Compare != NULL) ht->Compare = Compare; else ht->Compare = HashTableDefaultCompare; /* setup the bitarray */ ht->array = SCMalloc(ht->array_size * sizeof(HashTableBucket *)); if (ht->array == NULL) goto error; memset(ht->array,0,ht->array_size * sizeof(HashTableBucket *)); return ht; error: if (ht != NULL) { if (ht->array != NULL) SCFree(ht->array); SCFree(ht); } return NULL; } void HashTableFree(HashTable *ht) { uint32_t i = 0; if (ht == NULL) return; /* free the buckets */ for (i = 0; i < ht->array_size; i++) { HashTableBucket *hashbucket = ht->array[i]; while (hashbucket != NULL) { HashTableBucket *next_hashbucket = hashbucket->next; if (ht->Free != NULL) ht->Free(hashbucket->data); SCFree(hashbucket); hashbucket = next_hashbucket; } } /* free the arrray */ if (ht->array != NULL) SCFree(ht->array); SCFree(ht); } void HashTablePrint(HashTable *ht) { printf("\n----------- Hash Table Stats ------------\n"); printf("Buckets: %" PRIu32 "\n", ht->array_size); printf("Hash function pointer: %p\n", ht->Hash); printf("-----------------------------------------\n"); } int HashTableAdd(HashTable *ht, void *data, uint16_t datalen) { if (ht == NULL || data == NULL) return -1; uint32_t hash = ht->Hash(ht, data, datalen); HashTableBucket *hb = SCMalloc(sizeof(HashTableBucket)); if (unlikely(hb == NULL)) goto error; memset(hb, 0, sizeof(HashTableBucket)); hb->data = data; hb->size = datalen; hb->next = NULL; if (ht->array[hash] == NULL) { ht->array[hash] = hb; } else { hb->next = ht->array[hash]; ht->array[hash] = hb; } #ifdef UNITTESTS ht->count++; #endif return 0; error: return -1; } int HashTableRemove(HashTable *ht, void *data, uint16_t datalen) { uint32_t hash = ht->Hash(ht, data, datalen); if (ht->array[hash] == NULL) { return -1; } if (ht->array[hash]->next == NULL) { if (ht->Free != NULL) ht->Free(ht->array[hash]->data); SCFree(ht->array[hash]); ht->array[hash] = NULL; return 0; } HashTableBucket *hashbucket = ht->array[hash], *prev_hashbucket = NULL; do { if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1) { if (prev_hashbucket == NULL) { /* root bucket */ ht->array[hash] = hashbucket->next; } else { /* child bucket */ prev_hashbucket->next = hashbucket->next; } /* remove this */ if (ht->Free != NULL) ht->Free(hashbucket->data); SCFree(hashbucket); return 0; } prev_hashbucket = hashbucket; hashbucket = hashbucket->next; } while (hashbucket != NULL); return -1; } void *HashTableLookup(HashTable *ht, void *data, uint16_t datalen) { uint32_t hash = 0; if (ht == NULL) return NULL; hash = ht->Hash(ht, data, datalen); if (ht->array[hash] == NULL) return NULL; HashTableBucket *hashbucket = ht->array[hash]; do { if (ht->Compare(hashbucket->data, hashbucket->size, data, datalen) == 1) return hashbucket->data; hashbucket = hashbucket->next; } while (hashbucket != NULL); return NULL; } uint32_t HashTableGenericHash(HashTable *ht, void *data, uint16_t datalen) { uint8_t *d = (uint8_t *)data; uint32_t i; uint32_t hash = 0; for (i = 0; i < datalen; i++) { if (i == 0) hash += (((uint32_t)*d++)); else if (i == 1) hash += (((uint32_t)*d++) * datalen); else hash *= (((uint32_t)*d++) * i) + datalen + i; } hash *= datalen; hash %= ht->array_size; return hash; } char HashTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2) { if (len1 != len2) return 0; if (SCMemcmp(data1,data2,len1) != 0) return 0; return 1; } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS static int HashTableTestInit01 (void) { HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); if (ht == NULL) return 0; HashTableFree(ht); return 1; } /* no hash function, so it should fail */ static int HashTableTestInit02 (void) { HashTable *ht = HashTableInit(1024, NULL, NULL, NULL); if (ht == NULL) return 1; HashTableFree(ht); return 0; } static int HashTableTestInit03 (void) { int result = 0; HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); if (ht == NULL) return 0; if (ht->Hash == HashTableGenericHash) result = 1; HashTableFree(ht); return result; } static int HashTableTestInit04 (void) { HashTable *ht = HashTableInit(0, HashTableGenericHash, NULL, NULL); if (ht == NULL) return 1; HashTableFree(ht); return 0; } static int HashTableTestInit05 (void) { int result = 0; HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); if (ht == NULL) return 0; if (ht->Compare == HashTableDefaultCompare) result = 1; HashTableFree(ht); return result; } static char HashTableDefaultCompareTest(void *data1, uint16_t len1, void *data2, uint16_t len2) { if (len1 != len2) return 0; if (SCMemcmp(data1,data2,len1) != 0) return 0; return 1; } static int HashTableTestInit06 (void) { int result = 0; HashTable *ht = HashTableInit(1024, HashTableGenericHash, HashTableDefaultCompareTest, NULL); if (ht == NULL) return 0; if (ht->Compare == HashTableDefaultCompareTest) result = 1; HashTableFree(ht); return result; } static int HashTableTestAdd01 (void) { int result = 0; HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashTableAdd(ht, "test", 0); if (r != 0) goto end; /* all is good! */ result = 1; end: if (ht != NULL) HashTableFree(ht); return result; } static int HashTableTestAdd02 (void) { int result = 0; HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashTableAdd(ht, NULL, 4); if (r == 0) goto end; /* all is good! */ result = 1; end: if (ht != NULL) HashTableFree(ht); return result; } static int HashTableTestFull01 (void) { int result = 0; HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashTableAdd(ht, "test", 4); if (r != 0) goto end; char *rp = HashTableLookup(ht, "test", 4); if (rp == NULL) goto end; r = HashTableRemove(ht, "test", 4); if (r != 0) goto end; /* all is good! */ result = 1; end: if (ht != NULL) HashTableFree(ht); return result; } static int HashTableTestFull02 (void) { int result = 0; HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); if (ht == NULL) goto end; int r = HashTableAdd(ht, "test", 4); if (r != 0) goto end; char *rp = HashTableLookup(ht, "test", 4); if (rp == NULL) goto end; r = HashTableRemove(ht, "test2", 5); if (r == 0) goto end; /* all is good! */ result = 1; end: if (ht != NULL) HashTableFree(ht); return result; } #endif void HashTableRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("HashTableTestInit01", HashTableTestInit01, 1); UtRegisterTest("HashTableTestInit02", HashTableTestInit02, 1); UtRegisterTest("HashTableTestInit03", HashTableTestInit03, 1); UtRegisterTest("HashTableTestInit04", HashTableTestInit04, 1); UtRegisterTest("HashTableTestInit05", HashTableTestInit05, 1); UtRegisterTest("HashTableTestInit06", HashTableTestInit06, 1); UtRegisterTest("HashTableTestAdd01", HashTableTestAdd01, 1); UtRegisterTest("HashTableTestAdd02", HashTableTestAdd02, 1); UtRegisterTest("HashTableTestFull01", HashTableTestFull01, 1); UtRegisterTest("HashTableTestFull02", HashTableTestFull02, 1); #endif } suricata-1.4.7/src/detect-byte-extract.c0000644000000000000000000044162212253546156015063 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "detect-bytejump.h" #include "detect-bytetest.h" #include "detect-byte-extract.h" #include "detect-isdataat.h" #include "app-layer-protos.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-byte.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" /* the default value of endianess to be used, if none's specified */ #define DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT DETECT_BYTE_EXTRACT_ENDIAN_BIG /* the base to be used if string mode is specified. These options would be * specified in DetectByteParseData->base */ #define DETECT_BYTE_EXTRACT_BASE_NONE 0 #define DETECT_BYTE_EXTRACT_BASE_HEX 16 #define DETECT_BYTE_EXTRACT_BASE_DEC 10 #define DETECT_BYTE_EXTRACT_BASE_OCT 8 /* the default value for multiplier. Either ways we always store a * multiplier, 1 or otherwise, so that we can always multiply the extracted * value and store it, instead of checking if a multiplier is set or not */ #define DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT 1 /* the min/max limit for multiplier */ #define DETECT_BYTE_EXTRACT_MULTIPLIER_MIN_LIMIT 1 #define DETECT_BYTE_EXTRACT_MULTIPLIER_MAX_LIMIT 65535 /* the max no of bytes that can be extracted in string mode - (string, hex) * (string, oct) or (string, dec) */ #define STRING_MAX_BYTES_TO_EXTRACT_FOR_OCT 23 #define STRING_MAX_BYTES_TO_EXTRACT_FOR_DEC 20 #define STRING_MAX_BYTES_TO_EXTRACT_FOR_HEX 14 /* the max no of bytes that can be extraced in non-string mode */ #define NO_STRING_MAX_BYTES_TO_EXTRACT 8 #define PARSE_REGEX "^" \ "\\s*([0-9]+)\\s*" \ ",\\s*(-?[0-9]+)\\s*" \ ",\\s*([^\\s,]+)\\s*" \ "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ "$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); void DetectByteExtractRegisterTests(void); void DetectByteExtractFree(void *); /** * \brief Registers the keyword handlers for the "byte_extract" keyword. */ void DetectByteExtractRegister(void) { const char *eb; int eo; int opts = 0; sigmatch_table[DETECT_BYTE_EXTRACT].name = "byte_extract"; sigmatch_table[DETECT_BYTE_EXTRACT].Match = NULL; sigmatch_table[DETECT_BYTE_EXTRACT].AppLayerMatch = NULL; sigmatch_table[DETECT_BYTE_EXTRACT].Setup = DetectByteExtractSetup; sigmatch_table[DETECT_BYTE_EXTRACT].Free = DetectByteExtractFree; sigmatch_table[DETECT_BYTE_EXTRACT].RegisterTests = DetectByteExtractRegisterTests; sigmatch_table[DETECT_BYTE_EXTRACT].flags |= SIGMATCH_PAYLOAD; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed " "at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, SigMatch *sm, Signature *s, uint8_t *payload, uint16_t payload_len, uint64_t *value, uint8_t endian) { DetectByteExtractData *data = (DetectByteExtractData *)sm->ctx; uint8_t *ptr = NULL; int32_t len = 0; uint64_t val = 0; int extbytes; if (payload_len == 0) { return 0; } /* Calculate the ptr value for the bytetest and length remaining in * the packet from that point. */ if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { SCLogDebug("relative, working with det_ctx->buffer_offset %"PRIu32", " "data->offset %"PRIu32"", det_ctx->buffer_offset, data->offset); ptr = payload + det_ctx->buffer_offset; len = payload_len - det_ctx->buffer_offset; ptr += data->offset; len -= data->offset; /* No match if there is no relative base */ if (len <= 0) { return 0; } //PrintRawDataFp(stdout,ptr,len); } else { SCLogDebug("absolute, data->offset %"PRIu32"", data->offset); ptr = payload + data->offset; len = payload_len - data->offset; } /* Validate that the to-be-extracted is within the packet */ if (ptr < payload || data->nbytes > len) { SCLogDebug("Data not within payload pkt=%p, ptr=%p, len=%"PRIu32", nbytes=%d", payload, ptr, len, data->nbytes); return 0; } /* Extract the byte data */ if (data->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) { extbytes = ByteExtractStringUint64(&val, data->base, data->nbytes, (const char *)ptr); if (extbytes <= 0) { /* strtoull() return 0 if there is no numeric value in data string */ if (val == 0) { SCLogDebug("No Numeric value"); return 0; } else { SCLogError(SC_ERR_INVALID_NUM_BYTES, "Error extracting %d " "bytes of string data: %d", data->nbytes, extbytes); return -1; } } } else { int endianness = (endian == DETECT_BYTE_EXTRACT_ENDIAN_BIG) ? BYTE_BIG_ENDIAN : BYTE_LITTLE_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, data->nbytes, ptr); if (extbytes != data->nbytes) { SCLogError(SC_ERR_INVALID_NUM_BYTES, "Error extracting %d bytes " "of numeric data: %d\n", data->nbytes, extbytes); return 0; } } /* Adjust the jump value based on flags */ val *= data->multiplier_value; if (data->flags & DETECT_BYTE_EXTRACT_FLAG_ALIGN) { if ((val % data->align_value) != 0) { val += data->align_value - (val % data->align_value); } } ptr += extbytes; det_ctx->buffer_offset = ptr - payload; *value = val; return 1; } int DetectByteExtractMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { goto end; end: return 1; } /** * \internal * \brief Used to parse byte_extract arg. * * \arg The argument to parse. * * \param bed On success an instance containing the parsed data. * On failure, NULL. */ static inline DetectByteExtractData *DetectByteExtractParse(char *arg) { DetectByteExtractData *bed = NULL; #define MAX_SUBSTRINGS 100 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; char *str_ptr; int i = 0; ret = pcre_exec(parse_regex, parse_regex_study, arg, strlen(arg), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3 || ret > 19) { SCLogError(SC_ERR_PCRE_PARSE, "parse error, ret %" PRId32 ", string \"%s\"", ret, arg); SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid arg to byte_extract : %s " "for byte_extract", arg); goto error; } bed = SCMalloc(sizeof(DetectByteExtractData)); if (unlikely(bed == NULL)) goto error; memset(bed, 0, sizeof(DetectByteExtractData)); /* no of bytes to extract */ res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, 1, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for arg 1 for byte_extract"); goto error; } bed->nbytes = atoi(str_ptr); /* offset */ res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, 2, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for arg 2 for byte_extract"); goto error; } int offset = atoi(str_ptr); if (offset < -65535 || offset > 65535) { SCLogError(SC_ERR_INVALID_SIGNATURE, "byte_extract offset invalid - %d. " "The right offset range is -65535 to 65535", offset); goto error; } bed->offset = offset; /* var name */ res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, 3, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for arg 3 for byte_extract"); goto error; } bed->name = SCStrdup(str_ptr); if (bed->name == NULL) goto error; /* check out other optional args */ for (i = 4; i < ret; i++) { res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, i, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for arg %d for byte_extract", i); goto error; } if (strcmp("relative", str_ptr) == 0) { if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "relative specified more " "than once for byte_extract"); goto error; } bed->flags |= DETECT_BYTE_EXTRACT_FLAG_RELATIVE; } else if (strcmp("multiplier", str_ptr) == 0) { if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER) { SCLogError(SC_ERR_INVALID_SIGNATURE, "multiplier specified more " "than once for byte_extract"); goto error; } bed->flags |= DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER; i++; res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, i, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for arg %d for byte_extract", i); goto error; } int multiplier = atoi(str_ptr); if (multiplier < DETECT_BYTE_EXTRACT_MULTIPLIER_MIN_LIMIT || multiplier > DETECT_BYTE_EXTRACT_MULTIPLIER_MAX_LIMIT) { SCLogError(SC_ERR_INVALID_SIGNATURE, "multipiler_value invalid " "- %d. The range is %d-%d", multiplier, DETECT_BYTE_EXTRACT_MULTIPLIER_MIN_LIMIT, DETECT_BYTE_EXTRACT_MULTIPLIER_MAX_LIMIT); goto error; } bed->multiplier_value = multiplier; } else if (strcmp("big", str_ptr) == 0) { if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "endian option specified " "more than once for byte_extract"); goto error; } bed->flags |= DETECT_BYTE_EXTRACT_FLAG_ENDIAN; bed->endian = DETECT_BYTE_EXTRACT_ENDIAN_BIG; } else if (strcmp("little", str_ptr) == 0) { if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "endian option specified " "more than once for byte_extract"); goto error; } bed->flags |= DETECT_BYTE_EXTRACT_FLAG_ENDIAN; bed->endian = DETECT_BYTE_EXTRACT_ENDIAN_LITTLE; } else if (strcmp("dce", str_ptr) == 0) { if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "endian option specified " "more than once for byte_extract"); goto error; } bed->flags |= DETECT_BYTE_EXTRACT_FLAG_ENDIAN; bed->endian = DETECT_BYTE_EXTRACT_ENDIAN_DCE; } else if (strcmp("string", str_ptr) == 0) { if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) { SCLogError(SC_ERR_INVALID_SIGNATURE, "string specified more " "than once for byte_extract"); goto error; } if (bed->base != DETECT_BYTE_EXTRACT_BASE_NONE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "The right way to specify " "base is (string, base) and not (base, string) " "for byte_extract"); goto error; } bed->flags |= DETECT_BYTE_EXTRACT_FLAG_STRING; } else if (strcmp("hex", str_ptr) == 0) { if (!(bed->flags & DETECT_BYTE_EXTRACT_FLAG_STRING)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Base(hex) specified " "without specifying string. The right way is " "(string, base) and not (base, string)"); goto error; } if (bed->base != DETECT_BYTE_EXTRACT_BASE_NONE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "More than one base " "specified for byte_extract"); goto error; } bed->base = DETECT_BYTE_EXTRACT_BASE_HEX; } else if (strcmp("oct", str_ptr) == 0) { if (!(bed->flags & DETECT_BYTE_EXTRACT_FLAG_STRING)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Base(oct) specified " "without specifying string. The right way is " "(string, base) and not (base, string)"); goto error; } if (bed->base != DETECT_BYTE_EXTRACT_BASE_NONE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "More than one base " "specified for byte_extract"); goto error; } bed->base = DETECT_BYTE_EXTRACT_BASE_OCT; } else if (strcmp("dec", str_ptr) == 0) { if (!(bed->flags & DETECT_BYTE_EXTRACT_FLAG_STRING)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Base(dec) specified " "without specifying string. The right way is " "(string, base) and not (base, string)"); goto error; } if (bed->base != DETECT_BYTE_EXTRACT_BASE_NONE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "More than one base " "specified for byte_extract"); goto error; } bed->base = DETECT_BYTE_EXTRACT_BASE_DEC; } else if (strcmp("align", str_ptr) == 0) { if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_ALIGN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Align specified more " "than once for byte_extract"); goto error; } bed->flags |= DETECT_BYTE_EXTRACT_FLAG_ALIGN; i++; res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, i, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for arg %d in byte_extract", i); goto error; } bed->align_value = atoi(str_ptr); if (!(bed->align_value == 2 || bed->align_value == 4)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid align_value for " "byte_extract - \"%d\"", bed->align_value); goto error; } } else if (strcmp("", str_ptr) == 0) { ; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid option - \"%s\" " "specified in byte_extract", str_ptr); goto error; } } /* for (i = 4; i < ret; i++) */ /* validation */ if (!(bed->flags & DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER)) { /* default value */ bed->multiplier_value = DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT; } if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) { if (bed->base == DETECT_BYTE_EXTRACT_BASE_NONE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Base not specified for " "byte_extract, though string was specified. " "The right options are (string, hex), (string, oct) " "or (string, dec)"); goto error; } if (bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "byte_extract can't have " "endian \"big\" or \"little\" specified along with " "\"string\""); goto error; } if (bed->base == DETECT_BYTE_EXTRACT_BASE_OCT) { /* if are dealing with octal nos, the max no that can fit in a 8 * byte value is 01777777777777777777777 */ if (bed->nbytes > STRING_MAX_BYTES_TO_EXTRACT_FOR_OCT) { SCLogError(SC_ERR_INVALID_SIGNATURE, "byte_extract can't process " "more than %d bytes in \"string\" extraction", STRING_MAX_BYTES_TO_EXTRACT_FOR_OCT); goto error; } } else if (bed->base == DETECT_BYTE_EXTRACT_BASE_DEC) { /* if are dealing with decimal nos, the max no that can fit in a 8 * byte value is 18446744073709551615 */ if (bed->nbytes > STRING_MAX_BYTES_TO_EXTRACT_FOR_DEC) { SCLogError(SC_ERR_INVALID_SIGNATURE, "byte_extract can't process " "more than %d bytes in \"string\" extraction", STRING_MAX_BYTES_TO_EXTRACT_FOR_DEC); goto error; } } else if (bed->base == DETECT_BYTE_EXTRACT_BASE_HEX) { /* if are dealing with hex nos, the max no that can fit in a 8 * byte value is 0xFFFFFFFFFFFFFFFF */ if (bed->nbytes > STRING_MAX_BYTES_TO_EXTRACT_FOR_HEX) { SCLogError(SC_ERR_INVALID_SIGNATURE, "byte_extract can't process " "more than %d bytes in \"string\" extraction", STRING_MAX_BYTES_TO_EXTRACT_FOR_HEX); goto error; } } else { ; // just a placeholder. we won't reach here. } } else { if (bed->nbytes > NO_STRING_MAX_BYTES_TO_EXTRACT) { SCLogError(SC_ERR_INVALID_SIGNATURE, "byte_extract can't process " "more than %d bytes in \"non-string\" extraction", NO_STRING_MAX_BYTES_TO_EXTRACT); goto error; } /* if string has not been specified and no endian option has been * specified, then set the default endian level of BIG */ if (!(bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN)) bed->endian = DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT; } return bed; error: if (bed != NULL) DetectByteExtractFree(bed); return NULL; } /** * \brief The setup function for the byte_extract keyword for a signature. * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to signature for the current Signature being parsed * from the rules. * \param m Pointer to the head of the SigMatch for the current rule * being parsed. * \param arg Pointer to the string holding the keyword value. * * \retval 0 On success. * \retval -1 On failure. */ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectByteExtractData *data = NULL; SigMatch *sm = NULL; data = DetectByteExtractParse(arg); if (data == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_BYTE_EXTRACT; sm->ctx = (void *)data; /* assign a local id for the byte extract var */ DetectByteExtractData *bed = (DetectByteExtractData *)sm->ctx; SigMatch *prev_bed_sm = SigMatchGetLastSMFromLists(s, 6, DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); if (prev_bed_sm == NULL) { /* first one */ bed->local_id = 0; } else { bed->local_id = ((DetectByteExtractData *)prev_bed_sm->ctx)->local_id + 1; } if (bed->local_id > de_ctx->byte_extract_max_local_id) de_ctx->byte_extract_max_local_id = bed->local_id; /* check bytetest modifiers against the signature alproto. In case they conflict * chuck out invalid signature */ if ((data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) && (s->alproto != ALPROTO_DCERPC)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " "bytetest with dce enabled"); goto error; } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { SigMatch *prev_sm = NULL; prev_sm = SigMatchGetLastSMFromLists(s, 8, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); if (prev_sm == NULL) { data->flags &= ~DETECT_BYTE_EXTRACT_FLAG_RELATIVE; } s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else { s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } } else if (s->alproto == ALPROTO_DCERPC && (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE)) { SigMatch *pm = NULL; SigMatch *dm = NULL; pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (dm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (pm->idx > dm->idx) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } } else { if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 30, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "No preceding content " "or uricontent or pcre option"); return -1; } int list = SigMatchListSMBelongsTo(s, pm); if (list == DETECT_SM_LIST_UMATCH) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { return 0; } if ( !(data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE)) { return 0; } SigMatch *prev_sm = NULL; prev_sm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, sm->prev, DETECT_BYTEJUMP, sm->prev, DETECT_PCRE, sm->prev); if (prev_sm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is a dce alproto sig."); return 0; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "No preceding content " "or uricontent or pcre option"); return -1; } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (prev_sm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_sm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; break; case DETECT_PCRE: pe = (DetectPcreData *)prev_sm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: SCLogDebug("No setting relative_next for bytejump. We " "have no use for it"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } /* switch */ return 0; error: if (data != NULL) DetectByteExtractFree(data); if (sm != NULL) SCFree(sm); return -1; } /** * \brief Used to free instances of DetectByteExtractData. * * \param ptr Instance of DetectByteExtractData to be freed. */ void DetectByteExtractFree(void *ptr) { if (ptr != NULL) { DetectByteExtractData *bed = ptr; if (bed->name != NULL) SCFree((void *)bed->name); SCFree(bed); } return; } SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, Signature *s, int list) { if (list == -1) return NULL; DetectByteExtractData *bed = NULL; SigMatch *sm = s->sm_lists[list]; while (sm != NULL) { if (sm->type == DETECT_BYTE_EXTRACT) { bed = (DetectByteExtractData *)sm->ctx; if (strcmp(bed->name, arg) == 0) { return sm; } } sm = sm->next; } return NULL; } /*************************************Unittests********************************/ #ifdef UNITTESTS int DetectByteExtractTest01(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != 0 || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest02(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, relative"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_RELATIVE || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest03(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, multiplier 10"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || bed->multiplier_value != 10) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest04(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, relative, multiplier 10"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || bed->multiplier_value != 10) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest05(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, big"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_BIG || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest06(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, little"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest07(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, dce"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DCE || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest08(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, string, hex"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest09(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, string, oct"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_OCT || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest10(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, string, dec"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_DEC || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest11(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_ALIGN || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest12(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, relative"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest13(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, relative, big"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_ENDIAN | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_BIG || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest14(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, relative, dce"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_ENDIAN | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DCE || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest15(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, relative, little"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_ENDIAN | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest16(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, relative, little, multiplier 2"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_ENDIAN | DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || bed->multiplier_value != 2) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest17(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "relative, little, " "multiplier 2, string hex"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest18(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "relative, little, " "multiplier 2, " "relative"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest19(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "relative, little, " "multiplier 2, " "little"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest20(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "relative, " "multiplier 2, " "align 2"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest21(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "multiplier 2, " "relative, " "multiplier 2"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest22(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "string hex, " "relative, " "string hex"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest23(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "string hex, " "relative, " "string oct"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest24(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("24, 2, one, align 4, " "string hex, " "relative"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest25(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("9, 2, one, align 4, " "little, " "relative"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest26(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "little, " "relative, " "multiplier 65536"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest27(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, align 4, " "little, " "relative, " "multiplier 0"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest28(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("23, 2, one, string, oct"); if (bed == NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest29(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("24, 2, one, string, oct"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest30(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("20, 2, one, string, dec"); if (bed == NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest31(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("21, 2, one, string, dec"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest32(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("14, 2, one, string, hex"); if (bed == NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest33(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("15, 2, one, string, hex"); if (bed != NULL) goto end; result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } int DetectByteExtractTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,2,two,relative,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 2 || strncmp(bed->name, "two", cd->content_len) != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectPcreData *pd = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; pcre:/asf/; " "byte_extract:4,0,two,relative,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_PCRE) { result = 0; goto end; } pd = (DetectPcreData *)sm->ctx; if (pd->flags != DETECT_PCRE_RELATIVE_NEXT) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectBytejumpData *bjd = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; byte_jump:1,13; " "byte_extract:4,0,two,relative,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest37(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectContentData *ud = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; uricontent:\"two\"; " "byte_extract:4,0,two,relative,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } if (sm->next != NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)ud->content, "two", cd->content_len) != 0 || ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || ud->flags & DETECT_CONTENT_NEGATED ) { printf("two failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest38(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectContentData *ud = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; uricontent:\"two\"; " "byte_extract:4,0,two,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags !=DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)ud->content, "two", cd->content_len) != 0 || ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || ud->flags & DETECT_CONTENT_RELATIVE_NEXT || ud->flags & DETECT_CONTENT_NEGATED ) { printf("two failed\n"); result = 0; goto end; } if (sm->next != NULL) { result = 0; goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest39(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectContentData *ud = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; content:\"two\"; http_uri; " "byte_extract:4,0,two,relative,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } if (sm->next != NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)ud->content, "two", cd->content_len) != 0 || ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || ud->flags & DETECT_CONTENT_NEGATED ) { printf("two failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest40(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectContentData *ud = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; content:\"two\"; http_uri; " "byte_extract:4,0,two,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags !=DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)ud->content, "two", cd->content_len) != 0 || ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || ud->flags & DETECT_CONTENT_RELATIVE_NEXT || ud->flags & DETECT_CONTENT_NEGATED ) { printf("two failed\n"); result = 0; goto end; } if (sm->next != NULL) { result = 0; goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest41(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "three") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 1) { result = 0; goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest42(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectContentData *ud = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "uricontent: \"three\"; " "byte_extract:4,0,four,string,hex,relative; " "byte_extract:4,0,five,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "five") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 2) { result = 0; goto end; } if (sm->next != NULL) goto end; sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)ud->content, "three", cd->content_len) != 0 || ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || ud->flags & DETECT_CONTENT_NEGATED ) { printf("two failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "four") != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 1) { result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest43(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "content: \"three\"; offset:two; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "three", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_OFFSET_BE | DETECT_CONTENT_OFFSET) || cd->offset != bed->local_id) { printf("three failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest44(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectByteExtractData *bed2 = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "content: \"four\"; offset:two; " "content: \"five\"; offset:three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed2 = (DetectByteExtractData *)sm->ctx; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_OFFSET_BE | DETECT_CONTENT_OFFSET) || cd->offset != bed1->local_id) { printf("four failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "five", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_OFFSET_BE | DETECT_CONTENT_OFFSET) || cd->offset != bed2->local_id) { printf("five failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest45(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "content: \"three\"; depth:two; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "three", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DEPTH_BE | DETECT_CONTENT_DEPTH) || cd->depth != bed->local_id || cd->offset != 0) { printf("three failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest46(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectByteExtractData *bed2 = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "content: \"four\"; depth:two; " "content: \"five\"; depth:three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed2 = (DetectByteExtractData *)sm->ctx; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DEPTH_BE | DETECT_CONTENT_DEPTH) || cd->depth != bed1->local_id) { printf("four failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "five", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DEPTH_BE | DETECT_CONTENT_DEPTH) || cd->depth != bed2->local_id) { printf("five failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest47(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "content: \"three\"; distance:two; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "three", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DISTANCE_BE | DETECT_CONTENT_DISTANCE) || cd->distance != bed->local_id || cd->offset != 0 || cd->depth != 0) { printf("three failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest48(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectByteExtractData *bed2 = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "content: \"four\"; distance:two; " "content: \"five\"; distance:three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed2 = (DetectByteExtractData *)sm->ctx; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DISTANCE_BE | DETECT_CONTENT_DISTANCE | DETECT_CONTENT_RELATIVE_NEXT) || cd->distance != bed1->local_id || cd->depth != 0 || cd->offset != 0) { printf("four failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "five", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DISTANCE_BE | DETECT_CONTENT_DISTANCE) || cd->distance != bed2->local_id || cd->depth != 0 || cd->offset != 0) { printf("five failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest49(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "content: \"three\"; within:two; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "three", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_WITHIN_BE | DETECT_CONTENT_WITHIN) || cd->within != bed->local_id || cd->offset != 0 || cd->depth != 0 || cd->distance != 0) { printf("three failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest50(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectByteExtractData *bed2 = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "content: \"four\"; within:two; " "content: \"five\"; within:three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed2 = (DetectByteExtractData *)sm->ctx; sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_WITHIN_BE | DETECT_CONTENT_WITHIN| DETECT_CONTENT_RELATIVE_NEXT) || cd->within != bed1->local_id || cd->depth != 0 || cd->offset != 0 || cd->distance != 0) { printf("four failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "five", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_WITHIN_BE | DETECT_CONTENT_WITHIN) || cd->within != bed2->local_id || cd->depth != 0 || cd->offset != 0 || cd->distance != 0) { printf("five failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest51(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed = NULL; DetectBytetestData *btd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_test: 2,=,10, two; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } btd = (DetectBytetestData *)sm->ctx; if (btd->flags != DETECT_BYTETEST_OFFSET_BE || btd->value != 10 || btd->offset != 0) { printf("three failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest52(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectBytetestData *btd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "byte_test: 2,=,two,three; " "byte_test: 3,=,10,three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } btd = (DetectBytetestData *)sm->ctx; if (btd->flags != (DETECT_BYTETEST_OFFSET_BE | DETECT_BYTETEST_VALUE_BE) || btd->value != 0 || btd->offset != 1) { printf("three failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; } btd = (DetectBytetestData *)sm->ctx; if (btd->flags != DETECT_BYTETEST_OFFSET_BE || btd->value != 10 || btd->offset != 1) { printf("four failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest53(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed = NULL; DetectBytejumpData *bjd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_jump: 2,two; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags != DETECT_BYTEJUMP_OFFSET_BE || bjd->offset != 0) { printf("three failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest54(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectBytejumpData *bjd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "byte_jump: 2,two; " "byte_jump: 3,three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags != DETECT_BYTEJUMP_OFFSET_BE || bjd->offset != 0) { printf("three failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags != DETECT_BYTEJUMP_OFFSET_BE || bjd->offset != 1) { printf("four failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest55(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectByteExtractData *bed2 = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing byte_extract\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "byte_extract:4,0,four,string,hex; " "byte_extract:4,0,five,string,hex; " "content: \"four\"; within:two; distance:three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed: "); goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { goto end; } bed2 = (DetectByteExtractData *)sm->ctx; sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DISTANCE_BE | DETECT_CONTENT_WITHIN_BE | DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || cd->within != bed1->local_id || cd->distance != bed2->local_id) { printf("four failed: "); goto end; } if (sm->next != NULL) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest56(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectByteExtractData *bed2 = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "uricontent:\"urione\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "byte_extract:4,0,four,string,hex; " "byte_extract:4,0,five,string,hex; " "content: \"four\"; within:two; distance:three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "urione", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed2 = (DetectByteExtractData *)sm->ctx; sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DISTANCE_BE | DETECT_CONTENT_WITHIN_BE | DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || cd->within != bed1->local_id || cd->distance != bed2->local_id ) { printf("four failed\n"); result = 0; goto end; } if (sm->next != NULL) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest57(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectByteExtractData *bed2 = NULL; DetectByteExtractData *bed3 = NULL; DetectByteExtractData *bed4 = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "uricontent: \"urione\"; " "byte_extract:4,0,two,string,hex,relative; " "byte_extract:4,0,three,string,hex,relative; " "byte_extract:4,0,four,string,hex,relative; " "byte_extract:4,0,five,string,hex,relative; " "uricontent: \"four\"; within:two; distance:three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "urione", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed2 = (DetectByteExtractData *)sm->ctx; if (bed2->local_id != 1) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed3 = (DetectByteExtractData *)sm->ctx; if (bed3->local_id != 2) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed4 = (DetectByteExtractData *)sm->ctx; if (bed4->local_id != 3) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || cd->flags != (DETECT_CONTENT_DISTANCE_BE | DETECT_CONTENT_WITHIN_BE | DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || cd->within != bed1->local_id || cd->distance != bed2->local_id) { printf("four failed\n"); result = 0; goto end; } if (sm->next != NULL) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest58(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectBytejumpData *bjd = NULL; DetectIsdataatData *isdd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "byte_jump: 2,two; " "byte_jump: 3,three; " "isdataat: three; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags != DETECT_BYTEJUMP_OFFSET_BE || bjd->offset != 0) { printf("three failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags != DETECT_BYTEJUMP_OFFSET_BE || bjd->offset != 1) { printf("four failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; } isdd = (DetectIsdataatData *)sm->ctx; if (isdd->flags != ISDATAAT_OFFSET_BE || isdd->dataat != 1) { printf("isdataat failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest59(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectBytejumpData *bjd = NULL; DetectIsdataatData *isdd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex; " "byte_extract:4,0,three,string,hex; " "byte_jump: 2,two; " "byte_jump: 3,three; " "isdataat: three,relative; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags != DETECT_BYTEJUMP_OFFSET_BE || bjd->offset != 0) { printf("three failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; } bjd = (DetectBytejumpData *)sm->ctx; if (bjd->flags != DETECT_BYTEJUMP_OFFSET_BE || bjd->offset != 1) { printf("four failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; } isdd = (DetectIsdataatData *)sm->ctx; if (isdd->flags != (ISDATAAT_OFFSET_BE | ISDATAAT_RELATIVE) || isdd->dataat != 1) { printf("isdataat failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest60(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectIsdataatData *isdd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex,relative; " "uricontent: \"three\"; " "byte_extract:4,0,four,string,hex,relative; " "isdataat: two; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; } isdd = (DetectIsdataatData *)sm->ctx; if (isdd->flags != (ISDATAAT_OFFSET_BE) || isdd->dataat != bed1->local_id) { printf("isdataat failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags != DETECT_CONTENT_RELATIVE_NEXT || strncmp((char *)cd->content, "three", cd->content_len) != 0) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "four") != 0 || bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 1) { result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest61(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *cd = NULL; DetectByteExtractData *bed1 = NULL; DetectIsdataatData *isdd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "byte_extract:4,0,two,string,hex,relative; " "uricontent: \"three\"; " "byte_extract:4,0,four,string,hex,relative; " "isdataat: four, relative; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || strncmp((char *)cd->content, "one", cd->content_len) != 0 || cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED ) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { result = 0; goto end; } if (sm->next != NULL) goto end; if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { result = 0; goto end; } sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; } cd = (DetectContentData *)sm->ctx; if (cd->flags != DETECT_CONTENT_RELATIVE_NEXT || strncmp((char *)cd->content, "three", cd->content_len) != 0) { printf("one failed\n"); result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed1 = (DetectByteExtractData *)sm->ctx; if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "four") != 0 || bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 1) { result = 0; goto end; } sm = sm->next; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; } isdd = (DetectIsdataatData *)sm->ctx; if (isdd->flags != (ISDATAAT_OFFSET_BE | ISDATAAT_RELATIVE) || isdd->dataat != bed1->local_id) { printf("isdataat failed\n"); result = 0; goto end; } if (sm->next != NULL) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } static int DetectByteExtractTest62(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; SigMatch *sm = NULL; DetectByteExtractData *bed = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; byte_extract:4,2,two,relative,string,hex; " "sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { goto end; } sm = s->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; } bed = (DetectByteExtractData *)sm->ctx; if (bed->nbytes != 4 || bed->offset != 2 || strncmp(bed->name, "two", 3) != 0 || bed->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING) || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectByteExtractTest63(void) { int result = 0; DetectByteExtractData *bed = DetectByteExtractParse("4, -2, one"); if (bed == NULL) goto end; if (bed->nbytes != 4 || bed->offset != -2 || strcmp(bed->name, "one") != 0 || bed->flags != 0 || bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; end: if (bed != NULL) DetectByteExtractFree(bed); return result; } #endif /* UNITTESTS */ void DetectByteExtractRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectByteExtractTest01", DetectByteExtractTest01, 1); UtRegisterTest("DetectByteExtractTest02", DetectByteExtractTest02, 1); UtRegisterTest("DetectByteExtractTest03", DetectByteExtractTest03, 1); UtRegisterTest("DetectByteExtractTest04", DetectByteExtractTest04, 1); UtRegisterTest("DetectByteExtractTest05", DetectByteExtractTest05, 1); UtRegisterTest("DetectByteExtractTest06", DetectByteExtractTest06, 1); UtRegisterTest("DetectByteExtractTest07", DetectByteExtractTest07, 1); UtRegisterTest("DetectByteExtractTest08", DetectByteExtractTest08, 1); UtRegisterTest("DetectByteExtractTest09", DetectByteExtractTest09, 1); UtRegisterTest("DetectByteExtractTest10", DetectByteExtractTest10, 1); UtRegisterTest("DetectByteExtractTest11", DetectByteExtractTest11, 1); UtRegisterTest("DetectByteExtractTest12", DetectByteExtractTest12, 1); UtRegisterTest("DetectByteExtractTest13", DetectByteExtractTest13, 1); UtRegisterTest("DetectByteExtractTest14", DetectByteExtractTest14, 1); UtRegisterTest("DetectByteExtractTest15", DetectByteExtractTest15, 1); UtRegisterTest("DetectByteExtractTest16", DetectByteExtractTest16, 1); UtRegisterTest("DetectByteExtractTest17", DetectByteExtractTest17, 1); UtRegisterTest("DetectByteExtractTest18", DetectByteExtractTest18, 1); UtRegisterTest("DetectByteExtractTest19", DetectByteExtractTest19, 1); UtRegisterTest("DetectByteExtractTest20", DetectByteExtractTest20, 1); UtRegisterTest("DetectByteExtractTest21", DetectByteExtractTest21, 1); UtRegisterTest("DetectByteExtractTest22", DetectByteExtractTest22, 1); UtRegisterTest("DetectByteExtractTest23", DetectByteExtractTest23, 1); UtRegisterTest("DetectByteExtractTest24", DetectByteExtractTest24, 1); UtRegisterTest("DetectByteExtractTest25", DetectByteExtractTest25, 1); UtRegisterTest("DetectByteExtractTest26", DetectByteExtractTest26, 1); UtRegisterTest("DetectByteExtractTest27", DetectByteExtractTest27, 1); UtRegisterTest("DetectByteExtractTest28", DetectByteExtractTest28, 1); UtRegisterTest("DetectByteExtractTest29", DetectByteExtractTest29, 1); UtRegisterTest("DetectByteExtractTest30", DetectByteExtractTest30, 1); UtRegisterTest("DetectByteExtractTest31", DetectByteExtractTest31, 1); UtRegisterTest("DetectByteExtractTest32", DetectByteExtractTest32, 1); UtRegisterTest("DetectByteExtractTest33", DetectByteExtractTest33, 1); UtRegisterTest("DetectByteExtractTest34", DetectByteExtractTest34, 1); UtRegisterTest("DetectByteExtractTest35", DetectByteExtractTest35, 1); UtRegisterTest("DetectByteExtractTest36", DetectByteExtractTest36, 1); UtRegisterTest("DetectByteExtractTest37", DetectByteExtractTest37, 1); UtRegisterTest("DetectByteExtractTest38", DetectByteExtractTest38, 1); UtRegisterTest("DetectByteExtractTest39", DetectByteExtractTest39, 1); UtRegisterTest("DetectByteExtractTest40", DetectByteExtractTest40, 1); UtRegisterTest("DetectByteExtractTest41", DetectByteExtractTest41, 1); UtRegisterTest("DetectByteExtractTest42", DetectByteExtractTest42, 1); UtRegisterTest("DetectByteExtractTest43", DetectByteExtractTest43, 1); UtRegisterTest("DetectByteExtractTest44", DetectByteExtractTest44, 1); UtRegisterTest("DetectByteExtractTest45", DetectByteExtractTest45, 1); UtRegisterTest("DetectByteExtractTest46", DetectByteExtractTest46, 1); UtRegisterTest("DetectByteExtractTest47", DetectByteExtractTest47, 1); UtRegisterTest("DetectByteExtractTest48", DetectByteExtractTest48, 1); UtRegisterTest("DetectByteExtractTest49", DetectByteExtractTest49, 1); UtRegisterTest("DetectByteExtractTest50", DetectByteExtractTest50, 1); UtRegisterTest("DetectByteExtractTest51", DetectByteExtractTest51, 1); UtRegisterTest("DetectByteExtractTest52", DetectByteExtractTest52, 1); UtRegisterTest("DetectByteExtractTest53", DetectByteExtractTest53, 1); UtRegisterTest("DetectByteExtractTest54", DetectByteExtractTest54, 1); UtRegisterTest("DetectByteExtractTest55", DetectByteExtractTest55, 1); UtRegisterTest("DetectByteExtractTest56", DetectByteExtractTest56, 1); UtRegisterTest("DetectByteExtractTest57", DetectByteExtractTest57, 1); UtRegisterTest("DetectByteExtractTest58", DetectByteExtractTest58, 1); UtRegisterTest("DetectByteExtractTest59", DetectByteExtractTest59, 1); UtRegisterTest("DetectByteExtractTest60", DetectByteExtractTest60, 1); UtRegisterTest("DetectByteExtractTest61", DetectByteExtractTest61, 1); UtRegisterTest("DetectByteExtractTest62", DetectByteExtractTest62, 1); UtRegisterTest("DetectByteExtractTest63", DetectByteExtractTest63, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/decode-ipv4.c0000644000000000000000000020170312253546156013277 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Victor Julien * \author Brian Rectanus * * Decode IPv4 */ #include "suricata-common.h" #include "packet-queue.h" #include "decode.h" #include "decode-ipv4.h" #include "decode-events.h" #include "defrag.h" #include "pkt-var.h" #include "host.h" #include "util-unittest.h" #include "util-debug.h" #include "util-optimize.h" #include "util-print.h" #include "util-profiling.h" /* Generic validation * * [--type--][--len---] * * \todo This function needs removed in favor of specific validation. * * See: RFC 791 */ static int IPV4OptValidateGeneric(Packet *p, const IPV4Opt *o) { switch (o->type) { /* See: RFC 4782 */ case IPV4_OPT_QS: if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len < IPV4_OPT_QS_MIN) { ENGINE_SET_EVENT(p,IPV4_OPT_INVALID_LEN); return -1; } break; /* See: RFC 1108 */ case IPV4_OPT_SEC: if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_SEC_LEN) { ENGINE_SET_EVENT(p,IPV4_OPT_INVALID_LEN); return -1; } break; case IPV4_OPT_SID: if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_SID_LEN) { ENGINE_SET_EVENT(p,IPV4_OPT_INVALID_LEN); return -1; } break; /* See: RFC 2113 */ case IPV4_OPT_RTRALT: if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_RTRALT_LEN) { ENGINE_SET_EVENT(p,IPV4_OPT_INVALID_LEN); return -1; } break; default: /* Should never get here unless there is a coding error */ ENGINE_SET_EVENT(p,IPV4_OPT_UNKNOWN); return -1; } return 0; } /* Validate route type options * * [--type--][--len---][--ptr---][address1]...[addressN] * * See: RFC 791 */ static int IPV4OptValidateRoute(Packet *p, const IPV4Opt *o) { uint8_t ptr; /* Check length */ if (o->len < IPV4_OPT_ROUTE_MIN) { ENGINE_SET_EVENT(p,IPV4_OPT_INVALID_LEN); return -1; } /* Data is required */ if (o->data == NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } ptr = *o->data; /* Address pointer is 1 based and points at least after type+len+ptr, * must be a incremented by 4 bytes (address size) and cannot extend * past option length. */ if ((ptr < 4) || (ptr % 4) || (ptr > o->len + 1)) { ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } return 0; } /* Validate timestamp type options * * [--type--][--len---][--ptr---][ovfl][flag][rec1----...]...[recN----...] * NOTE: rec could be 4 (ts only) or 8 (ip+ts) bytes in length. * * See: RFC 781 */ static int IPV4OptValidateTimestamp(Packet *p, const IPV4Opt *o) { uint8_t ptr; uint8_t flag; uint8_t rec_size; /* Check length */ if (o->len < IPV4_OPT_TS_MIN) { ENGINE_SET_EVENT(p,IPV4_OPT_INVALID_LEN); return -1; } /* Data is required */ if (o->data == NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } ptr = *o->data; /* We need the flag to determine what is in the option payload */ if (ptr < 5) { ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } flag = *(o->data + 3) & 0x00ff; /* A flag of 1|3 means we have both the ip+ts in each record */ rec_size = ((flag == 1) || (flag == 3)) ? 8 : 4; /* Address pointer is 1 based and points at least after * type+len+ptr+ovfl+flag, must be incremented by by the rec_size * and cannot extend past option length. */ if (((ptr - 5) % rec_size) || (ptr > o->len + 1)) { ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } return 0; } /* Validate CIPSO option * * [--type--][--len---][--doi---][tags--...] * * See: draft-ietf-cipso-ipsecurity-01.txt * See: FIPS 188 (tags 6 & 7) */ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) { uint32_t doi; uint8_t *tag; uint16_t len; /* Check length */ if (o->len < IPV4_OPT_CIPSO_MIN) { ENGINE_SET_EVENT(p,IPV4_OPT_INVALID_LEN); return -1; } /* Data is required */ if (o->data == NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } doi = *o->data; tag = o->data + 4; len = o->len - 1 - 1 - 4; /* Length of tags after header */ /* Domain of Interest (DOI) of 0 is reserved and thus invalid */ /** \todo Aparently a DOI of zero is fine in practice - verify. */ if (doi == 0) { #if 0 ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; #endif } /* NOTE: We know len has passed min tests prior to this call */ /* Check that tags are formatted correctly * [-ttype--][--tlen--][-tagdata-...] */ while (len) { uint8_t ttype; uint8_t tlen; /* Tag header must fit within option length */ if (len < 2) { //printf("CIPSO tag header too large %" PRIu16 " < 2\n", len); ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } /* Tag header is type+len */ ttype = *(tag++); tlen = *(tag++); /* Tag length must fit within the option length */ if (tlen > len) { //printf("CIPSO tag len too large %" PRIu8 " > %" PRIu16 "\n", tlen, len); ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } switch(ttype) { case 0: /* Tag type 0 is reserved and thus invalid */ /** \todo Wireshark marks this a padding, but spec says reserved. */ ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; case 1: case 2: case 5: case 6: case 7: /* Tag is at least 4 and at most the remainder of option len */ if ((tlen < 4) || (tlen > len)) { //printf("CIPSO tag %" PRIu8 " bad tlen=%" PRIu8 " len=%" PRIu8 "\n", ttype, tlen, len); ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } /* The alignment octet is always 0 except tag * type 7, which has no such field. */ if ((ttype != 7) && (*tag != 0)) { //printf("CIPSO tag %" PRIu8 " ao=%" PRIu8 "\n", ttype, tlen); ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); return -1; } /* Skip the rest of the tag payload */ tag += tlen - 2; len -= tlen; continue; default: //printf("CIPSO tag %" PRIu8 " unknown tag\n", ttype); ENGINE_SET_EVENT(p,IPV4_OPT_MALFORMED); /** \todo May not want to return error here on unknown tag type (at least not for 3|4) */ return -1; } } return 0; } /** * Decode/Validate IPv4 Options. */ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) { uint16_t plen = len; p->IPV4_OPTS_CNT = 0; #ifdef DEBUG if (SCLogDebugEnabled()) { uint16_t i; char buf[256] = ""; int offset = 0; for (i = 0; i < len; i++) { offset += snprintf(buf + offset, (sizeof(buf) - offset), "%02" PRIx8 " ", pkt[i]); } SCLogDebug("IPV4OPTS: { %s}", buf); } #endif /* Options length must be padded to 8byte boundary */ if (plen % 8) { ENGINE_SET_EVENT(p,IPV4_OPT_PAD_REQUIRED); /* Warn - we can keep going */ } while (plen) { /* single byte options */ if (*pkt == IPV4_OPT_EOL) { /** \todo What if more data exist after EOL (possible covert channel or data leakage)? */ SCLogDebug("IPV4OPT %" PRIu16 " len 1 @ %" PRIu16 "/%" PRIu16 "", *pkt, (len - plen), (len - 1)); break; } else if (*pkt == IPV4_OPT_NOP) { SCLogDebug("IPV4OPT %" PRIu16 " len 1 @ %" PRIu16 "/%" PRIu16 "", *pkt, (len - plen), (len - 1)); pkt++; plen--; /* multibyte options */ } else { if (plen < 2) { /** \todo What if padding is non-zero (possible covert channel or data leakage)? */ /** \todo Spec seems to indicate EOL required if there is padding */ ENGINE_SET_EVENT(p,IPV4_OPT_EOL_REQUIRED); break; } /* Option length is too big for packet */ if (*(pkt+1) > plen) { ENGINE_SET_EVENT(p,IPV4_OPT_INVALID_LEN); return -1; } p->IPV4_OPTS[p->IPV4_OPTS_CNT].type = *pkt; p->IPV4_OPTS[p->IPV4_OPTS_CNT].len = *(pkt+1); if (plen > 2) p->IPV4_OPTS[p->IPV4_OPTS_CNT].data = (pkt+2); else p->IPV4_OPTS[p->IPV4_OPTS_CNT].data = NULL; SCLogDebug("IPV4OPT %" PRIu16 " len %" PRIu16 " @ %" PRIu16 "/%" PRIu16 "", p->IPV4_OPTS[p->IPV4_OPTS_CNT].type, p->IPV4_OPTS[p->IPV4_OPTS_CNT].len, (len - plen), (len - 1)); /* 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->IPV4_OPTS[p->IPV4_OPTS_CNT].len > plen || p->IPV4_OPTS[p->IPV4_OPTS_CNT].len < 2) { ENGINE_SET_EVENT(p,IPV4_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. */ /** \todo Figure out which IP options are more common and list them first */ switch (p->IPV4_OPTS[p->IPV4_OPTS_CNT].type) { case IPV4_OPT_TS: if (p->ip4vars.o_ts != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateTimestamp(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { return -1; } p->ip4vars.o_ts = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; case IPV4_OPT_RR: if (p->ip4vars.o_rr != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { return -1; } p->ip4vars.o_rr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; case IPV4_OPT_QS: if (p->ip4vars.o_qs != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { return -1; } p->ip4vars.o_qs = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; case IPV4_OPT_SEC: if (p->ip4vars.o_sec != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { return -1; } p->ip4vars.o_sec = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; case IPV4_OPT_LSRR: if (p->ip4vars.o_lsrr != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { return -1; } p->ip4vars.o_lsrr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; case IPV4_OPT_CIPSO: if (p->ip4vars.o_cipso != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateCIPSO(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { return -1; } p->ip4vars.o_cipso = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; case IPV4_OPT_SID: if (p->ip4vars.o_sid != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { return -1; } p->ip4vars.o_sid = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; case IPV4_OPT_SSRR: if (p->ip4vars.o_ssrr != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { return -1; } p->ip4vars.o_ssrr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; case IPV4_OPT_RTRALT: if (p->ip4vars.o_rtralt != NULL) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { return -1; } p->ip4vars.o_rtralt = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; break; default: SCLogDebug("IPV4OPT (%" PRIu8 ") len %" PRIu8 "", p->IPV4_OPTS[p->IPV4_OPTS_CNT].type, p->IPV4_OPTS[p->IPV4_OPTS_CNT].len); ENGINE_SET_EVENT(p,IPV4_OPT_INVALID); /* Warn - we can keep going */ break; } pkt += p->IPV4_OPTS[p->IPV4_OPTS_CNT].len; plen -= (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len); p->IPV4_OPTS_CNT++; } } return 0; } static int DecodeIPV4Packet(Packet *p, uint8_t *pkt, uint16_t len) { if (unlikely(len < IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p,IPV4_PKT_TOO_SMALL); return -1; } if (unlikely(IP_GET_RAW_VER(pkt) != 4)) { SCLogDebug("wrong ip version %" PRIu8 "",IP_GET_RAW_VER(pkt)); ENGINE_SET_EVENT(p,IPV4_WRONG_IP_VER); return -1; } p->ip4h = (IPV4Hdr *)pkt; if (unlikely(IPV4_GET_HLEN(p) < IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p,IPV4_HLEN_TOO_SMALL); return -1; } if (unlikely(IPV4_GET_IPLEN(p) < IPV4_GET_HLEN(p))) { ENGINE_SET_EVENT(p,IPV4_IPLEN_SMALLER_THAN_HLEN); return -1; } if (unlikely(len < IPV4_GET_IPLEN(p))) { ENGINE_SET_EVENT(p,IPV4_TRUNC_PKT); return -1; } /* set the address struct */ SET_IPV4_SRC_ADDR(p,&p->src); SET_IPV4_DST_ADDR(p,&p->dst); /* save the options len */ uint8_t ip_opt_len = IPV4_GET_HLEN(p) - IPV4_HEADER_LEN; if (ip_opt_len > 0) { DecodeIPV4Options(p, pkt + IPV4_HEADER_LEN, ip_opt_len); } return 0; } void DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_ipv4, tv->sc_perf_pca); SCLogDebug("pkt %p len %"PRIu16"", pkt, len); /* do the actual decoding */ if (unlikely(DecodeIPV4Packet (p, pkt, len) < 0)) { SCLogDebug("decoding IPv4 packet failed"); p->ip4h = NULL; return; } p->proto = IPV4_GET_IPPROTO(p); /* If a fragment, pass off for re-assembly. */ if (unlikely(IPV4_GET_IPOFFSET(p) > 0 || IPV4_GET_MF(p) == 1)) { Packet *rp = Defrag(tv, dtv, p); if (rp != NULL) { /* Got re-assembled packet, re-run through decoder. */ DecodeIPV4(tv, dtv, rp, (void *)rp->ip4h, IPV4_GET_IPLEN(rp), pq); PacketEnqueue(pq, rp); } p->flags |= PKT_IS_FRAGMENT; return; } /* do hdr test, process hdr rules */ #ifdef DEBUG if (SCLogDebugEnabled()) { /* only convert the addresses if debug is really enabled */ /* debug print */ char s[16], d[16]; PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), s, sizeof(s)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), d, sizeof(d)); SCLogDebug("IPV4 %s->%s PROTO: %" PRIu32 " OFFSET: %" PRIu32 " RF: %" PRIu32 " DF: %" PRIu32 " MF: %" PRIu32 " ID: %" PRIu32 "", 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: DecodeTCP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), pq); break; case IPPROTO_UDP: DecodeUDP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), pq); break; case IPPROTO_ICMP: DecodeICMPV4(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), pq); break; case IPPROTO_GRE: DecodeGRE(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), pq); break; case IPPROTO_SCTP: DecodeSCTP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), pq); break; case IPPROTO_IPV6: { if (pq != NULL) { /* spawn off tunnel packet */ Packet *tp = PacketPseudoPktSetup(p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), IPV4_GET_IPPROTO(p)); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV4); /* send that to the Tunnel decoder */ DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPV4_GET_IPPROTO(p)); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); } } break; } case IPPROTO_IP: /* check PPP VJ uncompressed packets and decode tcp dummy */ if(p->ppph != NULL && ntohs(p->ppph->protocol) == PPP_VJ_UCOMP) { DecodeTCP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), pq); } break; } return; } /* UNITTESTS */ #ifdef UNITTESTS void DecodeIPV4OptionsPrint(Packet *p) { IPV4Vars *pv = &p->ip4vars; printf("DecodeIPV4Options: cnt=%" PRIu8 ",rr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" ",qs={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" ",ts={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" ",sec={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" ",lsrr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" ",cipso={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" ",sid={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" ",ssrr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" ",rtralt={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" "}\n", pv->ip_opt_cnt, (pv->o_rr ? pv->o_rr->type : 0), (pv->o_rr ? pv->o_rr->len : 0), (pv->o_rr ? pv->o_rr->data : 0), (pv->o_qs ? pv->o_qs->type : 0), (pv->o_qs ? pv->o_qs->len : 0), (pv->o_qs ? pv->o_qs->data : 0), (pv->o_ts ? pv->o_ts->type : 0), (pv->o_ts ? pv->o_ts->len : 0), (pv->o_ts ? pv->o_ts->data : 0), (pv->o_sec ? pv->o_sec->type : 0), (pv->o_sec ? pv->o_sec->len : 0), (pv->o_sec ? pv->o_sec->data : 0), (pv->o_lsrr ? pv->o_lsrr->type : 0), (pv->o_lsrr ? pv->o_lsrr->len : 0), (pv->o_lsrr ? pv->o_lsrr->data : 0), (pv->o_cipso ? pv->o_cipso->type : 0), (pv->o_cipso ? pv->o_cipso->len : 0), (pv->o_cipso ? pv->o_cipso->data : 0), (pv->o_sid ? pv->o_sid->type : 0), (pv->o_sid ? pv->o_sid->len : 0), (pv->o_sid ? pv->o_sid->data : 0), (pv->o_ssrr ? pv->o_ssrr->type : 0), (pv->o_ssrr ? pv->o_ssrr->len : 0), (pv->o_ssrr ? pv->o_ssrr->data : 0), (pv->o_rtralt ? pv->o_rtralt->type : 0), (pv->o_rtralt ? pv->o_rtralt->len : 0), (pv->o_rtralt ? pv->o_rtralt->data : 0)); } /** \test IPV4 with no options. */ int DecodeIPV4OptionsNONETest01(void) { uint8_t raw_opts[] = { }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; uint8_t *data = (uint8_t *)p; uint16_t i; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); if (rc != 0) { DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { if (*data) { /* Should not have modified packet data */ //printf("Data modified at offset %" PRIu16 "\n", i); DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } } SCFree(p); return 1; } /** \test IPV4 with EOL option. */ int DecodeIPV4OptionsEOLTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_EOL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; uint8_t *data = (uint8_t *)p; uint16_t i; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); if (rc != 0) { DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { if (*data) { /* Should not have modified packet data */ //printf("Data modified at offset %" PRIu16 "\n", i); DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } } SCFree(p); return 1; } /** \test IPV4 with NOP option. */ int DecodeIPV4OptionsNOPTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_NOP, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; uint8_t *data = (uint8_t *)p; uint16_t i; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); if (rc != 0) { DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { if (*data) { /* Should not have modified packet data */ //printf("Data modified at offset %" PRIu16 "\n", i); DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } } SCFree(p); return 1; } /** \test IPV4 with RR option. */ int DecodeIPV4OptionsRRTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_RR, 0x27, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_RR) && (p->IPV4_OPTS[0].len == 0x27) && (p->ip4vars.o_rr == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with RR option (len too large). */ int DecodeIPV4OptionsRRTest02(void) { uint8_t raw_opts[] = { IPV4_OPT_RR, 0xff, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with RR option (ptr too large). */ int DecodeIPV4OptionsRRTest03(void) { uint8_t raw_opts[] = { IPV4_OPT_RR, 0x27, 0xff, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with RR option (ptr not in 4 byte increment). */ int DecodeIPV4OptionsRRTest04(void) { uint8_t raw_opts[] = { IPV4_OPT_RR, 0x27, 0x05, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with QS option. */ int DecodeIPV4OptionsQSTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_QS, 0x08, 0x0d, 0x00, 0xbe, 0xef, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",qs=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_qs, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_QS) && (p->IPV4_OPTS[0].len == 0x08) && (p->ip4vars.o_qs == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with QS option (len too small) */ int DecodeIPV4OptionsQSTest02(void) { uint8_t raw_opts[] = { IPV4_OPT_QS, 0x07, 0x0d, 0x00, 0xbe, 0xef, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",qs=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_qs, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with TS option. */ int DecodeIPV4OptionsTSTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_TS, 0x24, 0x0d, 0x01, 0x0a, 0x0a, 0x0a, 0x69, 0x04, 0xce, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_TS) && (p->IPV4_OPTS[0].len == 0x24) && (p->ip4vars.o_ts == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with TS option (ptr too small). */ int DecodeIPV4OptionsTSTest02(void) { uint8_t raw_opts[] = { IPV4_OPT_TS, 0x24, 0x04, 0x01, 0x0a, 0x0a, 0x0a, 0x69, 0x04, 0xce, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with TS option (ptr too large). */ int DecodeIPV4OptionsTSTest03(void) { uint8_t raw_opts[] = { IPV4_OPT_TS, 0x24, 0xff, 0x01, 0x0a, 0x0a, 0x0a, 0x69, 0x04, 0xce, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with TS option (ptr not valid). */ int DecodeIPV4OptionsTSTest04(void) { uint8_t raw_opts[] = { IPV4_OPT_TS, 0x24, 0x0a, 0x01, 0x0a, 0x0a, 0x0a, 0x69, 0x04, 0xce, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with SEC option. */ int DecodeIPV4OptionsSECTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_SEC, 0x0b, 0xf1, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sec=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sec, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_SEC) && (p->IPV4_OPTS[0].len == 0x0b) && (p->ip4vars.o_sec == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with SEC option (invalid length). */ int DecodeIPV4OptionsSECTest02(void) { uint8_t raw_opts[] = { IPV4_OPT_SEC, 0x0a, 0xf1, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sec=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sec, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with LSRR option. */ int DecodeIPV4OptionsLSRRTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_LSRR, 0x27, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_LSRR) && (p->IPV4_OPTS[0].len == 0x27) && (p->ip4vars.o_lsrr == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with LSRR option (len too large). */ int DecodeIPV4OptionsLSRRTest02(void) { uint8_t raw_opts[] = { IPV4_OPT_LSRR, 0xff, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with LSRR option (ptr too large). */ int DecodeIPV4OptionsLSRRTest03(void) { uint8_t raw_opts[] = { IPV4_OPT_LSRR, 0x27, 0xff, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with LSRR option (ptr not in 4 byte increment). */ int DecodeIPV4OptionsLSRRTest04(void) { uint8_t raw_opts[] = { IPV4_OPT_LSRR, 0x27, 0x05, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with CIPSO option. */ int DecodeIPV4OptionsCIPSOTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_CIPSO, 0x18, 0x00, 0x00, 0x00, 0x05, 0x05, 0x12, 0x00, 0x03, 0x00, 0xef, 0x00, 0xef, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_cipso, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_CIPSO) && (p->IPV4_OPTS[0].len == 0x18) && (p->ip4vars.o_cipso == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with SID option. */ int DecodeIPV4OptionsSIDTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_SID, 0x04, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sid=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sid, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_SID) && (p->IPV4_OPTS[0].len == 0x04) && (p->ip4vars.o_sid == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with SID option (len invalid. */ int DecodeIPV4OptionsSIDTest02(void) { uint8_t raw_opts[] = { IPV4_OPT_SID, 0x05, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sid=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sid, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with SSRR option. */ int DecodeIPV4OptionsSSRRTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_SSRR, 0x27, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_SSRR) && (p->IPV4_OPTS[0].len == 0x27) && (p->ip4vars.o_ssrr == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with SSRR option (len too large). */ int DecodeIPV4OptionsSSRRTest02(void) { uint8_t raw_opts[] = { IPV4_OPT_SSRR, 0xff, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with SSRR option (ptr too large). */ int DecodeIPV4OptionsSSRRTest03(void) { uint8_t raw_opts[] = { IPV4_OPT_SSRR, 0x27, 0xff, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with SSRR option (ptr not in 4 byte increment). */ int DecodeIPV4OptionsSSRRTest04(void) { uint8_t raw_opts[] = { IPV4_OPT_SSRR, 0x27, 0x05, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with RTRALT option. */ int DecodeIPV4OptionsRTRALTTest01(void) { uint8_t raw_opts[] = { IPV4_OPT_RTRALT, 0x04, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rtralt=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rtralt, (uintmax_t)&p.IPV4_OPTS[0]); if ( (rc == 0) && (p->IPV4_OPTS_CNT == 1) && (p->IPV4_OPTS[0].type == IPV4_OPT_RTRALT) && (p->IPV4_OPTS[0].len == 0x04) && (p->ip4vars.o_rtralt == &p->IPV4_OPTS[0])) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } /** \test IPV4 with RTRALT option (len invalid. */ int DecodeIPV4OptionsRTRALTTest02(void) { uint8_t raw_opts[] = { IPV4_OPT_RTRALT, 0x05, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; int rc; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rtralt=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rtralt, (uintmax_t)&p.IPV4_OPTS[0]); if (rc != 0) { SCFree(p); return 1; } DecodeIPV4OptionsPrint(p); SCFree(p); return 0; } static int IPV4CalculateValidChecksumtest01(void) { uint16_t csum = 0; uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x03}; csum = *( ((uint16_t *)raw_ipv4) + 5); return (csum == IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); } static int IPV4CalculateInvalidChecksumtest02(void) { uint16_t csum = 0; uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x07}; csum = *( ((uint16_t *)raw_ipv4) + 5); return (csum == IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); } /** * \test IPV4 defrag and packet recursion level test */ int DecodeIPV4DefragTest01(void) { uint8_t pkt1[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0xe9, 0xef, 0x20, 0x00, 0x40, 0x06, 0x9a, 0xc8, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5e }; uint8_t pkt2[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0xe9, 0xef, 0x20, 0x01, 0x40, 0x06, 0x9a, 0xc7, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00 }; uint8_t pkt3[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x18, 0xe9, 0xef, 0x00, 0x02, 0x40, 0x06, 0xba, 0xca, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0xb1, 0xa3, 0x00, 0x00 }; uint8_t tunnel_pkt[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0xe9, 0xef, 0x00, 0x00, 0x40, 0x06, 0xba, 0xbc, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; PacketQueue pq; int result = 1; memset(&tv, 0, sizeof(ThreadVars)); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&pq, 0, sizeof(PacketQueue)); PACKET_INITIALIZE(p); FlowInitConfig(FLOW_QUIET); DefragInit(); PacketCopyData(p, pkt1, sizeof(pkt1)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; goto end; } PACKET_DO_RECYCLE(p); PacketCopyData(p, pkt2, sizeof(pkt2)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; goto end; } PACKET_DO_RECYCLE(p); PacketCopyData(p, pkt3, sizeof(pkt3)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; goto end; } Packet *tp = PacketDequeue(&pq); if (tp == NULL) { printf("Failed to get defragged pseudo packet\n"); result = 0; goto end; } if (tp->recursion_level != p->recursion_level) { printf("defragged pseudo packet's and parent packet's recursion " "level don't match\n %d != %d", tp->recursion_level, p->recursion_level); result = 0; goto end; } if (tp->ip4h == NULL || tp->tcph == NULL) { printf("pseudo packet's ip header and tcp header shouldn't be NULL, " "but it is\n"); result = 0; goto end; } if (GET_PKT_LEN(tp) != sizeof(tunnel_pkt)) { printf("defragged pseudo packet's and parent packet's pkt lens " "don't match\n %u != %"PRIuMAX, GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); result = 0; goto end; } if (memcmp(GET_PKT_DATA(tp), tunnel_pkt, sizeof(tunnel_pkt)) != 0) { result = 0; goto end; } PACKET_CLEANUP(p); SCFree(tp); end: DefragDestroy(); FlowShutdown(); PACKET_CLEANUP(p); SCFree(p); return result; } /** * \test Don't send IPv4 fragments to the upper layer decoder and * and packet recursion level test. */ int DecodeIPV4DefragTest02(void) { uint8_t pkt1[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x24, 0xe9, 0xef, 0x20, 0x00, 0x40, 0x06, 0x9a, 0xc8, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, /* first frag */ 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, }; uint8_t pkt2[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x2c, 0xe9, 0xef, 0x20, 0x02, 0x40, 0x06, 0xba, 0xca, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, /* second frag */ 0xb1, 0xa3, 0x00, 0x10, 0x5b, 0xa3, 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04 }; uint8_t pkt3[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x16, 0xe9, 0xef, 0x00, 0x05, 0x40, 0x06, 0xba, 0xca, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, /* final frag */ 0xb1, 0xa3, }; uint8_t tunnel_pkt[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3e, 0xe9, 0xef, 0x00, 0x00, 0x40, 0x06, 0xba, 0xae, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x10, 0x5b, 0xa3, 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04, 0xb1, 0xa3, }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; PacketQueue pq; int result = 0; memset(&tv, 0, sizeof(ThreadVars)); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&pq, 0, sizeof(PacketQueue)); PACKET_INITIALIZE(p); FlowInitConfig(FLOW_QUIET); DefragInit(); PacketCopyData(p, pkt1, sizeof(pkt1)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); goto end; } PACKET_DO_RECYCLE(p); PacketCopyData(p, pkt2, sizeof(pkt2)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); goto end; } PACKET_DO_RECYCLE(p); p->recursion_level = 3; PacketCopyData(p, pkt3, sizeof(pkt3)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); goto end; } Packet *tp = PacketDequeue(&pq); if (tp == NULL) { printf("Failed to get defragged pseudo packet\n"); goto end; } if (tp->recursion_level != p->recursion_level) { printf("defragged pseudo packet's and parent packet's recursion " "level don't match %d != %d: ", tp->recursion_level, p->recursion_level); goto end; } if (tp->ip4h == NULL || tp->tcph == NULL) { printf("pseudo packet's ip header and tcp header shouldn't be NULL, " "but it is\n"); goto end; } if (GET_PKT_LEN(tp) != sizeof(tunnel_pkt)) { printf("defragged pseudo packet's and parent packet's pkt lens " "don't match %u != %"PRIuMAX": ", GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); goto end; } if (memcmp(GET_PKT_DATA(tp), tunnel_pkt, sizeof(tunnel_pkt)) != 0) { goto end; } result = 1; PACKET_CLEANUP(p); SCFree(tp); end: DefragDestroy(); FlowShutdown(); PACKET_CLEANUP(p); SCFree(p); return result; } /** * \test IPV4 defrag and flow retrieval test. */ int DecodeIPV4DefragTest03(void) { uint8_t pkt[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0xe9, 0xee, 0x00, 0x00, 0x40, 0x06, 0xba, 0xbd, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x80, 0x00, 0x0c, 0xee, 0x00, 0x00 }; uint8_t pkt1[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0xe9, 0xef, 0x20, 0x00, 0x40, 0x06, 0x9a, 0xc8, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5e }; uint8_t pkt2[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0xe9, 0xef, 0x20, 0x01, 0x40, 0x06, 0x9a, 0xc7, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00 }; uint8_t pkt3[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x18, 0xe9, 0xef, 0x00, 0x02, 0x40, 0x06, 0xba, 0xca, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0xb1, 0xa3, 0x00, 0x00 }; uint8_t tunnel_pkt[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0xe9, 0xef, 0x00, 0x00, 0x40, 0x06, 0xba, 0xbc, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x00 }; Flow *f = NULL; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; PacketQueue pq; int result = 1; memset(&tv, 0, sizeof(ThreadVars)); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&pq, 0, sizeof(PacketQueue)); PACKET_INITIALIZE(p); FlowInitConfig(FLOW_QUIET); DefragInit(); PacketCopyData(p, pkt, sizeof(pkt)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph == NULL) { printf("tcp header shouldn't be NULL, but it is\n"); result = 0; goto end; } if (p->flow == NULL) { printf("packet flow shouldn't be NULL\n"); result = 0; goto end; } f = p->flow; PACKET_DO_RECYCLE(p); PacketCopyData(p, pkt1, sizeof(pkt1)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; goto end; } PACKET_DO_RECYCLE(p); PacketCopyData(p, pkt2, sizeof(pkt2)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; goto end; } PACKET_DO_RECYCLE(p); PacketCopyData(p, pkt3, sizeof(pkt3)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, GET_PKT_LEN(p) - ETHERNET_HEADER_LEN, &pq); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; goto end; } Packet *tp = PacketDequeue(&pq); if (tp == NULL) { printf("Failed to get defragged pseudo packet\n"); result = 0; goto end; } if (tp->flow == NULL) { result = 0; goto end; } if (tp->flow != f) { result = 0; goto end; } if (tp->recursion_level != p->recursion_level) { printf("defragged pseudo packet's and parent packet's recursion " "level don't match\n %d != %d", tp->recursion_level, p->recursion_level); result = 0; goto end; } if (tp->ip4h == NULL || tp->tcph == NULL) { printf("pseudo packet's ip header and tcp header shouldn't be NULL, " "but it is\n"); result = 0; goto end; } if (GET_PKT_LEN(tp) != sizeof(tunnel_pkt)) { printf("defragged pseudo packet's and parent packet's pkt lens " "don't match\n %u != %"PRIuMAX, GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); result = 0; goto end; } if (memcmp(GET_PKT_DATA(tp), tunnel_pkt, sizeof(tunnel_pkt)) != 0) { result = 0; goto end; } PACKET_CLEANUP(p); SCFree(tp); end: DefragDestroy(); FlowShutdown(); PACKET_CLEANUP(p); SCFree(p); return result; } #endif /* UNITTESTS */ void DecodeIPV4RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeIPV4OptionsNONETest01", DecodeIPV4OptionsNONETest01, 1); UtRegisterTest("DecodeIPV4OptionsEOLTest01", DecodeIPV4OptionsEOLTest01, 1); UtRegisterTest("DecodeIPV4OptionsNOPTest01", DecodeIPV4OptionsNOPTest01, 1); UtRegisterTest("DecodeIPV4OptionsRRTest01", DecodeIPV4OptionsRRTest01, 1); UtRegisterTest("DecodeIPV4OptionsRRTest02", DecodeIPV4OptionsRRTest02, 1); UtRegisterTest("DecodeIPV4OptionsRRTest03", DecodeIPV4OptionsRRTest03, 1); UtRegisterTest("DecodeIPV4OptionsRRTest04", DecodeIPV4OptionsRRTest04, 1); UtRegisterTest("DecodeIPV4OptionsQSTest01", DecodeIPV4OptionsQSTest01, 1); UtRegisterTest("DecodeIPV4OptionsQSTest02", DecodeIPV4OptionsQSTest02, 1); UtRegisterTest("DecodeIPV4OptionsTSTest01", DecodeIPV4OptionsTSTest01, 1); UtRegisterTest("DecodeIPV4OptionsTSTest02", DecodeIPV4OptionsTSTest02, 1); UtRegisterTest("DecodeIPV4OptionsTSTest03", DecodeIPV4OptionsTSTest03, 1); UtRegisterTest("DecodeIPV4OptionsTSTest04", DecodeIPV4OptionsTSTest04, 1); UtRegisterTest("DecodeIPV4OptionsSECTest01", DecodeIPV4OptionsSECTest01, 1); UtRegisterTest("DecodeIPV4OptionsSECTest02", DecodeIPV4OptionsSECTest02, 1); UtRegisterTest("DecodeIPV4OptionsLSRRTest01", DecodeIPV4OptionsLSRRTest01, 1); UtRegisterTest("DecodeIPV4OptionsLSRRTest02", DecodeIPV4OptionsLSRRTest02, 1); UtRegisterTest("DecodeIPV4OptionsLSRRTest03", DecodeIPV4OptionsLSRRTest03, 1); UtRegisterTest("DecodeIPV4OptionsLSRRTest04", DecodeIPV4OptionsLSRRTest04, 1); UtRegisterTest("DecodeIPV4OptionsCIPSOTest01", DecodeIPV4OptionsCIPSOTest01, 1); UtRegisterTest("DecodeIPV4OptionsSIDTest01", DecodeIPV4OptionsSIDTest01, 1); UtRegisterTest("DecodeIPV4OptionsSIDTest02", DecodeIPV4OptionsSIDTest02, 1); UtRegisterTest("DecodeIPV4OptionsSSRRTest01", DecodeIPV4OptionsSSRRTest01, 1); UtRegisterTest("DecodeIPV4OptionsSSRRTest02", DecodeIPV4OptionsSSRRTest02, 1); UtRegisterTest("DecodeIPV4OptionsSSRRTest03", DecodeIPV4OptionsSSRRTest03, 1); UtRegisterTest("DecodeIPV4OptionsSSRRTest04", DecodeIPV4OptionsSSRRTest04, 1); UtRegisterTest("DecodeIPV4OptionsRTRALTTest01", DecodeIPV4OptionsRTRALTTest01, 1); UtRegisterTest("DecodeIPV4OptionsRTRALTTest02", DecodeIPV4OptionsRTRALTTest02, 1); UtRegisterTest("IPV4CalculateValidChecksumtest01", IPV4CalculateValidChecksumtest01, 1); UtRegisterTest("IPV4CalculateInvalidChecksumtest02", IPV4CalculateInvalidChecksumtest02, 0); UtRegisterTest("DecodeIPV4DefragTest01", DecodeIPV4DefragTest01, 1); UtRegisterTest("DecodeIPV4DefragTest02", DecodeIPV4DefragTest02, 1); UtRegisterTest("DecodeIPV4DefragTest03", DecodeIPV4DefragTest03, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/detect-gid.c0000644000000000000000000001103112253546156013176 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * * Implements the gid keyword */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "flow-var.h" #include "decode-events.h" #include "detect-gid.h" #include "util-unittest.h" #include "util-debug.h" #define PARSE_REGEX "[0-9]+" static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectGidSetup (DetectEngineCtx *, Signature *, char *); /** * \brief Registration function for gid: keyword */ void DetectGidRegister (void) { sigmatch_table[DETECT_GID].name = "gid"; sigmatch_table[DETECT_GID].desc = "give different groups of signatures another id value"; sigmatch_table[DETECT_GID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Gid-group-id"; sigmatch_table[DETECT_GID].Match = NULL; sigmatch_table[DETECT_GID].Setup = DetectGidSetup; sigmatch_table[DETECT_GID].Free = NULL; sigmatch_table[DETECT_GID].RegisterTests = GidRegisterTests; const char *eb; int opts = 0; int eo; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } error: return; } /** * \internal * \brief This function is used to parse gid options passed via gid: keyword * * \param rawstr Pointer to the user provided gid options * * \retval gid number on success * \retval -1 on failure */ static uint32_t DetectGidParse (char *rawstr) { int ret = 0, res = 0; #define MAX_SUBSTRINGS 30 int ov[MAX_SUBSTRINGS]; const char *str_ptr = NULL; char *ptr = NULL; uint32_t rc; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); return -1; } res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 0, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } ptr = (char *)str_ptr; if(ptr == NULL) return -1; rc = (uint32_t )atol(ptr); SCFree(ptr); return rc; } /** * \internal * \brief this function is used to add the parsed gid into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param rawstr pointer to the user provided gid options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { s->gid = DetectGidParse(rawstr); if(s->gid > 0) return 0; return -1; } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS /** * \test GidTestParse01 is a test for a valid gid value * * \retval 1 on succces * \retval 0 on failure */ static int GidTestParse01 (void) { int gid = 0; gid = DetectGidParse("1"); if (gid == 1) { return 1; } return 0; } /** * \test GidTestParse02 is a test for an invalid gid value * * \retval 1 on succces * \retval 0 on failure */ static int GidTestParse02 (void) { int gid = 0; gid = DetectGidParse("a"); if (gid > 1) { return 1; } return 0; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for Gid */ void GidRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("GidTestParse01", GidTestParse01, 1); UtRegisterTest("GidTestParse02", GidTestParse02, 0); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-http-server-body.c0000644000000000000000000035573412253546156015676 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Anoop Saldanha * \author Victor Julien * * Implements support for the http_server_body keyword */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-server-body.h" #include "stream-tcp.h" int DetectHttpServerBodySetup(DetectEngineCtx *, Signature *, char *); void DetectHttpServerBodyRegisterTests(void); void DetectHttpServerBodyFree(void *); /** * \brief Registers the keyword handlers for the "http_server_body" keyword. */ void DetectHttpServerBodyRegister(void) { sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].name = "http_server_body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].desc = "content modifier to match only on the HTTP response-body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_server_body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Match = NULL; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Setup = DetectHttpServerBodySetup; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Free = DetectHttpServerBodyFree; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_PAYLOAD ; } /** * \brief The setup function for the http_server_body keyword for a signature. * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to signature for the current Signature being parsed * from the rules. * \param m Pointer to the head of the SigMatchs for the current rule * being parsed. * \param arg Pointer to the string holding the keyword value. * * \retval 0 On success * \retval -1 On failure */ int DetectHttpServerBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_server_body supplied with args"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if still we are unable to find any content previous keywords, it is an * invalid rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_server_body\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_server_body\" keyword"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_server_body should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_server_body rule can not " "be used with the rawbytes rule keyword"); return -1; } if ((s->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_server_body cannot be used with flow:to_server or from_client"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_server_body seen with a " "distance or within without a previous http_server_body " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HSBDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hsbdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HSBDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; /* enable http request body callback in the http app layer parser */ AppLayerHtpEnableResponseBodyCallback(); return 0; error: //if (cd != NULL) // DetectHttpServerBodyFree(cd); //if (sm != NULL) // SCFree(sm); return -1; } /** * \brief The function to free the http_server_body data. * * \param ptr Pointer to the http_server_body. */ void DetectHttpServerBodyFree(void *ptr) { SCEnter(); DetectContentData *hsbd = (DetectContentData *)ptr; if (hsbd == NULL) SCReturn; if (hsbd->content != NULL) SCFree(hsbd->content); BoyerMooreCtxDeInit(hsbd->bm_ctx); SCFree(hsbd); SCReturn; } /************************************Unittests*********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Test that a signature containting a http_server_body is correctly parsed * and the keyword is registered. */ static int DetectHttpServerBodyTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; SigMatch *sm = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_server_body\"; " "content:\"one\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } /* sm should not be in the MATCH list */ sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; if (sm != NULL) { goto end; } sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm == NULL) { goto end; } if (sm->type != DETECT_CONTENT) { printf("sm type not DETECT_AL_HTTP_SERVER_BODY: "); goto end; } if (sm->next != NULL) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a signature containing an valid http_server_body entry is * parsed. */ static int DetectHttpServerBodyTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_server_body\"; " "content:\"one\"; http_server_body:; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing no content but a http_server_body * is invalidated. */ static int DetectHttpServerBodyTest03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_server_body\"; " "http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_server_body is invalidated. */ static int DetectHttpServerBodyTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_server_body\"; " "content:\"one\"; rawbytes; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_server_body is invalidated. */ static int DetectHttpServerBodyTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_server_body\"; " "content:\"one\"; http_server_body; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. */ static int DetectHttpServerBodyTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 7\r\n" "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"message\"; http_server_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. */ static int DetectHttpServerBodyTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "message"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"message\"; http_server_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched on chunk2 but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match on p2 (chunk3) but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. */ static int DetectHttpServerBodyTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n" "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "sage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"message\"; http_server_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. */ static int DetectHttpServerBodyTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n" "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "sag"; uint32_t http_len3 = sizeof(http_buf3) - 1; uint8_t http_buf4[] = "e4u!!"; uint32_t http_len4 = sizeof(http_buf4) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"message\"; http_server_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. Case insensitve. */ static int DetectHttpServerBodyTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n" "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "sag"; uint32_t http_len3 = sizeof(http_buf3) - 1; uint8_t http_buf4[] = "e4u!!"; uint32_t http_len4 = sizeof(http_buf4) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"MeSSaGE\"; http_server_body; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. Negated match. */ static int DetectHttpServerBodyTest11(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "bigmessage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:!\"MaSSaGE\"; http_server_body; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have (p1): "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have (p2): "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. Negated match. */ static int DetectHttpServerBodyTest12(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "bigmessage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:!\"MeSSaGE\"; http_server_body; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have (p1): "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have (p2): "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectHttpServerBodyTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 55\r\n" "\r\n" "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "content:\"longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\"; http_server_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test multiple http transactions and body chunks of request handling */ static int DetectHttpServerBodyTest14(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" "User-Agent: Mozilla/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Connection: keep-alive\r\n" "Cookie: dummy1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 3\r\n" "\r\n" "one"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" "User-Agent: Firefox/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Connection: keep-alive\r\n" "Cookie: dummy2\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 3\r\n" "\r\n" "two"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; content:\"one\"; http_server_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; content:\"two\"; http_server_body; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCLogDebug("add chunk 1"); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } SCLogDebug("add chunk 2"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } SCLogDebug("inspect chunk 1"); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert (tx 1): "); goto end; } p->alerts.cnt = 0; SCLogDebug("add chunk 3"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } SCLogDebug("add chunk 4"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SCLogDebug("inspect chunk 4"); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sig 1 alerted (tx 2): "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sig 2 didn't alert (tx 2): "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int DetectHttpServerBodyTest15(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" "User-Agent: Mozilla/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Connection: keep-alive\r\n" "Cookie: dummy1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 3\r\n" "\r\n" "one"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" "User-Agent: Firefox/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Connection: keep-alive\r\n" "Cookie: dummy2\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 3\r\n" "\r\n" "two"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; content:\"one\"; http_server_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; content:\"two\"; http_server_body; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert (tx 1): "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sig 2 alerted (tx 1): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sig 1 alerted (tx 2): "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sig 2 didn't alert (tx 2): "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test multiple http transactions and body chunks of request handling */ int DetectHttpServerBodyTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (cd->id == hsbd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (cd->id == hsbd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_server_body; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (cd->id != 0 || hsbd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (cd->id != 1 || hsbd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"one\"; content:\"one\"; http_server_body; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (cd->id != 1 || hsbd1->id != 0 || hsbd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"one\"; content:\"one\"; http_server_body; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; if (cd->id != 2 || hsbd1->id != 0 || hsbd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; http_server_body; " "content:\"three\"; distance:10; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "two", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd1) || !DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hsbd1) || DETECT_CONTENT_IS_SINGLE(hsbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hsbd1) || DETECT_CONTENT_IS_SINGLE(hsbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; within:15; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hsbd1) || DETECT_CONTENT_IS_SINGLE(hsbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hsbd1) || DETECT_CONTENT_IS_SINGLE(hsbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; offset:10; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hsbd1) || DETECT_CONTENT_IS_SINGLE(hsbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** \test invalid combination for content: distance, depth, http_server_body */ int DetectHttpServerBodyTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; offset:10; http_server_body; pcre:/two/; distance:10; " "content:\"three\"; distance:10; http_server_body; depth:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL: "); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; http_server_body; depth:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != 0 || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DEPTH || memcmp(hsbd2->content, "three", hsbd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || !DETECT_CONTENT_IS_SINGLE(hsbd1) || DETECT_CONTENT_IS_SINGLE(hsbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; distance:0; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "two", hsbd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hsbd2->content, "two", hsbd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_server_body; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(pcre:/one/Q; " "content:\"two\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_SERVER_BODY) || hsbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_server_body; " "pcre:/one/QR; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_CONTENT) { goto end; } DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_SERVER_BODY) || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "two", hsbd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpServerBodyTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(pcre:/one/Q; " "content:\"two\"; distance:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_SERVER_BODY) || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. */ static int DetectHttpServerBodyFileDataTest01(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 7\r\n" "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "file_data; content:\"message\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. */ static int DetectHttpServerBodyFileDataTest02(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "message"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "file_data; content:\"message\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched on p1 but should have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match on p2 but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. */ static int DetectHttpServerBodyFileDataTest03(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n" "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "sage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "file_data; content:\"message\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. */ static int DetectHttpServerBodyFileDataTest04(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n" "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "sag"; uint32_t http_len3 = sizeof(http_buf3) - 1; uint8_t http_buf4[] = "e4u!!"; uint32_t http_len4 = sizeof(http_buf4) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "file_data; content:\"message\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. Case insensitve. */ static int DetectHttpServerBodyFileDataTest05(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n" "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "sag"; uint32_t http_len3 = sizeof(http_buf3) - 1; uint8_t http_buf4[] = "e4u!!"; uint32_t http_len4 = sizeof(http_buf4) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "file_data; content:\"MeSSaGE\"; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. Negated match. */ static int DetectHttpServerBodyFileDataTest06(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "bigmessage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http file_data test\"; " "file_data; content:!\"MaSSaGE\"; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have (p1): "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have (p2): "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_server_body content matches against a http request * which holds the content. Negated match. */ static int DetectHttpServerBodyFileDataTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 14\r\n" "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "bigmessage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http file_data test\"; " "file_data; content:!\"MeSSaGE\"; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have (p1): "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have (p2): "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectHttpServerBodyFileDataTest08(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 55\r\n" "\r\n" "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "file_data; content:\"longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test multiple http transactions and body chunks of request handling */ static int DetectHttpServerBodyFileDataTest09(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" "User-Agent: Mozilla/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Connection: keep-alive\r\n" "Cookie: dummy1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 3\r\n" "\r\n" "one"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" "User-Agent: Firefox/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Connection: keep-alive\r\n" "Cookie: dummy2\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 3\r\n" "\r\n" "two"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; file_data; content:\"one\"; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; file_data; content:\"two\"; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert (tx 1): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sig 1 alerted (tx 2): "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sig 2 didn't alert (tx 2): "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } static int DetectHttpServerBodyFileDataTest10(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" "User-Agent: Mozilla/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Connection: keep-alive\r\n" "Cookie: dummy1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 3\r\n" "\r\n" "one"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" "User-Agent: Firefox/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Connection: keep-alive\r\n" "Cookie: dummy2\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 3\r\n" "\r\n" "two"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; file_data; content:\"one\"; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; file_data; content:\"two\"; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert (tx 1): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sig 1 alerted (tx 2): "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sig 2 didn't alert (tx 2): "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } #endif /* UNITTESTS */ void DetectHttpServerBodyRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectHttpServerBodyTest01", DetectHttpServerBodyTest01, 1); UtRegisterTest("DetectHttpServerBodyTest02", DetectHttpServerBodyTest02, 1); UtRegisterTest("DetectHttpServerBodyTest03", DetectHttpServerBodyTest03, 1); UtRegisterTest("DetectHttpServerBodyTest04", DetectHttpServerBodyTest04, 1); UtRegisterTest("DetectHttpServerBodyTest05", DetectHttpServerBodyTest05, 1); UtRegisterTest("DetectHttpServerBodyTest06", DetectHttpServerBodyTest06, 1); UtRegisterTest("DetectHttpServerBodyTest07", DetectHttpServerBodyTest07, 1); UtRegisterTest("DetectHttpServerBodyTest08", DetectHttpServerBodyTest08, 1); UtRegisterTest("DetectHttpServerBodyTest09", DetectHttpServerBodyTest09, 1); UtRegisterTest("DetectHttpServerBodyTest10", DetectHttpServerBodyTest10, 1); UtRegisterTest("DetectHttpServerBodyTest11", DetectHttpServerBodyTest11, 1); UtRegisterTest("DetectHttpServerBodyTest12", DetectHttpServerBodyTest12, 1); UtRegisterTest("DetectHttpServerBodyTest13", DetectHttpServerBodyTest13, 1); UtRegisterTest("DetectHttpServerBodyTest14", DetectHttpServerBodyTest14, 1); UtRegisterTest("DetectHttpServerBodyTest15", DetectHttpServerBodyTest15, 1); UtRegisterTest("DetectHttpServerBodyTest16", DetectHttpServerBodyTest16, 1); UtRegisterTest("DetectHttpServerBodyTest17", DetectHttpServerBodyTest17, 1); UtRegisterTest("DetectHttpServerBodyTest18", DetectHttpServerBodyTest18, 1); UtRegisterTest("DetectHttpServerBodyTest19", DetectHttpServerBodyTest19, 1); UtRegisterTest("DetectHttpServerBodyTest20", DetectHttpServerBodyTest20, 1); UtRegisterTest("DetectHttpServerBodyTest21", DetectHttpServerBodyTest21, 1); UtRegisterTest("DetectHttpServerBodyTest22", DetectHttpServerBodyTest22, 1); UtRegisterTest("DetectHttpServerBodyTest23", DetectHttpServerBodyTest23, 1); UtRegisterTest("DetectHttpServerBodyTest24", DetectHttpServerBodyTest24, 1); UtRegisterTest("DetectHttpServerBodyTest25", DetectHttpServerBodyTest25, 1); UtRegisterTest("DetectHttpServerBodyTest26", DetectHttpServerBodyTest26, 1); UtRegisterTest("DetectHttpServerBodyTest27", DetectHttpServerBodyTest27, 1); UtRegisterTest("DetectHttpServerBodyTest28", DetectHttpServerBodyTest28, 1); UtRegisterTest("DetectHttpServerBodyTest29", DetectHttpServerBodyTest29, 1); UtRegisterTest("DetectHttpServerBodyTest30", DetectHttpServerBodyTest30, 1); UtRegisterTest("DetectHttpServerBodyTest31", DetectHttpServerBodyTest31, 1); UtRegisterTest("DetectHttpServerBodyTest32", DetectHttpServerBodyTest32, 1); UtRegisterTest("DetectHttpServerBodyTest33", DetectHttpServerBodyTest33, 1); UtRegisterTest("DetectHttpServerBodyTest34", DetectHttpServerBodyTest34, 1); UtRegisterTest("DetectHttpServerBodyTest35", DetectHttpServerBodyTest35, 1); UtRegisterTest("DetectHttpServerBodyTest36", DetectHttpServerBodyTest36, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest01", DetectHttpServerBodyFileDataTest01, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest02", DetectHttpServerBodyFileDataTest02, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest03", DetectHttpServerBodyFileDataTest03, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest04", DetectHttpServerBodyFileDataTest04, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest05", DetectHttpServerBodyFileDataTest05, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest06", DetectHttpServerBodyFileDataTest06, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest07", DetectHttpServerBodyFileDataTest07, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest08", DetectHttpServerBodyFileDataTest08, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest09", DetectHttpServerBodyFileDataTest09, 1); UtRegisterTest("DetectHttpServerBodyFileDataTest10", DetectHttpServerBodyFileDataTest10, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-engine-payload.c0000644000000000000000000007460712253546156015351 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Performs payload matching functions */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "detect-engine-content-inspection.h" #include "util-debug.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" /** * \brief Do the content inspection & validation for a signature * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param f flow (for pcre flowvar storage) * \param flags app layer flags * \param state App layer state * \param p Packet * * \retval 0 no match * \retval 1 match */ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, Packet *p) { SCEnter(); int r = 0; if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; det_ctx->replist = NULL; //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], f, p->payload, p->payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD, p); //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], p, f, p->payload, p->payload_len); //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; if (r == 1) { SCReturnInt(1); } SCReturnInt(0); } /** * \brief Do the content inspection & validation for a signature for a stream chunk * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param f flow (for pcre flowvar storage) * \param payload ptr to the payload to inspect * \param payload_len length of the payload * * \retval 0 no match * \retval 1 match * * \todo we might also pass the packet to this function for the pktvar * storage. Only, would that be right? We're not inspecting data * from the current packet here. */ int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t *payload, uint32_t payload_len) { SCEnter(); int r = 0; if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], f, payload, payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, NULL); //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], NULL, f, payload, payload_len); //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; if (r == 1) { SCReturnInt(1); } SCReturnInt(0); } #ifdef UNITTESTS /** \test Not the first but the second occurence of "abc" should be used * for the 2nd match */ static int PayloadTestSig01 (void) { uint8_t *buf = (uint8_t *) "abcabcd"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (content:\"abc\"; content:\"d\"; distance:0; within:1; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** \test Nocase matching */ static int PayloadTestSig02 (void) { uint8_t *buf = (uint8_t *) "abcaBcd"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (content:\"abc\"; nocase; content:\"d\"; distance:0; within:1; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** \test Negative distance matching */ static int PayloadTestSig03 (void) { uint8_t *buf = (uint8_t *) "abcaBcd"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (content:\"aBc\"; nocase; content:\"abca\"; distance:-10; within:4; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test multiple relative matches. */ static int PayloadTestSig04(void) { uint8_t *buf = (uint8_t *)"now this is is big big string now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test multiple relative matches. */ static int PayloadTestSig05(void) { uint8_t *buf = (uint8_t *)"now this is is is big big big string now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"this\"; content:\"is\"; within:9; content:\"big\"; within:12; " "content:\"string\"; within:8; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test multiple relative matches. */ static int PayloadTestSig06(void) { uint8_t *buf = (uint8_t *)"this this now is is big string now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"now\"; content:\"this\"; content:\"is\"; within:12; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test multiple relative matches. */ static int PayloadTestSig07(void) { uint8_t *buf = (uint8_t *)" thus thus is a big"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"thus\"; offset:8; content:\"is\"; within:6; content:\"big\"; within:8; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test multiple relative matches with negative matches * and show the need for det_ctx->discontinue_matching. */ static int PayloadTestSig08(void) { uint8_t *buf = (uint8_t *)"we need to fix this and yes fix this now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"fix\"; content:\"this\"; within:6; content:!\"and\"; distance:0; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) != 1) { goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test pcre recursive matching. */ static int PayloadTestSig09(void) { uint8_t *buf = (uint8_t *)"this is a super duper nova in super nova now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "pcre:/super/; content:\"nova\"; within:7; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test invalid sig. */ static int PayloadTestSig10(void) { uint8_t *buf = (uint8_t *)"this is a super duper nova in super nova now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "byte_test:4,>,2,0,relative; sid:11;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test invalid sig. */ static int PayloadTestSig11(void) { uint8_t *buf = (uint8_t *)"this is a super duper nova in super nova now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "byte_jump:1,0,relative; sid:11;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test invalid sig. */ static int PayloadTestSig12(void) { uint8_t *buf = (uint8_t *)"this is a super duper nova in super nova now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "isdataat:10,relative; sid:11;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Used to check the working of recursion_limit counter. */ static int PayloadTestSig13(void) { uint8_t *buf = (uint8_t *)"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; uint16_t mpm_type = MPM_B2G; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"aa\"; content:\"aa\"; distance:0; content:\"aa\"; distance:0; " "byte_test:1,>,200,0,relative; sid:1;)"; struct timeval tv_start, tv_end, tv_diff; gettimeofday(&tv_start, NULL); do { DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("de_ctx == NULL: "); goto end; } de_ctx->inspection_recursion_limit = 3000; de_ctx->flags |= DE_QUIET; de_ctx->mpm_matcher = mpm_type; de_ctx->sig_list = SigInit(de_ctx, sig); if (de_ctx->sig_list == NULL) { printf("signature == NULL: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); } while (0); gettimeofday(&tv_end, NULL); tv_diff.tv_sec = tv_end.tv_sec - tv_start.tv_sec; tv_diff.tv_usec = tv_end.tv_usec - tv_start.tv_usec; printf("%ld.%06ld\n", tv_diff.tv_sec, (long int)tv_diff.tv_usec); result = 1; if (p != NULL) UTHFreePacket(p); return result; } /** * \test normal & negated matching, both absolute and relative */ static int PayloadTestSig14(void) { uint8_t *buf = (uint8_t *)"User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.6 GTB5"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (content:\"User-Agent|3A| Mozilla/5.0 |28|Macintosh|3B| \"; content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; content:!\"Mozilla/5.0 |28|Macintosh|3B| U|3B| Intel Mac OS X 10.5|3B| en-US|3B| rv|3A|1.9.1b4|29| Gecko/20090423 Firefox/3.6 GTB5\"; sid:1; rev:1;)"; //char sig[] = "alert tcp any any -> any any (content:\"User-Agent: Mozilla/5.0 (Macintosh; \"; content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; content:!\"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.6 GTB5\"; sid:1; rev:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig15(void) { uint8_t *buf = (uint8_t *)"this is a super duper nova in super nova now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; isdataat:18,relative; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig16(void) { uint8_t *buf = (uint8_t *)"this is a super duper nova in super nova now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; isdataat:!20,relative; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig17(void) { uint8_t buf[] = { 0xEB, 0x29, 0x25, 0x38, 0x78, 0x25, 0x38, 0x78, 0x25 }; uint16_t buflen = 9; Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"%\"; depth:4; offset:0; " "content:\"%\"; within:2; distance:1; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig18(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|01 02 03 04|\"; " "byte_extract:1,2,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig19(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|01 02 03 04|\"; " "byte_extract:1,2,one,string,hex,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig20(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|01 02 03 04|\"; " "byte_extract:1,2,one,string,dec,relative; " "content:\"|06 35 07 08|\"; offset:one; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig21(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x36, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|01 02 03 04|\"; " "byte_extract:1,2,one,string,dec,relative; " "content:\"|03 04 05 06|\"; depth:one; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig22(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x36, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|01 02 03 04|\"; " "byte_extract:1,2,one,string,dec,relative; " "content:\"|09 0A 0B 0C|\"; within:one; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig23(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x32, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x33, 0x0B, 0x0C, 0x0D, 0x32, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|01 02 03 04|\"; " "byte_extract:1,2,one,string,dec,relative; " "byte_extract:1,3,two,string,dec,relative; " "byte_test:1,=,one,two,string,dec,relative; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig24(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x32, /* the last byte is 2 */ 0x07, 0x08, 0x33, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|01 02 03 04|\"; " "byte_extract:1,2,one,string,dec,relative; " "byte_jump:1,one,string,dec,relative; " "content:\"|0D 0E 0F|\"; distance:0; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /* * \test Test negative byte extract. */ static int PayloadTestSig25(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|35 07 08 09|\"; " "byte_extract:1,-4,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /* * \test Test negative byte extract. */ static int PayloadTestSig26(void) { uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"|35 07 08 09|\"; " "byte_extract:1,-3000,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) != 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /* * \test Test packet/stream sigs */ static int PayloadTestSig27(void) { uint8_t buf[] = "dummypayload"; uint16_t buflen = sizeof(buf) - 1; int result = 0; Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); char sig[] = "alert tcp any any -> any any (content:\"dummy\"; " "depth:5; sid:1;)"; p->flags |= PKT_STREAM_ADD; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) != 1) goto end; result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /* * \test Test packet/stream sigs */ static int PayloadTestSig28(void) { uint8_t buf[] = "dummypayload"; uint16_t buflen = sizeof(buf) - 1; int result = 0; Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); char sig[] = "alert tcp any any -> any any (content:\"payload\"; " "offset:4; depth:12; sid:1;)"; p->flags |= PKT_STREAM_ADD; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) != 1) goto end; result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test pcre recursive matching - bug #529 */ static int PayloadTestSig29(void) { uint8_t *buf = (uint8_t *)"this is a super dupernova in super nova now"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "pcre:/^.{4}/; content:\"nova\"; within:4; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 1) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig30(void) { uint8_t *buf = (uint8_t *) "xyonexxxxxxtwojunkonetwo"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (content:\"one\"; pcre:\"/^two/R\"; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int PayloadTestSig31(void) { uint8_t *buf = (uint8_t *) "xyonexxxxxxtwojunkonetwo"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (content:\"one\"; pcre:\"/(fiv|^two)/R\"; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test byte_jump. */ static int PayloadTestSig32(void) { uint8_t *buf = (uint8_t *)"dummy2xxcardmessage"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_jump:2,-14,string,dec,relative; content:\"card\"; within:4; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) goto end; result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test byte_test. */ static int PayloadTestSig33(void) { uint8_t *buf = (uint8_t *)"dummy2xxcardmessage"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_test:1,=,2,-14,string,dec,relative; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) goto end; result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** * \test Test byte_extract. */ static int PayloadTestSig34(void) { uint8_t *buf = (uint8_t *)"dummy2xxcardmessage"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_extract:1,-14,boom,string,dec,relative; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) goto end; result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } #endif /* UNITTESTS */ void PayloadRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("PayloadTestSig01", PayloadTestSig01, 1); UtRegisterTest("PayloadTestSig02", PayloadTestSig02, 1); UtRegisterTest("PayloadTestSig03", PayloadTestSig03, 1); UtRegisterTest("PayloadTestSig04", PayloadTestSig04, 1); UtRegisterTest("PayloadTestSig05", PayloadTestSig05, 1); UtRegisterTest("PayloadTestSig06", PayloadTestSig06, 1); UtRegisterTest("PayloadTestSig07", PayloadTestSig07, 1); UtRegisterTest("PayloadTestSig08", PayloadTestSig08, 1); UtRegisterTest("PayloadTestSig09", PayloadTestSig09, 1); UtRegisterTest("PayloadTestSig10", PayloadTestSig10, 1); UtRegisterTest("PayloadTestSig11", PayloadTestSig11, 1); UtRegisterTest("PayloadTestSig12", PayloadTestSig12, 1); UtRegisterTest("PayloadTestSig13", PayloadTestSig13, 1); UtRegisterTest("PayloadTestSig14", PayloadTestSig14, 1); UtRegisterTest("PayloadTestSig15", PayloadTestSig15, 1); UtRegisterTest("PayloadTestSig16", PayloadTestSig16, 1); UtRegisterTest("PayloadTestSig17", PayloadTestSig17, 1); UtRegisterTest("PayloadTestSig18", PayloadTestSig18, 1); UtRegisterTest("PayloadTestSig19", PayloadTestSig19, 1); UtRegisterTest("PayloadTestSig20", PayloadTestSig20, 1); UtRegisterTest("PayloadTestSig21", PayloadTestSig21, 1); UtRegisterTest("PayloadTestSig22", PayloadTestSig22, 1); UtRegisterTest("PayloadTestSig23", PayloadTestSig23, 1); UtRegisterTest("PayloadTestSig24", PayloadTestSig24, 1); UtRegisterTest("PayloadTestSig25", PayloadTestSig25, 1); UtRegisterTest("PayloadTestSig26", PayloadTestSig26, 1); UtRegisterTest("PayloadTestSig27", PayloadTestSig27, 1); UtRegisterTest("PayloadTestSig28", PayloadTestSig28, 1); UtRegisterTest("PayloadTestSig29", PayloadTestSig29, 1); UtRegisterTest("PayloadTestSig30", PayloadTestSig30, 1); UtRegisterTest("PayloadTestSig31", PayloadTestSig31, 1); UtRegisterTest("PayloadTestSig32", PayloadTestSig32, 1); UtRegisterTest("PayloadTestSig33", PayloadTestSig33, 1); UtRegisterTest("PayloadTestSig34", PayloadTestSig34, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/tmqh-ringbuffer.h0000644000000000000000000000167012253546156014302 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __TMQH_RINGBUFFER_H__ #define __TMQH_RINGBUFFER_H__ void TmqhRingBufferRegister (void); void TmqhRingBufferDestroy (void); #endif /* __TMQH_RINGBUFFER_H__ */ suricata-1.4.7/src/detect-engine-hhhd.c0000644000000000000000000022341612253546156014625 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP host header. * HHHD - Http Host Header Data * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" #include "detect-engine-hhhd.h" int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { htp_tx_t *tx = NULL; uint32_t cnt = 0; int idx; /* we need to lock because the buffers are not actually true buffers * but are ones that point to a buffer given by libhtp */ FLOWLOCK_RDLOCK(f); if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->parsed_uri == NULL || tx->parsed_uri->hostname == NULL) continue; uint8_t *hname = (uint8_t *)bstr_ptr(tx->parsed_uri->hostname); if (hname == NULL) continue; uint32_t hname_len = bstr_len(tx->parsed_uri->hostname); cnt += HttpHHPatternSearch(det_ctx, hname, hname_len, flags); } end: FLOWLOCK_UNLOCK(f); return cnt; } /** * \brief Do the http_header content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpHH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL || tx->parsed_uri == NULL || tx->parsed_uri->hostname == NULL) return 0; uint8_t *hname = (uint8_t *)bstr_ptr(tx->parsed_uri->hostname); if (hname == NULL) return 0; uint32_t hname_len = bstr_len(tx->parsed_uri->hostname); det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HHHDMATCH], f, hname, hname_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** * \test Test that the http_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest01(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"connect\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest02(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"co\"; depth:4; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest03(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:!\"ect\"; depth:4; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest04(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"ect\"; depth:4; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest05(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:!\"con\"; depth:4; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"ect\"; offset:3; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest07(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:!\"co\"; offset:3; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest08(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:!\"ect\"; offset:3; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest09(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"con\"; offset:3; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest10(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"co\"; http_host; " "content:\"ec\"; within:4; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"co\"; http_host; " "content:!\"ec\"; within:3; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"co\"; http_host; " "content:\"ec\"; within:3; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"co\"; http_host; " "content:!\"ec\"; within:4; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest14(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"co\"; http_host; " "content:\"ec\"; distance:2; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest15(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"co\"; http_host; " "content:!\"ec\"; distance:3; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest16(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"co\"; http_host; " "content:\"ec\"; distance:3; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHHTest17(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"co\"; http_host; " "content:!\"ec\"; distance:2; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest18(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.kaboom.com\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"kaboom\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest19(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.kaboom.com:8080\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"kaboom\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest20(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.kaboom.com:8080\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"8080\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but it shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest21(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"kaboom\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest22(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"kaboom\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest23(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"8080\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but it shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest24(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" "Host: www.rabbit.com\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"kaboom\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but it should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest25(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" "Host: www.rabbit.com\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_host header test\"; " "content:\"rabbit\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but it shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest26(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://[fdaf:222d::2342]/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"2342\"; http_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest27(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://[fdaf:222d::2342]:8080/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"2342\"; http_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest28(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: [fdaf:222d::2342]\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"2342\"; http_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHHTest29(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: [fdaf:222d::2342]:8080\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"2342\"; http_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpHHRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpHHTest01", DetectEngineHttpHHTest01, 1); UtRegisterTest("DetectEngineHttpHHTest02", DetectEngineHttpHHTest02, 1); UtRegisterTest("DetectEngineHttpHHTest03", DetectEngineHttpHHTest03, 1); UtRegisterTest("DetectEngineHttpHHTest04", DetectEngineHttpHHTest04, 1); UtRegisterTest("DetectEngineHttpHHTest05", DetectEngineHttpHHTest05, 1); UtRegisterTest("DetectEngineHttpHHTest06", DetectEngineHttpHHTest06, 1); UtRegisterTest("DetectEngineHttpHHTest07", DetectEngineHttpHHTest07, 1); UtRegisterTest("DetectEngineHttpHHTest08", DetectEngineHttpHHTest08, 1); UtRegisterTest("DetectEngineHttpHHTest09", DetectEngineHttpHHTest09, 1); UtRegisterTest("DetectEngineHttpHHTest10", DetectEngineHttpHHTest10, 1); UtRegisterTest("DetectEngineHttpHHTest11", DetectEngineHttpHHTest11, 1); UtRegisterTest("DetectEngineHttpHHTest12", DetectEngineHttpHHTest12, 1); UtRegisterTest("DetectEngineHttpHHTest13", DetectEngineHttpHHTest13, 1); UtRegisterTest("DetectEngineHttpHHTest14", DetectEngineHttpHHTest14, 1); UtRegisterTest("DetectEngineHttpHHTest15", DetectEngineHttpHHTest15, 1); UtRegisterTest("DetectEngineHttpHHTest16", DetectEngineHttpHHTest16, 1); UtRegisterTest("DetectEngineHttpHHTest17", DetectEngineHttpHHTest17, 1); UtRegisterTest("DetectEngineHttpHHTest18", DetectEngineHttpHHTest18, 1); UtRegisterTest("DetectEngineHttpHHTest19", DetectEngineHttpHHTest19, 1); UtRegisterTest("DetectEngineHttpHHTest20", DetectEngineHttpHHTest20, 1); UtRegisterTest("DetectEngineHttpHHTest21", DetectEngineHttpHHTest21, 1); UtRegisterTest("DetectEngineHttpHHTest22", DetectEngineHttpHHTest22, 1); UtRegisterTest("DetectEngineHttpHHTest23", DetectEngineHttpHHTest23, 1); UtRegisterTest("DetectEngineHttpHHTest24", DetectEngineHttpHHTest24, 1); UtRegisterTest("DetectEngineHttpHHTest25", DetectEngineHttpHHTest25, 1); UtRegisterTest("DetectEngineHttpHHTest26", DetectEngineHttpHHTest26, 1); UtRegisterTest("DetectEngineHttpHHTest27", DetectEngineHttpHHTest27, 1); UtRegisterTest("DetectEngineHttpHHTest28", DetectEngineHttpHHTest28, 1); UtRegisterTest("DetectEngineHttpHHTest29", DetectEngineHttpHHTest29, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/tm-queuehandlers.h0000644000000000000000000000270012253546156014460 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __TM_QUEUEHANDLERS_H__ #define __TM_QUEUEHANDLERS_H__ enum { TMQH_SIMPLE, TMQH_NFQ, TMQH_PACKETPOOL, TMQH_FLOW, TMQH_RINGBUFFER_MRSW, TMQH_RINGBUFFER_SRSW, TMQH_RINGBUFFER_SRMW, TMQH_SIZE, }; typedef struct Tmqh_ { char *name; Packet *(*InHandler)(ThreadVars *); void (*InShutdownHandler)(ThreadVars *); void (*OutHandler)(ThreadVars *, Packet *); void *(*OutHandlerCtxSetup)(char *); void (*OutHandlerCtxFree)(void *); void (*RegisterTests)(void); } Tmqh; Tmqh tmqh_table[TMQH_SIZE]; void TmqhSetup (void); void TmqhCleanup(void); Tmqh* TmqhGetQueueHandlerByName(char *name); #endif /* __TM_QUEUEHANDLERS_H__ */ suricata-1.4.7/src/detect-ipopts.c0000644000000000000000000002144312253546156013761 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * * Implements the ipopts keyword */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "flow-var.h" #include "decode-events.h" #include "util-debug.h" /* Need to get the DIpOpts[] array */ #define DETECT_EVENTS #include "detect-ipopts.h" #include "util-unittest.h" #define PARSE_REGEX "\\S[A-z]" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectIpOptsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, char *); void IpOptsRegisterTests(void); void DetectIpOptsFree(void *); /** * \brief Registration function for ipopts: keyword */ void DetectIpOptsRegister (void) { sigmatch_table[DETECT_IPOPTS].name = "ipopts"; sigmatch_table[DETECT_IPOPTS].desc = "check if a specific IP option is set"; sigmatch_table[DETECT_IPOPTS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Ipopts"; sigmatch_table[DETECT_IPOPTS].Match = DetectIpOptsMatch; sigmatch_table[DETECT_IPOPTS].Setup = DetectIpOptsSetup; sigmatch_table[DETECT_IPOPTS].Free = DetectIpOptsFree; sigmatch_table[DETECT_IPOPTS].RegisterTests = IpOptsRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \internal * \brief This function is used to match ip option on a packet with those passed via ipopts: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param s pointer to the Signature * \param m pointer to the sigmatch * * \retval 0 no match * \retval 1 match */ int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { int ret = 0; int ipopt = 0; DetectIpOptsData *de = (DetectIpOptsData *)m->ctx; if (!de || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) return ret; /* IPV4_OPT_ANY matches on any options */ if (p->IPV4_OPTS_CNT && (de->ipopt == IPV4_OPT_ANY)) { return 1; } /* Loop through instead of using o_xxx direct access fields so that * future options do not require any modification here. */ while(ipopt < p->IPV4_OPTS_CNT) { if (p->IPV4_OPTS[ipopt].type == de->ipopt) { return 1; } ipopt++; } return ret; } /** * \internal * \brief This function is used to parse ipopts options passed via ipopts: keyword * * \param rawstr Pointer to the user provided ipopts options * * \retval de pointer to DetectIpOptsData on success * \retval NULL on failure */ DetectIpOptsData *DetectIpOptsParse (char *rawstr) { int i; DetectIpOptsData *de = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, found = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); goto error; } for(i = 0; DIpOpts[i].ipopt_name != NULL; i++) { if((strcasecmp(DIpOpts[i].ipopt_name,rawstr)) == 0) { found = 1; break; } } if(found == 0) goto error; de = SCMalloc(sizeof(DetectIpOptsData)); if (unlikely(de == NULL)) goto error; de->ipopt = DIpOpts[i].code; return de; error: if (de) SCFree(de); return NULL; } /** * \internal * \brief this function is used to add the parsed ipopts into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param rawstr pointer to the user provided ipopts options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectIpOptsData *de = NULL; SigMatch *sm = NULL; de = DetectIpOptsParse(rawstr); if (de == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_IPOPTS; sm->ctx = (void *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (de) SCFree(de); if (sm) SCFree(sm); return -1; } /** * \internal * \brief this function will free memory associated with DetectIpOptsData * * \param de pointer to DetectIpOptsData */ void DetectIpOptsFree(void *de_ptr) { DetectIpOptsData *de = (DetectIpOptsData *)de_ptr; if(de) SCFree(de); } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS /** * \test IpOptsTestParse01 is a test for a valid ipopts value * * \retval 1 on succces * \retval 0 on failure */ int IpOptsTestParse01 (void) { DetectIpOptsData *de = NULL; de = DetectIpOptsParse("lsrr"); if (de) { DetectIpOptsFree(de); return 1; } return 0; } /** * \test IpOptsTestParse02 is a test for an invalid ipopts value * * \retval 1 on succces * \retval 0 on failure */ int IpOptsTestParse02 (void) { DetectIpOptsData *de = NULL; de = DetectIpOptsParse("invalidopt"); if (de) { DetectIpOptsFree(de); return 1; } return 0; } /** * \test IpOptsTestParse03 test the match function on a packet that needs to match * * \retval 1 on succces * \retval 0 on failure */ int IpOptsTestParse03 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectIpOptsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ip4h; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ip4h, 0, sizeof(IPV4Hdr)); p->ip4h = &ip4h; p->IPV4_OPTS[0].type = IPV4_OPT_RR; p->IPV4_OPTS_CNT++; de = DetectIpOptsParse("rr"); if (de == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_IPOPTS; sm->ctx = (void *)de; ret = DetectIpOptsMatch(&tv,NULL,p,NULL,sm); if(ret) { SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test IpOptsTestParse04 test the match function on a packet that needs to not match * * \retval 1 on succces * \retval 0 on failure */ int IpOptsTestParse04 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectIpOptsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ip4h; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ip4h, 0, sizeof(IPV4Hdr)); p->ip4h = &ip4h; p->IPV4_OPTS[0].type = IPV4_OPT_RR; p->IPV4_OPTS_CNT++; de = DetectIpOptsParse("lsrr"); if (de == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_IPOPTS; sm->ctx = (void *)de; ret = DetectIpOptsMatch(&tv,NULL,p,NULL,sm); if(ret) { SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for IpOpts */ void IpOptsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01, 1); UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02, 0); UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03, 1); UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04, 0); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-icode.h0000644000000000000000000000241512253546156013531 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \file detect-icode.c * * \author Gerardo Iglesias */ #ifndef __DETECT_ICODE_H__ #define __DETECT_ICODE_H__ #define DETECT_ICODE_EQ 0 /**< "equal" operator */ #define DETECT_ICODE_LT 1 /**< "less than" operator */ #define DETECT_ICODE_GT 2 /**< "greater than" operator */ #define DETECT_ICODE_RN 3 /**< "range" operator */ typedef struct DetectICodeData_ { uint8_t code1; uint8_t code2; uint8_t mode; }DetectICodeData; /* prototypes */ void DetectICodeRegister(void); #endif /* __DETECT_ICODE_H__ */ suricata-1.4.7/src/runmode-pcap.h0000644000000000000000000000210012253546156013561 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien */ #ifndef __RUNMODE_PCAP_H__ #define __RUNMODE_PCAP_H__ int RunModeIdsPcapAuto(DetectEngineCtx *); int RunModeIdsPcapSingle(DetectEngineCtx *); int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx); void RunModeIdsPcapRegister(void); const char *RunModeIdsGetDefaultMode(void); #endif /* __RUNMODE_PCAP_H__ */ suricata-1.4.7/src/log-file.c0000644000000000000000000003607112253546156012676 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Log files we track. * */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "pkt-var.h" #include "conf.h" #include "threadvars.h" #include "tm-modules.h" #include "threads.h" #include "app-layer-parser.h" #include "detect-filemagic.h" #include "stream.h" #include "util-print.h" #include "util-unittest.h" #include "util-privs.h" #include "util-debug.h" #include "util-atomic.h" #include "util-file.h" #include "output.h" #include "log-file.h" #include "util-logopenfile.h" #include "app-layer-htp.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" #define MODULE_NAME "LogFileLog" #define DEFAULT_LOG_FILENAME "files-json.log" TmEcode LogFileLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogFileLogIPv4(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogFileLogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogFileLogThreadInit(ThreadVars *, void *, void **); TmEcode LogFileLogThreadDeinit(ThreadVars *, void *); void LogFileLogExitPrintStats(ThreadVars *, void *); int LogFileLogOpenFileCtx(LogFileCtx* , const char *, const char *); static OutputCtx *LogFileLogInitCtx(ConfNode *); static void LogFileLogDeInitCtx(OutputCtx *); void TmModuleLogFileLogRegister (void) { tmm_modules[TMM_FILELOG].name = MODULE_NAME; tmm_modules[TMM_FILELOG].ThreadInit = LogFileLogThreadInit; tmm_modules[TMM_FILELOG].Func = LogFileLog; tmm_modules[TMM_FILELOG].ThreadExitPrintStats = LogFileLogExitPrintStats; tmm_modules[TMM_FILELOG].ThreadDeinit = LogFileLogThreadDeinit; tmm_modules[TMM_FILELOG].RegisterTests = NULL; tmm_modules[TMM_FILELOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "file-log", LogFileLogInitCtx); SCLogDebug("registered"); } typedef struct LogFileLogThread_ { LogFileCtx *file_ctx; /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ uint32_t file_cnt; } LogFileLogThread; static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); } static void LogFileMetaGetUri(FILE *fp, Packet *p, File *ff) { HtpState *htp_state = (HtpState *)p->flow->alstate; if (htp_state != NULL) { htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, ff->txid); if (tx != NULL && tx->request_uri_normalized != NULL) { PrintRawJsonFp(fp, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized)); return; } } fprintf(fp, ""); } static void LogFileMetaGetHost(FILE *fp, Packet *p, File *ff) { HtpState *htp_state = (HtpState *)p->flow->alstate; if (htp_state != NULL) { htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, ff->txid); if (tx != NULL) { table_t *headers; headers = tx->request_headers; htp_header_t *h = NULL; table_iterator_reset(headers); while (table_iterator_next(headers, (void **)&h) != NULL) { if (bstr_len(h->name) >= 4 && SCMemcmpLowercase((uint8_t *)"host", (uint8_t *)bstr_ptr(h->name), bstr_len(h->name)) == 0) { PrintRawJsonFp(fp, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value)); return; } } } } fprintf(fp, ""); } static void LogFileMetaGetReferer(FILE *fp, Packet *p, File *ff) { HtpState *htp_state = (HtpState *)p->flow->alstate; if (htp_state != NULL) { htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, ff->txid); if (tx != NULL) { table_t *headers; headers = tx->request_headers; htp_header_t *h = NULL; table_iterator_reset(headers); while (table_iterator_next(headers, (void **)&h) != NULL) { if (bstr_len(h->name) >= 7 && SCMemcmpLowercase((uint8_t *)"referer", (uint8_t *)bstr_ptr(h->name), bstr_len(h->name)) == 0) { PrintRawJsonFp(fp, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value)); return; } } } } fprintf(fp, ""); } static void LogFileMetaGetUserAgent(FILE *fp, Packet *p, File *ff) { HtpState *htp_state = (HtpState *)p->flow->alstate; if (htp_state != NULL) { htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, ff->txid); if (tx != NULL) { table_t *headers; headers = tx->request_headers; htp_header_t *h = NULL; table_iterator_reset(headers); while (table_iterator_next(headers, (void **)&h) != NULL) { if (bstr_len(h->name) >= 10 && SCMemcmpLowercase((uint8_t *)"user-agent", (uint8_t *)bstr_ptr(h->name), bstr_len(h->name)) == 0) { PrintRawJsonFp(fp, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value)); return; } } } } fprintf(fp, ""); } /** * \internal * \brief Write meta data on a single line json record */ static void LogFileWriteJsonRecord(LogFileLogThread *aft, Packet *p, File *ff, int ipver) { SCMutexLock(&aft->file_ctx->fp_mutex); FILE *fp = aft->file_ctx->fp; char timebuf[64]; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); fprintf(fp, "{ "); if (ff->file_id > 0) fprintf(fp, "\"id\": %u, ", ff->file_id); fprintf(fp, "\"timestamp\": \""); PrintRawJsonFp(fp, (uint8_t *)timebuf, strlen(timebuf)); fprintf(fp, "\", "); if (p->pcap_cnt > 0) { fprintf(fp, "\"pcap_pkt_num\": %"PRIu64", ", p->pcap_cnt); } fprintf(fp, "\"ipver\": %d, ", ipver == AF_INET ? 4 : 6); char srcip[46], dstip[46]; Port sp, dp; switch (ipver) { case AF_INET: PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); break; case AF_INET6: PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); break; default: strlcpy(srcip, "", sizeof(srcip)); strlcpy(dstip, "", sizeof(dstip)); break; } sp = p->sp; dp = p->dp; fprintf(fp, "\"srcip\": \"%s\", ", srcip); fprintf(fp, "\"dstip\": \"%s\", ", dstip); fprintf(fp, "\"protocol\": %" PRIu32 ", ", p->proto); if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { fprintf(fp, "\"sp\": %" PRIu16 ", ", sp); fprintf(fp, "\"dp\": %" PRIu16 ", ", dp); } fprintf(fp, "\"http_uri\": \""); LogFileMetaGetUri(fp, p, ff); fprintf(fp, "\", "); fprintf(fp, "\"http_host\": \""); LogFileMetaGetHost(fp, p, ff); fprintf(fp, "\", "); fprintf(fp, "\"http_referer\": \""); LogFileMetaGetReferer(fp, p, ff); fprintf(fp, "\", "); fprintf(fp, "\"http_user_agent\": \""); LogFileMetaGetUserAgent(fp, p, ff); fprintf(fp, "\", "); fprintf(fp, "\"filename\": \""); PrintRawJsonFp(fp, ff->name, ff->name_len); fprintf(fp, "\", "); fprintf(fp, "\"magic\": \""); if (ff->magic) { PrintRawJsonFp(fp, (uint8_t *)ff->magic, strlen(ff->magic)); } else { fprintf(fp, "unknown"); } fprintf(fp, "\", "); switch (ff->state) { case FILE_STATE_CLOSED: fprintf(fp, "\"state\": \"CLOSED\", "); #ifdef HAVE_NSS if (ff->flags & FILE_MD5) { fprintf(fp, "\"md5\": \""); size_t x; for (x = 0; x < sizeof(ff->md5); x++) { fprintf(fp, "%02x", ff->md5[x]); } fprintf(fp, "\", "); } #endif break; case FILE_STATE_TRUNCATED: fprintf(fp, "\"state\": \"TRUNCATED\", "); break; case FILE_STATE_ERROR: fprintf(fp, "\"state\": \"ERROR\", "); break; default: fprintf(fp, "\"state\": \"UNKNOWN\", "); break; } fprintf(fp, "\"stored\": %s, ", ff->flags & FILE_STORED ? "true" : "false"); fprintf(fp, "\"size\": %"PRIu64" ", ff->size); fprintf(fp, "}\n"); fflush(fp); SCMutexUnlock(&aft->file_ctx->fp_mutex); } static TmEcode LogFileLogWrap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq, int ipver) { SCEnter(); LogFileLogThread *aft = (LogFileLogThread *)data; uint8_t flags = 0; /* no flow, no htp state */ if (p->flow == NULL) { SCReturnInt(TM_ECODE_OK); } if (p->flowflags & FLOW_PKT_TOCLIENT) flags |= STREAM_TOCLIENT; else flags |= STREAM_TOSERVER; int file_close = (p->flags & PKT_PSEUDO_STREAM_END) ? 1 : 0; int file_trunc = 0; FLOWLOCK_WRLOCK(p->flow); file_trunc = StreamTcpReassembleDepthReached(p); FileContainer *ffc = AppLayerGetFilesFromFlow(p->flow, flags); SCLogDebug("ffc %p", ffc); if (ffc != NULL) { File *ff; for (ff = ffc->head; ff != NULL; ff = ff->next) { if (ff->flags & FILE_LOGGED) continue; if (FileForceMagic() && ff->magic == NULL) { FilemagicGlobalLookup(ff); } SCLogDebug("ff %p", ff); if (file_trunc && ff->state < FILE_STATE_CLOSED) ff->state = FILE_STATE_TRUNCATED; if (ff->state == FILE_STATE_CLOSED || ff->state == FILE_STATE_TRUNCATED || ff->state == FILE_STATE_ERROR || (file_close == 1 && ff->state < FILE_STATE_CLOSED)) { LogFileWriteJsonRecord(aft, p, ff, ipver); ff->flags |= FILE_LOGGED; aft->file_cnt++; } } FilePrune(ffc); } FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_OK); } TmEcode LogFileLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return LogFileLogWrap(tv, p, data, NULL, NULL, AF_INET); } TmEcode LogFileLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return LogFileLogWrap(tv, p, data, NULL, NULL, AF_INET6); } TmEcode LogFileLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); int r = TM_ECODE_OK; /* no flow, no htp state */ if (p->flow == NULL) { SCReturnInt(TM_ECODE_OK); } if (!(PKT_IS_TCP(p))) { SCReturnInt(TM_ECODE_OK); } SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); if (PKT_IS_IPV4(p)) { r = LogFileLogIPv4(tv, p, data, pq, postpq); } else if (PKT_IS_IPV6(p)) { r = LogFileLogIPv6(tv, p, data, pq, postpq); } SCReturnInt(r); } TmEcode LogFileLogThreadInit(ThreadVars *t, void *initdata, void **data) { LogFileLogThread *aft = SCMalloc(sizeof(LogFileLogThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(LogFileLogThread)); if (initdata == NULL) { SCLogDebug("Error getting context for LogFile. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } /* Use the Ouptut Context (file pointer and mutex) */ aft->file_ctx = ((OutputCtx *)initdata)->data; *data = (void *)aft; return TM_ECODE_OK; } TmEcode LogFileLogThreadDeinit(ThreadVars *t, void *data) { LogFileLogThread *aft = (LogFileLogThread *)data; if (aft == NULL) { return TM_ECODE_OK; } /* clear memory */ memset(aft, 0, sizeof(LogFileLogThread)); SCFree(aft); return TM_ECODE_OK; } void LogFileLogExitPrintStats(ThreadVars *tv, void *data) { LogFileLogThread *aft = (LogFileLogThread *)data; if (aft == NULL) { return; } SCLogInfo("(%s) Files logged: %" PRIu32 "", tv->name, aft->file_cnt); } /** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful * */ static OutputCtx *LogFileLogInitCtx(ConfNode *conf) { LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("Could not create new LogFileCtx"); return NULL; } if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; output_ctx->data = logfile_ctx; output_ctx->DeInit = LogFileLogDeInitCtx; const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); SCLogInfo("forcing magic lookup for logged files"); } const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); if (force_md5 != NULL && ConfValIsTrue(force_md5)) { #ifdef HAVE_NSS FileForceMd5Enable(); SCLogInfo("forcing md5 calculation for logged files"); #else SCLogInfo("md5 calculation requires linking against libnss"); #endif } FileForceTrackingEnable(); SCReturnPtr(output_ctx, "OutputCtx"); } /** * \internal * * \brief deinit the log ctx and write out the waldo * * \param output_ctx output context to deinit */ static void LogFileLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; LogFileFreeCtx(logfile_ctx); free(output_ctx); } /** \brief Read the config set the file pointer, open the file * \param file_ctx pointer to a created LogFileCtx using LogFileNewCtx() * \param config_file for loading separate configs * \return -1 if failure, 0 if succesful * */ int LogFileLogOpenFileCtx(LogFileCtx *file_ctx, const char *filename, const char *mode) { return 0; } suricata-1.4.7/src/detect-http-stat-msg.c0000644000000000000000000004514512253546156015164 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Gurvinder Singh * \author Anoop Saldanha * * Implements the http_stat_msg keyword */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-content.h" #include "detect-pcre.h" #include "detect-engine-mpm.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-error.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "util-print.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-stat-msg.h" #include "stream-tcp-private.h" #include "stream-tcp.h" int DetectHttpStatMsgMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t , void *, Signature *, SigMatch *); static int DetectHttpStatMsgSetup (DetectEngineCtx *, Signature *, char *); void DetectHttpStatMsgRegisterTests(void); void DetectHttpStatMsgFree(void *); /** * \brief Registration function for keyword: http_stat_msg */ void DetectHttpStatMsgRegister (void) { sigmatch_table[DETECT_AL_HTTP_STAT_MSG].name = "http_stat_msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].desc = "content modifier to match on HTTP stat-msg-buffer"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_stat_msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Match = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Free = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].RegisterTests = DetectHttpStatMsgRegisterTests; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_PAYLOAD; } /** * \brief this function setups the http_stat_msg modifier keyword used in the rule * * \param de_ctx Pointer to the Detection Engine Context * \param s Pointer to the Signature to which the current keyword belongs * \param str Should hold an empty string always * * \retval 0 On success * \retval -1 On failure */ static int DetectHttpStatMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_msg supplied with args"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if still we are unable to find any content previous keywords, it is an * invalid rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_stat_msg\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_stat_msg\" keyword"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_stat_msg should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg rule can not " "be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg seen with a " "distance or within without a previous http_stat_msg " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HSMDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hcbdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HSMDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } #ifdef UNITTESTS /** * \test Checks if a http_stat_msg is registered in a Signature, if content is not * specified in the signature or rawbyes is specified or fast_pattern is * provided in the signature. */ int DetectHttpStatMsgTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_msg\"; http_stat_msg;sid:1;)"); if (de_ctx->sig_list != NULL) goto end; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_msg\"; content:\"|FF F1|\";" " rawbytes; http_stat_msg;sid:1;)"); if (de_ctx->sig_list != NULL) goto end; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_msg\"; content:\"one\";" "fast_pattern; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_stat_msg is registered in a Signature and also checks * the nocase */ int DetectHttpStatMsgTest02(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_msg\"; content:\"one\"; " "http_stat_msg; content:\"two\"; http_stat_msg; " "content:\"two\"; nocase; http_stat_msg; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; } SigMatch *prev = NULL; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { result = 1; } else { printf("expected DETECT_CONTENT for http_stat_msg, got %d: ", sm->type); goto end; } prev = sm; sm = sm->next; } if (! (((DetectContentData *)prev->ctx)->flags & DETECT_CONTENT_NOCASE)) { result = 0; } end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check the signature working to alert when http_stat_msg is matched . */ static int DetectHttpStatMsgSigTest01(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP status message\"; content:\"OK\"; " "http_stat_msg; sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " "Status message nocase\"; content:\"ok\"; nocase; " "http_stat_msg; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_stat_msg is not matched . */ static int DetectHttpStatMsgSigTest02(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP status message\"; content:\"no\"; " "http_stat_msg; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_stat_msg is used with * negated content . */ static int DetectHttpStatMsgSigTest03(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP status message\"; content:\"ok\"; " "nocase; http_stat_msg; sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " "Status message nocase\"; content:!\"Not\"; " "http_stat_msg; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (! PacketAlertCheck(p, 1)) { printf("sid 1 didn't matched but should have: "); goto end; } if (! PacketAlertCheck(p, 2)) { printf("sid 2 didn't matched but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief Register the UNITTESTS for the http_stat_msg keyword */ void DetectHttpStatMsgRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectHttpStatMsgTest01", DetectHttpStatMsgTest01, 1); UtRegisterTest("DetectHttpStatMsgTest02", DetectHttpStatMsgTest02, 1); UtRegisterTest("DetectHttpStatMsgSigTest01", DetectHttpStatMsgSigTest01, 1); UtRegisterTest("DetectHttpStatMsgSigTest02", DetectHttpStatMsgSigTest02, 1); UtRegisterTest("DetectHttpStatMsgSigTest03", DetectHttpStatMsgSigTest03, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/host-queue.h0000644000000000000000000000441112253546156013275 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __HOST_QUEUE_H__ #define __HOST_QUEUE_H__ #include "suricata-common.h" #include "host.h" /** Spinlocks or Mutex for the host queues. */ //#define HQLOCK_SPIN #define HQLOCK_MUTEX #ifdef HQLOCK_SPIN #ifdef HQLOCK_MUTEX #error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX #endif #endif /* Define a queue for storing hosts */ typedef struct HostQueue_ { Host *top; Host *bot; uint32_t len; #ifdef DBG_PERF uint32_t dbg_maxlen; #endif /* DBG_PERF */ #ifdef HQLOCK_MUTEX SCMutex m; #elif defined HQLOCK_SPIN SCSpinlock s; #else #error Enable HQLOCK_SPIN or HQLOCK_MUTEX #endif } HostQueue; #ifdef HQLOCK_SPIN #define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) #define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) #define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) #define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) #define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) #elif defined HQLOCK_MUTEX #define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) #define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) #define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) #define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) #define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) #else #error Enable HQLOCK_SPIN or HQLOCK_MUTEX #endif /* prototypes */ HostQueue *HostQueueNew(); HostQueue *HostQueueInit(HostQueue *); void HostQueueDestroy (HostQueue *); void HostEnqueue (HostQueue *, Host *); Host *HostDequeue (HostQueue *); uint32_t HostQueueLen(HostQueue *); #endif /* __HOST_QUEUE_H__ */ suricata-1.4.7/src/app-layer-smb2.c0000644000000000000000000005133112253546156013727 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Kirby Kuehl * * SMBv2 parser/decoder */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "util-spm.h" #include "util-unittest.h" #include "util-debug.h" #include "util-memcmp.h" #include "app-layer-smb2.h" enum { SMB2_FIELD_NONE = 0, SMB2_PARSE_NBSS_HEADER, SMB2_PARSE_SMB_HEADER, /* must be last */ SMB_FIELD_MAX, }; static uint32_t NBSSParseHeader(void *smb2_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMB2State *sstate = (SMB2State *) smb2_state; uint8_t *p = input; if (input_len && sstate->bytesprocessed < NBSS_HDR_LEN - 1) { switch (sstate->bytesprocessed) { case 0: /* Initialize */ if (input_len >= NBSS_HDR_LEN) { sstate->nbss.type = *p; sstate->nbss.length = (*(p + 1) & 0x01) << 16; sstate->nbss.length |= *(p + 2) << 8; sstate->nbss.length |= *(p + 3); sstate->bytesprocessed += NBSS_HDR_LEN; SCReturnUInt(4U); } else { sstate->nbss.type = *(p++); if (!(--input_len)) break; } case 1: sstate->nbss.length = (*(p++) & 0x01) << 16; if (!(--input_len)) break; case 2: sstate->nbss.length |= *(p++) << 8; if (!(--input_len)) break; case 3: sstate->nbss.length |= *(p++); --input_len; break; } sstate->bytesprocessed += (p - input); } SCReturnUInt((uint32_t)(p - input)); } static uint32_t SMB2ParseHeader(void *smb2_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMB2State *sstate = (SMB2State *) smb2_state; uint8_t *p = input; if (input_len) { switch (sstate->bytesprocessed) { case 4: // fallthrough /* above statement to prevent coverity FPs from the switch * fall through */ if (input_len >= SMB2_HDR_LEN) { if (SCMemcmp(p, "\xfe\x53\x4d\x42", 4) != 0) { //printf("SMB2 Header did not validate\n"); return 0; } sstate->smb2.StructureSize = *(p + 4); sstate->smb2.StructureSize |= *(p + 5) << 8; sstate->smb2.CreditCharge = *(p + 6); sstate->smb2.CreditCharge |= *(p + 7) << 8; sstate->smb2.Status = *(p + 8); sstate->smb2.Status |= *(p + 9) << 8; sstate->smb2.Status |= *(p + 10) << 16; sstate->smb2.Status |= *(p + 11) << 24; sstate->smb2.Command = *(p + 12); sstate->smb2.Command |= *(p + 13) << 8; sstate->smb2.CreditRequestResponse = *(p + 14); sstate->smb2.CreditRequestResponse |= *(p + 15) << 8; sstate->smb2.Flags = *(p + 16); sstate->smb2.Flags |= *(p + 17) << 8; sstate->smb2.Flags |= *(p + 18) << 16; sstate->smb2.Flags |= *(p + 19) << 24; sstate->smb2.NextCommand = *(p + 20); sstate->smb2.NextCommand |= *(p + 21) << 8; sstate->smb2.NextCommand |= *(p + 22) << 16; sstate->smb2.NextCommand |= *(p + 23) << 24; sstate->smb2.MessageId = *(p + 24); sstate->smb2.MessageId |= *(p + 25) << 8; sstate->smb2.MessageId |= *(p + 26) << 16; sstate->smb2.MessageId |= (uint64_t) *(p + 27) << 24; sstate->smb2.MessageId |= (uint64_t) *(p + 28) << 32; sstate->smb2.MessageId |= (uint64_t) *(p + 29) << 40; sstate->smb2.MessageId |= (uint64_t) *(p + 30) << 48; sstate->smb2.MessageId |= (uint64_t) *(p + 31) << 56; sstate->smb2.ProcessId = *(p + 32); sstate->smb2.ProcessId |= *(p + 33) << 8; sstate->smb2.ProcessId |= *(p + 34) << 16; sstate->smb2.ProcessId |= *(p + 35) << 24; sstate->smb2.TreeId = *(p + 36); sstate->smb2.TreeId |= *(p + 37) << 8; sstate->smb2.TreeId |= *(p + 38) << 16; sstate->smb2.TreeId |= *(p + 39) << 24; sstate->smb2.SessionId = *(p + 40); sstate->smb2.SessionId |= *(p + 41) << 8; sstate->smb2.SessionId |= *(p + 42) << 16; sstate->smb2.SessionId |= (uint64_t) *(p + 43) << 24; sstate->smb2.SessionId |= (uint64_t) *(p + 44) << 32; sstate->smb2.SessionId |= (uint64_t) *(p + 45) << 40; sstate->smb2.SessionId |= (uint64_t) *(p + 46) << 48; sstate->smb2.SessionId |= (uint64_t) *(p + 47) << 56; sstate->smb2.Signature[0] = *(p + 48); sstate->smb2.Signature[1] = *(p + 49); sstate->smb2.Signature[2] = *(p + 50); sstate->smb2.Signature[3] = *(p + 51); sstate->smb2.Signature[4] = *(p + 52); sstate->smb2.Signature[5] = *(p + 53); sstate->smb2.Signature[6] = *(p + 54); sstate->smb2.Signature[7] = *(p + 55); sstate->smb2.Signature[8] = *(p + 56); sstate->smb2.Signature[9] = *(p + 57); sstate->smb2.Signature[10] = *(p + 58); sstate->smb2.Signature[11] = *(p + 59); sstate->smb2.Signature[12] = *(p + 60); sstate->smb2.Signature[13] = *(p + 61); sstate->smb2.Signature[14] = *(p + 62); sstate->smb2.Signature[15] = *(p + 63); sstate->bytesprocessed += SMB2_HDR_LEN; SCReturnUInt(64U); break; } else { //sstate->smb2.protocol[0] = *(p++); if (*(p++) != 0xfe) return 0; if (!(--input_len)) break; /* We fall through to the next case if we still have input. * Same applies for other cases as well */ } case 5: //sstate->smb2.protocol[1] = *(p++); if (*(p++) != 'S') return 0; if (!(--input_len)) break; case 6: //sstate->smb2.protocol[2] = *(p++); if (*(p++) != 'M') return 0; if (!(--input_len)) break; case 7: //sstate->smb2.protocol[3] = *(p++); if (*(p++) != 'B') return 0; if (!(--input_len)) break; case 8: sstate->smb2.StructureSize = *(p++); if (!(--input_len)) break; case 9: sstate->smb2.StructureSize |= *(p++) << 8; if (!(--input_len)) break; case 10: sstate->smb2.CreditCharge = *(p++); if (!(--input_len)) break; case 11: sstate->smb2.CreditCharge |= *(p++) << 8; if (!(--input_len)) break; case 12: sstate->smb2.Status = *(p++); if (!(--input_len)) break; case 13: sstate->smb2.Status |= *(p++) << 8; if (!(--input_len)) break; case 14: sstate->smb2.Status |= *(p++) << 16; if (!(--input_len)) break; case 15: sstate->smb2.Status |= *(p++) << 24; if (!(--input_len)) break; case 16: sstate->smb2.Command = *(p++); if (!(--input_len)) break; case 17: sstate->smb2.Command |= *(p++) << 8; if (!(--input_len)) break; case 18: sstate->smb2.CreditRequestResponse = *(p++); if (!(--input_len)) break; case 19: sstate->smb2.CreditRequestResponse |= *(p++) << 8; if (!(--input_len)) break; case 20: sstate->smb2.Flags = *(p++); if (!(--input_len)) break; case 21: sstate->smb2.Flags |= *(p++) << 8; if (!(--input_len)) break; case 22: sstate->smb2.Flags |= *(p++) << 16; if (!(--input_len)) break; case 23: sstate->smb2.Flags |= *(p++) << 24; if (!(--input_len)) break; case 24: sstate->smb2.NextCommand = *(p++); if (!(--input_len)) break; case 25: sstate->smb2.NextCommand |= *(p++) << 8; if (!(--input_len)) break; case 26: sstate->smb2.NextCommand |= *(p++) << 16; if (!(--input_len)) break; case 27: sstate->smb2.NextCommand |= *(p++) << 24; if (!(--input_len)) break; case 28: sstate->smb2.MessageId = *(p++); if (!(--input_len)) break; case 29: sstate->smb2.MessageId = *(p++) << 8; if (!(--input_len)) break; case 30: sstate->smb2.MessageId = *(p++) << 16; if (!(--input_len)) break; case 31: sstate->smb2.MessageId = (uint64_t) *(p++) << 24; if (!(--input_len)) break; case 32: sstate->smb2.MessageId = (uint64_t) *(p++) << 32; if (!(--input_len)) break; case 33: sstate->smb2.MessageId = (uint64_t) *(p++) << 40; if (!(--input_len)) break; case 34: sstate->smb2.MessageId = (uint64_t) *(p++) << 48; if (!(--input_len)) break; case 35: sstate->smb2.MessageId = (uint64_t) *(p++) << 56; if (!(--input_len)) break; case 36: sstate->smb2.ProcessId = *(p++); if (!(--input_len)) break; case 37: sstate->smb2.ProcessId |= *(p++) << 8; if (!(--input_len)) break; case 38: sstate->smb2.ProcessId |= *(p++) << 16; if (!(--input_len)) break; case 39: sstate->smb2.ProcessId |= *(p++) << 24; if (!(--input_len)) break; case 40: sstate->smb2.TreeId = *(p++); if (!(--input_len)) break; case 41: sstate->smb2.TreeId |= *(p++) << 8; if (!(--input_len)) break; case 42: sstate->smb2.TreeId |= *(p++) << 16; if (!(--input_len)) break; case 43: sstate->smb2.TreeId |= *(p++) << 24; if (!(--input_len)) break; case 44: sstate->smb2.SessionId = *(p++); if (!(--input_len)) break; case 45: sstate->smb2.SessionId |= *(p++) << 8; if (!(--input_len)) break; case 46: sstate->smb2.SessionId |= *(p++) << 16; if (!(--input_len)) break; case 47: sstate->smb2.SessionId |= (uint64_t) *(p++) << 24; if (!(--input_len)) break; case 48: sstate->smb2.SessionId |= (uint64_t) *(p++) << 32; if (!(--input_len)) break; case 49: sstate->smb2.SessionId |= (uint64_t) *(p++) << 40; if (!(--input_len)) break; case 50: sstate->smb2.SessionId |= (uint64_t) *(p++) << 48; if (!(--input_len)) break; case 51: sstate->smb2.SessionId |= (uint64_t) *(p++) << 56; if (!(--input_len)) break; case 52: sstate->smb2.Signature[0] = *(p++); if (!(--input_len)) break; case 53: sstate->smb2.Signature[1] = *(p++); if (!(--input_len)) break; case 54: sstate->smb2.Signature[2] = *(p++); if (!(--input_len)) break; case 55: sstate->smb2.Signature[3] = *(p++); if (!(--input_len)) break; case 56: sstate->smb2.Signature[4] = *(p++); if (!(--input_len)) break; case 57: sstate->smb2.Signature[5] = *(p++); if (!(--input_len)) break; case 58: sstate->smb2.Signature[6] = *(p++); if (!(--input_len)) break; case 59: sstate->smb2.Signature[7] = *(p++); if (!(--input_len)) break; case 60: sstate->smb2.Signature[8] = *(p++); if (!(--input_len)) break; case 61: sstate->smb2.Signature[9] = *(p++); if (!(--input_len)) break; case 62: sstate->smb2.Signature[10] = *(p++); if (!(--input_len)) break; case 63: sstate->smb2.Signature[11] = *(p++); if (!(--input_len)) break; case 64: sstate->smb2.Signature[12] = *(p++); if (!(--input_len)) break; case 65: sstate->smb2.Signature[13] = *(p++); if (!(--input_len)) break; case 66: sstate->smb2.Signature[14] = *(p++); if (!(--input_len)) break; case 67: sstate->smb2.Signature[15] = *(p++); --input_len; break; } } sstate->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } static int SMB2Parse(Flow *f, void *smb2_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SCEnter(); SMB2State *sstate = (SMB2State *) smb2_state; uint32_t retval = 0; uint32_t parsed = 0; if (pstate == NULL) return -1; while (sstate->bytesprocessed < NBSS_HDR_LEN && input_len) { retval = NBSSParseHeader(smb2_state, pstate, input, input_len, output); if (retval <= input_len) { parsed += retval; input_len -= retval; } else { return -1; } SCLogDebug("NBSS Header (%u/%u) Type 0x%02x Length 0x%04x parsed %u input_len %u", sstate->bytesprocessed, NBSS_HDR_LEN, sstate->nbss.type, sstate->nbss.length, parsed, input_len); } switch(sstate->nbss.type) { case NBSS_SESSION_MESSAGE: while (input_len && (sstate->bytesprocessed >= NBSS_HDR_LEN && sstate->bytesprocessed < NBSS_HDR_LEN + SMB2_HDR_LEN)) { retval = SMB2ParseHeader(smb2_state, pstate, input + parsed, input_len, output); if (retval <= input_len) { parsed += retval; input_len -= retval; } else { return -1; } SCLogDebug("SMB2 Header (%u/%u) Command 0x%04x parsed %u input_len %u", sstate->bytesprocessed, NBSS_HDR_LEN + SMB2_HDR_LEN, sstate->smb2.Command, parsed, input_len); } break; default: break; } pstate->parse_field = 0; pstate->flags |= APP_LAYER_PARSER_DONE; SCReturnInt(1); } static void *SMB2StateAlloc(void) { void *s = SCMalloc(sizeof(SMB2State)); if (unlikely(s == NULL)) return NULL; memset(s, 0, sizeof(SMB2State)); return s; } static void SMB2StateFree(void *s) { if (s) { SCFree(s); s = NULL; } } void RegisterSMB2Parsers(void) { AppLayerRegisterProto("smb", ALPROTO_SMB2, STREAM_TOSERVER, SMB2Parse); AppLayerRegisterProto("smb", ALPROTO_SMB2, STREAM_TOCLIENT, SMB2Parse); AppLayerRegisterStateFuncs(ALPROTO_SMB2, SMB2StateAlloc, SMB2StateFree); } /* UNITTESTS */ #ifdef UNITTESTS int SMB2ParserTest01(void) { int result = 1; Flow f; uint8_t smb2buf[] = "\x00\x00\x00\x66" // NBSS "\xfe\x53\x4d\x42\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00" // SMB2 "\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x24\x00\x01\x00x00\x00\x00\x00\x00\x00\x0\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x02"; uint32_t smb2len = sizeof(smb2buf) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SMB2, STREAM_TOSERVER|STREAM_EOF, smb2buf, smb2len); if (r != 0) { printf("smb2 header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SMB2State *smb2_state = f.alstate; if (smb2_state == NULL) { printf("no smb2 state: "); result = 0; goto end; } if (smb2_state->nbss.type != NBSS_SESSION_MESSAGE) { printf("expected nbss type 0x%02x , got 0x%02x : ", NBSS_SESSION_MESSAGE, smb2_state->nbss.type); result = 0; goto end; } if (smb2_state->nbss.length != 102) { printf("expected nbss length 0x%02x , got 0x%02x : ", 102, smb2_state->nbss.length); result = 0; goto end; } if (smb2_state->smb2.Command != SMB2_NEGOTIATE) { printf("expected SMB2 command 0x%04x , got 0x%04x : ", SMB2_NEGOTIATE, smb2_state->smb2.Command); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } void SMB2ParserRegisterTests(void) { printf("SMB2ParserRegisterTests\n"); UtRegisterTest("SMB2ParserTest01", SMB2ParserTest01, 1); } #endif suricata-1.4.7/src/detect-tos.h0000644000000000000000000000173512253546156013257 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_TOS_H__ #define __DETECT_TOS_H__ typedef struct DetectTosData_ { uint8_t negated; uint8_t tos; } DetectTosData; void DetectTosRegister(void); #endif /* __DETECT_TOS_H__ */ suricata-1.4.7/src/detect-fileext.c0000644000000000000000000001747012253546156014110 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon * */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm-bm.h" #include "util-print.h" #include "util-memcmp.h" #include "app-layer.h" #include "stream-tcp.h" #include "detect-fileext.h" static int DetectFileextMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFileextSetup (DetectEngineCtx *, Signature *, char *); static void DetectFileextRegisterTests(void); static void DetectFileextFree(void *); /** * \brief Registration function for keyword: fileext */ void DetectFileextRegister(void) { sigmatch_table[DETECT_FILEEXT].name = "fileext"; sigmatch_table[DETECT_FILEEXT].desc = "match on the extension of a file name"; sigmatch_table[DETECT_FILEEXT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#fileext"; sigmatch_table[DETECT_FILEEXT].FileMatch = DetectFileextMatch; sigmatch_table[DETECT_FILEEXT].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEEXT].Setup = DetectFileextSetup; sigmatch_table[DETECT_FILEEXT].Free = DetectFileextFree; sigmatch_table[DETECT_FILEEXT].RegisterTests = DetectFileextRegisterTests; SCLogDebug("registering fileext rule option"); return; } /** * \brief match the specified file extension * * \param t thread local vars * \param det_ctx pattern matcher thread local data * \param f *LOCKED* flow * \param flags direction flags * \param file file being inspected * \param s signature being inspected * \param m sigmatch that we will cast into DetectFileextData * * \retval 0 no match * \retval 1 match */ static int DetectFileextMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; DetectFileextData *fileext = (DetectFileextData *)m->ctx; if (file->name == NULL) SCReturnInt(0); if (file->txid < det_ctx->tx_id) SCReturnInt(0); if (file->txid > det_ctx->tx_id) SCReturnInt(0); if (file->name_len <= fileext->len) SCReturnInt(0); int offset = file->name_len - fileext->len; if (file->name[offset - 1] == '.' && SCMemcmp(file->name + offset, fileext->ext, fileext->len) == 0) { if (!(fileext->flags & DETECT_CONTENT_NEGATED)) { ret = 1; SCLogDebug("File ext found"); } } if (ret == 0 && (fileext->flags & DETECT_CONTENT_NEGATED)) { SCLogDebug("negated match"); ret = 1; } SCReturnInt(ret); } /** * \brief This function is used to parse fileet * * \param str Pointer to the fileext value string * * \retval pointer to DetectFileextData on success * \retval NULL on failure */ static DetectFileextData *DetectFileextParse (char *str) { DetectFileextData *fileext = NULL; /* We have a correct filename option */ fileext = SCMalloc(sizeof(DetectFileextData)); if (unlikely(fileext == NULL)) goto error; memset(fileext, 0x00, sizeof(DetectFileextData)); if (DetectParseContentString (str, &fileext->ext, &fileext->len, &fileext->flags) == -1) { goto error; } SCLogDebug("flags %02X", fileext->flags); if (fileext->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("negated fileext"); } #ifdef DEBUG if (SCLogDebugEnabled()) { char *ext = SCMalloc(fileext->len + 1); if (ext != NULL) { memcpy(ext, fileext->ext, fileext->len); ext[fileext->len] = '\0'; SCLogDebug("will look for fileext %s", ext); } } #endif return fileext; error: if (fileext != NULL) DetectFileextFree(fileext); return NULL; } /** * \brief this function is used to add the parsed "id" option * into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "id" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFileextSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectFileextData *fileext= NULL; SigMatch *sm = NULL; fileext = DetectFileextParse(str); if (fileext == 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_FILEEXT; sm->ctx = (void *)fileext; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } AppLayerHtpNeedFileInspection(); s->alproto = ALPROTO_HTTP; s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; error: if (fileext != NULL) DetectFileextFree(fileext); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectFileextData * * \param fileext pointer to DetectFileextData */ static void DetectFileextFree(void *ptr) { if (ptr != NULL) { DetectFileextData *fileext = (DetectFileextData *)ptr; if (fileext->ext != NULL) SCFree(fileext->ext); SCFree(fileext); } } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectFileextTestParse01 */ int DetectFileextTestParse01 (void) { DetectFileextData *dfd = DetectFileextParse("doc"); if (dfd != NULL) { DetectFileextFree(dfd); return 1; } return 0; } /** * \test DetectFileextTestParse02 */ int DetectFileextTestParse02 (void) { int result = 0; DetectFileextData *dfd = DetectFileextParse("\"tar.gz\""); if (dfd != NULL) { if (dfd->len == 6 && memcmp(dfd->ext, "tar.gz", 6) == 0) { result = 1; } DetectFileextFree(dfd); return result; } return 0; } /** * \test DetectFileextTestParse03 */ int DetectFileextTestParse03 (void) { int result = 0; DetectFileextData *dfd = DetectFileextParse("\"pdf\""); if (dfd != NULL) { if (dfd->len == 3 && memcmp(dfd->ext, "pdf", 3) == 0) { result = 1; } DetectFileextFree(dfd); return result; } return 0; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectFileext */ void DetectFileextRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectFileextTestParse01", DetectFileextTestParse01, 1); UtRegisterTest("DetectFileextTestParse02", DetectFileextTestParse02, 1); UtRegisterTest("DetectFileextTestParse03", DetectFileextTestParse03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-mpm-ac-bs.h0000644000000000000000000000536212253546156013733 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * */ #define SC_AC_BS_STATE_TYPE_U16 uint16_t #define SC_AC_BS_STATE_TYPE_U32 uint32_t typedef struct SCACBSPattern_ { /* length of the pattern */ uint16_t len; /* flags decribing the pattern */ uint8_t flags; /* holds the original pattern that was added */ uint8_t *original_pat; /* case sensitive */ uint8_t *cs; /* case INsensitive */ uint8_t *ci; /* pattern id */ uint32_t id; struct SCACBSPattern_ *next; } SCACBSPattern; typedef struct SCACBSPatternList_ { uint8_t *cs; uint16_t patlen; uint16_t case_state; } SCACBSPatternList; typedef struct SCACBSOutputTable_ { /* list of pattern sids */ uint32_t *pids; /* no of entries we have in pids */ uint32_t no_of_entries; } SCACBSOutputTable; typedef struct SCACBSCtx_ { /* hash used during ctx initialization */ SCACBSPattern **init_hash; /* pattern arrays. We need this only during the goto table creation phase */ SCACBSPattern **parray; /* no of states used by ac */ uint32_t state_count; /* the all important memory hungry state_table */ SC_AC_BS_STATE_TYPE_U16 (*state_table_u16)[256]; /* the all important memory hungry state_table */ SC_AC_BS_STATE_TYPE_U32 (*state_table_u32)[256]; /* the modified goto_table */ uint8_t *state_table_mod; uint8_t **state_table_mod_pointers; /* goto_table, failure table and output table. Needed to create state_table. * Will be freed, once we have created the state_table */ int32_t (*goto_table)[256]; int32_t *failure_table; SCACBSOutputTable *output_table; SCACBSPatternList *pid_pat_list; /* the size of each state */ uint16_t single_state_size; uint16_t max_pat_id; } SCACBSCtx; typedef struct SCACBSThreadCtx_ { /* the total calls we make to the search function */ uint32_t total_calls; /* the total patterns that we ended up matching against */ uint64_t total_matches; } SCACBSThreadCtx; void MpmACBSRegister(void); suricata-1.4.7/src/util-memcmp.h0000644000000000000000000002464512253546156013442 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Memcmp implementations for SSE3, SSE4.1 and SSE4.2. * * Both SCMemcmp and SCMemcmpLowercase return 0 on a exact match, * 1 on a failed match. */ #ifndef __UTIL_MEMCMP_H__ #define __UTIL_MEMCMP_H__ #include "util-optimize.h" /** \brief compare two patterns, converting the 2nd to lowercase * \warning *ONLY* the 2nd pattern is converted to lowercase */ static inline int SCMemcmpLowercase(void *, void *, size_t); void MemcmpRegisterTests(void); static inline int MemcmpLowercase(void *s1, void *s2, size_t n) { size_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ for (i = n - 1; i; i--) { if (((uint8_t *)s1)[i] != u8_tolower(*(((uint8_t *)s2)+i))) return 1; } return 0; } #if defined(__SSE4_2__) #include static inline int SCMemcmp(void *s1, void *s2, size_t n) { __m128i b1, b2; int r; /* counter for how far we already matched in the buffer */ size_t m = 0; do { /* load the buffers into the 128bit vars */ b1 = _mm_loadu_si128((const __m128i *) s1); b2 = _mm_loadu_si128((const __m128i *) s2); /* do the actual compare */ m += (r = _mm_cmpestri(b1, n - m, b2, 16, _SIDD_CMP_EQUAL_EACH | _SIDD_MASKED_NEGATIVE_POLARITY)); s1 += 16; s2 += 16; } while (r == 16); return ((m == n) ? 0 : 1); } /* Range of values of uppercase characters */ static char scmemcmp_uppercase[2] __attribute__((aligned(16))) = { 'A', 'Z' }; /** \brief compare two buffers in a case insensitive way * \param s1 buffer already in lowercase * \param s2 buffer with mixed upper and lowercase */ static inline int SCMemcmpLowercase(void *s1, void *s2, size_t n) { __m128i b1, b2, mask; int r; /* counter for how far we already matched in the buffer */ size_t m = 0; __m128i ucase = _mm_load_si128((const __m128i *) scmemcmp_uppercase); __m128i nulls = _mm_setzero_si128(); __m128i uplow = _mm_set1_epi8(0x20); do { b1 = _mm_loadu_si128((const __m128i *) s1); b2 = _mm_loadu_si128((const __m128i *) s2); size_t len = n - m; /* The first step is creating a mask that is FF for all uppercase * characters, 00 for all others */ mask = _mm_cmpestrm(ucase, 2, b2, len, _SIDD_CMP_RANGES | _SIDD_UNIT_MASK); /* Next we use that mask to create a new: this one has 0x20 for * the uppercase chars, 00 for all other. */ mask = _mm_blendv_epi8(nulls, uplow, mask); /* finally, merge the mask and the buffer converting the * uppercase to lowercase */ b2 = _mm_add_epi8(b2, mask); /* search using our converted buffer */ m += (r = _mm_cmpestri(b1, len, b2, 16, _SIDD_CMP_EQUAL_EACH | _SIDD_MASKED_NEGATIVE_POLARITY)); s1 += 16; s2 += 16; } while (r == 16); return ((m == n) ? 0 : 1); } #elif defined(__SSE4_1__) #include #define SCMEMCMP_BYTES 16 static inline int SCMemcmp(void *s1, void *s2, size_t len) { size_t offset = 0; __m128i b1, b2, c; do { /* apparently we can't just read 16 bytes even though * it almost always works fine :) */ if (likely(len - offset < 16)) { return memcmp(s1, s2, len - offset) ? 1 : 0; } /* do unaligned loads using _mm_loadu_si128. On my Core2 E6600 using * _mm_lddqu_si128 was about 2% slower even though it's supposed to * be faster. */ b1 = _mm_loadu_si128((const __m128i *) s1); b2 = _mm_loadu_si128((const __m128i *) s2); c = _mm_cmpeq_epi8(b1, b2); int diff = len - offset; if (diff < 16) { int rmask = ~(0xFFFFFFFF << diff); if ((_mm_movemask_epi8(c) & rmask) != rmask) { return 1; } } else { if (_mm_movemask_epi8(c) != 0x0000FFFF) { return 1; } } offset += SCMEMCMP_BYTES; s1 += SCMEMCMP_BYTES; s2 += SCMEMCMP_BYTES; } while (len > offset); return 0; } #define UPPER_LOW 0x40 /* "A" - 1 */ #define UPPER_HIGH 0x5B /* "Z" + 1 */ static inline int SCMemcmpLowercase(void *s1, void *s2, size_t len) { size_t offset = 0; __m128i b1, b2, mask1, mask2, upper1, upper2, nulls, uplow; /* setup registers for upper to lower conversion */ upper1 = _mm_set1_epi8(UPPER_LOW); upper2 = _mm_set1_epi8(UPPER_HIGH); nulls = _mm_setzero_si128(); uplow = _mm_set1_epi8(0x20); do { /* apparently we can't just read 16 bytes even though * it almost always works fine :) */ if (likely(len - offset < 16)) { return MemcmpLowercase(s1, s2, len - offset); } /* unaligned loading of the bytes to compare */ b1 = _mm_loadu_si128((const __m128i *) s1); b2 = _mm_loadu_si128((const __m128i *) s2); /* mark all chars bigger than upper1 */ mask1 = _mm_cmpgt_epi8(b2, upper1); /* mark all chars lower than upper2 */ mask2 = _mm_cmplt_epi8(b2, upper2); /* merge the two, leaving only those that are true in both */ mask1 = _mm_cmpeq_epi8(mask1, mask2); /* Next we use that mask to create a new: this one has 0x20 for * the uppercase chars, 00 for all other. */ mask1 = _mm_blendv_epi8(nulls, uplow, mask1); /* add to b2, converting uppercase to lowercase */ b2 = _mm_add_epi8(b2, mask1); /* now all is lowercase, let's do the actual compare (reuse mask1 reg) */ mask1 = _mm_cmpeq_epi8(b1, b2); int diff = len - offset; if (diff < 16) { int rmask = ~(0xFFFFFFFF << diff); if ((_mm_movemask_epi8(mask1) & rmask) != rmask) { return 1; } } else { if (_mm_movemask_epi8(mask1) != 0x0000FFFF) { return 1; } } offset += SCMEMCMP_BYTES; s1 += SCMEMCMP_BYTES; s2 += SCMEMCMP_BYTES; } while (len > offset); return 0; } #elif defined(__SSE3__) #include /* for SSE3 */ #define SCMEMCMP_BYTES 16 static inline int SCMemcmp(void *s1, void *s2, size_t len) { size_t offset = 0; __m128i b1, b2, c; do { /* apparently we can't just read 16 bytes even though * it almost always works fine :) */ if (likely(len - offset < 16)) { return memcmp(s1, s2, len - offset) ? 1 : 0; } /* do unaligned loads using _mm_loadu_si128. On my Core2 E6600 using * _mm_lddqu_si128 was about 2% slower even though it's supposed to * be faster. */ b1 = _mm_loadu_si128((const __m128i *) s1); b2 = _mm_loadu_si128((const __m128i *) s2); c = _mm_cmpeq_epi8(b1, b2); int diff = len - offset; if (diff < 16) { int rmask = ~(0xFFFFFFFF << diff); if ((_mm_movemask_epi8(c) & rmask) != rmask) { return 1; } } else { if (_mm_movemask_epi8(c) != 0x0000FFFF) { return 1; } } offset += SCMEMCMP_BYTES; s1 += SCMEMCMP_BYTES; s2 += SCMEMCMP_BYTES; } while (len > offset); return 0; } #define UPPER_LOW 0x40 /* "A" - 1 */ #define UPPER_HIGH 0x5B /* "Z" + 1 */ #define UPPER_DELTA 0xDF /* 0xFF - 0x20 */ static inline int SCMemcmpLowercase(void *s1, void *s2, size_t len) { size_t offset = 0; __m128i b1, b2, mask1, mask2, upper1, upper2, delta; /* setup registers for upper to lower conversion */ upper1 = _mm_set1_epi8(UPPER_LOW); upper2 = _mm_set1_epi8(UPPER_HIGH); delta = _mm_set1_epi8(UPPER_DELTA); do { /* apparently we can't just read 16 bytes even though * it almost always works fine :) */ if (likely(len - offset < 16)) { return MemcmpLowercase(s1, s2, len - offset); } /* unaligned loading of the bytes to compare */ b1 = _mm_loadu_si128((const __m128i *) s1); b2 = _mm_loadu_si128((const __m128i *) s2); /* mark all chars bigger than upper1 */ mask1 = _mm_cmpgt_epi8(b2, upper1); /* mark all chars lower than upper2 */ mask2 = _mm_cmplt_epi8(b2, upper2); /* merge the two, leaving only those that are true in both */ mask1 = _mm_cmpeq_epi8(mask1, mask2); /* sub delta leaves 0x20 only for uppercase positions, the rest is 0x00 due to the saturation (reuse mask1 reg)*/ mask1 = _mm_subs_epu8(mask1, delta); /* add to b2, converting uppercase to lowercase */ b2 = _mm_add_epi8(b2, mask1); /* now all is lowercase, let's do the actual compare (reuse mask1 reg) */ mask1 = _mm_cmpeq_epi8(b1, b2); int diff = len - offset; if (diff < 16) { int rmask = ~(0xFFFFFFFF << diff); if ((_mm_movemask_epi8(mask1) & rmask) != rmask) { return 1; } } else { if (_mm_movemask_epi8(mask1) != 0x0000FFFF) { return 1; } } offset += SCMEMCMP_BYTES; s1 += SCMEMCMP_BYTES; s2 += SCMEMCMP_BYTES; } while (len > offset); return 0; } #else /* No SIMD support, fall back to plain memcmp and a home grown lowercase one */ /* wrapper around memcmp to match the retvals of the SIMD implementations */ #define SCMemcmp(a,b,c) ({ \ memcmp((a), (b), (c)) ? 1 : 0; \ }) static inline int SCMemcmpLowercase(void *s1, void *s2, size_t len) { return MemcmpLowercase(s1, s2, len); } #endif /* SIMD */ #endif /* __UTIL_MEMCMP_H__ */ suricata-1.4.7/src/runmode-ipfw.c0000644000000000000000000000601412253546156013606 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * \author Eric Leblond * * Handling of ipfw runmodes. */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-ipfw.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "util-runmodes.h" #include "source-ipfw.h" static const char *default_mode; const char *RunModeIpsIPFWGetDefaultMode(void) { return default_mode; } void RunModeIpsIPFWRegister(void) { default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_IPFW, "auto", "Multi threaded IPFW IPS mode", RunModeIpsIPFWAuto); RunModeRegisterNewRunMode(RUNMODE_IPFW, "autofp", "Multi threaded IPFW IPS mode with respect to flow", RunModeIpsIPFWAutoFp); RunModeRegisterNewRunMode(RUNMODE_IPFW, "workers", "Multi queue IPFW IPS mode with one thread per queue", RunModeIpsIPFWWorker); return; } int RunModeIpsIPFWAuto(DetectEngineCtx *de_ctx) { SCEnter(); int ret = 0; #ifdef IPFW RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetIPSAuto(de_ctx, IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); #endif /* IPFW */ return ret; } int RunModeIpsIPFWAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); int ret = 0; #ifdef IPFW RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetIPSAutoFp(de_ctx, IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); #endif /* IPFW */ return ret; } int RunModeIpsIPFWWorker(DetectEngineCtx *de_ctx) { SCEnter(); int ret = 0; #ifdef IPFW RunModeInitialize(); TimeModeSetLive(); ret = RunModeSetIPSWorker(de_ctx, IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); #endif /* IPFW */ return ret; } suricata-1.4.7/src/util-var-name.c0000644000000000000000000001236412253546156013660 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Generic variable name utility functions */ #include "suricata-common.h" #include "detect.h" #include "util-hashlist.h" /** \brief Name2idx mapping structure for flowbits, flowvars and pktvars. */ typedef struct VariableName_ { char *name; uint8_t type; /* flowbit, pktvar, etc */ uint16_t idx; uint8_t flags; } VariableName; static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen) { VariableName *fn = (VariableName *)buf; uint32_t hash = strlen(fn->name) + fn->type; uint16_t u; for (u = 0; u < buflen; u++) { hash += fn->name[u]; } return hash; } static char VariableNameCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2) { VariableName *fn1 = (VariableName *)buf1; VariableName *fn2 = (VariableName *)buf2; if (fn1->type != fn2->type) return 0; if (strcmp(fn1->name,fn2->name) == 0) return 1; return 0; } static uint32_t VariableIdxHash(HashListTable *ht, void *buf, uint16_t buflen) { VariableName *fn = (VariableName *)buf; uint32_t hash = fn->idx + fn->type; return hash; } static char VariableIdxCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2) { VariableName *fn1 = (VariableName *)buf1; VariableName *fn2 = (VariableName *)buf2; if (fn1->type != fn2->type) return 0; if (fn1->idx == fn2->idx) return 1; return 0; } static void VariableNameFree(void *data) { VariableName *fn = (VariableName *)data; if (fn == NULL) return; if (fn->name != NULL) { SCFree(fn->name); fn->name = NULL; } SCFree(fn); } /** \brief Initialize the Name idx hash. * \param de_ctx Ptr to the detection engine ctx. * \retval -1 in case of error * \retval 0 in case of success */ int VariableNameInitHash(DetectEngineCtx *de_ctx) { de_ctx->variable_names = HashListTableInit(4096, VariableNameHash, VariableNameCompare, VariableNameFree); if (de_ctx->variable_names == NULL) return -1; de_ctx->variable_idxs = HashListTableInit(4096, VariableIdxHash, VariableIdxCompare, NULL); if (de_ctx->variable_idxs == NULL) return -1; de_ctx->variable_names_idx = 0; return 0; } void VariableNameFreeHash(DetectEngineCtx *de_ctx) { if (de_ctx->variable_names != NULL) { HashListTableFree(de_ctx->variable_names); HashListTableFree(de_ctx->variable_idxs); de_ctx->variable_names = NULL; de_ctx->variable_idxs = NULL; } return; } /** \brief Get a name idx for a name. If the name is already used reuse the idx. * \param name nul terminated string with the name * \param type variable type (DETECT_FLOWBITS, DETECT_PKTVAR, etc) * \retval 0 in case of error * \retval _ the idx. */ uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, uint8_t type) { uint16_t idx = 0; VariableName *fn = SCMalloc(sizeof(VariableName)); if (unlikely(fn == NULL)) goto error; memset(fn, 0, sizeof(VariableName)); fn->type = type; fn->name = SCStrdup(name); if (fn->name == NULL) goto error; VariableName *lookup_fn = (VariableName *)HashListTableLookup(de_ctx->variable_names, (void *)fn, 0); if (lookup_fn == NULL) { de_ctx->variable_names_idx++; idx = fn->idx = de_ctx->variable_names_idx; HashListTableAdd(de_ctx->variable_names, (void *)fn, 0); HashListTableAdd(de_ctx->variable_idxs, (void *)fn, 0); } else { idx = lookup_fn->idx; VariableNameFree(fn); } return idx; error: VariableNameFree(fn); return 0; } /** \brief Get a name from the idx. * \param idx index of the variable whose name is to be fetched * \param type variable type (DETECT_FLOWBITS, DETECT_PKTVAR, etc) * \retval NULL in case of error * \retval name of the variable if successful. */ char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, uint8_t type) { VariableName *fn = SCMalloc(sizeof(VariableName)); if (unlikely(fn == NULL)) goto error; char *name = NULL; memset(fn, 0, sizeof(VariableName)); fn->type = type; fn->idx = idx; VariableName *lookup_fn = (VariableName *)HashListTableLookup(de_ctx->variable_idxs, (void *)fn, 0); if (lookup_fn != NULL) { name = SCStrdup(lookup_fn->name); if (unlikely(name == NULL)) goto error; VariableNameFree(fn); } else { goto error; } return name; error: VariableNameFree(fn); return NULL; } suricata-1.4.7/src/runmode-napatech.c0000644000000000000000000002021312253546156014421 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author nPulse Technologies, LLC. * \author Matt Keeler */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "log-httplog.h" #include "output.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "util-runmodes.h" #include "util-device.h" #include "runmode-napatech.h" // need NapatechStreamDevConf structure #include "source-napatech.h" #define NT_RUNMODE_AUTO 1 #define NT_RUNMODE_AUTOFP 2 #define NT_RUNMODE_WORKERS 4 static const char *default_mode = NULL; #ifdef HAVE_NAPATECH static int num_configured_streams = 0; #endif const char *RunModeNapatechGetDefaultMode(void) { return default_mode; } void RunModeNapatechRegister(void) { #ifdef HAVE_NAPATECH default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_NAPATECH, "auto", "Multi threaded Napatech mode", RunModeNapatechAuto); RunModeRegisterNewRunMode(RUNMODE_NAPATECH, "autofp", "Multi threaded Napatech mode. Packets from " "each flow are assigned to a single detect " "thread instead of any detect thread", RunModeNapatechAutoFp); RunModeRegisterNewRunMode(RUNMODE_NAPATECH, "workers", "Workers Napatech mode, each thread does all" " tasks from acquisition to logging", RunModeNapatechWorkers); return; #endif } #ifdef HAVE_NAPATECH int NapatechRegisterDeviceStreams() { NtInfoStream_t info_stream; NtInfo_t info; char error_buf[100]; int status; int i; char live_dev_buf[9]; int use_all_streams; ConfNode *ntstreams; ConfNode *stream_id; if (ConfGetBool("napatech.use-all-streams", &use_all_streams) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving napatech.use-all-streams from Conf"); exit(EXIT_FAILURE); } if (use_all_streams) { SCLogInfo("Using All Napatech Streams"); // When using the default streams we need to query the service for a list of all configured if ((status = NT_InfoOpen(&info_stream, "SuricataStreamInfo")) != NT_SUCCESS) { NT_ExplainError(status, error_buf, sizeof(error_buf) -1); SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, "NT_InfoOpen failed: %s", error_buf); return -1; } info.cmd = NT_INFO_CMD_READ_STREAM; if ((status = NT_InfoRead(info_stream, &info)) != NT_SUCCESS) { NT_ExplainError(status, error_buf, sizeof(error_buf) -1); SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, "NT_InfoRead failed: %s", error_buf); return -1; } num_configured_streams = info.u.stream.data.count; for (i = 0; i < num_configured_streams; i++) { // The Stream IDs do not have to be sequential snprintf(live_dev_buf, sizeof(live_dev_buf), "nt%d", info.u.stream.data.streamIDList[i]); LiveRegisterDevice(live_dev_buf); } if ((status = NT_InfoClose(info_stream)) != NT_SUCCESS) { NT_ExplainError(status, error_buf, sizeof(error_buf) -1); SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, "NT_InfoClose failed: %s", error_buf); return -1; } } else { SCLogInfo("Using Selected Napatech Streams"); // When not using the default streams we need to parse the array of streams from the conf if ((ntstreams = ConfGetNode("napatech.streams")) == NULL) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving napatech.streams from Conf"); exit(EXIT_FAILURE); } // Loop through all stream numbers in the array and register the devices TAILQ_FOREACH(stream_id, &ntstreams->head, next) { if (stream_id == NULL) { SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, "Couldn't Parse Stream Configuration"); exit(EXIT_FAILURE); } num_configured_streams++; snprintf(live_dev_buf, sizeof(live_dev_buf), "nt%d", atoi(stream_id->val)); LiveRegisterDevice(live_dev_buf); } } return 0; } void *NapatechConfigParser(const char *device) { // Expect device to be of the form nt%d where %d is the stream id to use int dev_len = strlen(device); struct NapatechStreamDevConf *conf = SCMalloc(sizeof(struct NapatechStreamDevConf)); if (unlikely(conf == NULL)) return NULL; if (dev_len < 3 || dev_len > 5) { SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG, "Could not parse config for device: %s - invalid length", device); return NULL; } // device+5 is a pointer to the beginning of the stream id after the constant nt portion conf->stream_id = atoi(device+2); // Set the host buffer allowance for this stream // Right now we just look at the global default - there is no per-stream hba configuration if (ConfGetInt("napatech.hba", &conf->hba) == 0) conf->hba = -1; return (void *) conf; } int NapatechGetThreadsCount(void *conf __attribute__((unused))) { // No matter which live device it is there is no reason to ever use more than 1 thread // 2 or more thread would cause packet duplication return 1; } int NapatechInit(DetectEngineCtx *de_ctx, int runmode) { int ret; char errbuf[100]; RunModeInitialize(); TimeModeSetLive(); /* Initialize the API and check version compatibility */ if ((ret = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) { NT_ExplainError(ret, errbuf, sizeof(errbuf)); SCLogError(SC_ERR_NAPATECH_INIT_FAILED ,"NT_Init failed. Code 0x%X = %s", ret, errbuf); exit(EXIT_FAILURE); } ret = NapatechRegisterDeviceStreams(); if (ret < 0 || num_configured_streams <= 0) { SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, "Unable to setup up Napatech Streams"); exit(EXIT_FAILURE); } switch(runmode) { case NT_RUNMODE_AUTO: ret = RunModeSetLiveCaptureAuto(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", "RxNT", NULL); break; case NT_RUNMODE_AUTOFP: ret = RunModeSetLiveCaptureAutoFp(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", "RxNT", NULL); break; case NT_RUNMODE_WORKERS: ret = RunModeSetLiveCaptureWorkers(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", "RxNT", NULL); break; default: ret = -1; } if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); exit(EXIT_FAILURE); } return 0; } int RunModeNapatechAuto(DetectEngineCtx *de_ctx) { return NapatechInit(de_ctx, NT_RUNMODE_AUTO); } int RunModeNapatechAutoFp(DetectEngineCtx *de_ctx) { return NapatechInit(de_ctx, NT_RUNMODE_AUTOFP); } int RunModeNapatechWorkers(DetectEngineCtx *de_ctx) { return NapatechInit(de_ctx, NT_RUNMODE_WORKERS); } #endif suricata-1.4.7/src/util-debug-filters.c0000644000000000000000000006726512253546156014720 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Debug filter utility functions */ #include "suricata-common.h" /* both of these are defined in util-debug.c */ extern int sc_log_module_initialized; extern int sc_log_module_cleaned; /* used to indicate if any FG filters are registered */ int sc_log_fg_filters_present = 0; /* used to indicate if any FD filters are registered */ int sc_log_fd_filters_present = 0; /** * \brief Holds the fine-grained filters */ SCLogFGFilterFile *sc_log_fg_filters[SC_LOG_FILTER_MAX] = { NULL, NULL }; /** * \brief Mutex for accessing the fine-grained fiters sc_log_fg_filters */ static SCMutex sc_log_fg_filters_m[SC_LOG_FILTER_MAX] = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }; /** * \brief Holds the function-dependent filters */ static SCLogFDFilter *sc_log_fd_filters = NULL; /** * \brief Mutex for accessing the function-dependent filters sc_log_fd_filters */ static SCMutex sc_log_fd_filters_m = PTHREAD_MUTEX_INITIALIZER; /** * \brief Holds the thread_list required by function-dependent filters */ static SCLogFDFilterThreadList *sc_log_fd_filters_tl = NULL; /** * \brief Mutex for accessing the FD thread_list sc_log_fd_filters_tl */ static SCMutex sc_log_fd_filters_tl_m = PTHREAD_MUTEX_INITIALIZER; /** * \brief Helper function used internally to add a FG filter * * \param file File_name of the filter * \param function Function_name of the filter * \param line Line number of the filter * \param listtype The filter listtype. Can be either a blacklist or whitelist * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) * * \retval 0 on successfully adding the filter; * \retval -1 on failure */ int SCLogAddFGFilter(const char *file, const char *function, int line, int listtype) { SCLogFGFilterFile *fgf_file = NULL; SCLogFGFilterFile *prev_fgf_file = NULL; SCLogFGFilterFunc *fgf_func = NULL; SCLogFGFilterFunc *prev_fgf_func = NULL; SCLogFGFilterLine *fgf_line = NULL; SCLogFGFilterLine *prev_fgf_line = NULL; int found = 0; if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return -1 ; } if (file == NULL && function == NULL && line < 0) { printf("Error: Invalid arguments supplied to SCLogAddFGFilter\n"); return -1; } SCMutex *m = &sc_log_fg_filters_m[listtype]; SCMutexLock(m); fgf_file = sc_log_fg_filters[listtype]; prev_fgf_file = fgf_file; while (fgf_file != NULL) { prev_fgf_file = fgf_file; if (file == NULL && fgf_file->file == NULL) found = 1; else if (file != NULL && fgf_file->file != NULL) found = (strcmp(file, fgf_file->file) == 0); else found = 0; if (found == 1) break; fgf_file = fgf_file->next; } if (found == 0) { SCLogAddToFGFFileList(prev_fgf_file, file, function, line, listtype); goto done; } found = 0; fgf_func = fgf_file->func; prev_fgf_func = fgf_func; while (fgf_func != NULL) { prev_fgf_func = fgf_func; if (function == NULL && fgf_func->func == NULL) found = 1; else if (function != NULL && fgf_func->func != NULL) found = (strcmp(function, fgf_func->func) == 0); else found = 0; if (found == 1) break; fgf_func = fgf_func->next; } if (found == 0) { SCLogAddToFGFFuncList(fgf_file, prev_fgf_func, function, line); goto done; } found = 0; fgf_line = fgf_func->line; prev_fgf_line = fgf_line; while(fgf_line != NULL) { prev_fgf_line = fgf_line; if (line == fgf_line->line) { found = 1; break; } fgf_line = fgf_line->next; } if (found == 0) { SCLogAddToFGFLineList(fgf_func, prev_fgf_line, line); goto done; } done: SCMutexUnlock(&sc_log_fg_filters_m[listtype]); sc_log_fg_filters_present = 1; return 0; } /** * \brief Internal function used to check for matches against registered FG * filters. Checks if there is a match for the incoming log_message with * any of the FG filters. Based on whether the filter type is whitelist * or blacklist, the function allows the message to be logged or not. * * \param file File_name from where the log_message originated * \param function Function_name from where the log_message originated * \param line Line number from where the log_message originated * \param listtype The filter listtype. Can be either a blacklist or whitelist * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) * * \retval 1 if there is a match * \retval 0 on no match * \retval -1 on failure */ static int SCLogMatchFGFilter(const char *file, const char *function, int line, int listtype) { SCLogFGFilterFile *fgf_file = NULL; SCLogFGFilterFunc *fgf_func = NULL; SCLogFGFilterLine *fgf_line = NULL; int match = 1; if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return -1; } SCMutexLock(&sc_log_fg_filters_m[listtype]); fgf_file = sc_log_fg_filters[listtype]; if (fgf_file == NULL) { SCMutexUnlock(&sc_log_fg_filters_m[listtype]); return 1; } while(fgf_file != NULL) { match = 1; match &= (fgf_file->file != NULL)? !strcmp(file, fgf_file->file): 1; if (match == 0) { fgf_file = fgf_file->next; continue; } fgf_func = fgf_file->func; while (fgf_func != NULL) { match = 1; match &= (fgf_func->func != NULL)? !strcmp(function, fgf_func->func): 1; if (match == 0) { fgf_func = fgf_func->next; continue; } fgf_line = fgf_func->line; while (fgf_line != NULL) { match = 1; match &= (fgf_line->line != -1)? (line == fgf_line->line): 1; if (match == 1) break; fgf_line = fgf_line->next; } if (match == 1) break; fgf_func = fgf_func->next; } if (match == 1) { SCMutexUnlock(&sc_log_fg_filters_m[listtype]); if (listtype == SC_LOG_FILTER_WL) return 1; else return 0; } fgf_file = fgf_file->next; } SCMutexUnlock(&sc_log_fg_filters_m[listtype]); if (listtype == SC_LOG_FILTER_WL) return 0; else return 1; } /** * \brief Checks if there is a match for the incoming log_message with any * of the FG filters. If there is a match, it allows the message * to be logged, else it rejects that message. * * \param file File_name from where the log_message originated * \param function Function_name from where the log_message originated * \param line Line number from where the log_message originated * * \retval 1 if there is a match * \retval 0 on no match * \retval -1 on failure */ int SCLogMatchFGFilterWL(const char *file, const char *function, int line) { return SCLogMatchFGFilter(file, function, line, SC_LOG_FILTER_WL); } /** * \brief Checks if there is a match for the incoming log_message with any * of the FG filters. If there is a match it rejects the logging * for that messages, else it allows that message to be logged * * \praram file File_name from where the log_message originated * \param function Function_name from where the log_message originated * \param line Line number from where the log_message originated * * \retval 1 if there is a match * \retval 0 on no match * \retval -1 on failure */ int SCLogMatchFGFilterBL(const char *file, const char *function, int line) { return SCLogMatchFGFilter(file, function, line, SC_LOG_FILTER_BL); } /** * \brief Adds a Whitelist(WL) fine-grained(FG) filter. A FG filter WL filter * allows messages that match this filter, to be logged, while the filter * is defined using a file_name, function_name and line_number. * * If a particular paramter in the fg-filter(file, function and line), * shouldn't be considered while logging the message, one can supply * NULL for the file_name or function_name and a negative line_no. * * \param file File_name of the filter * \param function Function_name of the filter * \param line Line number of the filter * * \retval 0 on successfully adding the filter; * \retval -1 on failure */ int SCLogAddFGFilterWL(const char *file, const char *function, int line) { return SCLogAddFGFilter(file, function, line, SC_LOG_FILTER_WL); } /** * \brief Adds a Blacklist(BL) fine-grained(FG) filter. A FG filter BL filter * allows messages that don't match this filter, to be logged, while the * filter is defined using a file_name, function_name and line_number * * If a particular paramter in the fg-filter(file, function and line), * shouldn't be considered while logging the message, one can supply * NULL for the file_name or function_name and a negative line_no. * * \param file File_name of the filter * \param function Function_name of the filter * \param line Line number of the filter * * \retval 0 on successfully adding the filter * \retval -1 on failure */ int SCLogAddFGFilterBL(const char *file, const char *function, int line) { return SCLogAddFGFilter(file, function, line, SC_LOG_FILTER_BL); } void SCLogReleaseFGFilters(void) { SCLogFGFilterFile *fgf_file = NULL; SCLogFGFilterFunc *fgf_func = NULL; SCLogFGFilterLine *fgf_line = NULL; void *temp = NULL; int i = 0; for (i = 0; i < SC_LOG_FILTER_MAX; i++) { SCMutexLock(&sc_log_fg_filters_m[i]); fgf_file = sc_log_fg_filters[i]; while (fgf_file != NULL) { fgf_func = fgf_file->func; while (fgf_func != NULL) { fgf_line = fgf_func->line; while(fgf_line != NULL) { temp = fgf_line; fgf_line = fgf_line->next; SCFree(temp); } if (fgf_func->func != NULL) SCFree(fgf_func->func); temp = fgf_func; fgf_func = fgf_func->next; SCFree(temp); } if (fgf_file->file != NULL) SCFree(fgf_file->file); temp = fgf_file; fgf_file = fgf_file->next; SCFree(temp); } SCMutexUnlock(&sc_log_fg_filters_m[i]); sc_log_fg_filters[i] = NULL; } return; } /** * \brief Prints the FG filters(both WL and BL). Used for debugging purposes. * * \retval count The no of FG filters */ int SCLogPrintFGFilters() { SCLogFGFilterFile *fgf_file = NULL; SCLogFGFilterFunc *fgf_func = NULL; SCLogFGFilterLine *fgf_line = NULL; int count = 0; int i = 0; if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return 0; } #ifdef DEBUG printf("Fine grained filters:\n"); #endif for (i = 0; i < SC_LOG_FILTER_MAX; i++) { SCMutexLock(&sc_log_fg_filters_m[i]); fgf_file = sc_log_fg_filters[i]; while (fgf_file != NULL) { fgf_func = fgf_file->func; while (fgf_func != NULL) { fgf_line = fgf_func->line; while(fgf_line != NULL) { #ifdef DEBUG printf("%s - ", fgf_file->file); printf("%s - ", fgf_func->func); printf("%d\n", fgf_line->line); #endif count++; fgf_line = fgf_line->next; } fgf_func = fgf_func->next; } fgf_file = fgf_file->next; } SCMutexUnlock(&sc_log_fg_filters_m[i]); } return count; } /* --------------------------------------------------|-------------------------- * -------------------------- Code for the FD Filter |-------------------------- * --------------------------------------------------V-------------------------- */ /** * \brief Checks if there is a match for the incoming log_message with any * of the FD filters * * \param function Function_name from where the log_message originated * * \retval 1 if there is a match * \retval 0 on no match; */ int SCLogMatchFDFilter(const char *function) { #ifndef DEBUG return 1; #else SCLogFDFilterThreadList *thread_list = NULL; pthread_t self = pthread_self(); if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return 0; } SCMutexLock(&sc_log_fd_filters_tl_m); if (sc_log_fd_filters_tl == NULL) { SCMutexUnlock(&sc_log_fd_filters_tl_m); if (sc_log_fd_filters != NULL) return 0; return 1; } thread_list = sc_log_fd_filters_tl; while (thread_list != NULL) { if (pthread_equal(self, thread_list->t)) { if (thread_list->entered > 0) { SCMutexUnlock(&sc_log_fd_filters_tl_m); return 1; } SCMutexUnlock(&sc_log_fd_filters_tl_m); return 0; } thread_list = thread_list->next; } SCMutexUnlock(&sc_log_fd_filters_tl_m); return 0; #endif } /** * \brief Updates a FD filter, based on whether the function that calls this * function, is registered as a FD filter or not. This is called by * a function only on its entry * * \param function Function_name from where the log_message originated * * \retval 1 Since it is a hack to get things working inside the macros */ int SCLogCheckFDFilterEntry(const char *function) { SCLogFDFilter *curr = NULL; SCLogFDFilterThreadList *thread_list = NULL; SCLogFDFilterThreadList *thread_list_temp = NULL; //pid_t self = syscall(SYS_gettid); pthread_t self = pthread_self(); if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return 0; } SCMutexLock(&sc_log_fd_filters_m); curr = sc_log_fd_filters; while (curr != NULL) { if (strcmp(function, curr->func) == 0) break; curr = curr->next; } if (curr == NULL) { SCMutexUnlock(&sc_log_fd_filters_m); return 1; } SCMutexUnlock(&sc_log_fd_filters_m); SCMutexLock(&sc_log_fd_filters_tl_m); thread_list = sc_log_fd_filters_tl; while (thread_list != NULL) { if (pthread_equal(self, thread_list->t)) break; thread_list = thread_list->next; } if (thread_list != NULL) { thread_list->entered++; SCMutexUnlock(&sc_log_fd_filters_tl_m); return 1; } if ( (thread_list_temp = SCMalloc(sizeof(SCLogFDFilterThreadList))) == NULL) { SCMutexUnlock(&sc_log_fd_filters_tl_m); return 0; } memset(thread_list_temp, 0, sizeof(SCLogFDFilterThreadList)); thread_list_temp->t = self; thread_list_temp->entered++; sc_log_fd_filters_tl = thread_list_temp; SCMutexUnlock(&sc_log_fd_filters_tl_m); return 1; } /** * \brief Updates a FD filter, based on whether the function that calls this * function, is registered as a FD filter or not. This is called by * a function only before its exit. * * \param function Function_name from where the log_message originated * */ void SCLogCheckFDFilterExit(const char *function) { SCLogFDFilter *curr = NULL; SCLogFDFilterThreadList *thread_list = NULL; //pid_t self = syscall(SYS_gettid); pthread_t self = pthread_self(); if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return; } SCMutexLock(&sc_log_fd_filters_m); curr = sc_log_fd_filters; while (curr != NULL) { if (strcmp(function, curr->func) == 0) break; curr = curr->next; } if (curr == NULL) { SCMutexUnlock(&sc_log_fd_filters_m); return; } SCMutexUnlock(&sc_log_fd_filters_m); SCMutexLock(&sc_log_fd_filters_tl_m); thread_list = sc_log_fd_filters_tl; while (thread_list != NULL) { if (pthread_equal(self, thread_list->t)) break; thread_list = thread_list->next; } SCMutexUnlock(&sc_log_fd_filters_tl_m); if (thread_list != NULL) thread_list->entered--; return; } /** * \brief Adds a Function-Dependent(FD) filter * * \param Name of the function for which a FD filter has to be registered * * \retval 0 on success * \retval -1 on failure */ int SCLogAddFDFilter(const char *function) { SCLogFDFilter *curr = NULL; SCLogFDFilter *prev = NULL; SCLogFDFilter *temp = NULL; if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return -1; } if (function == NULL) { printf("Invalid argument supplied to SCLogAddFDFilter\n"); return -1; } SCMutexLock(&sc_log_fd_filters_m); curr = sc_log_fd_filters; while (curr != NULL) { prev = curr; if (strcmp(function, curr->func) == 0) { SCMutexUnlock(&sc_log_fd_filters_m); return 0; } curr = curr->next; } if ( (temp = SCMalloc(sizeof(SCLogFDFilter))) == NULL) { printf("Error Allocating memory (SCMalloc)\n"); exit(EXIT_FAILURE); } memset(temp, 0, sizeof(SCLogFDFilter)); if ( (temp->func = SCStrdup(function)) == NULL) { printf("Error Allocating memory (SCStrdup)\n"); exit(EXIT_FAILURE); } if (sc_log_fd_filters == NULL) sc_log_fd_filters = temp; /* clang thinks prev can be NULL, but it can't be unless * sc_log_fd_filters is also NULL which is handled here. * Doing this "fix" to shut clang up. */ else if (prev != NULL) prev->next = temp; SCMutexUnlock(&sc_log_fd_filters_m); sc_log_fd_filters_present = 1; return 0; } /** * \brief Releases all the FD filters added to the logging module */ void SCLogReleaseFDFilters(void) { SCLogFDFilter *fdf = NULL; SCLogFDFilter *temp = NULL; SCMutexLock(&sc_log_fd_filters_m); fdf = sc_log_fd_filters; while (fdf != NULL) { temp = fdf; fdf = fdf->next; SCLogReleaseFDFilter(temp); } sc_log_fd_filters = NULL; SCMutexUnlock( &sc_log_fd_filters_m ); return; } /** * \brief Removes a Function-Dependent(FD) filter * * \param Name of the function for which a FD filter has to be unregistered * * \retval 0 on success(the filter was removed or the filter was not present) * \retval -1 on failure/error */ int SCLogRemoveFDFilter(const char *function) { SCLogFDFilter *curr = NULL; SCLogFDFilter *prev = NULL; if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return -1 ; } if (function == NULL) { printf("Invalid argument(s) supplied to SCLogRemoveFDFilter\n"); return -1; } SCMutexLock(&sc_log_fd_filters_m); if (sc_log_fd_filters == NULL) { SCMutexUnlock(&sc_log_fd_filters_m); return 0; } curr = sc_log_fd_filters; prev = curr; while (curr != NULL) { if (strcmp(function, curr->func) == 0) break; prev = curr; curr = curr->next; } if (curr == NULL) { SCMutexUnlock(&sc_log_fd_filters_m); return 0; } if (sc_log_fd_filters == curr) sc_log_fd_filters = curr->next; else prev->next = curr->next; SCLogReleaseFDFilter(curr); SCMutexUnlock(&sc_log_fd_filters_m); if (sc_log_fd_filters == NULL) sc_log_fd_filters_present = 0; return 0; } /** * \brief Prints the FG filters(both WL and BL). Used for debugging purposes. * * \retval count The no of FG filters */ int SCLogPrintFDFilters(void) { SCLogFDFilter *fdf = NULL; int count = 0; if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return 0; } #ifdef DEBUG printf("FD filters:\n"); #endif SCMutexLock(&sc_log_fd_filters_m); fdf = sc_log_fd_filters; while (fdf != NULL) { #ifdef DEBUG printf("%s \n", fdf->func); #endif fdf = fdf->next; count++; } SCMutexUnlock(&sc_log_fd_filters_m); return count; } /** * \brief Helper function used internally to add a FG filter. This function is * called when the file component of the incoming filter has no entry * in the filter list. * * \param fgf_file The file component(basically the position in the list) from * the filter list, after which the new filter has to be added * \param file File_name of the filter * \param function Function_name of the filter * \param line Line number of the filter * \param listtype The filter listtype. Can be either a blacklist or whitelist * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) */ void SCLogAddToFGFFileList(SCLogFGFilterFile *fgf_file, const char *file, const char *function, int line, int listtype) { SCLogFGFilterFile *fgf_file_temp = NULL; SCLogFGFilterFunc *fgf_func_temp = NULL; SCLogFGFilterLine *fgf_line_temp = NULL; if ( (fgf_file_temp = SCMalloc(sizeof(SCLogFGFilterFile))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); exit(EXIT_FAILURE); } memset(fgf_file_temp, 0, sizeof(SCLogFGFilterFile)); if ( file != NULL && (fgf_file_temp->file = SCStrdup(file)) == NULL) { printf("Error Allocating memory\n"); exit(EXIT_FAILURE); } if ( (fgf_func_temp = SCMalloc(sizeof(SCLogFGFilterFunc))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); exit(EXIT_FAILURE); } memset(fgf_func_temp, 0, sizeof(SCLogFGFilterFunc)); if ( function != NULL && (fgf_func_temp->func = SCStrdup(function)) == NULL) { printf("Error Allocating memory\n"); exit(EXIT_FAILURE); } if ( (fgf_line_temp = SCMalloc(sizeof(SCLogFGFilterLine))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); exit(EXIT_FAILURE); } memset(fgf_line_temp, 0, sizeof(SCLogFGFilterLine)); fgf_line_temp->line = line; /* add to the lists */ fgf_func_temp->line = fgf_line_temp; fgf_file_temp->func = fgf_func_temp; if (fgf_file == NULL) sc_log_fg_filters[listtype] = fgf_file_temp; else fgf_file->next = fgf_file_temp; return; } /** * \brief Helper function used internally to add a FG filter. This function is * called when the file component of the incoming filter has an entry * in the filter list, but the function component doesn't have an entry * for the corresponding file component * * \param fgf_file The file component from the filter list to which the new * filter has to be added * \param fgf_func The function component(basically the position in the list), * from the filter list, after which the new filter has to be * added * \param function Function_name of the filter * \param line Line number of the filter */ void SCLogAddToFGFFuncList(SCLogFGFilterFile *fgf_file, SCLogFGFilterFunc *fgf_func, const char *function, int line) { SCLogFGFilterFunc *fgf_func_temp = NULL; SCLogFGFilterLine *fgf_line_temp = NULL; if ( (fgf_func_temp = SCMalloc(sizeof(SCLogFGFilterFunc))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogAddToFGFFuncList. Exiting..."); exit(EXIT_FAILURE); } memset(fgf_func_temp, 0, sizeof(SCLogFGFilterFunc)); if ( function != NULL && (fgf_func_temp->func = SCStrdup(function)) == NULL) { printf("Error Allocating memory\n"); exit(EXIT_FAILURE); } if ( (fgf_line_temp = SCMalloc(sizeof(SCLogFGFilterLine))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogAddToFGFFuncList. Exiting..."); exit(EXIT_FAILURE); } memset(fgf_line_temp, 0, sizeof(SCLogFGFilterLine)); fgf_line_temp->line = line; /* add to the lists */ fgf_func_temp->line = fgf_line_temp; if (fgf_func == NULL) fgf_file->func = fgf_func_temp; else fgf_func->next = fgf_func_temp; return; } /** * \brief Helper function used internally to add a FG filter. This function is * called when the file and function components of the incoming filter * have an entry in the filter list, but the line component doesn't have * an entry for the corresponding function component * * \param fgf_func The function component from the filter list to which the new * filter has to be added * \param fgf_line The function component(basically the position in the list), * from the filter list, after which the new filter has to be * added * \param line Line number of the filter */ void SCLogAddToFGFLineList(SCLogFGFilterFunc *fgf_func, SCLogFGFilterLine *fgf_line, int line) { SCLogFGFilterLine *fgf_line_temp = NULL; if ( (fgf_line_temp = SCMalloc(sizeof(SCLogFGFilterLine))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogAddToFGFLineList. Exiting..."); exit(EXIT_FAILURE); } memset(fgf_line_temp, 0, sizeof(SCLogFGFilterLine)); fgf_line_temp->line = line; /* add to the lists */ if (fgf_line == NULL) fgf_func->line = fgf_line_temp; else fgf_line->next = fgf_line_temp; return; } /** * \brief Releases the memory alloted to a FD filter * * \param Pointer to the FD filter that has to be freed */ void SCLogReleaseFDFilter(SCLogFDFilter *fdf) { if (fdf != NULL) { if (fdf->func != NULL) SCFree(fdf->func); SCFree(fdf); } return; } suricata-1.4.7/src/detect-flags.c0000644000000000000000000007525012253546156013544 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * * Implements the flags keyword */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "flow-var.h" #include "decode-events.h" #include "detect-flags.h" #include "util-unittest.h" #include "util-debug.h" /** * Regex (by Brian Rectanus) * flags: [!+*](SAPRFU120)[,SAPRFU12] */ #define PARSE_REGEX "^\\s*(?:([\\+\\*!]))?\\s*([SAPRFU120CE\\+\\*!]+)(?:\\s*,\\s*([SAPRFU12CE]+))?\\s*$" /** * Flags args[0] *(3) +(2) !(1) * */ #define MODIFIER_NOT 1 #define MODIFIER_PLUS 2 #define MODIFIER_ANY 3 static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectFlagsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFlagsFree(void *); /** * \brief Registration function for flags: keyword */ void DetectFlagsRegister (void) { sigmatch_table[DETECT_FLAGS].name = "flags"; sigmatch_table[DETECT_FLAGS].Match = DetectFlagsMatch; sigmatch_table[DETECT_FLAGS].Setup = DetectFlagsSetup; sigmatch_table[DETECT_FLAGS].Free = DetectFlagsFree; sigmatch_table[DETECT_FLAGS].RegisterTests = FlagsRegisterTests; const char *eb; int opts = 0; int eo; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } error: return; } /** * \internal * \brief This function is used to match flags on a packet with those passed via flags: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param s pointer to the Signature * \param m pointer to the sigmatch * * \retval 0 no match * \retval 1 match */ static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { SCEnter(); uint8_t flags = 0; DetectFlagsData *de = (DetectFlagsData *)m->ctx; if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { SCReturnInt(0); } flags = p->tcph->th_flags; if (!de->flags && flags) { if(de->modifier == MODIFIER_NOT) { SCReturnInt(1); } SCReturnInt(0); } flags &= de->ignored_flags; switch (de->modifier) { case MODIFIER_ANY: if ((flags & de->flags) > 0) { SCReturnInt(1); } SCReturnInt(0); case MODIFIER_PLUS: if (((flags & de->flags) == de->flags)) { SCReturnInt(1); } SCReturnInt(0); case MODIFIER_NOT: if ((flags & de->flags) != de->flags) { SCReturnInt(1); } SCReturnInt(0); default: SCLogDebug("flags %"PRIu8" and de->flags %"PRIu8"",flags,de->flags); if (flags == de->flags) { SCReturnInt(1); } } SCReturnInt(0); } /** * \internal * \brief This function is used to parse flags options passed via flags: keyword * * \param rawstr Pointer to the user provided flags options * * \retval de pointer to DetectFlagsData on success * \retval NULL on failure */ static DetectFlagsData *DetectFlagsParse (char *rawstr) { SCEnter(); DetectFlagsData *de = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, found = 0, ignore = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr = NULL; char *args[3] = { NULL, NULL, NULL }; char *ptr; int i; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_PCRE_MATCH, "pcre match failed"); goto error; } for (i = 0; i < (ret - 1); i++) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS,i + 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i] = (char *)str_ptr; } if(args[1] == NULL) { SCLogDebug("args[1] == NULL"); goto error; } de = SCMalloc(sizeof(DetectFlagsData)); if (unlikely(de == NULL)) goto error; memset(de,0,sizeof(DetectFlagsData)); de->ignored_flags = 0xff; /** First parse args[0] */ if(args[0]) { ptr = args[0]; while (*ptr != '\0') { switch (*ptr) { case 'S': case 's': de->flags |= TH_SYN; found++; break; case 'A': case 'a': de->flags |= TH_ACK; found++; break; case 'F': case 'f': de->flags |= TH_FIN; found++; break; case 'R': case 'r': de->flags |= TH_RST; found++; break; case 'P': case 'p': de->flags |= TH_PUSH; found++; break; case 'U': case 'u': de->flags |= TH_URG; found++; break; case '1': de->flags |= TH_CWR; found++; break; case '2': de->flags |= TH_ECN; found++; break; case 'C': case 'c': de->flags |= TH_CWR; found++; break; case 'E': case 'e': de->flags |= TH_ECN; found++; break; case '0': de->flags = 0; found++; break; case '!': de->modifier = MODIFIER_NOT; break; case '+': de->modifier = MODIFIER_PLUS; break; case '*': de->modifier = MODIFIER_ANY; break; } ptr++; } } /** Second parse first set of flags */ ptr = args[1]; while (*ptr != '\0') { switch (*ptr) { case 'S': case 's': de->flags |= TH_SYN; found++; break; case 'A': case 'a': de->flags |= TH_ACK; found++; break; case 'F': case 'f': de->flags |= TH_FIN; found++; break; case 'R': case 'r': de->flags |= TH_RST; found++; break; case 'P': case 'p': de->flags |= TH_PUSH; found++; break; case 'U': case 'u': de->flags |= TH_URG; found++; break; case '1': de->flags |= TH_CWR; found++; break; case '2': de->flags |= TH_ECN; found++; break; case 'C': case 'c': de->flags |= TH_CWR; found++; break; case 'E': case 'e': de->flags |= TH_ECN; found++; break; case '0': de->flags = 0; found++; break; case '!': if (de->modifier != 0) { SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only" " one modifier at a time"); goto error; } de->modifier = MODIFIER_NOT; SCLogDebug("NOT modifier is set"); break; case '+': if (de->modifier != 0) { SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only" " one modifier at a time"); goto error; } de->modifier = MODIFIER_PLUS; SCLogDebug("PLUS modifier is set"); break; case '*': if (de->modifier != 0) { SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only" " one modifier at a time"); goto error; } de->modifier = MODIFIER_ANY; SCLogDebug("ANY modifier is set"); break; default: break; } ptr++; } if(found == 0) goto error; /** Finally parse ignored flags */ if(args[2]) { ptr = args[2]; while (*ptr != '\0') { switch (*ptr) { case 'S': case 's': de->ignored_flags &= ~TH_SYN; ignore++; break; case 'A': case 'a': de->ignored_flags &= ~TH_ACK; ignore++; break; case 'F': case 'f': de->ignored_flags &= ~TH_FIN; ignore++; break; case 'R': case 'r': de->ignored_flags &= ~TH_RST; ignore++; break; case 'P': case 'p': de->ignored_flags &= ~TH_PUSH; ignore++; break; case 'U': case 'u': de->ignored_flags &= ~TH_URG; ignore++; break; case '1': de->ignored_flags &= ~TH_CWR; ignore++; break; case '2': de->ignored_flags &= ~TH_ECN; ignore++; break; case 'C': case 'c': de->ignored_flags &= ~TH_CWR; ignore++; break; case 'E': case 'e': de->ignored_flags &= ~TH_ECN; ignore++; break; case '0': break; default: break; } ptr++; } if(ignore == 0) { SCLogDebug("ignore == 0"); goto error; } } for (i = 0; i < (ret - 1); i++){ SCLogDebug("args[%"PRId32"] = %s",i, args[i]); if (args[i] != NULL) SCFree(args[i]); } SCLogDebug("found %"PRId32" ignore %"PRId32"", found, ignore); SCReturnPtr(de, "DetectFlagsData"); error: for (i = 0; i < (ret - 1); i++){ if (args[i] != NULL) SCFree(args[i]); } if (de) SCFree(de); SCReturnPtr(NULL, "DetectFlagsData"); } /** * \internal * \brief this function is used to add the parsed flags into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param m pointer to the Current SigMatch * \param rawstr pointer to the user provided flags options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFlagsSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectFlagsData *de = NULL; SigMatch *sm = NULL; de = DetectFlagsParse(rawstr); if (de == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (de) SCFree(de); if (sm) SCFree(sm); return -1; } /** * \internal * \brief this function will free memory associated with DetectFlagsData * * \param de pointer to DetectFlagsData */ static void DetectFlagsFree(void *de_ptr) { DetectFlagsData *de = (DetectFlagsData *)de_ptr; if(de) SCFree(de); } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS /** * \test FlagsTestParse01 is a test for a valid flags value * * \retval 1 on succces * \retval 0 on failure */ static int FlagsTestParse01 (void) { DetectFlagsData *de = NULL; de = DetectFlagsParse("S"); if (de && (de->flags == TH_SYN) ) { DetectFlagsFree(de); return 1; } return 0; } /** * \test FlagsTestParse02 is a test for an invalid flags value * * \retval 1 on succces * \retval 0 on failure */ static int FlagsTestParse02 (void) { DetectFlagsData *de = NULL; de = DetectFlagsParse("G"); if (de) { DetectFlagsFree(de); return 1; } return 0; } /** * \test FlagsTestParse03 test if ACK and PUSH are set. Must return success * * \retval 1 on success * \retval 0 on failure */ static int FlagsTestParse03 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST; de = DetectFlagsParse("AP+"); if (de == NULL || (de->flags != (TH_ACK|TH_PUSH)) ) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse04 check if ACK bit is set. Must fails. * * \retval 1 on succces * \retval 0 on failure */ static int FlagsTestParse04 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_SYN; de = DetectFlagsParse("A"); if (de == NULL || de->flags != TH_ACK) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse05 test if ACK+PUSH and more flags are set. Ignore SYN and RST bits. * Must fails. * \retval 1 on success * \retval 0 on failure */ static int FlagsTestParse05 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST; de = DetectFlagsParse("+AP,SR"); if (de == NULL || (de->modifier != MODIFIER_PLUS) || (de->flags != (TH_ACK|TH_PUSH)) || (de->ignored_flags != (TH_SYN|TH_RST))) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse06 test if ACK+PUSH and more flags are set. Ignore URG and RST bits. * Must return success. * \retval 1 on success * \retval 0 on failure */ static int FlagsTestParse06 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST; de = DetectFlagsParse("+AP,UR"); if (de == NULL || (de->modifier != MODIFIER_PLUS) || (de->flags != (TH_ACK|TH_PUSH)) || ((0xff - de->ignored_flags) != (TH_URG|TH_RST))) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse07 test if SYN or RST are set. Must fails. * * \retval 1 on success * \retval 0 on failure */ static int FlagsTestParse07 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_SYN|TH_RST; de = DetectFlagsParse("*AP"); if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_PUSH))) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse08 test if SYN or RST are set. Must return success. * * \retval 1 on success * \retval 0 on failure */ static int FlagsTestParse08 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_SYN|TH_RST; de = DetectFlagsParse("*SA"); if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_SYN))) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse09 test if SYN and RST are not set. Must fails. * * \retval 1 on success * \retval 0 on failure */ static int FlagsTestParse09 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_SYN|TH_RST; de = DetectFlagsParse("!PA"); if (de == NULL || (de->modifier != MODIFIER_NOT) || (de->flags != (TH_ACK|TH_PUSH))) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse10 test if ACK and PUSH are not set. Must return success. * * \retval 1 on success * \retval 0 on failure */ static int FlagsTestParse10 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_SYN|TH_RST; de = DetectFlagsParse("!AP"); if (de == NULL || (de->modifier != MODIFIER_NOT) || (de->flags != (TH_ACK|TH_PUSH))) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse11 test if ACK or PUSH are set. Ignore SYN and RST. Must fails. * * \retval 1 on success * \retval 0 on failure */ static int FlagsTestParse11 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_SYN|TH_RST|TH_URG; de = DetectFlagsParse("*AP,SR"); if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_PUSH)) || ((0xff - de->ignored_flags) != (TH_SYN|TH_RST))) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test FlagsTestParse12 check if no flags are set. Must fails. * * \retval 1 on succces * \retval 0 on failure */ static int FlagsTestParse12 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_SYN; de = DetectFlagsParse("0"); if (de == NULL || de->flags != 0) { printf("de setup: "); goto error; } sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test test for a valid flags value * * \retval 1 on succces * \retval 0 on failure */ static int FlagsTestParse13 (void) { DetectFlagsData *de = NULL; de = DetectFlagsParse("+S*"); if (de != NULL) { DetectFlagsFree(de); return 0; } return 1; } /** * \test Parse 'C' and 'E' flags. * * \retval 1 on success. * \retval 0 on failure. */ static int FlagsTestParse14(void) { DetectFlagsData *de = DetectFlagsParse("CE"); if (de != NULL && (de->flags == (TH_CWR | TH_ECN)) ) { DetectFlagsFree(de); return 1; } return 0; } static int FlagsTestParse15(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_ECN | TH_CWR | TH_SYN | TH_RST; de = DetectFlagsParse("EC+"); if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) ) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); if (ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } static int FlagsTestParse16(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_ECN | TH_SYN | TH_RST; de = DetectFlagsParse("EC*"); if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) ) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); if (ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } /** * \test Negative test. */ static int FlagsTestParse17(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectFlagsData *de = NULL; SigMatch *sm = NULL; IPV4Hdr ipv4h; TCPHdr tcph; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ipv4h, 0, sizeof(IPV4Hdr)); memset(&tcph, 0, sizeof(TCPHdr)); p->ip4h = &ipv4h; p->tcph = &tcph; p->tcph->th_flags = TH_ECN | TH_SYN | TH_RST; de = DetectFlagsParse("EC+"); if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) ) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLAGS; sm->ctx = (void *)de; ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); if (ret == 0) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for Flags */ void FlagsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FlagsTestParse01", FlagsTestParse01, 1); UtRegisterTest("FlagsTestParse02", FlagsTestParse02, 0); UtRegisterTest("FlagsTestParse03", FlagsTestParse03, 1); UtRegisterTest("FlagsTestParse04", FlagsTestParse04, 0); UtRegisterTest("FlagsTestParse05", FlagsTestParse05, 0); UtRegisterTest("FlagsTestParse06", FlagsTestParse06, 1); UtRegisterTest("FlagsTestParse07", FlagsTestParse07, 0); UtRegisterTest("FlagsTestParse08", FlagsTestParse08, 1); UtRegisterTest("FlagsTestParse09", FlagsTestParse09, 1); UtRegisterTest("FlagsTestParse10", FlagsTestParse10, 1); UtRegisterTest("FlagsTestParse11", FlagsTestParse11, 0); UtRegisterTest("FlagsTestParse12", FlagsTestParse12, 0); UtRegisterTest("FlagsTestParse13", FlagsTestParse13, 1); UtRegisterTest("FlagsTestParse14", FlagsTestParse14, 1); UtRegisterTest("FlagsTestParse15", FlagsTestParse15, 1); UtRegisterTest("FlagsTestParse16", FlagsTestParse16, 1); UtRegisterTest("FlagsTestParse17", FlagsTestParse17, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/flow-hash.h0000644000000000000000000000502512253546156013070 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __FLOW_HASH_H__ #define __FLOW_HASH_H__ /** Spinlocks or Mutex for the flow buckets. */ //#define FBLOCK_SPIN #define FBLOCK_MUTEX #ifdef FBLOCK_SPIN #ifdef FBLOCK_MUTEX #error Cannot enable both FBLOCK_SPIN and FBLOCK_MUTEX #endif #endif /* 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 *head; Flow *tail; #ifdef FBLOCK_MUTEX SCMutex m; #elif defined FBLOCK_SPIN SCSpinlock s; #else #error Enable FBLOCK_SPIN or FBLOCK_MUTEX #endif } FlowBucket; #ifdef FBLOCK_SPIN #define FBLOCK_INIT(fb) SCSpinInit(&(fb)->s, 0) #define FBLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->s) #define FBLOCK_LOCK(fb) SCSpinLock(&(fb)->s) #define FBLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->s) #define FBLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->s) #elif defined FBLOCK_MUTEX #define FBLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL) #define FBLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m) #define FBLOCK_LOCK(fb) SCMutexLock(&(fb)->m) #define FBLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->m) #define FBLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m) #else #error Enable FBLOCK_SPIN or FBLOCK_MUTEX #endif /* prototypes */ Flow *FlowGetFlowFromHash(Packet *); /** enable to print stats on hash lookups in flow-debug.log */ //#define FLOW_DEBUG_STATS #ifdef FLOW_DEBUG_STATS void FlowHashDebugInit(void); void FlowHashDebugDeinit(void); void FlowHashDebugPrint(uint32_t); #else #define FlowHashDebugInit(...) #define FlowHashDebugPrint(...) #define FlowHashDebugDeinit(...) #endif #endif /* __FLOW_HASH_H__ */ suricata-1.4.7/src/log-filestore.c0000644000000000000000000005203112253546156013745 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "pkt-var.h" #include "conf.h" #include "threadvars.h" #include "tm-modules.h" #include "threads.h" #include "app-layer-parser.h" #include "detect-filemagic.h" #include "stream.h" #include "util-print.h" #include "util-unittest.h" #include "util-privs.h" #include "util-debug.h" #include "util-atomic.h" #include "util-file.h" #include "output.h" #include "log-file.h" #include "util-logopenfile.h" #include "app-layer-htp.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" #define MODULE_NAME "LogFilestoreLog" TmEcode LogFilestoreLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogFilestoreLogIPv4(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogFilestoreLogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogFilestoreLogThreadInit(ThreadVars *, void *, void **); TmEcode LogFilestoreLogThreadDeinit(ThreadVars *, void *); void LogFilestoreLogExitPrintStats(ThreadVars *, void *); int LogFilestoreLogOpenFileCtx(LogFileCtx* , const char *, const char *); static OutputCtx *LogFilestoreLogInitCtx(ConfNode *); static void LogFilestoreLogDeInitCtx(OutputCtx *); SC_ATOMIC_DECLARE(unsigned int, file_id); static char g_logfile_base_dir[PATH_MAX] = "/tmp"; static char g_waldo[PATH_MAX] = ""; void TmModuleLogFilestoreRegister (void) { tmm_modules[TMM_FILESTORE].name = MODULE_NAME; tmm_modules[TMM_FILESTORE].ThreadInit = LogFilestoreLogThreadInit; tmm_modules[TMM_FILESTORE].Func = LogFilestoreLog; tmm_modules[TMM_FILESTORE].ThreadExitPrintStats = LogFilestoreLogExitPrintStats; tmm_modules[TMM_FILESTORE].ThreadDeinit = LogFilestoreLogThreadDeinit; tmm_modules[TMM_FILESTORE].RegisterTests = NULL; tmm_modules[TMM_FILESTORE].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "file", LogFilestoreLogInitCtx); OutputRegisterModule(MODULE_NAME, "file-store", LogFilestoreLogInitCtx); SCLogDebug("registered"); SC_ATOMIC_INIT(file_id); } typedef struct LogFilestoreLogThread_ { LogFileCtx *file_ctx; /** LogFilestoreCtx has the pointer to the file and a mutex to allow multithreading */ uint32_t file_cnt; } LogFilestoreLogThread; static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); } static void LogFilestoreMetaGetUri(FILE *fp, Packet *p, File *ff) { HtpState *htp_state = (HtpState *)p->flow->alstate; if (htp_state != NULL) { htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, ff->txid); if (tx != NULL && tx->request_uri_normalized != NULL) { PrintRawUriFp(fp, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized)); return; } } fprintf(fp, ""); } static void LogFilestoreMetaGetHost(FILE *fp, Packet *p, File *ff) { HtpState *htp_state = (HtpState *)p->flow->alstate; if (htp_state != NULL) { htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, ff->txid); if (tx != NULL) { table_t *headers; headers = tx->request_headers; htp_header_t *h = NULL; table_iterator_reset(headers); while (table_iterator_next(headers, (void **)&h) != NULL) { if (bstr_len(h->name) >= 4 && SCMemcmpLowercase((uint8_t *)"host", (uint8_t *)bstr_ptr(h->name), bstr_len(h->name)) == 0) { PrintRawUriFp(fp, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value)); return; } } } } fprintf(fp, ""); } static void LogFilestoreMetaGetReferer(FILE *fp, Packet *p, File *ff) { HtpState *htp_state = (HtpState *)p->flow->alstate; if (htp_state != NULL) { htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, ff->txid); if (tx != NULL) { table_t *headers; headers = tx->request_headers; htp_header_t *h = NULL; table_iterator_reset(headers); while (table_iterator_next(headers, (void **)&h) != NULL) { if (bstr_len(h->name) >= 7 && SCMemcmpLowercase((uint8_t *)"referer", (uint8_t *)bstr_ptr(h->name), bstr_len(h->name)) == 0) { PrintRawUriFp(fp, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value)); return; } } } } fprintf(fp, ""); } static void LogFilestoreMetaGetUserAgent(FILE *fp, Packet *p, File *ff) { HtpState *htp_state = (HtpState *)p->flow->alstate; if (htp_state != NULL) { htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, ff->txid); if (tx != NULL) { table_t *headers; headers = tx->request_headers; htp_header_t *h = NULL; table_iterator_reset(headers); while (table_iterator_next(headers, (void **)&h) != NULL) { if (bstr_len(h->name) >= 10 && SCMemcmpLowercase((uint8_t *)"user-agent", (uint8_t *)bstr_ptr(h->name), bstr_len(h->name)) == 0) { PrintRawUriFp(fp, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value)); return; } } } } fprintf(fp, ""); } static void LogFilestoreLogCreateMetaFile(Packet *p, File *ff, char *filename, int ipver) { char metafilename[PATH_MAX] = ""; snprintf(metafilename, sizeof(metafilename), "%s.meta", filename); FILE *fp = fopen(metafilename, "w+"); if (fp != NULL) { char timebuf[64]; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); fprintf(fp, "TIME: %s\n", timebuf); if (p->pcap_cnt > 0) { fprintf(fp, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt); } char srcip[46], dstip[46]; Port sp, dp; switch (ipver) { case AF_INET: PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); break; case AF_INET6: PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); break; default: strlcpy(srcip, "", sizeof(srcip)); strlcpy(dstip, "", sizeof(dstip)); break; } sp = p->sp; dp = p->dp; fprintf(fp, "SRC IP: %s\n", srcip); fprintf(fp, "DST IP: %s\n", dstip); fprintf(fp, "PROTO: %" PRIu32 "\n", p->proto); if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { fprintf(fp, "SRC PORT: %" PRIu16 "\n", sp); fprintf(fp, "DST PORT: %" PRIu16 "\n", dp); } fprintf(fp, "HTTP URI: "); LogFilestoreMetaGetUri(fp, p, ff); fprintf(fp, "\n"); fprintf(fp, "HTTP HOST: "); LogFilestoreMetaGetHost(fp, p, ff); fprintf(fp, "\n"); fprintf(fp, "HTTP REFERER: "); LogFilestoreMetaGetReferer(fp, p, ff); fprintf(fp, "\n"); fprintf(fp, "HTTP USER AGENT: "); LogFilestoreMetaGetUserAgent(fp, p, ff); fprintf(fp, "\n"); fprintf(fp, "FILENAME: "); PrintRawUriFp(fp, ff->name, ff->name_len); fprintf(fp, "\n"); fclose(fp); } } static void LogFilestoreLogCloseMetaFile(File *ff) { char filename[PATH_MAX] = ""; snprintf(filename, sizeof(filename), "%s/file.%u", g_logfile_base_dir, ff->file_id); char metafilename[PATH_MAX] = ""; snprintf(metafilename, sizeof(metafilename), "%s.meta", filename); FILE *fp = fopen(metafilename, "a"); if (fp != NULL) { fprintf(fp, "MAGIC: %s\n", ff->magic ? ff->magic : ""); switch (ff->state) { case FILE_STATE_CLOSED: fprintf(fp, "STATE: CLOSED\n"); #ifdef HAVE_NSS if (ff->flags & FILE_MD5) { fprintf(fp, "MD5: "); size_t x; for (x = 0; x < sizeof(ff->md5); x++) { fprintf(fp, "%02x", ff->md5[x]); } fprintf(fp, "\n"); } #endif break; case FILE_STATE_TRUNCATED: fprintf(fp, "STATE: TRUNCATED\n"); break; case FILE_STATE_ERROR: fprintf(fp, "STATE: ERROR\n"); break; default: fprintf(fp, "STATE: UNKNOWN\n"); break; } fprintf(fp, "SIZE: %"PRIu64"\n", ff->size); fclose(fp); } else { SCLogInfo("opening %s failed: %s", metafilename, strerror(errno)); } } static TmEcode LogFilestoreLogWrap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq, int ipver) { SCEnter(); LogFilestoreLogThread *aft = (LogFilestoreLogThread *)data; uint8_t flags = 0; /* no flow, no htp state */ if (p->flow == NULL) { SCReturnInt(TM_ECODE_OK); } if (p->flowflags & FLOW_PKT_TOCLIENT) flags |= STREAM_TOCLIENT; else flags |= STREAM_TOSERVER; int file_close = (p->flags & PKT_PSEUDO_STREAM_END) ? 1 : 0; int file_trunc = 0; FLOWLOCK_WRLOCK(p->flow); file_trunc = StreamTcpReassembleDepthReached(p); FileContainer *ffc = AppLayerGetFilesFromFlow(p->flow, flags); SCLogDebug("ffc %p", ffc); if (ffc != NULL) { File *ff; for (ff = ffc->head; ff != NULL; ff = ff->next) { int file_fd = -1; if (FileForceMagic() && ff->magic == NULL) { FilemagicGlobalLookup(ff); } SCLogDebug("ff %p", ff); if (ff->flags & FILE_STORED) { SCLogDebug("stored flag set"); continue; } if (!(ff->flags & FILE_STORE)) { SCLogDebug("ff FILE_STORE not set"); continue; } FileData *ffd; for (ffd = ff->chunks_head; ffd != NULL; ffd = ffd->next) { SCLogDebug("ffd %p", ffd); if (ffd->stored == 1) { if (file_close == 1 && ffd->next == NULL) { LogFilestoreLogCloseMetaFile(ff); ff->flags |= FILE_STORED; } continue; } /* store */ SCLogDebug("trying to open file"); char filename[PATH_MAX] = ""; if (ff->file_id == 0) { ff->file_id = SC_ATOMIC_ADD(file_id, 1); snprintf(filename, sizeof(filename), "%s/file.%u", g_logfile_base_dir, ff->file_id); file_fd = open(filename, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644); if (file_fd == -1) { SCLogDebug("failed to open file"); continue; } /* create a .meta file that contains time, src/dst/sp/dp/proto */ LogFilestoreLogCreateMetaFile(p, ff, filename, ipver); aft->file_cnt++; } else { snprintf(filename, sizeof(filename), "%s/file.%u", g_logfile_base_dir, ff->file_id); file_fd = open(filename, O_APPEND | O_NOFOLLOW | O_WRONLY); if (file_fd == -1) { SCLogDebug("failed to open file %s: %s", filename, strerror(errno)); continue; } } ssize_t r = write(file_fd, (const void *)ffd->data, (size_t)ffd->len); if (r == -1) { SCLogDebug("write failed: %s", strerror(errno)); close(file_fd); continue; } close(file_fd); if (file_trunc && ff->state < FILE_STATE_CLOSED) ff->state = FILE_STATE_TRUNCATED; if (ff->state == FILE_STATE_CLOSED || ff->state == FILE_STATE_TRUNCATED || ff->state == FILE_STATE_ERROR || (file_close == 1 && ff->state < FILE_STATE_CLOSED)) { if (ffd->next == NULL) { LogFilestoreLogCloseMetaFile(ff); ff->flags |= FILE_STORED; } } ffd->stored = 1; } } FilePrune(ffc); } FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_OK); } TmEcode LogFilestoreLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return LogFilestoreLogWrap(tv, p, data, NULL, NULL, AF_INET); } TmEcode LogFilestoreLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return LogFilestoreLogWrap(tv, p, data, NULL, NULL, AF_INET6); } TmEcode LogFilestoreLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); int r = TM_ECODE_OK; /* no flow, no htp state */ if (p->flow == NULL) { SCReturnInt(TM_ECODE_OK); } if (!(PKT_IS_TCP(p))) { SCReturnInt(TM_ECODE_OK); } SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); if (PKT_IS_IPV4(p)) { r = LogFilestoreLogIPv4(tv, p, data, pq, postpq); } else if (PKT_IS_IPV6(p)) { r = LogFilestoreLogIPv6(tv, p, data, pq, postpq); } SCReturnInt(r); } TmEcode LogFilestoreLogThreadInit(ThreadVars *t, void *initdata, void **data) { LogFilestoreLogThread *aft = SCMalloc(sizeof(LogFilestoreLogThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(LogFilestoreLogThread)); if (initdata == NULL) { SCLogDebug("Error getting context for LogFilestore. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } /* Use the Ouptut Context (file pointer and mutex) */ aft->file_ctx = ((OutputCtx *)initdata)->data; struct stat stat_buf; if (stat(g_logfile_base_dir, &stat_buf) != 0) { int ret; ret = mkdir(g_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP); if (ret != 0) { int err = errno; if (err != EEXIST) { SCLogError(SC_ERR_LOGDIR_CONFIG, "Cannot create file drop directory %s: %s", g_logfile_base_dir, strerror(err)); exit(EXIT_FAILURE); } } else { SCLogInfo("Created file drop directory %s", g_logfile_base_dir); } } *data = (void *)aft; return TM_ECODE_OK; } TmEcode LogFilestoreLogThreadDeinit(ThreadVars *t, void *data) { LogFilestoreLogThread *aft = (LogFilestoreLogThread *)data; if (aft == NULL) { return TM_ECODE_OK; } /* clear memory */ memset(aft, 0, sizeof(LogFilestoreLogThread)); SCFree(aft); return TM_ECODE_OK; } void LogFilestoreLogExitPrintStats(ThreadVars *tv, void *data) { LogFilestoreLogThread *aft = (LogFilestoreLogThread *)data; if (aft == NULL) { return; } SCLogInfo("(%s) Files extracted %" PRIu32 "", tv->name, aft->file_cnt); } /** * \internal * * \brief Open the waldo file (if available) and load the file_id * * \param path full path for the waldo file */ static void LogFilestoreLogLoadWaldo(const char *path) { char line[16] = ""; unsigned int id = 0; FILE *fp = fopen(path, "r"); if (fp == NULL) { SCLogInfo("couldn't open waldo: %s", strerror(errno)); SCReturn; } if (fgets(line, (int)sizeof(line), fp) != NULL) { if (sscanf(line, "%10u", &id) == 1) { SCLogInfo("id %u", id); (void) SC_ATOMIC_CAS(&file_id, 0, id); } } fclose(fp); } /** * \internal * * \brief Store the waldo file based on the file_id * * \param path full path for the waldo file */ static void LogFilestoreLogStoreWaldo(const char *path) { char line[16] = ""; if (SC_ATOMIC_GET(file_id) == 0) { SCReturn; } FILE *fp = fopen(path, "w"); if (fp == NULL) { SCLogInfo("couldn't open waldo: %s", strerror(errno)); SCReturn; } snprintf(line, sizeof(line), "%u\n", SC_ATOMIC_GET(file_id)); if (fwrite(line, strlen(line), 1, fp) != 1) { SCLogError(SC_ERR_FWRITE, "fwrite failed: %s", strerror(errno)); } fclose(fp); } /** \brief Create a new http log LogFilestoreCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFilestoreCtx* to the file_ctx if succesful * */ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) { LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("Could not create new LogFilestoreCtx"); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; output_ctx->data = NULL; output_ctx->DeInit = LogFilestoreLogDeInitCtx; char *s_default_log_dir = NULL; if (ConfGet("default-log-dir", &s_default_log_dir) != 1) s_default_log_dir = DEFAULT_LOG_DIR; const char *s_base_dir = NULL; s_base_dir = ConfNodeLookupChildValue(conf, "log-dir"); if (s_base_dir == NULL || strlen(s_base_dir) == 0) { strlcpy(g_logfile_base_dir, s_default_log_dir, sizeof(g_logfile_base_dir)); } else { if (PathIsAbsolute(s_base_dir)) { strlcpy(g_logfile_base_dir, s_base_dir, sizeof(g_logfile_base_dir)); } else { snprintf(g_logfile_base_dir, sizeof(g_logfile_base_dir), "%s/%s", s_default_log_dir, s_base_dir); } } const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); SCLogInfo("forcing magic lookup for stored files"); } const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); if (force_md5 != NULL && ConfValIsTrue(force_md5)) { #ifdef HAVE_NSS FileForceMd5Enable(); SCLogInfo("forcing md5 calculation for stored files"); #else SCLogInfo("md5 calculation requires linking against libnss"); #endif } const char *waldo = ConfNodeLookupChildValue(conf, "waldo"); if (waldo != NULL && strlen(waldo) > 0) { if (PathIsAbsolute(waldo)) { snprintf(g_waldo, sizeof(g_waldo), "%s", waldo); } else { snprintf(g_waldo, sizeof(g_waldo), "%s/%s", s_default_log_dir, waldo); } SCLogInfo("loading waldo file %s", g_waldo); LogFilestoreLogLoadWaldo(g_waldo); } SCLogInfo("storing files in %s", g_logfile_base_dir); SCReturnPtr(output_ctx, "OutputCtx"); } /** * \internal * * \brief deinit the log ctx and write out the waldo * * \param output_ctx output context to deinit */ static void LogFilestoreLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; LogFileFreeCtx(logfile_ctx); free(output_ctx); if (strlen(g_waldo) > 0) { LogFilestoreLogStoreWaldo(g_waldo); } } /** \brief Read the config set the file pointer, open the file * \param file_ctx pointer to a created LogFilestoreCtx using LogFilestoreNewCtx() * \param config_file for loading separate configs * \return -1 if failure, 0 if succesful * */ int LogFilestoreLogOpenFileCtx(LogFileCtx *file_ctx, const char *filename, const char *mode) { return 0; } suricata-1.4.7/src/detect-engine-hcd.h0000644000000000000000000000235312253546156014450 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HCD_H__ #define __DETECT_ENGINE_HCD_H__ #include "app-layer-htp.h" int DetectEngineInspectHttpCookie(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *, Flow *, HtpState *, uint8_t); void DetectEngineHttpCookieRegisterTests(void); #endif /* __DETECT_ENGINE_HCD_H__ */ suricata-1.4.7/src/app-layer-smb.h0000644000000000000000000001136012253546156013650 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Kirby Kuehl */ #ifndef __APP_LAYER_SMB_H__ #define __APP_LAYER_SMB_H__ #include "suricata-common.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "flow.h" #include "stream.h" #include "app-layer-nbss.h" #include "app-layer-dcerpc-common.h" typedef struct SMBHdr_ { uint8_t protocol[4]; uint8_t command; uint32_t status; uint8_t flags; uint16_t flags2; uint16_t pidhigh; uint64_t securitysignature; uint16_t unused; uint16_t tid; uint16_t pid; uint16_t uid; uint16_t mid; } SMBHdr; #define SMB_HDR_LEN 32 #define MINIMUM_SMB_LEN 35 #define NBSS_SMB_HDRS_LEN 36 typedef struct SMBWordCount_ { uint8_t wordcount; uint8_t wordcountleft; uint8_t *words; } SMBWordCount; typedef struct SMBByteCount_ { uint8_t bytecountbytes; uint16_t bytecount; uint16_t bytecountleft; uint8_t *bytes; } SMBByteCount; typedef struct SMBAndX_ { uint8_t isandx; uint8_t paddingparsed; uint8_t andxcommand; uint8_t maxchainedandx; uint16_t andxoffset; uint16_t andxbytesprocessed; uint16_t datalength; uint16_t datalengthhigh; uint64_t dataoffset; } SMBAndX; typedef struct SMBState_ { NBSSHdr nbss; uint16_t transaction_id; uint16_t bytesprocessed; SMBHdr smb; SMBWordCount wordcount; SMBByteCount bytecount; SMBAndX andx; DCERPC dcerpc; uint8_t dcerpc_present; uint8_t data_needed_for_dir; } SMBState; #define SMB_FLAGS_SERVER_TO_REDIR 0x80 #define SMB_NO_SECONDARY_ANDX_COMMAND 0xff /* http://msdn.microsoft.com/en-us/library/dd327674.aspx */ #define SMB_COM_CREATE_DIRECTORY 0x00 #define SMB_COM_DELETE_DIRECTORY 0x01 #define SMB_COM_OPEN 0x02 #define SMB_COM_CREATE 0x03 #define SMB_COM_CLOSE 0x04 #define SMB_COM_FLUSH 0x05 #define SMB_COM_DELETE 0x06 #define SMB_COM_RENAME 0x07 #define SMB_COM_QUERY_INFORMATION 0x08 #define SMB_COM_SET_INFORMATION 0x09 #define SMB_COM_READ 0x0A #define SMB_COM_WRITE 0x0B #define SMB_COM_LOCK_BYTE_RANGE 0x0C #define SMB_COM_UNLOCK_BYTE_RANGE 0x0D #define SMB_COM_CREATE_TEMPORARY 0x0E #define SMB_COM_CREATE_NEW 0x0F #define SMB_COM_CHECK_DIRECTORY 0x10 #define SMB_COM_PROCESS_EXIT 0x11 #define SMB_COM_SEEK 0x12 #define SMB_COM_LOCK_AND_READ 0x13 #define SMB_COM_WRITE_AND_UNLOCK 0x14 #define SMB_COM_READ_RAW 0x1A #define SMB_COM_READ_MPX 0x1B #define SMB_COM_READ_MPX_SECONDARY 0x1C #define SMB_COM_WRITE_RAW 0x1D #define SMB_COM_WRITE_MPX 0x1E #define SMB_COM_WRITE_COMPLETE 0x20 #define SMB_COM_SET_INFORMATION2 0x22 #define SMB_COM_QUERY_INFORMATION2 0x23 #define SMB_COM_LOCKING_ANDX 0x24 #define SMB_COM_TRANSACTION 0x25 #define SMB_COM_TRANSACTION_SECONDARY 0x26 #define SMB_COM_IOCTL 0x27 #define SMB_COM_IOCTL_SECONDARY 0x28 #define SMB_COM_COPY 0x29 #define SMB_COM_MOVE 0x2A #define SMB_COM_ECHO 0x2B #define SMB_COM_WRITE_AND_CLOSE 0x2C #define SMB_COM_OPEN_ANDX 0x2D #define SMB_COM_READ_ANDX 0x2E #define SMB_COM_WRITE_ANDX 0x2F #define SMB_COM_CLOSE_AND_TREE_DISC 0x31 #define SMB_COM_TRANSACTION2 0x32 #define SMB_COM_TRANSACTION2_SECONDARY 0x33 #define SMB_COM_FIND_CLOSE2 0x34 #define SMB_COM_FIND_NOTIFY_CLOSE 0x35 #define SMB_COM_TREE_CONNECT 0x70 #define SMB_COM_TREE_DISCONNECT 0x71 #define SMB_COM_NEGOTIATE 0x72 #define SMB_COM_SESSION_SETUP_ANDX 0x73 #define SMB_COM_LOGOFF_ANDX 0x74 #define SMB_COM_TREE_CONNECT_ANDX 0x75 #define SMB_COM_QUERY_INFORMATION_DISK 0x80 #define SMB_COM_SEARCH 0x81 #define SMB_COM_FIND 0x82 #define SMB_COM_FIND_UNIQUE 0x83 #define SMB_COM_NT_TRANSACT 0xA0 #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 #define SMB_COM_NT_CREATE_ANDX 0xA2 #define SMB_COM_NT_CANCEL 0xA4 #define SMB_COM_NT_RENAME 0xA5 #define SMB_COM_OPEN_PRINT_FILE 0xC0 #define SMB_COM_WRITE_PRINT_FILE 0xC1 #define SMB_COM_CLOSE_PRINT_FILE 0xC2 #define SMB_COM_GET_PRINT_QUEUE 0xC3 void RegisterSMBParsers(void); void SMBParserRegisterTests(void); int isAndX(SMBState *smb_state); #endif /* __APP_LAYER_SMB_H__ */ suricata-1.4.7/src/detect-nocase.c0000644000000000000000000001171512253546156013714 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the nocase keyword */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "flow-var.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-pcre.h" #include "detect-http-client-body.h" #include "detect-http-cookie.h" #include "detect-http-header.h" #include "detect-http-method.h" #include "detect-http-uri.h" #include "util-debug.h" static int DetectNocaseSetup (DetectEngineCtx *, Signature *, char *); void DetectNocaseRegister (void) { sigmatch_table[DETECT_NOCASE].name = "nocase"; sigmatch_table[DETECT_NOCASE].desc = "modify content match to be case insensitive"; sigmatch_table[DETECT_NOCASE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#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; sigmatch_table[DETECT_NOCASE].flags |= SIGMATCH_PAYLOAD; } /** * \internal * \brief Apply the nocase keyword to the last pattern match, either content or uricontent * \param det_ctx detection engine ctx * \param s signature * \param nullstr should be null * \retval 0 ok * \retval -1 failure */ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr) { SCEnter(); if (nullstr != NULL) { SCLogError(SC_ERR_INVALID_VALUE, "nocase has value"); SCReturnInt(-1); } /* Search for the first previous SigMatch that supports nocase */ SigMatch *pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "\"nocase\" needs a preceding " "content, uricontent, http_client_body, http_server_body, " "http_header, http_method, http_uri, http_cookie, " "http_raw_uri, http_stat_msg, http_stat_code, " "http_user_agent, http_host or http_raw_host option"); SCReturnInt(-1); } DetectContentData *cd = NULL; switch (pm->type) { case DETECT_CONTENT: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); SCReturnInt(-1); } if (cd->flags & DETECT_CONTENT_NOCASE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple nocase modifiers with the same content"); SCReturnInt(-1); } cd->flags |= DETECT_CONTENT_NOCASE; /* Recreate the context with nocase chars */ BoyerMooreCtxToNocase(cd->bm_ctx, cd->content, cd->content_len); break; /* should never happen */ default: SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "\"nocase\" needs a preceding " "content, uricontent, http_client_body, http_server_body, " "http_header, http_method, http_uri, http_cookie or " "http_raw_uri option"); SCReturnInt(-1); break; } SCReturnInt(0); } suricata-1.4.7/src/stream-tcp-inline.h0000644000000000000000000000214312253546156014531 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __STREAM_TCP_INLINE_H__ #define __STREAM_TCP_INLINE_H__ #include "stream-tcp-private.h" int StreamTcpInlineMode(void); int StreamTcpInlineSegmentCompare(TcpSegment *, TcpSegment *); void StreamTcpInlineSegmentReplacePacket(Packet *, TcpSegment *); void StreamTcpInlineRegisterTests(void); #endif /* __STREAM_TCP_INLINE_H__ */ suricata-1.4.7/src/util-validate.h0000644000000000000000000000743112253546156013747 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Functions & Macro's for validation of data structures. This is used for * code correctness. * * These will abort() the program if they fail, so they should _only_ be * used for testing. */ #ifndef __UTIL_VALIDATE_H__ #define __UTIL_VALIDATE_H__ #ifdef DEBUG_VALIDATION /** \brief test if a flow is locked. * * If trylock returns 0 it got a lock. Which means * the flow was previously unlocked. */ #define DEBUG_ASSERT_FLOW_LOCKED(f) do { \ if ((f) != NULL) { \ int r = SCMutexTrylock(&(f)->m); \ if (r == 0) { \ BUG_ON(1); \ } \ } \ } while(0) /** \brief validate the integrity of the flow * * BUG_ON's on problems */ #define DEBUG_VALIDATE_FLOW(f) do { \ if ((f) != NULL) { \ SCMutexLock(&(f)->m); \ BUG_ON((f)->flags & FLOW_IPV4 && \ (f)->flags & FLOW_IPV6); \ if ((f)->proto == IPPROTO_TCP) { \ BUG_ON((f)->alstate != NULL && \ (f)->alparser == NULL); \ } \ SCMutexUnlock(&(f)->m); \ } \ } while(0) /** \brief validate the integrity of the packet * * BUG_ON's on problems */ #define DEBUG_VALIDATE_PACKET(p) do { \ if ((p) != NULL) { \ if ((p)->flow != NULL) { \ DEBUG_VALIDATE_FLOW((p)->flow); \ } \ if ((p)->proto == IPPROTO_TCP) { \ BUG_ON((p)->tcph == NULL); \ } else if ((p)->proto == IPPROTO_UDP) { \ BUG_ON((p)->udph == NULL); \ } else if ((p)->proto == IPPROTO_ICMP) { \ BUG_ON((p)->icmpv4h == NULL); \ } else if ((p)->proto == IPPROTO_SCTP) { \ BUG_ON((p)->sctph == NULL); \ } else if ((p)->proto == IPPROTO_ICMPV6) { \ BUG_ON((p)->icmpv6h == NULL); \ } \ if ((p)->payload_len > 0) { \ BUG_ON((p)->payload == NULL); \ } \ BUG_ON((p)->ip4h != NULL && (p)->ip6h != NULL); \ BUG_ON((p)->flowflags != 0 && (p)->flow == NULL); \ BUG_ON((p)->flowflags & FLOW_PKT_TOSERVER &&\ (p)->flowflags & FLOW_PKT_TOCLIENT); \ } \ } while(0) #else /* DEBUG_VALIDATE */ #define DEBUG_ASSERT_FLOW_LOCKED(f) #define DEBUG_VALIDATE_FLOW(f) #define DEBUG_VALIDATE_PACKET(p) #endif /* DEBUG_VALIDATE */ #endif /* __UTIL_VALIDATE_H__ */ suricata-1.4.7/src/detect-engine.c0000644000000000000000000020476312253546156013720 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "conf.h" #include "conf-yaml-loader.h" #include "app-layer-htp.h" #include "detect-parse.h" #include "detect-engine-sigorder.h" #include "detect-engine-siggroup.h" #include "detect-engine-address.h" #include "detect-engine-port.h" #include "detect-engine-mpm.h" #include "detect-engine-hcbd.h" #include "detect-engine-iponly.h" #include "detect-engine-tag.h" #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-hua.h" #include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" #include "detect-engine-file.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "detect-byte-extract.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-engine-threshold.h" #include "util-classification-config.h" #include "util-reference-config.h" #include "util-threshold-config.h" #include "util-error.h" #include "util-hash.h" #include "util-byte.h" #include "util-debug.h" #include "util-unittest.h" #include "util-action.h" #include "util-magic.h" #include "util-signal.h" #include "util-var-name.h" #include "tm-threads.h" #include "runmodes.h" #ifdef PROFILING #include "util-profiling.h" #endif #include "reputation.h" #define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000 static uint32_t detect_engine_ctx_id = 1; static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *, void *, void **); static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); /* 2 - for each direction */ DetectEngineAppInspectionEngine *app_inspection_engine[ALPROTO_MAX][2]; #if 0 static void DetectEnginePrintAppInspectionEngines(DetectEngineAppInspectionEngine *list[][2]) { printf("\n"); uint16_t alproto = ALPROTO_UNKNOWN + 1; for ( ; alproto < ALPROTO_MAX; alproto++) { printf("alproto - %d\n", alproto); int dir = 0; for ( ; dir < 2; dir++) { printf(" direction - %d\n", dir); DetectEngineAppInspectionEngine *engine = list[alproto][dir]; while (engine != NULL) { printf(" engine->alproto - %"PRIu16"\n", engine->alproto); printf(" engine->dir - %"PRIu16"\n", engine->dir); printf(" engine->sm_list - %d\n", engine->sm_list); printf(" engine->inspect_flags - %"PRIu32"\n", engine->inspect_flags); printf(" engine->match_flags - %"PRIu32"\n", engine->match_flags); printf("\n"); engine = engine->next; } } /* for ( ; dir < 2; dir++) */ } /* for ( ; alproto < ALPROTO_MAX; alproto++) */ return; } #endif void DetectEngineRegisterAppInspectionEngines(void) { struct tmp_t { uint16_t alproto; int32_t sm_list; uint32_t inspect_flags; uint32_t match_flags; uint16_t dir; int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, int32_t tx_id); }; struct tmp_t data_toserver[] = { { ALPROTO_HTTP, DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, DE_STATE_FLAG_URI_MATCH, 0, DetectEngineInspectPacketUris }, { ALPROTO_HTTP, DETECT_SM_LIST_HCBDMATCH, DE_STATE_FLAG_HCBD_INSPECT, DE_STATE_FLAG_HCBD_MATCH, 0, DetectEngineInspectHttpClientBody }, { ALPROTO_HTTP, DETECT_SM_LIST_HHDMATCH, DE_STATE_FLAG_HHD_INSPECT, DE_STATE_FLAG_HHD_MATCH, 0, DetectEngineInspectHttpHeader }, { ALPROTO_HTTP, DETECT_SM_LIST_HRHDMATCH, DE_STATE_FLAG_HRHD_INSPECT, DE_STATE_FLAG_HRHD_MATCH, 0, DetectEngineInspectHttpRawHeader }, { ALPROTO_HTTP, DETECT_SM_LIST_HMDMATCH, DE_STATE_FLAG_HMD_INSPECT, DE_STATE_FLAG_HMD_MATCH, 0, DetectEngineInspectHttpMethod }, { ALPROTO_HTTP, DETECT_SM_LIST_HCDMATCH, DE_STATE_FLAG_HCD_INSPECT, DE_STATE_FLAG_HCD_MATCH, 0, DetectEngineInspectHttpCookie }, { ALPROTO_HTTP, DETECT_SM_LIST_HRUDMATCH, DE_STATE_FLAG_HRUD_INSPECT, DE_STATE_FLAG_HRUD_MATCH, 0, DetectEngineInspectHttpRawUri }, { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DE_STATE_FLAG_FILE_TS_INSPECT, DE_STATE_FLAG_FILE_TS_MATCH, 0, DetectFileInspectHttp }, { ALPROTO_HTTP, DETECT_SM_LIST_HUADMATCH, DE_STATE_FLAG_HUAD_INSPECT, DE_STATE_FLAG_HUAD_MATCH, 0, DetectEngineInspectHttpUA }, { ALPROTO_HTTP, DETECT_SM_LIST_HHHDMATCH, DE_STATE_FLAG_HHHD_INSPECT, DE_STATE_FLAG_HHHD_MATCH, 0, DetectEngineInspectHttpHH }, { ALPROTO_HTTP, DETECT_SM_LIST_HRHHDMATCH, DE_STATE_FLAG_HRHHD_INSPECT, DE_STATE_FLAG_HRHHD_MATCH, 0, DetectEngineInspectHttpHRH }, }; struct tmp_t data_toclient[] = { { ALPROTO_HTTP, DETECT_SM_LIST_HSBDMATCH, DE_STATE_FLAG_HSBD_INSPECT, DE_STATE_FLAG_HSBD_MATCH, 1, DetectEngineInspectHttpServerBody }, { ALPROTO_HTTP, DETECT_SM_LIST_HHDMATCH, DE_STATE_FLAG_HHD_INSPECT, DE_STATE_FLAG_HHD_MATCH, 1, DetectEngineInspectHttpHeader }, { ALPROTO_HTTP, DETECT_SM_LIST_HRHDMATCH, DE_STATE_FLAG_HRHD_INSPECT, DE_STATE_FLAG_HRHD_MATCH, 1, DetectEngineInspectHttpRawHeader }, { ALPROTO_HTTP, DETECT_SM_LIST_HCDMATCH, DE_STATE_FLAG_HCD_INSPECT, DE_STATE_FLAG_HCD_MATCH, 1, DetectEngineInspectHttpCookie }, { ALPROTO_HTTP, DETECT_SM_LIST_FILEMATCH, DE_STATE_FLAG_FILE_TC_INSPECT, DE_STATE_FLAG_FILE_TC_MATCH, 1, DetectFileInspectHttp }, { ALPROTO_HTTP, DETECT_SM_LIST_HSMDMATCH, DE_STATE_FLAG_HSMD_INSPECT, DE_STATE_FLAG_HSMD_MATCH, 1, DetectEngineInspectHttpStatMsg }, { ALPROTO_HTTP, DETECT_SM_LIST_HSCDMATCH, DE_STATE_FLAG_HSCD_INSPECT, DE_STATE_FLAG_HSCD_MATCH, 1, DetectEngineInspectHttpStatCode } }; size_t i; for (i = 0 ; i < sizeof(data_toserver) / sizeof(struct tmp_t); i++) { DetectEngineRegisterAppInspectionEngine(data_toserver[i].alproto, data_toserver[i].dir, data_toserver[i].sm_list, data_toserver[i].inspect_flags, data_toserver[i].match_flags, data_toserver[i].Callback, app_inspection_engine); } for (i = 0 ; i < sizeof(data_toclient) / sizeof(struct tmp_t); i++) { DetectEngineRegisterAppInspectionEngine(data_toclient[i].alproto, data_toclient[i].dir, data_toclient[i].sm_list, data_toclient[i].inspect_flags, data_toclient[i].match_flags, data_toclient[i].Callback, app_inspection_engine); } #if 0 DetectEnginePrintAppInspectionEngines(app_inspection_engine); #endif return; } static void AppendAppInspectionEngine(DetectEngineAppInspectionEngine *engine, DetectEngineAppInspectionEngine *list[][2]) { /* append to the list */ DetectEngineAppInspectionEngine *tmp = list[engine->alproto][engine->dir]; DetectEngineAppInspectionEngine *insert = NULL; while (tmp != NULL) { if (tmp->dir == engine->dir && (tmp->sm_list == engine->sm_list || tmp->inspect_flags == engine->inspect_flags || tmp->match_flags == engine->match_flags)) { SCLogError(SC_ERR_DETECT_PREPARE, "App Inspection Engine already " "registered for this direction(%"PRIu16") ||" "sm_list(%d) || " "[match(%"PRIu32")|inspect(%"PRIu32")]_flags", tmp->dir, tmp->sm_list, tmp->inspect_flags, tmp->match_flags); exit(EXIT_FAILURE); } insert = tmp; tmp = tmp->next; } if (insert == NULL) list[engine->alproto][engine->dir] = engine; else insert->next = engine; return; } void DetectEngineRegisterAppInspectionEngine(uint16_t alproto, uint16_t dir, int32_t sm_list, uint32_t inspect_flags, uint32_t match_flags, int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, int32_t tx_id), DetectEngineAppInspectionEngine *list[][2]) { if ((list == NULL) || (alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_FAILED) || (dir > 1) || (sm_list < DETECT_SM_LIST_MATCH || sm_list >= DETECT_SM_LIST_MAX) || (Callback == NULL)) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments"); exit(EXIT_FAILURE); } DetectEngineAppInspectionEngine *new_engine = SCMalloc(sizeof(DetectEngineAppInspectionEngine)); if (unlikely(new_engine == NULL)) { exit(EXIT_FAILURE); } memset(new_engine, 0, sizeof(*new_engine)); new_engine->alproto = alproto; new_engine->dir = dir; new_engine->sm_list = sm_list; new_engine->inspect_flags = inspect_flags; new_engine->match_flags = match_flags; new_engine->Callback = Callback; AppendAppInspectionEngine(new_engine, list); return; } static void *DetectEngineLiveRuleSwap(void *arg) { SCEnter(); if (SCSetThreadName("LiveRuleSwap") < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } SCLogInfo("===== Starting live rule swap triggered by user signal USR2 ====="); ThreadVars *tv_local = (ThreadVars *)arg; /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); if (tv_local->thread_setup_flags != 0) TmThreadSetupOptions(tv_local); /* release TmThreadSpawn */ TmThreadsSetFlag(tv_local, THV_INIT_DONE); ConfDeInit(); ConfInit(); /* re-load the yaml file */ if (conf_filename != NULL) { if (ConfYamlLoadFile(conf_filename) != 0) { /* Error already displayed. */ exit(EXIT_FAILURE); } ConfNode *file; ConfNode *includes = ConfGetNode("include"); if (includes != NULL) { TAILQ_FOREACH(file, &includes->head, next) { char *ifile = ConfLoadCompleteIncludePath(file->val); SCLogInfo("Live Rule Swap: Including: %s", ifile); if (ConfYamlLoadFile(ifile) != 0) { /* Error already displayed. */ exit(EXIT_FAILURE); } } } } /* if (conf_filename != NULL) */ #if 0 ConfDump(); #endif DetectEngineCtx *de_ctx = DetectEngineCtxInit(); SCClassConfLoadClassficationConfigFile(de_ctx); SCRConfLoadReferenceConfigFile(de_ctx); if (ActionInitConfig() < 0) { exit(EXIT_FAILURE); } if (SigLoadSignatures(de_ctx, NULL, FALSE) < 0) { SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); if (de_ctx->failure_fatal) exit(EXIT_FAILURE); } SCThresholdConfInitContext(de_ctx, NULL); /* start the process of swapping detect threads ctxs */ SCMutexLock(&tv_root_lock); int no_of_detect_tvs = 0; ThreadVars *tv = tv_root[TVT_PPT]; while (tv) { /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { TmModule *tm = TmModuleGetById(slots->tm_id); if (suricata_ctl_flags != 0) { TmThreadsSetFlag(tv_local, THV_CLOSED); SCLogInfo("===== Live rule swap premature exit, since " "engine is in shutdown phase ====="); UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); SCMutexUnlock(&tv_root_lock); pthread_exit(NULL); } if (!(tm->flags & TM_FLAG_DETECT_TM)) { slots = slots->slot_next; continue; } no_of_detect_tvs++; slots = slots->slot_next; } tv = tv->next; } DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs]; DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs]; ThreadVars *detect_tvs[no_of_detect_tvs]; /* all receive threads are part of packet processing threads */ tv = tv_root[TVT_PPT]; int i = 0; while (tv) { /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { TmModule *tm = TmModuleGetById(slots->tm_id); if (!(tm->flags & TM_FLAG_DETECT_TM)) { slots = slots->slot_next; continue; } old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data); detect_tvs[i] = tv; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineThreadCtxInitForLiveRuleSwap(tv, (void *)de_ctx, (void **)&det_ctx); SCLogDebug("live rule swap done with new det_ctx - %p and de_ctx " "- %p\n", det_ctx, de_ctx); new_det_ctx[i] = det_ctx; i++; SCLogDebug("swapping new det_ctx - %p with older one - %p", det_ctx, SC_ATOMIC_GET(slots->slot_data)); (void)SC_ATOMIC_SET(slots->slot_data, det_ctx); slots = slots->slot_next; } tv = tv->next; } SCMutexUnlock(&tv_root_lock); SCLogInfo("Live rule swap has swapped %d old det_ctx's with new ones, " "along with the new de_ctx", no_of_detect_tvs); for (i = 0; i < no_of_detect_tvs; i++) { int break_out = 0; int pseudo_pkt_inserted = 0; usleep(1000); while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) { if (suricata_ctl_flags != 0) { break_out = 1; break; } if (pseudo_pkt_inserted == 0) { pseudo_pkt_inserted = 1; if (detect_tvs[i]->inq != NULL) { Packet *p = PacketGetFromAlloc(); if (p != NULL) { p->flags |= PKT_PSEUDO_STREAM_END; PacketQueue *q = &trans_q[detect_tvs[i]->inq->id]; SCMutexLock(&q->mutex_q); PacketEnqueue(q, p); SCCondSignal(&q->cond_q); SCMutexUnlock(&q->mutex_q); } } } usleep(1000); } if (break_out) break; SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]); } /* this is to make sure that if someone initiated shutdown during a live * rule swap, the live rule swap won't clean up the old det_ctx and * de_ctx, till all detect threads have stopped working and sitting * silently after setting RUNNING_DONE flag and while waiting for * THV_DEINIT flag */ if (i != no_of_detect_tvs) { ThreadVars *tv = tv_root[TVT_PPT]; while (tv) { /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { TmModule *tm = TmModuleGetById(slots->tm_id); if (!(tm->flags & TM_FLAG_DETECT_TM)) { slots = slots->slot_next; continue; } while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { usleep(100); } slots = slots->slot_next; } tv = tv->next; } } /* free all the ctxs */ DetectEngineCtx *old_de_ctx = old_det_ctx[0]->de_ctx; for (i = 0; i < no_of_detect_tvs; i++) { SCLogDebug("Freeing old_det_ctx - %p used by detect", old_det_ctx[i]); DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]); } DetectEngineCtxFree(old_de_ctx); SRepReloadComplete(); /* reset the handler */ UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); TmThreadsSetFlag(tv_local, THV_CLOSED); SCLogInfo("===== Live rule swap DONE ====="); pthread_exit(NULL); return NULL; } void DetectEngineSpawnLiveRuleSwapMgmtThread(void) { SCEnter(); SCLogDebug("Spawning mgmt thread for live rule swap"); ThreadVars *tv = TmThreadCreateMgmtThread("DetectEngineLiveRuleSwap", DetectEngineLiveRuleSwap, 0); if (tv == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "Live rule swap thread spawn failed"); exit(EXIT_FAILURE); } TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); if (TmThreadSpawn(tv) != 0) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " "DetectEngineLiveRuleSwap"); exit(EXIT_FAILURE); } SCReturn; } DetectEngineCtx *DetectEngineGetGlobalDeCtx(void) { DetectEngineCtx *de_ctx = NULL; SCMutexLock(&tv_root_lock); ThreadVars *tv = tv_root[TVT_PPT]; while (tv) { /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { TmModule *tm = TmModuleGetById(slots->tm_id); if (tm->flags & TM_FLAG_DETECT_TM) { DetectEngineThreadCtx *det_ctx = SC_ATOMIC_GET(slots->slot_data); de_ctx = det_ctx->de_ctx; SCMutexUnlock(&tv_root_lock); return de_ctx; } slots = slots->slot_next; } tv = tv->next; } SCMutexUnlock(&tv_root_lock); return NULL; } DetectEngineCtx *DetectEngineCtxInit(void) { DetectEngineCtx *de_ctx; ConfNode *seq_node = NULL; ConfNode *insp_recursion_limit_node = NULL; ConfNode *de_engine_node = NULL; char *insp_recursion_limit = NULL; de_ctx = SCMalloc(sizeof(DetectEngineCtx)); if (unlikely(de_ctx == NULL)) goto error; memset(de_ctx,0,sizeof(DetectEngineCtx)); if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) { SCLogDebug("ConfGetBool could not load the value."); } de_engine_node = ConfGetNode("detect-engine"); if (de_engine_node != NULL) { TAILQ_FOREACH(seq_node, &de_engine_node->head, next) { if (strcmp(seq_node->val, "inspection-recursion-limit") != 0) continue; insp_recursion_limit_node = ConfNodeLookupChild(seq_node, seq_node->val); if (insp_recursion_limit_node == NULL) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf " "entry for detect-engine:inspection-recursion-limit"); break; } insp_recursion_limit = insp_recursion_limit_node->val; SCLogDebug("Found detect-engine:inspection-recursion-limit - %s:%s", insp_recursion_limit_node->name, insp_recursion_limit_node->val); break; } } if (insp_recursion_limit != NULL) { de_ctx->inspection_recursion_limit = atoi(insp_recursion_limit); } else { de_ctx->inspection_recursion_limit = DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; } if (de_ctx->inspection_recursion_limit == 0) de_ctx->inspection_recursion_limit = -1; SCLogDebug("de_ctx->inspection_recursion_limit: %d", de_ctx->inspection_recursion_limit); de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); DetectEngineCtxLoadConf(de_ctx); SigGroupHeadHashInit(de_ctx); SigGroupHeadMpmHashInit(de_ctx); SigGroupHeadMpmUriHashInit(de_ctx); SigGroupHeadSPortHashInit(de_ctx); SigGroupHeadDPortHashInit(de_ctx); DetectPortSpHashInit(de_ctx); DetectPortDpHashInit(de_ctx); ThresholdHashInit(de_ctx); VariableNameInitHash(de_ctx); DetectParseDupSigHashInit(de_ctx); de_ctx->mpm_pattern_id_store = MpmPatternIdTableInitHash(); if (de_ctx->mpm_pattern_id_store == NULL) { goto error; } de_ctx->id = detect_engine_ctx_id++; /* init iprep... ignore errors for now */ (void)SRepInit(de_ctx); return de_ctx; error: return NULL; } static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx) { DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list; while (item) { DetectEngineThreadKeywordCtxItem *next = item->next; SCFree(item); item = next; } de_ctx->keyword_list = NULL; } void DetectEngineCtxFree(DetectEngineCtx *de_ctx) { if (de_ctx == NULL) return; #ifdef PROFILING if (de_ctx->profile_ctx != NULL) { SCProfilingRuleDestroyCtx(de_ctx->profile_ctx); de_ctx->profile_ctx = NULL; } #endif /* Normally the hashes are freed elsewhere, but * to be sure look at them again here. */ MpmPatternIdTableFreeHash(de_ctx->mpm_pattern_id_store); /* normally cleaned up in SigGroupBuild */ SigGroupHeadHashFree(de_ctx); SigGroupHeadMpmHashFree(de_ctx); SigGroupHeadMpmUriHashFree(de_ctx); SigGroupHeadSPortHashFree(de_ctx); SigGroupHeadDPortHashFree(de_ctx); DetectParseDupSigHashFree(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); DetectPortSpHashFree(de_ctx); DetectPortDpHashFree(de_ctx); ThresholdContextDestroy(de_ctx); SigCleanSignatures(de_ctx); VariableNameFreeHash(de_ctx); if (de_ctx->sig_array) SCFree(de_ctx->sig_array); SCClassConfDeInitContext(de_ctx); SCRConfDeInitContext(de_ctx); SigGroupCleanup(de_ctx); if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx); } DetectEngineCtxFreeThreadKeywordData(de_ctx); SCFree(de_ctx); //DetectAddressGroupPrintMemory(); //DetectSigGroupPrintMemory(); //DetectPortPrintMemory(); } /** \brief Function that load DetectEngineCtx config for grouping sigs * used by the engine * \retval 0 if no config provided, 1 if config was provided * and loaded successfuly */ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) { uint8_t profile = ENGINE_PROFILE_UNKNOWN; char *de_ctx_profile = NULL; const char *max_uniq_toclient_src_groups_str = NULL; const char *max_uniq_toclient_dst_groups_str = NULL; const char *max_uniq_toclient_sp_groups_str = NULL; const char *max_uniq_toclient_dp_groups_str = NULL; const char *max_uniq_toserver_src_groups_str = NULL; const char *max_uniq_toserver_dst_groups_str = NULL; const char *max_uniq_toserver_sp_groups_str = NULL; const char *max_uniq_toserver_dp_groups_str = NULL; char *sgh_mpm_context = NULL; ConfNode *de_ctx_custom = ConfGetNode("detect-engine"); ConfNode *opt = NULL; if (de_ctx_custom != NULL) { TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { if (strcmp(opt->val, "profile") == 0) { de_ctx_profile = opt->head.tqh_first->val; } else if (strcmp(opt->val, "sgh-mpm-context") == 0) { sgh_mpm_context = opt->head.tqh_first->val; } } } if (de_ctx_profile != NULL) { if (strcmp(de_ctx_profile, "low") == 0) { profile = ENGINE_PROFILE_LOW; } else if (strcmp(de_ctx_profile, "medium") == 0) { profile = ENGINE_PROFILE_MEDIUM; } else if (strcmp(de_ctx_profile, "high") == 0) { profile = ENGINE_PROFILE_HIGH; } else if (strcmp(de_ctx_profile, "custom") == 0) { profile = ENGINE_PROFILE_CUSTOM; } SCLogDebug("Profile for detection engine groups is \"%s\"", de_ctx_profile); } else { SCLogDebug("Profile for detection engine groups not provided " "at suricata.yaml. Using default (\"medium\")."); } /* detect-engine.sgh-mpm-context option parsing */ if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) { /* for now, since we still haven't implemented any intelligence into * understanding the patterns and distributing mpm_ctx across sgh */ if (de_ctx->mpm_matcher == MPM_AC || de_ctx->mpm_matcher == MPM_AC_GFBS || de_ctx->mpm_matcher == MPM_AC_BS) { de_ctx->sgh_mpm_context = ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE; } else { de_ctx->sgh_mpm_context = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL; } } else { if (strcmp(sgh_mpm_context, "single") == 0) { de_ctx->sgh_mpm_context = ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE; } else if (strcmp(sgh_mpm_context, "full") == 0) { de_ctx->sgh_mpm_context = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL; } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "You have supplied an " "invalid conf value for detect-engine.sgh-mpm-context-" "%s", sgh_mpm_context); exit(EXIT_FAILURE); } } if (run_mode == RUNMODE_UNITTEST) { de_ctx->sgh_mpm_context = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL; } opt = NULL; switch (profile) { case ENGINE_PROFILE_LOW: de_ctx->max_uniq_toclient_src_groups = 2; de_ctx->max_uniq_toclient_dst_groups = 2; de_ctx->max_uniq_toclient_sp_groups = 2; de_ctx->max_uniq_toclient_dp_groups = 3; de_ctx->max_uniq_toserver_src_groups = 2; de_ctx->max_uniq_toserver_dst_groups = 2; de_ctx->max_uniq_toserver_sp_groups = 2; de_ctx->max_uniq_toserver_dp_groups = 3; break; case ENGINE_PROFILE_HIGH: de_ctx->max_uniq_toclient_src_groups = 15; de_ctx->max_uniq_toclient_dst_groups = 15; de_ctx->max_uniq_toclient_sp_groups = 15; de_ctx->max_uniq_toclient_dp_groups = 20; de_ctx->max_uniq_toserver_src_groups = 15; de_ctx->max_uniq_toserver_dst_groups = 15; de_ctx->max_uniq_toserver_sp_groups = 15; de_ctx->max_uniq_toserver_dp_groups = 40; break; case ENGINE_PROFILE_CUSTOM: TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { if (strcmp(opt->val, "custom-values") == 0) { max_uniq_toclient_src_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toclient-src-groups"); max_uniq_toclient_dst_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toclient-dst-groups"); max_uniq_toclient_sp_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toclient-sp-groups"); max_uniq_toclient_dp_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toclient-dp-groups"); max_uniq_toserver_src_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toserver-src-groups"); max_uniq_toserver_dst_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toserver-dst-groups"); max_uniq_toserver_sp_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toserver-sp-groups"); max_uniq_toserver_dp_groups_str = ConfNodeLookupChildValue (opt->head.tqh_first, "toserver-dp-groups"); } } if (max_uniq_toclient_src_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_src_groups, 10, strlen(max_uniq_toclient_src_groups_str), (const char *)max_uniq_toclient_src_groups_str) <= 0) { de_ctx->max_uniq_toclient_src_groups = 4; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toclient-src-groups failed, using %u", max_uniq_toclient_src_groups_str, de_ctx->max_uniq_toclient_src_groups); } } else { de_ctx->max_uniq_toclient_src_groups = 4; } if (max_uniq_toclient_dst_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dst_groups, 10, strlen(max_uniq_toclient_dst_groups_str), (const char *)max_uniq_toclient_dst_groups_str) <= 0) { de_ctx->max_uniq_toclient_dst_groups = 4; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toclient-dst-groups failed, using %u", max_uniq_toclient_dst_groups_str, de_ctx->max_uniq_toclient_dst_groups); } } else { de_ctx->max_uniq_toclient_dst_groups = 4; } if (max_uniq_toclient_sp_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_sp_groups, 10, strlen(max_uniq_toclient_sp_groups_str), (const char *)max_uniq_toclient_sp_groups_str) <= 0) { de_ctx->max_uniq_toclient_sp_groups = 4; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toclient-sp-groups failed, using %u", max_uniq_toclient_sp_groups_str, de_ctx->max_uniq_toclient_sp_groups); } } else { de_ctx->max_uniq_toclient_sp_groups = 4; } if (max_uniq_toclient_dp_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dp_groups, 10, strlen(max_uniq_toclient_dp_groups_str), (const char *)max_uniq_toclient_dp_groups_str) <= 0) { de_ctx->max_uniq_toclient_dp_groups = 6; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toclient-dp-groups failed, using %u", max_uniq_toclient_dp_groups_str, de_ctx->max_uniq_toclient_dp_groups); } } else { de_ctx->max_uniq_toclient_dp_groups = 6; } if (max_uniq_toserver_src_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_src_groups, 10, strlen(max_uniq_toserver_src_groups_str), (const char *)max_uniq_toserver_src_groups_str) <= 0) { de_ctx->max_uniq_toserver_src_groups = 4; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toserver-src-groups failed, using %u", max_uniq_toserver_src_groups_str, de_ctx->max_uniq_toserver_src_groups); } } else { de_ctx->max_uniq_toserver_src_groups = 4; } if (max_uniq_toserver_dst_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dst_groups, 10, strlen(max_uniq_toserver_dst_groups_str), (const char *)max_uniq_toserver_dst_groups_str) <= 0) { de_ctx->max_uniq_toserver_dst_groups = 8; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toserver-dst-groups failed, using %u", max_uniq_toserver_dst_groups_str, de_ctx->max_uniq_toserver_dst_groups); } } else { de_ctx->max_uniq_toserver_dst_groups = 8; } if (max_uniq_toserver_sp_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_sp_groups, 10, strlen(max_uniq_toserver_sp_groups_str), (const char *)max_uniq_toserver_sp_groups_str) <= 0) { de_ctx->max_uniq_toserver_sp_groups = 4; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toserver-sp-groups failed, using %u", max_uniq_toserver_sp_groups_str, de_ctx->max_uniq_toserver_sp_groups); } } else { de_ctx->max_uniq_toserver_sp_groups = 4; } if (max_uniq_toserver_dp_groups_str != NULL) { if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dp_groups, 10, strlen(max_uniq_toserver_dp_groups_str), (const char *)max_uniq_toserver_dp_groups_str) <= 0) { de_ctx->max_uniq_toserver_dp_groups = 30; SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " "toserver-dp-groups failed, using %u", max_uniq_toserver_dp_groups_str, de_ctx->max_uniq_toserver_dp_groups); } } else { de_ctx->max_uniq_toserver_dp_groups = 30; } break; /* Default (or no config provided) is profile medium */ case ENGINE_PROFILE_MEDIUM: case ENGINE_PROFILE_UNKNOWN: default: de_ctx->max_uniq_toclient_src_groups = 4; de_ctx->max_uniq_toclient_dst_groups = 4; de_ctx->max_uniq_toclient_sp_groups = 4; de_ctx->max_uniq_toclient_dp_groups = 6; de_ctx->max_uniq_toserver_src_groups = 4; de_ctx->max_uniq_toserver_dst_groups = 8; de_ctx->max_uniq_toserver_sp_groups = 4; de_ctx->max_uniq_toserver_dp_groups = 30; break; } if (profile == ENGINE_PROFILE_UNKNOWN) return 0; return 1; } /* * getting & (re)setting the internal sig i */ //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx) { // return de_ctx->signum; //} void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx) { de_ctx->signum = 0; } static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { if (de_ctx->keyword_id > 0) { det_ctx->keyword_ctxs_array = SCMalloc(de_ctx->keyword_id * sizeof(void *)); if (det_ctx->keyword_ctxs_array == NULL) { SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx"); return TM_ECODE_FAILED; } memset(det_ctx->keyword_ctxs_array, 0x00, de_ctx->keyword_id * sizeof(void *)); det_ctx->keyword_ctxs_size = de_ctx->keyword_id; DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list; while (item) { det_ctx->keyword_ctxs_array[item->id] = item->InitFunc(item->data); if (det_ctx->keyword_ctxs_array[item->id] == NULL) { SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx " "for keyword \"%s\" failed", item->name); return TM_ECODE_FAILED; } item = item->next; } } return TM_ECODE_OK; } static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { if (de_ctx->keyword_id > 0) { DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list; while (item) { if (det_ctx->keyword_ctxs_array[item->id] != NULL) item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]); item = item->next; } det_ctx->keyword_ctxs_size = 0; SCFree(det_ctx->keyword_ctxs_array); det_ctx->keyword_ctxs_array = NULL; } } TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { DetectEngineCtx *de_ctx = (DetectEngineCtx *)initdata; if (de_ctx == NULL) return TM_ECODE_FAILED; DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) return TM_ECODE_FAILED; memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); det_ctx->de_ctx = de_ctx; /** \todo we still depend on the global mpm_ctx here * * Initialize the thread pattern match ctx with the max size * of the content and uricontent id's so our match lookup * table is always big enough */ PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher, DetectUricontentMaxId(de_ctx)); //PmqSetup(&det_ctx->pmq, DetectEngineGetMaxSigId(de_ctx), DetectContentMaxId(de_ctx)); PmqSetup(&det_ctx->pmq, 0, DetectContentMaxId(de_ctx)); int i; for (i = 0; i < 256; i++) { PmqSetup(&det_ctx->smsg_pmq[i], 0, DetectContentMaxId(de_ctx)); } /* IP-ONLY */ DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx); /* DeState */ if (de_ctx->sig_array_len > 0) { det_ctx->de_state_sig_array_len = de_ctx->sig_array_len; det_ctx->de_state_sig_array = SCMalloc(det_ctx->de_state_sig_array_len * sizeof(uint8_t)); if (det_ctx->de_state_sig_array == NULL) { return TM_ECODE_FAILED; } memset(det_ctx->de_state_sig_array, 0, det_ctx->de_state_sig_array_len * sizeof(uint8_t)); det_ctx->match_array_len = de_ctx->sig_array_len; det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *)); if (det_ctx->match_array == NULL) { return TM_ECODE_FAILED; } memset(det_ctx->match_array, 0, det_ctx->match_array_len * sizeof(Signature *)); } /** alert counter setup */ det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, SC_PERF_TYPE_UINT64, "NULL"); tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->sc_perf_pctx); /* this detection engine context belongs to this thread instance */ det_ctx->tv = tv; det_ctx->bj_values = SCMalloc(sizeof(*det_ctx->bj_values) * (de_ctx->byte_extract_max_local_id + 1)); if (det_ctx->bj_values == NULL) { return TM_ECODE_FAILED; } DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx); #ifdef PROFILING SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx); #endif SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect); *data = (void *)det_ctx; return TM_ECODE_OK; } /** * \internal * \brief This thread is an exact duplicate of DetectEngineThreadCtxInit(), * except that the counters API 2 calls doesn't let us use the same * init function. Once we have the new counters API it should let * us use the same init function. */ static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *tv, void *initdata, void **data) { DetectEngineCtx *de_ctx = (DetectEngineCtx *)initdata; if (de_ctx == NULL) return TM_ECODE_FAILED; DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) return TM_ECODE_FAILED; memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); det_ctx->de_ctx = de_ctx; /** \todo we still depend on the global mpm_ctx here * * Initialize the thread pattern match ctx with the max size * of the content and uricontent id's so our match lookup * table is always big enough */ PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher, DetectUricontentMaxId(de_ctx)); //PmqSetup(&det_ctx->pmq, DetectEngineGetMaxSigId(de_ctx), DetectContentMaxId(de_ctx)); PmqSetup(&det_ctx->pmq, 0, DetectContentMaxId(de_ctx)); int i; for (i = 0; i < 256; i++) { PmqSetup(&det_ctx->smsg_pmq[i], 0, DetectContentMaxId(de_ctx)); } /* IP-ONLY */ DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx); /* DeState */ if (de_ctx->sig_array_len > 0) { det_ctx->de_state_sig_array_len = de_ctx->sig_array_len; det_ctx->de_state_sig_array = SCMalloc(det_ctx->de_state_sig_array_len * sizeof(uint8_t)); if (det_ctx->de_state_sig_array == NULL) { return TM_ECODE_FAILED; } memset(det_ctx->de_state_sig_array, 0, det_ctx->de_state_sig_array_len * sizeof(uint8_t)); det_ctx->match_array_len = de_ctx->sig_array_len; det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *)); if (det_ctx->match_array == NULL) { return TM_ECODE_FAILED; } memset(det_ctx->match_array, 0, det_ctx->match_array_len * sizeof(Signature *)); } /** alert counter setup */ det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, SC_PERF_TYPE_UINT64, "NULL"); //tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); //SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, &tv->sc_perf_pctx); /* this detection engine context belongs to this thread instance */ det_ctx->tv = tv; det_ctx->bj_values = SCMalloc(sizeof(*det_ctx->bj_values) * (de_ctx->byte_extract_max_local_id + 1)); if (det_ctx->bj_values == NULL) { return TM_ECODE_FAILED; } DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx); #ifdef PROFILING SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx); #endif SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect); *data = (void *)det_ctx; return TM_ECODE_OK; } TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) { DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; if (det_ctx == NULL) { SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL"); return TM_ECODE_OK; } #ifdef PROFILING SCProfilingRuleThreadCleanup(det_ctx); #endif DetectEngineIPOnlyThreadDeinit(&det_ctx->io_ctx); /** \todo get rid of this static */ PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher); PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher); PmqFree(&det_ctx->pmq); int i; for (i = 0; i < 256; i++) { PmqFree(&det_ctx->smsg_pmq[i]); } if (det_ctx->de_state_sig_array != NULL) SCFree(det_ctx->de_state_sig_array); if (det_ctx->match_array != NULL) SCFree(det_ctx->match_array); if (det_ctx->bj_values != NULL) SCFree(det_ctx->bj_values); if (det_ctx->hsbd != NULL) { SCLogDebug("det_ctx hsbd %u", det_ctx->hsbd_buffers_list_len); for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) { if (det_ctx->hsbd[i].buffer != NULL) SCFree(det_ctx->hsbd[i].buffer); } SCFree(det_ctx->hsbd); } if (det_ctx->hcbd != NULL) { SCLogDebug("det_ctx hcbd %u", det_ctx->hcbd_buffers_list_len); for (i = 0; i < det_ctx->hcbd_buffers_list_len; i++) { if (det_ctx->hcbd[i].buffer != NULL) SCFree(det_ctx->hcbd[i].buffer); SCLogDebug("det_ctx->hcbd[i].buffer_size %u", det_ctx->hcbd[i].buffer_size); } SCFree(det_ctx->hcbd); } DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); SCFree(det_ctx); return TM_ECODE_OK; } void DetectEngineThreadCtxInfo(ThreadVars *t, DetectEngineThreadCtx *det_ctx) { /* XXX */ PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher); PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher); } /** \brief Register Thread keyword context Funcs * * \param de_ctx detection engine to register in * \param name keyword name for error printing * \param InitFunc function ptr * \param data keyword init data to pass to Func * \param FreeFunc function ptr * \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct) * * \retval id for retrieval of ctx at runtime * \retval -1 on error * * \note make sure "data" remains valid and it free'd elsewhere. It's * recommended to store it in the keywords global ctx so that * it's freed when the de_ctx is freed. */ int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode) { BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL || data == NULL); if (mode) { DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list; while (item != NULL) { if (strcmp(name, item->name) == 0) { return item->id; } item = item->next; } } DetectEngineThreadKeywordCtxItem *item = SCMalloc(sizeof(DetectEngineThreadKeywordCtxItem)); if (unlikely(item == NULL)) return -1; memset(item, 0x00, sizeof(DetectEngineThreadKeywordCtxItem)); item->InitFunc = InitFunc; item->FreeFunc = FreeFunc; item->data = data; item->name = name; item->next = de_ctx->keyword_list; de_ctx->keyword_list = item; item->id = de_ctx->keyword_id++; return item->id; } /** \brief Retrieve thread local keyword ctx by id * * \param det_ctx detection engine thread ctx to retrieve the ctx from * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at * keyword init. * * \retval ctx or NULL on error */ void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) { if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL) return NULL; return det_ctx->keyword_ctxs_array[id]; } /*************************************Unittest*********************************/ #ifdef UNITTESTS static int DetectEngineInitYamlConf(char *conf) { ConfCreateContextBackup(); ConfInit(); return ConfYamlLoadString(conf, strlen(conf)); } static void DetectEngineDeInitYamlConf(void) { ConfDeInit(); ConfRestoreContextBackup(); return; } static int DetectEngineTest01(void) { char *conf = "%YAML 1.1\n" "---\n" "detect-engine:\n" " - profile: medium\n" " - custom-values:\n" " toclient_src_groups: 2\n" " toclient_dst_groups: 2\n" " toclient_sp_groups: 2\n" " toclient_dp_groups: 3\n" " toserver_src_groups: 2\n" " toserver_dst_groups: 4\n" " toserver_sp_groups: 2\n" " toserver_dp_groups: 25\n" " - inspection-recursion-limit: 0\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (DetectEngineInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; result = (de_ctx->inspection_recursion_limit == -1); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); DetectEngineDeInitYamlConf(); return result; } static int DetectEngineTest02(void) { char *conf = "%YAML 1.1\n" "---\n" "detect-engine:\n" " - profile: medium\n" " - custom-values:\n" " toclient_src_groups: 2\n" " toclient_dst_groups: 2\n" " toclient_sp_groups: 2\n" " toclient_dp_groups: 3\n" " toserver_src_groups: 2\n" " toserver_dst_groups: 4\n" " toserver_sp_groups: 2\n" " toserver_dp_groups: 25\n" " - inspection-recursion-limit:\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (DetectEngineInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; result = (de_ctx->inspection_recursion_limit == -1); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); DetectEngineDeInitYamlConf(); return result; } static int DetectEngineTest03(void) { char *conf = "%YAML 1.1\n" "---\n" "detect-engine:\n" " - profile: medium\n" " - custom-values:\n" " toclient_src_groups: 2\n" " toclient_dst_groups: 2\n" " toclient_sp_groups: 2\n" " toclient_dp_groups: 3\n" " toserver_src_groups: 2\n" " toserver_dst_groups: 4\n" " toserver_sp_groups: 2\n" " toserver_dp_groups: 25\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (DetectEngineInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; result = (de_ctx->inspection_recursion_limit == DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); DetectEngineDeInitYamlConf(); return result; } static int DetectEngineTest04(void) { char *conf = "%YAML 1.1\n" "---\n" "detect-engine:\n" " - profile: medium\n" " - custom-values:\n" " toclient_src_groups: 2\n" " toclient_dst_groups: 2\n" " toclient_sp_groups: 2\n" " toclient_dp_groups: 3\n" " toserver_src_groups: 2\n" " toserver_dst_groups: 4\n" " toserver_sp_groups: 2\n" " toserver_dp_groups: 25\n" " - inspection-recursion-limit: 10\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (DetectEngineInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; result = (de_ctx->inspection_recursion_limit == 10); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); DetectEngineDeInitYamlConf(); return result; } int DummyTestAppInspectionEngine01(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, int32_t tx_id) { return 0; } int DummyTestAppInspectionEngine02(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, int32_t tx_id) { return 0; } int DetectEngineTest05(void) { int result = 0; DetectEngineAppInspectionEngine *engine_list[ALPROTO_MAX][2]; memset(engine_list, 0, sizeof(engine_list)); DetectEngineRegisterAppInspectionEngine(ALPROTO_HTTP, 0 /* STREAM_TOSERVER */, DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, DE_STATE_FLAG_URI_MATCH, DummyTestAppInspectionEngine01, engine_list); int alproto = ALPROTO_UNKNOWN + 1; for ( ; alproto < ALPROTO_FAILED; alproto++) { int dir = 0; for ( ; dir < 2; dir++) { if (alproto == ALPROTO_HTTP && dir == 0) { if (engine_list[alproto][dir]->next != NULL) { printf("more than one entry found\n"); goto end; } DetectEngineAppInspectionEngine *engine = engine_list[alproto][dir]; if (engine->alproto != alproto || engine->dir != dir || engine->sm_list != DETECT_SM_LIST_UMATCH || engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || engine->match_flags != DE_STATE_FLAG_URI_MATCH || engine->Callback != DummyTestAppInspectionEngine01) { printf("failed for http and dir(0-toserver)\n"); goto end; } } /* if (alproto == ALPROTO_HTTP && dir == 0) */ if (alproto == ALPROTO_HTTP && dir == 1) { if (engine_list[alproto][dir] != NULL) { printf("failed for http and dir(1-toclient)\n"); goto end; } } if (alproto != ALPROTO_HTTP && engine_list[alproto][0] != NULL && engine_list[alproto][1] != NULL) { printf("failed for protocol %d\n", alproto); goto end; } } /* for ( ; dir < 2 ..)*/ } /* for ( ; alproto < ALPROTO_FAILED; ..) */ result = 1; end: return result; } int DetectEngineTest06(void) { int result = 0; DetectEngineAppInspectionEngine *engine_list[ALPROTO_MAX][2]; memset(engine_list, 0, sizeof(engine_list)); DetectEngineRegisterAppInspectionEngine(ALPROTO_HTTP, 0 /* STREAM_TOSERVER */, DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, DE_STATE_FLAG_URI_MATCH, DummyTestAppInspectionEngine01, engine_list); DetectEngineRegisterAppInspectionEngine(ALPROTO_HTTP, 1 /* STREAM_TOCLIENT */, DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, DE_STATE_FLAG_URI_MATCH, DummyTestAppInspectionEngine02, engine_list); int alproto = ALPROTO_UNKNOWN + 1; for ( ; alproto < ALPROTO_FAILED; alproto++) { int dir = 0; for ( ; dir < 2; dir++) { if (alproto == ALPROTO_HTTP && dir == 0) { if (engine_list[alproto][dir]->next != NULL) { printf("more than one entry found\n"); goto end; } DetectEngineAppInspectionEngine *engine = engine_list[alproto][dir]; if (engine->alproto != alproto || engine->dir != dir || engine->sm_list != DETECT_SM_LIST_UMATCH || engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || engine->match_flags != DE_STATE_FLAG_URI_MATCH || engine->Callback != DummyTestAppInspectionEngine01) { printf("failed for http and dir(0-toserver)\n"); goto end; } } /* if (alproto == ALPROTO_HTTP && dir == 0) */ if (alproto == ALPROTO_HTTP && dir == 1) { if (engine_list[alproto][dir]->next != NULL) { printf("more than one entry found\n"); goto end; } DetectEngineAppInspectionEngine *engine = engine_list[alproto][dir]; if (engine->alproto != alproto || engine->dir != dir || engine->sm_list != DETECT_SM_LIST_UMATCH || engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || engine->match_flags != DE_STATE_FLAG_URI_MATCH || engine->Callback != DummyTestAppInspectionEngine02) { printf("failed for http and dir(0-toclient)\n"); goto end; } } /* if (alproto == ALPROTO_HTTP && dir == 1) */ if (alproto != ALPROTO_HTTP && engine_list[alproto][0] != NULL && engine_list[alproto][1] != NULL) { printf("failed for protocol %d\n", alproto); goto end; } } /* for ( ; dir < 2 ..)*/ } /* for ( ; alproto < ALPROTO_FAILED; ..) */ result = 1; end: return result; } int DetectEngineTest07(void) { int result = 0; DetectEngineAppInspectionEngine *engine_list[ALPROTO_MAX][2]; memset(engine_list, 0, sizeof(engine_list)); struct test_data_t { int32_t sm_list; uint32_t inspect_flags; uint32_t match_flags; uint16_t dir; int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, int32_t tx_id); }; struct test_data_t data[] = { { DETECT_SM_LIST_UMATCH, DE_STATE_FLAG_URI_INSPECT, DE_STATE_FLAG_URI_MATCH, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HCBDMATCH, DE_STATE_FLAG_HCBD_INSPECT, DE_STATE_FLAG_HCBD_MATCH, 0, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_HSBDMATCH, DE_STATE_FLAG_HSBD_INSPECT, DE_STATE_FLAG_HSBD_MATCH, 1, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_HHDMATCH, DE_STATE_FLAG_HHD_INSPECT, DE_STATE_FLAG_HHD_MATCH, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HRHDMATCH, DE_STATE_FLAG_HRHD_INSPECT, DE_STATE_FLAG_HRHD_MATCH, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HMDMATCH, DE_STATE_FLAG_HMD_INSPECT, DE_STATE_FLAG_HMD_MATCH, 0, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_HCDMATCH, DE_STATE_FLAG_HCD_INSPECT, DE_STATE_FLAG_HCD_MATCH, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HRUDMATCH, DE_STATE_FLAG_HRUD_INSPECT, DE_STATE_FLAG_HRUD_MATCH, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_FILEMATCH, DE_STATE_FLAG_FILE_TS_INSPECT, DE_STATE_FLAG_FILE_TS_MATCH, 0, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_FILEMATCH, DE_STATE_FLAG_FILE_TC_INSPECT, DE_STATE_FLAG_FILE_TC_MATCH, 1, DummyTestAppInspectionEngine02 }, { DETECT_SM_LIST_HSMDMATCH, DE_STATE_FLAG_HSMD_INSPECT, DE_STATE_FLAG_HSMD_MATCH, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HSCDMATCH, DE_STATE_FLAG_HSCD_INSPECT, DE_STATE_FLAG_HSCD_MATCH, 0, DummyTestAppInspectionEngine01 }, { DETECT_SM_LIST_HUADMATCH, DE_STATE_FLAG_HUAD_INSPECT, DE_STATE_FLAG_HUAD_MATCH, 0, DummyTestAppInspectionEngine02 }, }; size_t i = 0; for ( ; i < sizeof(data) / sizeof(struct test_data_t); i++) { DetectEngineRegisterAppInspectionEngine(ALPROTO_HTTP, data[i].dir /* STREAM_TOCLIENT */, data[i].sm_list, data[i].inspect_flags, data[i].match_flags, data[i].Callback, engine_list); } #if 0 DetectEnginePrintAppInspectionEngines(engine_list); #endif int alproto = ALPROTO_UNKNOWN + 1; for ( ; alproto < ALPROTO_FAILED; alproto++) { int dir = 0; for ( ; dir < 2; dir++) { if (alproto == ALPROTO_HTTP) { DetectEngineAppInspectionEngine *engine = engine_list[alproto][dir]; size_t i = 0; for ( ; i < (sizeof(data) / sizeof(struct test_data_t)); i++) { if (data[i].dir != dir) continue; if (engine->alproto != ALPROTO_HTTP || engine->dir != data[i].dir || engine->sm_list != data[i].sm_list || engine->inspect_flags != data[i].inspect_flags || engine->match_flags != data[i].match_flags || engine->Callback != data[i].Callback) { printf("failed for http\n"); goto end; } engine = engine->next; } } else { if (engine_list[alproto][0] != NULL && engine_list[alproto][1] != NULL) { printf("failed for protocol %d\n", alproto); goto end; } } /* else */ } /* for ( ; dir < 2; dir++) */ } /* for ( ; alproto < ALPROTO_FAILED; ..) */ result = 1; end: return result; } static int DetectEngineTest08(void) { char *conf = "%YAML 1.1\n" "---\n" "detect-engine:\n" " - profile: custom\n" " - custom-values:\n" " toclient-src-groups: 20\n" " toclient-dst-groups: 21\n" " toclient-sp-groups: 22\n" " toclient-dp-groups: 23\n" " toserver-src-groups: 24\n" " toserver-dst-groups: 25\n" " toserver-sp-groups: 26\n" " toserver-dp-groups: 27\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (DetectEngineInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; if (de_ctx->max_uniq_toclient_src_groups == 20 && de_ctx->max_uniq_toclient_dst_groups == 21 && de_ctx->max_uniq_toclient_sp_groups == 22 && de_ctx->max_uniq_toclient_dp_groups == 23 && de_ctx->max_uniq_toserver_src_groups == 24 && de_ctx->max_uniq_toserver_dst_groups == 25 && de_ctx->max_uniq_toserver_sp_groups == 26 && de_ctx->max_uniq_toserver_dp_groups == 27) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); DetectEngineDeInitYamlConf(); return result; } /** \test bug 892 bad values */ static int DetectEngineTest09(void) { char *conf = "%YAML 1.1\n" "---\n" "detect-engine:\n" " - profile: custom\n" " - custom-values:\n" " toclient-src-groups: BA\n" " toclient-dst-groups: BA\n" " toclient-sp-groups: BA\n" " toclient-dp-groups: BA\n" " toserver-src-groups: BA\n" " toserver-dst-groups: BA\n" " toserver-sp-groups: BA\n" " toserver-dp-groups: BA\n" " - inspection-recursion-limit: 10\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; if (DetectEngineInitYamlConf(conf) == -1) return 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; if (de_ctx->max_uniq_toclient_src_groups == 4 && de_ctx->max_uniq_toclient_dst_groups == 4 && de_ctx->max_uniq_toclient_sp_groups == 4 && de_ctx->max_uniq_toclient_dp_groups == 6 && de_ctx->max_uniq_toserver_src_groups == 4 && de_ctx->max_uniq_toserver_dst_groups == 8 && de_ctx->max_uniq_toserver_sp_groups == 4 && de_ctx->max_uniq_toserver_dp_groups == 30) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); DetectEngineDeInitYamlConf(); return result; } #endif void DetectEngineRegisterTests() { #ifdef UNITTESTS UtRegisterTest("DetectEngineTest01", DetectEngineTest01, 1); UtRegisterTest("DetectEngineTest02", DetectEngineTest02, 1); UtRegisterTest("DetectEngineTest03", DetectEngineTest03, 1); UtRegisterTest("DetectEngineTest04", DetectEngineTest04, 1); UtRegisterTest("DetectEngineTest05", DetectEngineTest05, 1); UtRegisterTest("DetectEngineTest06", DetectEngineTest06, 1); UtRegisterTest("DetectEngineTest07", DetectEngineTest07, 1); UtRegisterTest("DetectEngineTest08", DetectEngineTest08, 1); UtRegisterTest("DetectEngineTest09", DetectEngineTest09, 1); #endif return; } suricata-1.4.7/src/tm-threads.c0000644000000000000000000017010512253546156013245 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * \author Eric Leblond * * Thread management functions. */ #include "suricata-common.h" #include "suricata.h" #include "stream.h" #include "runmodes.h" #include "threadvars.h" #include "tm-queues.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "tmqh-packetpool.h" #include "threads.h" #include "util-debug.h" #include "util-privs.h" #include "util-cpu.h" #include "util-optimize.h" #include "util-profiling.h" #include "util-signal.h" #include "queue.h" #ifdef PROFILE_LOCKING __thread uint64_t mutex_lock_contention; __thread uint64_t mutex_lock_wait_ticks; __thread uint64_t mutex_lock_cnt; __thread uint64_t spin_lock_contention; __thread uint64_t spin_lock_wait_ticks; __thread uint64_t spin_lock_cnt; __thread uint64_t rww_lock_contention; __thread uint64_t rww_lock_wait_ticks; __thread uint64_t rww_lock_cnt; __thread uint64_t rwr_lock_contention; __thread uint64_t rwr_lock_wait_ticks; __thread uint64_t rwr_lock_cnt; #endif #ifdef OS_FREEBSD #include #include #include #include #include #define cpu_set_t cpuset_t #endif /* OS_FREEBSD */ /* prototypes */ static int SetCPUAffinity(uint16_t cpu); /* root of the threadvars list */ ThreadVars *tv_root[TVT_MAX] = { NULL }; /* lock to protect tv_root */ SCMutex tv_root_lock = PTHREAD_MUTEX_INITIALIZER; /* Action On Failure(AOF). Determines how the engine should behave when a * thread encounters a failure. Defaults to restart the failed thread */ uint8_t tv_aof = THV_RESTART_THREAD; /** * \brief Check if a thread flag is set. * * \retval 1 flag is set. * \retval 0 flag is not set. */ int TmThreadsCheckFlag(ThreadVars *tv, uint16_t flag) { return (SC_ATOMIC_GET(tv->flags) & flag) ? 1 : 0; } /** * \brief Set a thread flag. */ void TmThreadsSetFlag(ThreadVars *tv, uint16_t flag) { SC_ATOMIC_OR(tv->flags, flag); } /** * \brief Unset a thread flag. */ void TmThreadsUnsetFlag(ThreadVars *tv, uint16_t flag) { SC_ATOMIC_AND(tv->flags, ~flag); } /** * \brief Function to use as dummy stack function * * \retval TM_ECODE_OK */ TmEcode TmDummyFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return TM_ECODE_OK; } /* 1 slot functions */ void *TmThreadsSlot1NoIn(void *td) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *tv = (ThreadVars *)td; TmSlot *s = (TmSlot *)tv->tm_slots; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ if (SCSetThreadName(tv->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); /* Drop the capabilities for this thread */ SCDropCaps(tv); if (s->SlotThreadInit != NULL) { void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; } (void)SC_ATOMIC_SET(s->slot_data, slot_data); } memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); TmThreadsSetFlag(tv, THV_INIT_DONE); while (run) { if (TmThreadsCheckFlag(tv, THV_PAUSE)) { TmThreadsSetFlag(tv, THV_PAUSED); TmThreadTestThreadUnPaused(tv); TmThreadsUnsetFlag(tv, THV_PAUSED); } TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); r = SlotFunc(tv, NULL, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); /* handle error */ if (r == TM_ECODE_FAILED) { TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); SCMutexLock(&s->slot_post_pq.mutex_q); TmqhReleasePacketsToPacketPool(&s->slot_post_pq); SCMutexUnlock(&s->slot_post_pq.mutex_q); TmThreadsSetFlag(tv, THV_FAILED); break; } /* handle pre queue */ while (s->slot_pre_pq.top != NULL) { Packet *extra_p = PacketDequeue(&s->slot_pre_pq); if (extra_p != NULL) tv->tmqh_out(tv, extra_p); } /* handle post queue */ if (s->slot_post_pq.top != NULL) { SCMutexLock(&s->slot_post_pq.mutex_q); while (s->slot_post_pq.top != NULL) { Packet *extra_p = PacketDequeue(&s->slot_post_pq); if (extra_p != NULL) tv->tmqh_out(tv, extra_p); } SCMutexUnlock(&s->slot_post_pq.mutex_q); } if (TmThreadsCheckFlag(tv, THV_KILL)) { SCPerfSyncCounters(tv, 0); run = 0; } } /* while (run) */ TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); if (s->SlotThreadExitPrintStats != NULL) { s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); } if (s->SlotThreadDeinit != NULL) { r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); return NULL; } } TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; } void *TmThreadsSlot1NoOut(void *td) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *tv = (ThreadVars *)td; TmSlot *s = (TmSlot *)tv->tm_slots; Packet *p = NULL; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ if (SCSetThreadName(tv->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); /* Drop the capabilities for this thread */ SCDropCaps(tv); if (s->SlotThreadInit != NULL) { void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; } (void)SC_ATOMIC_SET(s->slot_data, slot_data); } memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); TmThreadsSetFlag(tv, THV_INIT_DONE); while (run) { if (TmThreadsCheckFlag(tv, THV_PAUSE)) { TmThreadsSetFlag(tv, THV_PAUSED); TmThreadTestThreadUnPaused(tv); TmThreadsUnsetFlag(tv, THV_PAUSED); } TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); p = tv->tmqh_in(tv); PACKET_PROFILING_TMM_START(p, s->tm_id); r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), /* no outqh no pq */ NULL, /* no outqh no pq */ NULL); PACKET_PROFILING_TMM_END(p, s->tm_id); /* handle error */ if (r == TM_ECODE_FAILED) { TmqhOutputPacketpool(tv, p); TmThreadsSetFlag(tv, THV_FAILED); break; } if (TmThreadsCheckFlag(tv, THV_KILL)) { SCPerfSyncCounters(tv, 0); run = 0; } } /* while (run) */ TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); if (s->SlotThreadExitPrintStats != NULL) { s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); } if (s->SlotThreadDeinit != NULL) { r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); return NULL; } } TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; } void *TmThreadsSlot1NoInOut(void *td) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *tv = (ThreadVars *)td; TmSlot *s = (TmSlot *)tv->tm_slots; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ if (SCSetThreadName(tv->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); /* Drop the capabilities for this thread */ SCDropCaps(tv); SCLogDebug("%s starting", tv->name); if (s->SlotThreadInit != NULL) { void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; } (void)SC_ATOMIC_SET(s->slot_data, slot_data); } memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); TmThreadsSetFlag(tv, THV_INIT_DONE); while (run) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); if (TmThreadsCheckFlag(tv, THV_PAUSE)) { TmThreadsSetFlag(tv, THV_PAUSED); TmThreadTestThreadUnPaused(tv); TmThreadsUnsetFlag(tv, THV_PAUSED); } r = SlotFunc(tv, NULL, SC_ATOMIC_GET(s->slot_data), /* no outqh, no pq */NULL, NULL); /* handle error */ if (r == TM_ECODE_FAILED) { TmThreadsSetFlag(tv, THV_FAILED); break; } if (TmThreadsCheckFlag(tv, THV_KILL)) { SCPerfSyncCounters(tv, 0); run = 0; } } /* while (run) */ TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); if (s->SlotThreadExitPrintStats != NULL) { s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); } if (s->SlotThreadDeinit != NULL) { r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); return NULL; } } TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; } void *TmThreadsSlot1(void *td) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *tv = (ThreadVars *)td; TmSlot *s = (TmSlot *)tv->tm_slots; Packet *p = NULL; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ if (SCSetThreadName(tv->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); /* Drop the capabilities for this thread */ SCDropCaps(tv); SCLogDebug("%s starting", tv->name); if (s->SlotThreadInit != NULL) { void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; } (void)SC_ATOMIC_SET(s->slot_data, slot_data); } memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); SCMutexInit(&s->slot_pre_pq.mutex_q, NULL); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); SCMutexInit(&s->slot_post_pq.mutex_q, NULL); TmThreadsSetFlag(tv, THV_INIT_DONE); while (run) { if (TmThreadsCheckFlag(tv, THV_PAUSE)) { TmThreadsSetFlag(tv, THV_PAUSED); TmThreadTestThreadUnPaused(tv); TmThreadsUnsetFlag(tv, THV_PAUSED); } /* input a packet */ p = tv->tmqh_in(tv); if (p != NULL) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); PACKET_PROFILING_TMM_START(p, s->tm_id); r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); PACKET_PROFILING_TMM_END(p, s->tm_id); /* handle error */ if (r == TM_ECODE_FAILED) { TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); SCMutexLock(&s->slot_post_pq.mutex_q); TmqhReleasePacketsToPacketPool(&s->slot_post_pq); SCMutexUnlock(&s->slot_post_pq.mutex_q); TmqhOutputPacketpool(tv, p); TmThreadsSetFlag(tv, THV_FAILED); break; } while (s->slot_pre_pq.top != NULL) { /* handle new packets from this func */ Packet *extra_p = PacketDequeue(&s->slot_pre_pq); if (extra_p != NULL) { tv->tmqh_out(tv, extra_p); } } /* output the packet */ tv->tmqh_out(tv, p); } if (s->slot_post_pq.top != NULL) { SCMutexLock(&s->slot_post_pq.mutex_q); while (s->slot_post_pq.top != NULL) { /* handle new packets from this func */ Packet *extra_p = PacketDequeue(&s->slot_post_pq); if (extra_p != NULL) { tv->tmqh_out(tv, extra_p); } } SCMutexUnlock(&s->slot_post_pq.mutex_q); } if (TmThreadsCheckFlag(tv, THV_KILL)) { SCPerfSyncCounters(tv, 0); run = 0; } } /* while (run) */ TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); if (s->SlotThreadExitPrintStats != NULL) { s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); } if (s->SlotThreadDeinit != NULL) { r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); return NULL; } } SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; } /** * \brief Separate run function so we can call it recursively. * * \todo Deal with post_pq for slots beyond the first. */ TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p, TmSlot *slot) { TmEcode r; TmSlot *s; Packet *extra_p; for (s = slot; s != NULL; s = s->slot_next) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); PACKET_PROFILING_TMM_START(p, s->tm_id); if (unlikely(s->id == 0)) { r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); } else { r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, NULL); } PACKET_PROFILING_TMM_END(p, s->tm_id); /* handle error */ if (unlikely(r == TM_ECODE_FAILED)) { /* Encountered error. Return packets to packetpool and return */ TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); SCMutexLock(&s->slot_post_pq.mutex_q); TmqhReleasePacketsToPacketPool(&s->slot_post_pq); SCMutexUnlock(&s->slot_post_pq.mutex_q); TmThreadsSetFlag(tv, THV_FAILED); return TM_ECODE_FAILED; } /* handle new packets */ while (s->slot_pre_pq.top != NULL) { extra_p = PacketDequeue(&s->slot_pre_pq); if (unlikely(extra_p == NULL)) continue; /* see if we need to process the packet */ if (s->slot_next != NULL) { r = TmThreadsSlotVarRun(tv, extra_p, s->slot_next); if (unlikely(r == TM_ECODE_FAILED)) { TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); SCMutexLock(&s->slot_post_pq.mutex_q); TmqhReleasePacketsToPacketPool(&s->slot_post_pq); SCMutexUnlock(&s->slot_post_pq.mutex_q); TmqhOutputPacketpool(tv, extra_p); TmThreadsSetFlag(tv, THV_FAILED); return TM_ECODE_FAILED; } } tv->tmqh_out(tv, extra_p); } } return TM_ECODE_OK; } /* pcap/nfq pkt read callback process_pkt pfring pkt read process_pkt slot: setup pkt_ack_loop(tv, slot_data) deinit process_pkt: while(s) run s; queue; */ void *TmThreadsSlotPktAcqLoop(void *td) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *tv = (ThreadVars *)td; TmSlot *s = tv->tm_slots; char run = 1; TmEcode r = TM_ECODE_OK; TmSlot *slot = NULL; /* Set the thread name */ if (SCSetThreadName(tv->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); /* Drop the capabilities for this thread */ SCDropCaps(tv); /* check if we are setup properly */ if (s == NULL || s->PktAcqLoop == NULL || tv->tmqh_in == NULL || tv->tmqh_out == NULL) { SCLogError(SC_ERR_FATAL, "TmSlot or ThreadVars badly setup: s=%p," " PktAcqLoop=%p, tmqh_in=%p," " tmqh_out=%p", s, s ? s->PktAcqLoop : NULL, tv->tmqh_in, tv->tmqh_out); EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; } for (slot = s; slot != NULL; slot = slot->slot_next) { if (slot->SlotThreadInit != NULL) { void *slot_data = NULL; r = slot->SlotThreadInit(tv, slot->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { if (r == TM_ECODE_DONE) { EngineDone(); TmThreadsSetFlag(tv, THV_CLOSED | THV_INIT_DONE | THV_RUNNING_DONE); pthread_exit((void *) -1); } else { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; } } (void)SC_ATOMIC_SET(slot->slot_data, slot_data); } memset(&slot->slot_pre_pq, 0, sizeof(PacketQueue)); SCMutexInit(&slot->slot_pre_pq.mutex_q, NULL); memset(&slot->slot_post_pq, 0, sizeof(PacketQueue)); SCMutexInit(&slot->slot_post_pq.mutex_q, NULL); } TmThreadsSetFlag(tv, THV_INIT_DONE); while(run) { if (TmThreadsCheckFlag(tv, THV_PAUSE)) { TmThreadsSetFlag(tv, THV_PAUSED); TmThreadTestThreadUnPaused(tv); TmThreadsUnsetFlag(tv, THV_PAUSED); } r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s); if (r == TM_ECODE_FAILED || TmThreadsCheckFlag(tv, THV_KILL) || suricata_ctl_flags) { run = 0; } if (r == TM_ECODE_DONE) { run = 0; } } SCPerfSyncCounters(tv, 0); TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); for (slot = s; slot != NULL; slot = slot->slot_next) { if (slot->SlotThreadExitPrintStats != NULL) { slot->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(slot->slot_data)); } if (slot->SlotThreadDeinit != NULL) { r = slot->SlotThreadDeinit(tv, SC_ATOMIC_GET(slot->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); return NULL; } } } SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; } /** * \todo Only the first "slot" currently makes the "post_pq" available * to the thread module. */ void *TmThreadsSlotVar(void *td) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); ThreadVars *tv = (ThreadVars *)td; TmSlot *s = (TmSlot *)tv->tm_slots; Packet *p = NULL; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ if (SCSetThreadName(tv->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); /* Drop the capabilities for this thread */ SCDropCaps(tv); /* check if we are setup properly */ if (s == NULL || tv->tmqh_in == NULL || tv->tmqh_out == NULL) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; } for (; s != NULL; s = s->slot_next) { if (s->SlotThreadInit != NULL) { void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; } (void)SC_ATOMIC_SET(s->slot_data, slot_data); } memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); SCMutexInit(&s->slot_pre_pq.mutex_q, NULL); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); SCMutexInit(&s->slot_post_pq.mutex_q, NULL); } TmThreadsSetFlag(tv, THV_INIT_DONE); s = (TmSlot *)tv->tm_slots; while (run) { if (TmThreadsCheckFlag(tv, THV_PAUSE)) { TmThreadsSetFlag(tv, THV_PAUSED); TmThreadTestThreadUnPaused(tv); TmThreadsUnsetFlag(tv, THV_PAUSED); } /* input a packet */ p = tv->tmqh_in(tv); if (p != NULL) { /* run the thread module(s) */ r = TmThreadsSlotVarRun(tv, p, s); if (r == TM_ECODE_FAILED) { TmqhOutputPacketpool(tv, p); TmThreadsSetFlag(tv, THV_FAILED); break; } /* output the packet */ tv->tmqh_out(tv, p); } /* if (p != NULL) */ /* now handle the post_pq packets */ TmSlot *slot; for (slot = s; slot != NULL; slot = slot->slot_next) { if (slot->slot_post_pq.top != NULL) { while (1) { SCMutexLock(&slot->slot_post_pq.mutex_q); Packet *extra_p = PacketDequeue(&slot->slot_post_pq); SCMutexUnlock(&slot->slot_post_pq.mutex_q); if (extra_p == NULL) break; if (slot->slot_next != NULL) { r = TmThreadsSlotVarRun(tv, extra_p, slot->slot_next); if (r == TM_ECODE_FAILED) { SCMutexLock(&slot->slot_post_pq.mutex_q); TmqhReleasePacketsToPacketPool(&slot->slot_post_pq); SCMutexUnlock(&slot->slot_post_pq.mutex_q); TmqhOutputPacketpool(tv, extra_p); TmThreadsSetFlag(tv, THV_FAILED); break; } } /* output the packet */ tv->tmqh_out(tv, extra_p); } /* while */ } /* if */ } /* for */ if (TmThreadsCheckFlag(tv, THV_KILL)) { run = 0; } } /* while (run) */ SCPerfSyncCounters(tv, 0); TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); s = (TmSlot *)tv->tm_slots; for ( ; s != NULL; s = s->slot_next) { if (s->SlotThreadExitPrintStats != NULL) { s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); } if (s->SlotThreadDeinit != NULL) { r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); return NULL; } } } SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; } /** * \brief We set the slot functions. * * \param tv Pointer to the TV to set the slot function for. * \param name Name of the slot variant. * \param fn_p Pointer to a custom slot function. Used only if slot variant * "name" is "custom". * * \retval TmEcode TM_ECODE_OK on success; TM_ECODE_FAILED on failure. */ TmEcode TmThreadSetSlots(ThreadVars *tv, char *name, void *(*fn_p)(void *)) { if (name == NULL) { if (fn_p == NULL) { printf("Both slot name and function pointer can't be NULL inside " "TmThreadSetSlots\n"); goto error; } else { name = "custom"; } } if (strcmp(name, "1slot") == 0) { tv->tm_func = TmThreadsSlot1; } else if (strcmp(name, "1slot_noout") == 0) { tv->tm_func = TmThreadsSlot1NoOut; } else if (strcmp(name, "1slot_noin") == 0) { tv->tm_func = TmThreadsSlot1NoIn; } else if (strcmp(name, "1slot_noinout") == 0) { tv->tm_func = TmThreadsSlot1NoInOut; } else if (strcmp(name, "varslot") == 0) { tv->tm_func = TmThreadsSlotVar; } else if (strcmp(name, "pktacqloop") == 0) { tv->tm_func = TmThreadsSlotPktAcqLoop; } else if (strcmp(name, "custom") == 0) { if (fn_p == NULL) goto error; tv->tm_func = fn_p; } else { printf("Error: Slot \"%s\" not supported\n", name); goto error; } return TM_ECODE_OK; error: return TM_ECODE_FAILED; } ThreadVars *TmThreadsGetTVContainingSlot(TmSlot *tm_slot) { ThreadVars *tv; int i; SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv) { TmSlot *slots = tv->tm_slots; while (slots != NULL) { if (slots == tm_slot) { SCMutexUnlock(&tv_root_lock); return tv; } slots = slots->slot_next; } tv = tv->next; } } SCMutexUnlock(&tv_root_lock); return NULL; } /** * \brief Appends a new entry to the slots. * * \param tv TV the slot is attached to. * \param tm TM to append. * \param data Data to be passed on to the slot init function. * * \retval The allocated TmSlot or NULL if there is an error */ static inline TmSlot * _TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data) { TmSlot *slot = SCMalloc(sizeof(TmSlot)); if (unlikely(slot == NULL)) return NULL; memset(slot, 0, sizeof(TmSlot)); SC_ATOMIC_INIT(slot->slot_data); slot->tv = tv; slot->SlotThreadInit = tm->ThreadInit; slot->slot_initdata = data; SC_ATOMIC_INIT(slot->SlotFunc); (void)SC_ATOMIC_SET(slot->SlotFunc, tm->Func); slot->PktAcqLoop = tm->PktAcqLoop; slot->SlotThreadExitPrintStats = tm->ThreadExitPrintStats; slot->SlotThreadDeinit = tm->ThreadDeinit; /* we don't have to check for the return value "-1". We wouldn't have * received a TM as arg, if it didn't exist */ slot->tm_id = TmModuleGetIDForTM(tm); tv->cap_flags |= tm->cap_flags; if (tv->tm_slots == NULL) { tv->tm_slots = slot; slot->id = 0; } else { TmSlot *a = (TmSlot *)tv->tm_slots, *b = NULL; /* get the last slot */ for ( ; a != NULL; a = a->slot_next) { b = a; } /* append the new slot */ if (b != NULL) { b->slot_next = slot; slot->id = b->id + 1; } } return slot; } /** * \brief Appends a new entry to the slots. * * \param tv TV the slot is attached to. * \param tm TM to append. * \param data Data to be passed on to the slot init function. */ void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data) { _TmSlotSetFuncAppend(tv, tm, data); } typedef struct TmDummySlot_ { TmSlot *slot; TmEcode (*SlotFunc)(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode (*SlotThreadInit)(ThreadVars *, void *, void **); TAILQ_ENTRY(TmDummySlot_) next; } TmDummySlot; static TAILQ_HEAD(, TmDummySlot_) dummy_slots = TAILQ_HEAD_INITIALIZER(dummy_slots); /** * \brief Appends a new entry to the slots with a delayed option. * * \param tv TV the slot is attached to. * \param tm TM to append. * \param data Data to be passed on to the slot init function. * \param delayed Delayed start of slot if equal to 1 */ void TmSlotSetFuncAppendDelayed(ThreadVars *tv, TmModule *tm, void *data, int delayed) { TmSlot *slot = _TmSlotSetFuncAppend(tv, tm, data); TmDummySlot *dslot = NULL; if ((slot == NULL) || (delayed == 0)) { return; } dslot = SCMalloc(sizeof(TmDummySlot)); if (unlikely(dslot == NULL)) { return; } memset(dslot, 0, sizeof(*dslot)); dslot->SlotFunc = SC_ATOMIC_GET(slot->SlotFunc); (void)SC_ATOMIC_SET(slot->SlotFunc, TmDummyFunc); dslot->SlotThreadInit = slot->SlotThreadInit; slot->SlotThreadInit = NULL; dslot->slot = slot; TAILQ_INSERT_TAIL(&dummy_slots, dslot, next); return; } /** * \brief Activate slots that have been started in delayed mode */ void TmThreadActivateDummySlot() { TmDummySlot *dslot; TmSlot *s; TmEcode r = TM_ECODE_OK; TAILQ_FOREACH(dslot, &dummy_slots, next) { void *slot_data = NULL; s = dslot->slot; if (dslot->SlotThreadInit != NULL) { s->SlotThreadInit = dslot->SlotThreadInit; r = s->SlotThreadInit(s->tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(s->tv, THV_CLOSED | THV_RUNNING_DONE); } (void)SC_ATOMIC_SET(s->slot_data, slot_data); } (void)SC_ATOMIC_CAS(&s->SlotFunc, TmDummyFunc, dslot->SlotFunc); } } /** * \brief Deactivate slots that have been started in delayed mode. */ void TmThreadDeActivateDummySlot() { TmDummySlot *dslot; TAILQ_FOREACH(dslot, &dummy_slots, next) { (void)SC_ATOMIC_CAS(&dslot->slot->SlotFunc, dslot->SlotFunc, TmDummyFunc); dslot->slot->SlotThreadInit = NULL; } } /** * \brief Returns the slot holding a TM with the particular tm_id. * * \param tm_id TM id of the TM whose slot has to be returned. * * \retval slots Pointer to the slot. */ TmSlot *TmSlotGetSlotForTM(int tm_id) { ThreadVars *tv = NULL; TmSlot *slots; int i; SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv) { slots = tv->tm_slots; while (slots != NULL) { if (slots->tm_id == tm_id) { SCMutexUnlock(&tv_root_lock); return slots; } slots = slots->slot_next; } tv = tv->next; } } SCMutexUnlock(&tv_root_lock); return NULL; } #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ static int SetCPUAffinitySet(cpu_set_t *cs) { #if defined OS_FREEBSD int r = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, SCGetThreadIdLong(), sizeof(cpu_set_t),cs); #elif OS_DARWIN int r = thread_policy_set(mach_thread_self(), THREAD_AFFINITY_POLICY, (void*)cs, THREAD_AFFINITY_POLICY_COUNT); #else pid_t tid = syscall(SYS_gettid); int r = sched_setaffinity(tid, sizeof(cpu_set_t), cs); #endif /* OS_FREEBSD */ if (r != 0) { printf("Warning: sched_setaffinity failed (%" PRId32 "): %s\n", r, strerror(errno)); return -1; } return 0; } #endif /** * \brief Set the thread affinity on the calling thread. * * \param cpuid Id of the core/cpu to setup the affinity. * * \retval 0 If all goes well; -1 if something is wrong. */ static int SetCPUAffinity(uint16_t cpuid) { #if defined __OpenBSD__ return 0; #else int cpu = (int)cpuid; #if defined OS_WIN32 || defined __CYGWIN__ DWORD cs = 1 << cpu; int r = (0 == SetThreadAffinityMask(GetCurrentThread(), cs)); if (r != 0) { printf("Warning: sched_setaffinity failed (%" PRId32 "): %s\n", r, strerror(errno)); return -1; } SCLogDebug("CPU Affinity for thread %lu set to CPU %" PRId32, SCGetThreadIdLong(), cpu); return 0; #else cpu_set_t cs; CPU_ZERO(&cs); CPU_SET(cpu, &cs); return SetCPUAffinitySet(&cs); #endif /* windows */ #endif /* not supported */ } /** * \brief Set the thread options (thread priority). * * \param tv Pointer to the ThreadVars to setup the thread priority. * * \retval TM_ECODE_OK. */ TmEcode TmThreadSetThreadPriority(ThreadVars *tv, int prio) { tv->thread_setup_flags |= THREAD_SET_PRIORITY; tv->thread_priority = prio; return TM_ECODE_OK; } /** * \brief Adjusting nice value for threads. */ void TmThreadSetPrio(ThreadVars *tv) { SCEnter(); #ifndef __CYGWIN__ #ifdef OS_WIN32 if (0 == SetThreadPriority(GetCurrentThread(), tv->thread_priority)) { SCLogError(SC_ERR_THREAD_NICE_PRIO, "Error setting priority for " "thread %s: %s", tv->name, strerror(errno)); } else { SCLogDebug("Priority set to %"PRId32" for thread %s", tv->thread_priority, tv->name); } #else int ret = nice(tv->thread_priority); if (ret == -1) { SCLogError(SC_ERR_THREAD_NICE_PRIO, "Error setting nice value " "for thread %s: %s", tv->name, strerror(errno)); } else { SCLogDebug("Nice value set to %"PRId32" for thread %s", tv->thread_priority, tv->name); } #endif /* OS_WIN32 */ #endif SCReturn; } /** * \brief Set the thread options (cpu affinity). * * \param tv pointer to the ThreadVars to setup the affinity. * \param cpu cpu on which affinity is set. * * \retval TM_ECODE_OK */ TmEcode TmThreadSetCPUAffinity(ThreadVars *tv, uint16_t cpu) { tv->thread_setup_flags |= THREAD_SET_AFFINITY; tv->cpu_affinity = cpu; return TM_ECODE_OK; } TmEcode TmThreadSetCPU(ThreadVars *tv, uint8_t type) { if (!threading_set_cpu_affinity) return TM_ECODE_OK; if (type > MAX_CPU_SET) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid cpu type family"); return TM_ECODE_FAILED; } tv->thread_setup_flags |= THREAD_SET_AFFTYPE; tv->cpu_affinity = type; return TM_ECODE_OK; } int TmThreadGetNbThreads(uint8_t type) { if (type >= MAX_CPU_SET) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid cpu type family"); return 0; } return thread_affinity[type].nb_threads; } /** * \brief Set the thread options (cpu affinitythread). * Priority should be already set by pthread_create. * * \param tv pointer to the ThreadVars of the calling thread. */ TmEcode TmThreadSetupOptions(ThreadVars *tv) { if (tv->thread_setup_flags & THREAD_SET_AFFINITY) { SCLogInfo("Setting affinity for \"%s\" Module to cpu/core " "%"PRIu16", thread id %lu", tv->name, tv->cpu_affinity, SCGetThreadIdLong()); SetCPUAffinity(tv->cpu_affinity); } #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ if (tv->thread_setup_flags & THREAD_SET_PRIORITY) TmThreadSetPrio(tv); if (tv->thread_setup_flags & THREAD_SET_AFFTYPE) { ThreadsAffinityType *taf = &thread_affinity[tv->cpu_affinity]; if (taf->mode_flag == EXCLUSIVE_AFFINITY) { int cpu = AffinityGetNextCPU(taf); SetCPUAffinity(cpu); /* If CPU is in a set overwrite the default thread prio */ if (CPU_ISSET(cpu, &taf->lowprio_cpu)) { tv->thread_priority = PRIO_LOW; } else if (CPU_ISSET(cpu, &taf->medprio_cpu)) { tv->thread_priority = PRIO_MEDIUM; } else if (CPU_ISSET(cpu, &taf->hiprio_cpu)) { tv->thread_priority = PRIO_HIGH; } else { tv->thread_priority = taf->prio; } SCLogInfo("Setting prio %d for \"%s\" Module to cpu/core " "%"PRIu16", thread id %lu", tv->thread_priority, tv->name, cpu, SCGetThreadIdLong()); } else { SetCPUAffinitySet(&taf->cpu_set); tv->thread_priority = taf->prio; SCLogInfo("Setting prio %d for \"%s\" thread " ", thread id %lu", tv->thread_priority, tv->name, SCGetThreadIdLong()); } TmThreadSetPrio(tv); } #endif return TM_ECODE_OK; } /** * \brief Creates and returns the TV instance for a new thread. * * \param name Name of this TV instance * \param inq_name Incoming queue name * \param inqh_name Incoming queue handler name as set by TmqhSetup() * \param outq_name Outgoing queue name * \param outqh_name Outgoing queue handler as set by TmqhSetup() * \param slots String representation for the slot function to be used * \param fn_p Pointer to function when \"slots\" is of type \"custom\" * \param mucond Flag to indicate whether to initialize the condition * and the mutex variables for this newly created TV. * * \retval the newly created TV instance, or NULL on error */ ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, char *outq_name, char *outqh_name, char *slots, void * (*fn_p)(void *), int mucond) { ThreadVars *tv = NULL; Tmq *tmq = NULL; Tmqh *tmqh = NULL; SCLogDebug("creating thread \"%s\"...", name); /* XXX create separate function for this: allocate a thread container */ tv = SCMalloc(sizeof(ThreadVars)); if (unlikely(tv == NULL)) goto error; memset(tv, 0, sizeof(ThreadVars)); SC_ATOMIC_INIT(tv->flags); SCMutexInit(&tv->sc_perf_pctx.m, NULL); tv->name = name; /* default state for every newly created thread */ TmThreadsSetFlag(tv, THV_PAUSE); TmThreadsSetFlag(tv, THV_USE); /* default aof for every newly created thread */ tv->aof = THV_RESTART_THREAD; /* set the incoming queue */ if (inq_name != NULL && strcmp(inq_name, "packetpool") != 0) { SCLogDebug("inq_name \"%s\"", inq_name); tmq = TmqGetQueueByName(inq_name); if (tmq == NULL) { tmq = TmqCreateQueue(inq_name); if (tmq == NULL) goto error; } SCLogDebug("tmq %p", tmq); tv->inq = tmq; tv->inq->reader_cnt++; SCLogDebug("tv->inq %p", tv->inq); } if (inqh_name != NULL) { SCLogDebug("inqh_name \"%s\"", inqh_name); tmqh = TmqhGetQueueHandlerByName(inqh_name); if (tmqh == NULL) goto error; tv->tmqh_in = tmqh->InHandler; tv->InShutdownHandler = tmqh->InShutdownHandler; SCLogDebug("tv->tmqh_in %p", tv->tmqh_in); } /* set the outgoing queue */ if (outqh_name != NULL) { SCLogDebug("outqh_name \"%s\"", outqh_name); tmqh = TmqhGetQueueHandlerByName(outqh_name); if (tmqh == NULL) goto error; tv->tmqh_out = tmqh->OutHandler; tv->outqh_name = tmqh->name; if (outq_name != NULL && strcmp(outq_name, "packetpool") != 0) { SCLogDebug("outq_name \"%s\"", outq_name); if (tmqh->OutHandlerCtxSetup != NULL) { tv->outctx = tmqh->OutHandlerCtxSetup(outq_name); tv->outq = NULL; } else { tmq = TmqGetQueueByName(outq_name); if (tmq == NULL) { tmq = TmqCreateQueue(outq_name); if (tmq == NULL) goto error; } SCLogDebug("tmq %p", tmq); tv->outq = tmq; tv->outctx = NULL; tv->outq->writer_cnt++; } } } if (TmThreadSetSlots(tv, slots, fn_p) != TM_ECODE_OK) { goto error; } if (mucond != 0) TmThreadInitMC(tv); return tv; error: SCLogError(SC_ERR_THREAD_CREATE, "failed to setup a thread"); if (tv != NULL) SCFree(tv); return NULL; } /** * \brief Creates and returns a TV instance for a Packet Processing Thread. * This function doesn't support custom slots, and hence shouldn't be * supplied \"custom\" as its slot type. All PPT threads are created * with a mucond(see TmThreadCreate declaration) of 0. Hence the tv * conditional variables are not used to kill the thread. * * \param name Name of this TV instance * \param inq_name Incoming queue name * \param inqh_name Incoming queue handler name as set by TmqhSetup() * \param outq_name Outgoing queue name * \param outqh_name Outgoing queue handler as set by TmqhSetup() * \param slots String representation for the slot function to be used * * \retval the newly created TV instance, or NULL on error */ ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name, char *inqh_name, char *outq_name, char *outqh_name, char *slots) { ThreadVars *tv = NULL; tv = TmThreadCreate(name, inq_name, inqh_name, outq_name, outqh_name, slots, NULL, 0); if (tv != NULL) tv->type = TVT_PPT; return tv; } /** * \brief Creates and returns the TV instance for a Management thread(MGMT). * This function supports only custom slot functions and hence a * function pointer should be sent as an argument. * * \param name Name of this TV instance * \param fn_p Pointer to function when \"slots\" is of type \"custom\" * \param mucond Flag to indicate whether to initialize the condition * and the mutex variables for this newly created TV. * * \retval the newly created TV instance, or NULL on error */ ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), int mucond) { ThreadVars *tv = NULL; tv = TmThreadCreate(name, NULL, NULL, NULL, NULL, "custom", fn_p, mucond); if (tv != NULL) { tv->type = TVT_MGMT; TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); } return tv; } /** * \brief Creates and returns the TV instance for a CMD thread. * This function supports only custom slot functions and hence a * function pointer should be sent as an argument. * * \param name Name of this TV instance * \param fn_p Pointer to function when \"slots\" is of type \"custom\" * \param mucond Flag to indicate whether to initialize the condition * and the mutex variables for this newly created TV. * * \retval the newly created TV instance, or NULL on error */ ThreadVars *TmThreadCreateCmdThread(char *name, void *(fn_p)(void *), int mucond) { ThreadVars *tv = NULL; tv = TmThreadCreate(name, NULL, NULL, NULL, NULL, "custom", fn_p, mucond); if (tv != NULL) { tv->type = TVT_CMD; TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); } return tv; } /** * \brief Appends this TV to tv_root based on its type * * \param type holds the type this TV belongs to. */ void TmThreadAppend(ThreadVars *tv, int type) { SCMutexLock(&tv_root_lock); if (tv_root[type] == NULL) { tv_root[type] = tv; tv->next = NULL; tv->prev = NULL; SCMutexUnlock(&tv_root_lock); return; } ThreadVars *t = tv_root[type]; while (t) { if (t->next == NULL) { t->next = tv; tv->prev = t; tv->next = NULL; break; } t = t->next; } SCMutexUnlock(&tv_root_lock); return; } /** * \brief Removes this TV from tv_root based on its type * * \param tv The tv instance to remove from the global tv list. * \param type Holds the type this TV belongs to. */ void TmThreadRemove(ThreadVars *tv, int type) { SCMutexLock(&tv_root_lock); if (tv_root[type] == NULL) { SCMutexUnlock(&tv_root_lock); return; } ThreadVars *t = tv_root[type]; while (t != tv) { t = t->next; } if (t != NULL) { if (t->prev != NULL) t->prev->next = t->next; if (t->next != NULL) t->next->prev = t->prev; if (t == tv_root[type]) tv_root[type] = t->next;; } SCMutexUnlock(&tv_root_lock); return; } /** * \brief Kill a thread. * * \param tv A ThreadVars instance corresponding to the thread that has to be * killed. */ void TmThreadKillThread(ThreadVars *tv) { int i = 0; if (tv == NULL) return; if (tv->inq != NULL) { /* we wait till we dry out all the inq packets, before we * kill this thread. Do note that you should have disabled * packet acquire by now using TmThreadDisableReceiveThreads()*/ if (!(strlen(tv->inq->name) == strlen("packetpool") && strcasecmp(tv->inq->name, "packetpool") == 0)) { PacketQueue *q = &trans_q[tv->inq->id]; while (q->len != 0) { usleep(1000); } } } /* set the thread flag informing the thread that it needs to be * terminated */ TmThreadsSetFlag(tv, THV_KILL); TmThreadsSetFlag(tv, THV_DEINIT); /* to be sure, signal more */ int cnt = 0; while (1) { if (TmThreadsCheckFlag(tv, THV_CLOSED)) { SCLogDebug("signalled the thread %" PRId32 " times", cnt); break; } cnt++; if (tv->InShutdownHandler != NULL) { tv->InShutdownHandler(tv); } if (tv->inq != NULL) { for (i = 0; i < (tv->inq->reader_cnt + tv->inq->writer_cnt); i++) { if (tv->inq->q_type == 0) SCCondSignal(&trans_q[tv->inq->id].cond_q); else SCCondSignal(&data_queues[tv->inq->id].cond_q); } SCLogDebug("signalled tv->inq->id %" PRIu32 "", tv->inq->id); } if (tv->cond != NULL ) { pthread_cond_broadcast(tv->cond); } usleep(100); } if (tv->outctx != NULL) { Tmqh *tmqh = TmqhGetQueueHandlerByName(tv->outqh_name); if (tmqh == NULL) BUG_ON(1); if (tmqh->OutHandlerCtxFree != NULL) { tmqh->OutHandlerCtxFree(tv->outctx); } } /* join it */ pthread_join(tv->t, NULL); SCLogDebug("thread %s stopped", tv->name); return; } /** * \brief Disable all threads having the specified TMs. */ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) { /* value in seconds */ #define THREAD_KILL_MAX_WAIT_TIME 60 /* value in microseconds */ #define WAIT_TIME 100 double total_wait_time = 0; ThreadVars *tv = NULL; SCMutexLock(&tv_root_lock); /* all receive threads are part of packet processing threads */ tv = tv_root[TVT_PPT]; /* we do have to keep in mind that TVs are arranged in the order * right from receive to log. The moment we fail to find a * receive TM amongst the slots in a tv, it indicates we are done * with all receive threads */ while (tv) { int disable = 0; /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { TmModule *tm = TmModuleGetById(slots->tm_id); if (tm->flags & tm_flags) { disable = 1; break; } slots = slots->slot_next; continue; } if (disable) { if (tv->inq != NULL) { /* we wait till we dry out all the inq packets, before we * kill this thread. Do note that you should have disabled * packet acquire by now using TmThreadDisableReceiveThreads()*/ if (!(strlen(tv->inq->name) == strlen("packetpool") && strcasecmp(tv->inq->name, "packetpool") == 0)) { PacketQueue *q = &trans_q[tv->inq->id]; while (q->len != 0) { usleep(1000); } } } /* we found our receive TV. Send it a KILL signal. This is all * we need to do to kill receive threads */ TmThreadsSetFlag(tv, THV_KILL); if (tv->inq != NULL) { int i; for (i = 0; i < (tv->inq->reader_cnt + tv->inq->writer_cnt); i++) { if (tv->inq->q_type == 0) SCCondSignal(&trans_q[tv->inq->id].cond_q); else SCCondSignal(&data_queues[tv->inq->id].cond_q); } SCLogDebug("signalled tv->inq->id %" PRIu32 "", tv->inq->id); } while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { usleep(WAIT_TIME); total_wait_time += WAIT_TIME / 1000000.0; if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { SCLogError(SC_ERR_FATAL, "Engine unable to " "disable detect thread - \"%s\". " "Killing engine", tv->name); exit(EXIT_FAILURE); } } } tv = tv->next; } SCMutexUnlock(&tv_root_lock); return; } TmSlot *TmThreadGetFirstTmSlotForPartialPattern(const char *tm_name) { ThreadVars *tv = NULL; TmSlot *slots = NULL; SCMutexLock(&tv_root_lock); /* all receive threads are part of packet processing threads */ tv = tv_root[TVT_PPT]; while (tv) { slots = tv->tm_slots; while (slots != NULL) { TmModule *tm = TmModuleGetById(slots->tm_id); char *found = strstr(tm->name, tm_name); if (found != NULL) goto end; slots = slots->slot_next; } tv = tv->next; } end: SCMutexUnlock(&tv_root_lock); return slots; } void TmThreadKillThreadsFamily(int family) { ThreadVars *tv = NULL; if ((family < 0) || (family >= TVT_MAX)) return; tv = tv_root[family]; while (tv) { TmThreadKillThread(tv); tv = tv->next; } } void TmThreadKillThreads(void) { int i = 0; for (i = 0; i < TVT_MAX; i++) { TmThreadKillThreadsFamily(i); } return; } void TmThreadFree(ThreadVars *tv) { TmSlot *s; TmSlot *ps; if (tv == NULL) return; SCLogDebug("Freeing thread '%s'.", tv->name); SCMutexDestroy(&tv->sc_perf_pctx.m); s = (TmSlot *)tv->tm_slots; while (s) { ps = s; s = s->slot_next; SCFree(ps); } SCFree(tv); } void TmThreadClearThreadsFamily(int family) { ThreadVars *tv = NULL; ThreadVars *ptv = NULL; if ((family < 0) || (family >= TVT_MAX)) return; tv = tv_root[family]; while (tv) { ptv = tv; tv = tv->next; TmThreadFree(ptv); } tv_root[family] = NULL; } /** * \brief Spawns a thread associated with the ThreadVars instance tv * * \retval TM_ECODE_OK on success and TM_ECODE_FAILED on failure */ TmEcode TmThreadSpawn(ThreadVars *tv) { pthread_attr_t attr; if (tv->tm_func == NULL) { printf("ERROR: no thread function set\n"); return TM_ECODE_FAILED; } /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); int rc = pthread_create(&tv->t, &attr, tv->tm_func, (void *)tv); if (rc) { printf("ERROR; return code from pthread_create() is %" PRId32 "\n", rc); return TM_ECODE_FAILED; } TmThreadWaitForFlag(tv, THV_INIT_DONE | THV_RUNNING_DONE); TmThreadAppend(tv, tv->type); return TM_ECODE_OK; } /** * \brief Sets the thread flags for a thread instance(tv) * * \param tv Pointer to the thread instance for which the flag has to be set * \param flags Holds the thread state this thread instance has to be set to */ #if 0 void TmThreadSetFlags(ThreadVars *tv, uint8_t flags) { if (tv != NULL) tv->flags = flags; return; } #endif /** * \brief Sets the aof(Action on failure) for a thread instance(tv) * * \param tv Pointer to the thread instance for which the aof has to be set * \param aof Holds the aof this thread instance has to be set to */ void TmThreadSetAOF(ThreadVars *tv, uint8_t aof) { if (tv != NULL) tv->aof = aof; return; } /** * \brief Initializes the mutex and condition variables for this TV * * \param tv Pointer to a TV instance */ void TmThreadInitMC(ThreadVars *tv) { if ( (tv->m = SCMalloc(sizeof(SCMutex))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in TmThreadInitMC. " "Exiting..."); exit(EXIT_FAILURE); } if (SCMutexInit(tv->m, NULL) != 0) { printf("Error initializing the tv->m mutex\n"); exit(0); } if ( (tv->cond = SCMalloc(sizeof(SCCondT))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in TmThreadInitMC. " "Exiting..."); exit(0); } if (SCCondInit(tv->cond, NULL) != 0) { SCLogError(SC_ERR_FATAL, "Error initializing the tv->cond condition " "variable"); exit(0); } return; } /** * \brief Tests if the thread represented in the arg has been unpaused or not. * * The function would return if the thread tv has been unpaused or if the * kill flag for the thread has been set. * * \param tv Pointer to the TV instance. */ void TmThreadTestThreadUnPaused(ThreadVars *tv) { while (TmThreadsCheckFlag(tv, THV_PAUSE)) { usleep(100); if (TmThreadsCheckFlag(tv, THV_KILL)) break; } return; } /** * \brief Waits till the specified flag(s) is(are) set. We don't bother if * the kill flag has been set or not on the thread. * * \param tv Pointer to the TV instance. */ void TmThreadWaitForFlag(ThreadVars *tv, uint16_t flags) { while (!TmThreadsCheckFlag(tv, flags)) { usleep(100); } return; } /** * \brief Unpauses a thread * * \param tv Pointer to a TV instance that has to be unpaused */ void TmThreadContinue(ThreadVars *tv) { TmThreadsUnsetFlag(tv, THV_PAUSE); return; } /** * \brief Unpauses all threads present in tv_root */ void TmThreadContinueThreads() { ThreadVars *tv = NULL; int i = 0; for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { TmThreadContinue(tv); tv = tv->next; } } return; } /** * \brief Pauses a thread * * \param tv Pointer to a TV instance that has to be paused */ void TmThreadPause(ThreadVars *tv) { TmThreadsSetFlag(tv, THV_PAUSE); return; } /** * \brief Pauses all threads present in tv_root */ void TmThreadPauseThreads() { ThreadVars *tv = NULL; int i = 0; for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { TmThreadPause(tv); tv = tv->next; } } return; } /** * \brief Restarts the thread sent as the argument * * \param tv Pointer to the thread instance(tv) to be restarted */ static void TmThreadRestartThread(ThreadVars *tv) { if (tv->restarted >= THV_MAX_RESTARTS) { SCLogError(SC_ERR_TM_THREADS_ERROR,"thread restarts exceeded " "threshold limit for thread \"%s\"", tv->name); exit(EXIT_FAILURE); } TmThreadsUnsetFlag(tv, THV_CLOSED); TmThreadsUnsetFlag(tv, THV_FAILED); if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_THREAD_SPAWN, "thread \"%s\" failed to spawn", tv->name); exit(EXIT_FAILURE); } tv->restarted++; SCLogInfo("thread \"%s\" restarted", tv->name); return; } /** * \brief Used to check the thread for certain conditions of failure. If the * thread has been specified to restart on failure, the thread is * restarted. If the thread has been specified to gracefully shutdown * the engine on failure, it does so. The global aof flag, tv_aof * overrides the thread aof flag, if it holds a THV_ENGINE_EXIT; */ void TmThreadCheckThreadState(void) { ThreadVars *tv = NULL; int i = 0; for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv) { if (TmThreadsCheckFlag(tv, THV_FAILED)) { TmThreadsSetFlag(tv, THV_DEINIT); pthread_join(tv->t, NULL); if ((tv_aof & THV_ENGINE_EXIT) || (tv->aof & THV_ENGINE_EXIT)) { EngineKill(); return; } else { /* if the engine kill-stop has been received by now, chuck * restarting and return to kill the engine */ if ((suricata_ctl_flags & SURICATA_KILL) || (suricata_ctl_flags & SURICATA_STOP)) { return; } TmThreadRestartThread(tv); } } tv = tv->next; } } return; } /** * \brief Used to check if all threads have finished their initialization. On * finding an un-initialized thread, it waits till that thread completes * its initialization, before proceeding to the next thread. * * \retval TM_ECODE_OK all initialized properly * \retval TM_ECODE_FAILED failure */ TmEcode TmThreadWaitOnThreadInit(void) { ThreadVars *tv = NULL; int i = 0; uint16_t mgt_num = 0; uint16_t ppt_num = 0; for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { char started = FALSE; while (started == FALSE) { if (TmThreadsCheckFlag(tv, THV_INIT_DONE)) { started = TRUE; } else { /* sleep a little to give the thread some * time to finish initialization */ usleep(100); } if (TmThreadsCheckFlag(tv, THV_FAILED)) { SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " "initialize.", tv->name); return TM_ECODE_FAILED; } if (TmThreadsCheckFlag(tv, THV_CLOSED)) { SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" closed on " "initialization.", tv->name); return TM_ECODE_FAILED; } } if (i == TVT_MGMT) mgt_num++; else if (i == TVT_PPT) ppt_num++; tv = tv->next; } } SCLogInfo("all %"PRIu16" packet processing threads, %"PRIu16" management " "threads initialized, engine started.", ppt_num, mgt_num); return TM_ECODE_OK; } /** * \brief Returns the TV for the calling thread. * * \retval tv Pointer to the ThreadVars instance for the calling thread; * NULL on no match */ ThreadVars *TmThreadsGetCallingThread(void) { pthread_t self = pthread_self(); ThreadVars *tv = NULL; int i = 0; SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv) { if (pthread_equal(self, tv->t)) { SCMutexUnlock(&tv_root_lock); return tv; } tv = tv->next; } } SCMutexUnlock(&tv_root_lock); return NULL; } suricata-1.4.7/src/detect-http-header.c0000644000000000000000000015245612253546156014661 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Pablo Rincon * * Implements support for http_header keyword. */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "util-print.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-header.h" #include "stream-tcp.h" int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpHeaderRegisterTests(void); void DetectHttpHeaderFree(void *); /** * \brief Registers the keyword handlers for the "http_header" keyword. */ void DetectHttpHeaderRegister(void) { sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header"; sigmatch_table[DETECT_AL_HTTP_HEADER].desc = "content modifier to match only on the HTTP header-buffer"; sigmatch_table[DETECT_AL_HTTP_HEADER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_header"; sigmatch_table[DETECT_AL_HTTP_HEADER].Match = NULL; sigmatch_table[DETECT_AL_HTTP_HEADER].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; sigmatch_table[DETECT_AL_HTTP_HEADER].Free = DetectHttpHeaderFree; sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; sigmatch_table[DETECT_AL_HTTP_HEADER].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; return; } /** * \brief this function clears the memory of http_header modifier keyword * * \param ptr Pointer to the Detection Header Data */ void DetectHttpHeaderFree(void *ptr) { DetectContentData *hhd = (DetectContentData *)ptr; if (hhd == NULL) return; if (hhd->content != NULL) SCFree(hhd->content); SCFree(hhd); return; } /** * \brief The setup function for the http_header keyword for a signature. * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to signature for the current Signature being parsed * from the rules. * \param m Pointer to the head of the SigMatchs for the current rule * being parsed. * \param arg Pointer to the string holding the keyword value. * * \retval 0 On success. * \retval -1 On failure. */ int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_header supplied with args"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if still we are unable to find any content previous keywords, it is an * invalid rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_header\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_header\" keyword"); return -1; } /* cast for further use */ cd = (DetectContentData *)sm->ctx; /* http_header should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_header rule can not " "be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); if (pm != NULL) { /* pm is never NULL. So no NULL check */ if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* please note. reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_header seen with a " "distance or within without a previous http_header " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HHDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hhdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HHDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: //if (cd != NULL) // DetectHttpHeaderFree(cd); // //if (sm != NULL) // SCFree(sm); return -1; } /************************************Unittests*********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Test that a signature containting a http_header is correctly parsed * and the keyword is registered. */ static int DetectHttpHeaderTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; SigMatch *sm = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; " "content:\"one\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("Error parsing signature: "); goto end; } sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; if (sm != NULL) { result &= (sm->type == DETECT_CONTENT); result &= (sm->next == NULL); } else { result = 0; printf("Error updating content pattern to http_header pattern: "); } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a signature containing an valid http_header entry is * parsed. */ static int DetectHttpHeaderTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; " "content:\"one\"; http_header:; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; else printf("Error parsing signature: "); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing no content but a http_header * is invalidated. */ static int DetectHttpHeaderTest03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; " "http_header; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; else printf("Error parsing signature: "); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_header is invalidated. */ static int DetectHttpHeaderTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; " "content:\"one\"; rawbytes; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; else printf("Error parsing signature: "); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_header is invalidated. */ static int DetectHttpHeaderTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_header\"; " "content:\"one\"; nocase; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; else printf("Error parsing signature: "); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectHttpHeaderTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Content-Type: text/html\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectHttpHeaderTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozi"; uint8_t http2_buf[] = "lla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\nContent-Type: text/html\r\n" "Content-Length: 67\r\n" "\r\n" "This is dummy message body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Mozilla\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ( (PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectHttpHeaderTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n"; uint8_t http2_buf[] = "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 67\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Gecko/20091221 Firefox/3.5.7\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content, against a cross boundary present pattern. */ static int DetectHttpHeaderTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n"; uint8_t http2_buf[] = "Content-Type: text/html\r\n" "Content-Length: 67\r\n" "\r\n" "This is dummy body\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->mpm_matcher = MPM_AC; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Firefox/3.5.7|0D 0A|Content\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_header content matches against a http request * against a case insensitive pattern. */ static int DetectHttpHeaderTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n"; uint8_t http2_buf[] = "Content-Type: text/html\r\n" "Content-Length: 67\r\n" "\r\n" "This is dummy body"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"firefox/3.5.7|0D 0A|content\"; nocase; http_header;" "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the negated http_header content matches against a * http request which doesn't hold the content. */ static int DetectHttpHeaderTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"lalalalala\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Negative test that the negated http_header content matches against a * http request which holds hold the content. */ static int DetectHttpHeaderTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"User-Agent: Mozilla/5.0 \"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectHttpHeaderTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 100\r\n" "\r\n" "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Host: www.openinfosecfoundation.org\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } int DetectHttpHeaderTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (cd->id == hhd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (cd->id == hhd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_header; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (cd->id != 0 || hhd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (cd->id != 1 || hhd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; " "content:\"one\"; content:\"one\"; http_header; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (cd->id != 1 || hhd1->id != 0 || hhd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; " "content:\"one\"; content:\"one\"; http_header; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; if (cd->id != 2 || hhd1->id != 0 || hhd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; " "content:\"two\"; distance:0; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "one", hhd1->content_len) != 0 || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; " "content:\"two\"; within:5; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "one", hhd1->content_len) != 0 || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_header; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(pcre:/one/H; " "content:\"two\"; within:5; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HEADER) || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_header; " "pcre:/one/HR; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_PCRE || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_CONTENT) { goto end; } DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HEADER) || hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "two", hhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHeaderTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(pcre:/one/H; " "content:\"two\"; distance:5; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HEADER) || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ void DetectHttpHeaderRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectHttpHeaderTest01", DetectHttpHeaderTest01, 1); UtRegisterTest("DetectHttpHeaderTest02", DetectHttpHeaderTest02, 1); UtRegisterTest("DetectHttpHeaderTest03", DetectHttpHeaderTest03, 1); UtRegisterTest("DetectHttpHeaderTest04", DetectHttpHeaderTest04, 1); UtRegisterTest("DetectHttpHeaderTest05", DetectHttpHeaderTest05, 1); UtRegisterTest("DetectHttpHeaderTest06", DetectHttpHeaderTest06, 1); UtRegisterTest("DetectHttpHeaderTest07", DetectHttpHeaderTest07, 1); UtRegisterTest("DetectHttpHeaderTest08", DetectHttpHeaderTest08, 1); UtRegisterTest("DetectHttpHeaderTest09", DetectHttpHeaderTest09, 1); UtRegisterTest("DetectHttpHeaderTest10", DetectHttpHeaderTest10, 1); UtRegisterTest("DetectHttpHeaderTest11", DetectHttpHeaderTest11, 1); UtRegisterTest("DetectHttpHeaderTest12", DetectHttpHeaderTest12, 1); UtRegisterTest("DetectHttpHeaderTest13", DetectHttpHeaderTest13, 1); UtRegisterTest("DetectHttpHeaderTest14", DetectHttpHeaderTest14, 1); UtRegisterTest("DetectHttpHeaderTest15", DetectHttpHeaderTest15, 1); UtRegisterTest("DetectHttpHeaderTest16", DetectHttpHeaderTest16, 1); UtRegisterTest("DetectHttpHeaderTest17", DetectHttpHeaderTest17, 1); UtRegisterTest("DetectHttpHeaderTest18", DetectHttpHeaderTest18, 1); UtRegisterTest("DetectHttpHeaderTest19", DetectHttpHeaderTest19, 1); UtRegisterTest("DetectHttpHeaderTest20", DetectHttpHeaderTest20, 1); UtRegisterTest("DetectHttpHeaderTest21", DetectHttpHeaderTest21, 1); UtRegisterTest("DetectHttpHeaderTest22", DetectHttpHeaderTest22, 1); UtRegisterTest("DetectHttpHeaderTest23", DetectHttpHeaderTest23, 1); UtRegisterTest("DetectHttpHeaderTest24", DetectHttpHeaderTest24, 1); UtRegisterTest("DetectHttpHeaderTest25", DetectHttpHeaderTest25, 1); UtRegisterTest("DetectHttpHeaderTest26", DetectHttpHeaderTest26, 1); UtRegisterTest("DetectHttpHeaderTest27", DetectHttpHeaderTest27, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/decode-gre.c0000644000000000000000000002671112253546156013176 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Breno Silva * * Decodes GRE */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "decode-events.h" #include "decode-gre.h" #include "util-unittest.h" #include "util-debug.h" /** * \brief Function to decode GRE packets */ void DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint16_t header_len = GRE_HDR_LEN; GRESreHdr *gsre = NULL; SCPerfCounterIncr(dtv->counter_gre, tv->sc_perf_pca); if(len < GRE_HDR_LEN) { ENGINE_SET_EVENT(p,GRE_PKT_TOO_SMALL); return; } p->greh = (GREHdr *)pkt; if(p->greh == NULL) return; SCLogDebug("p %p pkt %p GRE protocol %04x Len: %d GRE version %x", p, pkt, GRE_GET_PROTO(p->greh), len,GRE_GET_VERSION(p->greh)); switch (GRE_GET_VERSION(p->greh)) { case GRE_VERSION_0: /* GRE version 0 doenst support the fields below RFC 1701 */ /** * \todo We need to make sure this does not allow bypassing * inspection. A server may just ignore these and * continue processing the packet, but we will not look * further into it. */ if (GRE_FLAG_ISSET_RECUR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION0_RECUR); return; } if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION0_FLAGS); return; } /* Adjust header length based on content */ if (GRE_FLAG_ISSET_KY(p->greh)) header_len += GRE_KEY_LEN; if (GRE_FLAG_ISSET_SQ(p->greh)) header_len += GRE_SEQ_LEN; if (GRE_FLAG_ISSET_CHKSUM(p->greh) || GRE_FLAG_ISSET_ROUTE(p->greh)) header_len += GRE_CHKSUM_LEN + GRE_OFFSET_LEN; if (header_len > len) { ENGINE_SET_EVENT(p,GRE_VERSION0_HDR_TOO_BIG); return; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { while (1) { if ((header_len + GRE_SRE_HDR_LEN) > len) { ENGINE_SET_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return; } gsre = (GRESreHdr *)(pkt + header_len); header_len += GRE_SRE_HDR_LEN; if ((ntohs(gsre->af) == 0) && (gsre->sre_length == 0)) break; header_len += gsre->sre_length; if (header_len > len) { ENGINE_SET_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return; } } } break; case GRE_VERSION_1: /* GRE version 1 doenst support the fields below RFC 1701 */ /** * \todo We need to make sure this does not allow bypassing * inspection. A server may just ignore these and * continue processing the packet, but we will not look * further into it. */ if (GRE_FLAG_ISSET_CHKSUM(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_CHKSUM); return; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_ROUTE); return; } if (GRE_FLAG_ISSET_SSR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_SSR); return; } if (GRE_FLAG_ISSET_RECUR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_RECUR); return; } if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_FLAGS); return; } if (GRE_GET_PROTO(p->greh) != GRE_PROTO_PPP) { ENGINE_SET_EVENT(p,GRE_VERSION1_WRONG_PROTOCOL); return; } if (!(GRE_FLAG_ISSET_KY(p->greh))) { ENGINE_SET_EVENT(p,GRE_VERSION1_NO_KEY); return; } header_len += GRE_KEY_LEN; /* Adjust header length based on content */ if (GRE_FLAG_ISSET_SQ(p->greh)) header_len += GRE_SEQ_LEN; if (GREV1_FLAG_ISSET_ACK(p->greh)) header_len += GREV1_ACK_LEN; if (header_len > len) { ENGINE_SET_EVENT(p,GRE_VERSION1_HDR_TOO_BIG); return; } break; default: ENGINE_SET_EVENT(p,GRE_WRONG_VERSION); return; } switch (GRE_GET_PROTO(p->greh)) { case ETHERNET_TYPE_IP: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, IPPROTO_IP); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IP); PacketEnqueue(pq,tp); } } break; } case GRE_PROTO_PPP: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, PPP_OVER_GRE); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, PPP_OVER_GRE); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_IPV6: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, IPPROTO_IPV6); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IPV6); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_VLAN: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, VLAN_OVER_GRE); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, VLAN_OVER_GRE); PacketEnqueue(pq,tp); } } break; } default: return; } } #ifdef UNITTESTS /** * \test DecodeGRETest01 is a test for small gre packet */ static int DecodeGREtest01 (void) { uint8_t raw_gre[] = { 0x00 ,0x6e ,0x62 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeGRE(&tv, &dtv, p, raw_gre, sizeof(raw_gre), NULL); if(ENGINE_ISSET_EVENT(p,GRE_PKT_TOO_SMALL)) { SCFree(p); return 1; } SCFree(p); return 0; } /** * \test DecodeGRETest02 is a test for wrong gre version */ static int DecodeGREtest02 (void) { uint8_t raw_gre[] = { 0x00, 0x6e, 0x62, 0xac, 0x40, 0x00, 0x40, 0x2f, 0xc2, 0xc7, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x0b, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x18, 0x4a, 0x50, 0xff, 0x03, 0x00, 0x21, 0x45, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, 0x94, 0x22, 0x50, 0x7e, 0x2b, 0x2d, 0xc2, 0x6d, 0x68, 0x68, 0x80, 0x0e, 0x00, 0x35, 0x00, 0x36, 0x9f, 0x18, 0xdb, 0xc4, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x73, 0x31, 0x36, 0x09, 0x73, 0x69, 0x74, 0x65, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeGRE(&tv, &dtv, p, raw_gre, sizeof(raw_gre), NULL); if(ENGINE_ISSET_EVENT(p,GRE_WRONG_VERSION)) { SCFree(p); return 1; } SCFree(p); return 0; } /** * \test DecodeGRETest03 is a test for valid gre packet */ static int DecodeGREtest03 (void) { uint8_t raw_gre[] = { 0x00, 0x6e, 0x62, 0xac, 0x40, 0x00, 0x40, 0x2f, 0xc2, 0xc7, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x88, 0x0b, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x18, 0x4a, 0x50, 0xff, 0x03, 0x00, 0x21, 0x45, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, 0x94, 0x22, 0x50, 0x7e, 0x2b, 0x2d, 0xc2, 0x6d, 0x68, 0x68, 0x80, 0x0e, 0x00, 0x35, 0x00, 0x36, 0x9f, 0x18, 0xdb, 0xc4, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x73, 0x31, 0x36, 0x09, 0x73, 0x69, 0x74, 0x65, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeGRE(&tv, &dtv, p, raw_gre, sizeof(raw_gre), NULL); if(p->greh == NULL) { SCFree(p); return 0; } SCFree(p); return 1; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for GRE decoder */ void DecodeGRERegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeGREtest01", DecodeGREtest01, 1); UtRegisterTest("DecodeGREtest02", DecodeGREtest02, 1); UtRegisterTest("DecodeGREtest03", DecodeGREtest03, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/util-crypt.h0000644000000000000000000000562712253546156013324 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Roliers Jean-Paul * * Implements cryptographic functions. * Based on the libtomcrypt library ( http://libtom.org/?page=features&newsitems=5&whatfile=crypt ) */ #ifndef UTIL_CRYPT_H_ #define UTIL_CRYPT_H_ #include "suricata-common.h" typedef enum { SC_SHA_1_OK, SC_SHA_1_NOK, SC_SHA_1_INVALID_ARG, SC_BASE64_OK, SC_BASE64_INVALID_ARG, SC_BASE64_OVERFLOW, } CryptId; #ifndef HAVE_NSS #define LOAD32H(x, y) \ { x = ((unsigned long)((y)[0] & 255)<<24) | \ ((unsigned long)((y)[1] & 255)<<16) | \ ((unsigned long)((y)[2] & 255)<<8) | \ ((unsigned long)((y)[3] & 255)); } #define STORE64H(x, y) \ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } #define STORE32H(x, y) \ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } #define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) #define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) #ifndef MIN #define MIN(x, y) ( ((x)<(y))?(x):(y) ) #endif typedef struct Sha1State_ { uint64_t length; uint32_t state[5], curlen; unsigned char buf[64]; } Sha1State; typedef union HashState_ { char dummy[1]; Sha1State sha1; void *data; } HashState; #endif /* don't HAVE_NSS */ unsigned char* ComputeSHA1(unsigned char* buff, int bufflen); int Base64Encode(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen); #endif /* UTIL_CRYPT_H_ */ suricata-1.4.7/src/detect-engine-siggroup.c0000644000000000000000000021220212253546156015540 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Signature grouping part of the detection engine. */ #include "suricata-common.h" #include "decode.h" #include "flow-var.h" #include "app-layer-protos.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-address.h" #include "detect-engine-mpm.h" #include "detect-engine-siggroup.h" #include "detect-content.h" #include "detect-uricontent.h" #include "util-hash.h" #include "util-hashlist.h" #include "util-error.h" #include "util-debug.h" #include "util-cidr.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-memcmp.h" /* prototypes */ int SigGroupHeadClearSigs(SigGroupHead *); static uint32_t detect_siggroup_head_memory = 0; static uint32_t detect_siggroup_head_init_cnt = 0; static uint32_t detect_siggroup_head_free_cnt = 0; static uint32_t detect_siggroup_head_initdata_memory = 0; static uint32_t detect_siggroup_head_initdata_init_cnt = 0; static uint32_t detect_siggroup_head_initdata_free_cnt = 0; static uint32_t detect_siggroup_sigarray_memory = 0; static uint32_t detect_siggroup_sigarray_init_cnt = 0; static uint32_t detect_siggroup_sigarray_free_cnt = 0; static uint32_t detect_siggroup_matcharray_memory = 0; static uint32_t detect_siggroup_matcharray_init_cnt = 0; static uint32_t detect_siggroup_matcharray_free_cnt = 0; void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid) { if (sghid->content_array != NULL) { SCFree(sghid->content_array); sghid->content_array = NULL; sghid->content_size = 0; } if (sghid->uri_content_array != NULL) { SCFree(sghid->uri_content_array); sghid->uri_content_array = NULL; sghid->uri_content_size = 0; } if (sghid->sig_array != NULL) { SCFree(sghid->sig_array); sghid->sig_array = NULL; detect_siggroup_sigarray_free_cnt++; detect_siggroup_sigarray_memory -= sghid->sig_size; } SCFree(sghid); detect_siggroup_head_initdata_free_cnt++; detect_siggroup_head_initdata_memory -= sizeof(SigGroupHeadInitData); } static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) { SigGroupHeadInitData *sghid = SCMalloc(sizeof(SigGroupHeadInitData)); if (unlikely(sghid == NULL)) return NULL; memset(sghid, 0x00, sizeof(SigGroupHeadInitData)); detect_siggroup_head_initdata_init_cnt++; detect_siggroup_head_initdata_memory += sizeof(SigGroupHeadInitData); /* initialize the signature bitarray */ sghid->sig_size = size; if ( (sghid->sig_array = SCMalloc(sghid->sig_size)) == NULL) goto error; memset(sghid->sig_array, 0, sghid->sig_size); detect_siggroup_sigarray_init_cnt++; detect_siggroup_sigarray_memory += sghid->sig_size; return sghid; error: SigGroupHeadInitDataFree(sghid); return NULL; } void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { //printf("de_ctx->sgh_array_cnt %u, de_ctx->sgh_array_size %u, de_ctx->sgh_array %p\n", de_ctx->sgh_array_cnt, de_ctx->sgh_array_size, de_ctx->sgh_array); if (de_ctx->sgh_array_cnt < de_ctx->sgh_array_size) { de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; } else { de_ctx->sgh_array = SCRealloc(de_ctx->sgh_array, sizeof(SigGroupHead *) * (16 + de_ctx->sgh_array_size)); if (de_ctx->sgh_array == NULL) return; de_ctx->sgh_array_size += 10; de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; } de_ctx->sgh_array_cnt++; } /** * \brief Alloc a SigGroupHead and its signature bit_array. * * \param size Size of the sig_array that has to be created for this * SigGroupHead. * * \retval sgh Pointer to the newly init SigGroupHead on success; or NULL in * case of error. */ static SigGroupHead *SigGroupHeadAlloc(DetectEngineCtx *de_ctx, uint32_t size) { SigGroupHead *sgh = SCMalloc(sizeof(SigGroupHead)); if (unlikely(sgh == NULL)) return NULL; memset(sgh, 0, sizeof(SigGroupHead)); sgh->init = SigGroupHeadInitDataAlloc(size); if (sgh->init == NULL) goto error; detect_siggroup_head_init_cnt++; detect_siggroup_head_memory += sizeof(SigGroupHead); return sgh; error: SigGroupHeadFree(sgh); return NULL; } /** * \brief Free a SigGroupHead and its members. * * \param sgh Pointer to the SigGroupHead that has to be freed. */ void SigGroupHeadFree(SigGroupHead *sgh) { if (sgh == NULL) return; SCLogDebug("sgh %p", sgh); PatternMatchDestroyGroup(sgh); #if defined(__SSE3__) if (sgh->mask_array != NULL) { /* mask is aligned */ SCFreeAligned(sgh->mask_array); sgh->mask_array = NULL; } #endif if (sgh->head_array != NULL) { SCFree(sgh->head_array); sgh->head_array = NULL; } if (sgh->match_array != NULL) { detect_siggroup_matcharray_free_cnt++; detect_siggroup_matcharray_memory -= (sgh->sig_cnt * sizeof(Signature *)); SCFree(sgh->match_array); sgh->match_array = NULL; } sgh->sig_cnt = 0; if (sgh->init != NULL) { SigGroupHeadInitDataFree(sgh->init); sgh->init = NULL; } SCFree(sgh); detect_siggroup_head_free_cnt++; detect_siggroup_head_memory -= sizeof(SigGroupHead); return; } /** * \brief The hash function to be the used by the mpm SigGroupHead hash table - * DetectEngineCtx->sgh_mpm_hash_table. * * \param ht Pointer to the hash table. * \param data Pointer to the SigGroupHead. * \param datalen Not used in our case. * * \retval hash The generated hash value. */ uint32_t SigGroupHeadMpmHashFunc(HashListTable *ht, void *data, uint16_t datalen) { SigGroupHead *sgh = (SigGroupHead *)data; uint32_t hash = 0; uint32_t b = 0; for (b = 0; b < sgh->init->content_size; b++) hash += sgh->init->content_array[b]; return hash % ht->array_size; } /** * \brief The Compare function to be used by the mpm SigGroupHead hash table - * DetectEngineCtx->sgh_mpm_hash_table. * * \param data1 Pointer to the first SigGroupHead. * \param len1 Not used. * \param data2 Pointer to the second SigGroupHead. * \param len2 Not used. * * \retval 1 If the 2 SigGroupHeads sent as args match. * \retval 0 If the 2 SigGroupHeads sent as args do not match. */ char SigGroupHeadMpmCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { SigGroupHead *sgh1 = (SigGroupHead *)data1; SigGroupHead *sgh2 = (SigGroupHead *)data2; if (sgh1->init->content_size != sgh2->init->content_size) return 0; if (SCMemcmp(sgh1->init->content_array, sgh2->init->content_array, sgh1->init->content_size) != 0) { return 0; } return 1; } /** * \brief Initializes the SigGroupHead mpm hash table to be used by the detection * engine context. * * \param de_ctx Pointer to the detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ int SigGroupHeadMpmHashInit(DetectEngineCtx *de_ctx) { de_ctx->sgh_mpm_hash_table = HashListTableInit(4096, SigGroupHeadMpmHashFunc, SigGroupHeadMpmCompareFunc, NULL); if (de_ctx->sgh_mpm_hash_table == NULL) goto error; return 0; error: return -1; } /** * \brief Adds a SigGroupHead to the detection engine context SigGroupHead * mpm hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval ret 0 on Successfully adding the argument sgh; -1 on failure. */ int SigGroupHeadMpmHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { int ret = HashListTableAdd(de_ctx->sgh_mpm_hash_table, (void *)sgh, 0); return ret; } /** * \brief Used to lookup a SigGroupHead from the detection engine context * SigGroupHead mpm hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is * found in the hash table; NULL on failure. */ SigGroupHead *SigGroupHeadMpmHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_hash_table, (void *)sgh, 0); return rsgh; } /** * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_hash_table, allocated by * SigGroupHeadMpmHashInit() function. * * \param de_ctx Pointer to the detection engine context. */ void SigGroupHeadMpmHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->sgh_mpm_hash_table == NULL) return; HashListTableFree(de_ctx->sgh_mpm_hash_table); de_ctx->sgh_mpm_hash_table = NULL; return; } /** * \brief The hash function to be the used by the mpm uri SigGroupHead hash * table - DetectEngineCtx->sgh_mpm_uri_hash_table. * * \param ht Pointer to the hash table. * \param data Pointer to the SigGroupHead. * \param datalen Not used in our case. * * \retval hash The generated hash value. */ uint32_t SigGroupHeadMpmUriHashFunc(HashListTable *ht, void *data, uint16_t datalen) { SigGroupHead *sgh = (SigGroupHead *)data; uint32_t hash = 0; uint32_t b = 0; for (b = 0; b < sgh->init->uri_content_size; b++) hash += sgh->init->uri_content_array[b]; return hash % ht->array_size; } /** * \brief The Compare function to be used by the mpm uri SigGroupHead hash * table - DetectEngineCtx->sgh_mpm_uri_hash_table. * * \param data1 Pointer to the first SigGroupHead. * \param len1 Not used. * \param data2 Pointer to the second SigGroupHead. * \param len2 Not used. * * \retval 1 If the 2 SigGroupHeads sent as args match. * \retval 0 If the 2 SigGroupHeads sent as args do not match. */ char SigGroupHeadMpmUriCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { SigGroupHead *sgh1 = (SigGroupHead *)data1; SigGroupHead *sgh2 = (SigGroupHead *)data2; if (sgh1->init->uri_content_size != sgh2->init->uri_content_size) return 0; if (SCMemcmp(sgh1->init->uri_content_array, sgh2->init->uri_content_array, sgh1->init->uri_content_size) != 0) { return 0; } return 1; } /** * \brief Initializes the mpm uri hash table to be used by the detection engine * context. * * \param de_ctx Pointer to the detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ int SigGroupHeadMpmUriHashInit(DetectEngineCtx *de_ctx) { de_ctx->sgh_mpm_uri_hash_table = HashListTableInit(4096, SigGroupHeadMpmUriHashFunc, SigGroupHeadMpmUriCompareFunc, NULL); if (de_ctx->sgh_mpm_uri_hash_table == NULL) goto error; return 0; error: return -1; } /** * \brief Adds a SigGroupHead to the detection engine context SigGroupHead * mpm uri hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. */ int SigGroupHeadMpmUriHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { int ret = HashListTableAdd(de_ctx->sgh_mpm_uri_hash_table, (void *)sgh, 0); return ret; } /** * \brief Used to lookup a SigGroupHead from the detection engine context * SigGroupHead mpm uri hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is * found in the hash table; NULL on failure. */ SigGroupHead *SigGroupHeadMpmUriHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_uri_hash_table, (void *)sgh, 0); return rsgh; } /** * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_uri_hash_table, * allocated by SigGroupHeadMpmUriHashInit() function. * * \param de_ctx Pointer to the detection engine context. */ void SigGroupHeadMpmUriHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->sgh_mpm_uri_hash_table == NULL) return; HashListTableFree(de_ctx->sgh_mpm_uri_hash_table); de_ctx->sgh_mpm_uri_hash_table = NULL; return; } /** * \brief The hash function to be the used by the mpm uri SigGroupHead hash * table - DetectEngineCtx->sgh_mpm_uri_hash_table. * * \param ht Pointer to the hash table. * \param data Pointer to the SigGroupHead. * \param datalen Not used in our case. * * \retval hash The generated hash value. */ uint32_t SigGroupHeadMpmStreamHashFunc(HashListTable *ht, void *data, uint16_t datalen) { SigGroupHead *sgh = (SigGroupHead *)data; uint32_t hash = 0; uint32_t b = 0; for (b = 0; b < sgh->init->stream_content_size; b++) hash += sgh->init->stream_content_array[b]; return hash % ht->array_size; } /** * \brief The Compare function to be used by the mpm uri SigGroupHead hash * table - DetectEngineCtx->sgh_mpm_uri_hash_table. * * \param data1 Pointer to the first SigGroupHead. * \param len1 Not used. * \param data2 Pointer to the second SigGroupHead. * \param len2 Not used. * * \retval 1 If the 2 SigGroupHeads sent as args match. * \retval 0 If the 2 SigGroupHeads sent as args do not match. */ char SigGroupHeadMpmStreamCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { SigGroupHead *sgh1 = (SigGroupHead *)data1; SigGroupHead *sgh2 = (SigGroupHead *)data2; if (sgh1->init->stream_content_size != sgh2->init->stream_content_size) return 0; if (SCMemcmp(sgh1->init->stream_content_array, sgh2->init->stream_content_array, sgh1->init->stream_content_size) != 0) { return 0; } return 1; } /** * \brief Initializes the mpm uri hash table to be used by the detection engine * context. * * \param de_ctx Pointer to the detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ int SigGroupHeadMpmStreamHashInit(DetectEngineCtx *de_ctx) { de_ctx->sgh_mpm_stream_hash_table = HashListTableInit(4096, SigGroupHeadMpmStreamHashFunc, SigGroupHeadMpmStreamCompareFunc, NULL); if (de_ctx->sgh_mpm_stream_hash_table == NULL) goto error; return 0; error: return -1; } /** * \brief Adds a SigGroupHead to the detection engine context SigGroupHead * mpm uri hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. */ int SigGroupHeadMpmStreamHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { int ret = HashListTableAdd(de_ctx->sgh_mpm_stream_hash_table, (void *)sgh, 0); return ret; } /** * \brief Used to lookup a SigGroupHead from the detection engine context * SigGroupHead mpm uri hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is * found in the hash table; NULL on failure. */ SigGroupHead *SigGroupHeadMpmStreamHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_stream_hash_table, (void *)sgh, 0); return rsgh; } /** * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_uri_hash_table, * allocated by SigGroupHeadMpmUriHashInit() function. * * \param de_ctx Pointer to the detection engine context. */ void SigGroupHeadMpmStreamHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->sgh_mpm_stream_hash_table == NULL) return; HashListTableFree(de_ctx->sgh_mpm_stream_hash_table); de_ctx->sgh_mpm_stream_hash_table = NULL; return; } /** * \brief The hash function to be the used by the hash table - * DetectEngineCtx->sgh_hash_table. * * \param ht Pointer to the hash table. * \param data Pointer to the SigGroupHead. * \param datalen Not used in our case. * * \retval hash The generated hash value. */ uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t datalen) { SigGroupHead *sgh = (SigGroupHead *)data; uint32_t hash = 0; uint32_t b = 0; SCLogDebug("hashing sgh %p (mpm_content_maxlen %u)", sgh, sgh->mpm_content_maxlen); for (b = 0; b < sgh->init->sig_size; b++) hash += sgh->init->sig_array[b]; hash %= ht->array_size; SCLogDebug("hash %"PRIu32" (sig_size %"PRIu32")", hash, sgh->init->sig_size); return hash; } /** * \brief The Compare function to be used by the SigGroupHead hash table - * DetectEngineCtx->sgh_hash_table. * * \param data1 Pointer to the first SigGroupHead. * \param len1 Not used. * \param data2 Pointer to the second SigGroupHead. * \param len2 Not used. * * \retval 1 If the 2 SigGroupHeads sent as args match. * \retval 0 If the 2 SigGroupHeads sent as args do not match. */ char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { SigGroupHead *sgh1 = (SigGroupHead *)data1; SigGroupHead *sgh2 = (SigGroupHead *)data2; if (data1 == NULL || data2 == NULL) return 0; if (sgh1->init->sig_size != sgh2->init->sig_size) return 0; if (SCMemcmp(sgh1->init->sig_array, sgh2->init->sig_array, sgh1->init->sig_size) != 0) return 0; return 1; } /** * \brief Initializes the hash table in the detection engine context to hold the * SigGroupHeads. * * \param de_ctx Pointer to the detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ int SigGroupHeadHashInit(DetectEngineCtx *de_ctx) { de_ctx->sgh_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, SigGroupHeadCompareFunc, NULL); if (de_ctx->sgh_hash_table == NULL) goto error; return 0; error: return -1; } /** * \brief Adds a SigGroupHead to the detection engine context SigGroupHead * hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval ret 0 on Successfully adding the SigGroupHead; -1 on failure. */ int SigGroupHeadHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { int ret = HashListTableAdd(de_ctx->sgh_hash_table, (void *)sgh, 0); return ret; } int SigGroupHeadHashRemove(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { return HashListTableRemove(de_ctx->sgh_hash_table, (void *)sgh, 0); } /** * \brief Used to lookup a SigGroupHead hash from the detection engine context * SigGroupHead hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is * found in the hash table; NULL on failure. */ SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table, (void *)sgh, 0); SCReturnPtr(rsgh, "SigGroupHead"); } /** * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by * SigGroupHeadHashInit() function. * * \param de_ctx Pointer to the detection engine context. */ void SigGroupHeadHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->sgh_hash_table == NULL) return; HashListTableFree(de_ctx->sgh_hash_table); de_ctx->sgh_hash_table = NULL; return; } /** * \brief Initializes the dport based SigGroupHead hash table to hold the * SigGroupHeads. The hash table that would be initialized is * DetectEngineCtx->sgh_dport_hash_table. * * \param de_ctx Pointer to the detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ int SigGroupHeadDPortHashInit(DetectEngineCtx *de_ctx) { de_ctx->sgh_dport_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, SigGroupHeadCompareFunc, NULL); if (de_ctx->sgh_dport_hash_table == NULL) goto error; return 0; error: return -1; } /** * \brief Adds a SigGroupHead to the detection engine context dport based * SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. */ int SigGroupHeadDPortHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { int ret = HashListTableAdd(de_ctx->sgh_dport_hash_table, (void *)sgh, 0); return ret; } /** * \brief Used to lookup a SigGroupHead hash from the detection engine ctx dport * based SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is * found in the hash table; NULL on failure. */ SigGroupHead *SigGroupHeadDPortHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_dport_hash_table, (void *)sgh, 0); SCReturnPtr(rsgh,"SigGroupHead"); } /** * \brief Frees the hash table - DetectEngineCtx->sgh_dport_hash_table, * allocated by the SigGroupHeadDPortHashInit() function. * * \param de_ctx Pointer to the detection engine context. */ void SigGroupHeadDPortHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->sgh_dport_hash_table == NULL) return; HashListTableFree(de_ctx->sgh_dport_hash_table); de_ctx->sgh_dport_hash_table = NULL; return; } /** * \brief Initializes the sport based SigGroupHead hash table to hold the * SigGroupHeads. The hash table that would be initialized is * DetectEngineCtx->sgh_sport_hash_table. * * \param de_ctx Pointer to the detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ int SigGroupHeadSPortHashInit(DetectEngineCtx *de_ctx) { de_ctx->sgh_sport_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, SigGroupHeadCompareFunc, NULL); if (de_ctx->sgh_sport_hash_table == NULL) goto error; return 0; error: return -1; } /** * \brief Adds a SigGroupHead to the detection engine context dport based * SigGroupHead hash table(DetectEngineCtx->sgh_sport_hash_table). * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. */ int SigGroupHeadSPortHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { int ret = HashListTableAdd(de_ctx->sgh_sport_hash_table, (void *)sgh, 0); return ret; } int SigGroupHeadSPortHashRemove(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { return HashListTableRemove(de_ctx->sgh_sport_hash_table, (void *)sgh, 0); } /** * \brief Used to lookup a SigGroupHead hash from the detection engine ctx sport * based SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is * found in the hash table; NULL on failure. */ SigGroupHead *SigGroupHeadSPortHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_sport_hash_table, (void *)sgh, 0); return rsgh; } /** * \brief Frees the hash table - DetectEngineCtx->sgh_sport_hash_table, * allocated by the SigGroupHeadSPortHashInit() function. * * \param de_ctx Pointer to the detection engine context. */ void SigGroupHeadSPortHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->sgh_sport_hash_table == NULL) return; HashListTableFree(de_ctx->sgh_sport_hash_table); de_ctx->sgh_sport_hash_table = NULL; return; } /** * \brief Used to free the signature array, content_array and uri_content_array * members from the SigGroupHeads in the HashListTable. * * \param de_ctx Pointer to the detection engine context. * \param ht Pointer to the HashListTable */ static void SigGroupHeadFreeSigArraysHash2(DetectEngineCtx *de_ctx, HashListTable *ht) { HashListTableBucket *htb = NULL; SigGroupHead *sgh = NULL; for (htb = HashListTableGetListHead(ht); htb != NULL; htb = HashListTableGetListNext(htb)) { sgh = (SigGroupHead *)HashListTableGetListData(htb); if (sgh == NULL) { continue; } if (sgh->init->sig_array != NULL) { detect_siggroup_sigarray_free_cnt++; detect_siggroup_sigarray_memory -= sgh->init->sig_size; SCFree(sgh->init->sig_array); sgh->init->sig_array = NULL; sgh->init->sig_size = 0; } SigGroupHeadInitDataFree(sgh->init); sgh->init = NULL; } return; } /** * \brief Used to free the sig_array member of the SigGroupHeads present * in the HashListTable. * * \param de_ctx Pointer to the detection engine context. * \param ht Pointer to the HashListTable */ static void SigGroupHeadFreeSigArraysHash(DetectEngineCtx *de_ctx, HashListTable *ht) { HashListTableBucket *htb = NULL; SigGroupHead *sgh = NULL; for (htb = HashListTableGetListHead(ht); htb != NULL; htb = HashListTableGetListNext(htb)) { sgh = (SigGroupHead *)HashListTableGetListData(htb); if (sgh->init != NULL) { SigGroupHeadInitDataFree(sgh->init); sgh->init = NULL; } } return; } /** * \brief Free the sigarrays in the sgh's. Those are only used during the init * stage. * * \param de_ctx Pointer to the detection engine context whose sigarrays have to * be freed. */ void SigGroupHeadFreeSigArrays(DetectEngineCtx *de_ctx) { SigGroupHeadFreeSigArraysHash2(de_ctx, de_ctx->sgh_hash_table); SigGroupHeadFreeSigArraysHash(de_ctx, de_ctx->sgh_dport_hash_table); SigGroupHeadFreeSigArraysHash(de_ctx, de_ctx->sgh_sport_hash_table); return; } /** * \brief Free the mpm arrays that are only used during the init stage. * * \param de_ctx Pointer to the detection engine context. */ void SigGroupHeadFreeMpmArrays(DetectEngineCtx *de_ctx) { HashListTableBucket *htb = NULL; SigGroupHead *sgh = NULL; for (htb = HashListTableGetListHead(de_ctx->sgh_dport_hash_table); htb != NULL; htb = HashListTableGetListNext(htb)) { sgh = (SigGroupHead *)HashListTableGetListData(htb); if (sgh->init != NULL) { SigGroupHeadInitDataFree(sgh->init); sgh->init = NULL; } } for (htb = HashListTableGetListHead(de_ctx->sgh_sport_hash_table); htb != NULL; htb = HashListTableGetListNext(htb)) { sgh = (SigGroupHead *)HashListTableGetListData(htb); if (sgh->init != NULL) { SigGroupHeadInitDataFree(sgh->init); sgh->init = NULL; } } return; } /** * \brief Add a Signature to a SigGroupHead. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to a SigGroupHead. Can be NULL also. * \param s Pointer to the Signature that has to be added to the * SigGroupHead. * * \retval 0 On success. * \retval -1 On failure. */ int SigGroupHeadAppendSig(DetectEngineCtx *de_ctx, SigGroupHead **sgh, Signature *s) { if (de_ctx == NULL) return 0; /* see if we have a head already */ if (*sgh == NULL) { *sgh = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1); if (*sgh == NULL) goto error; } /* enable the sig in the bitarray */ (*sgh)->init->sig_array[s->num / 8] |= 1 << (s->num % 8); /* update maxlen for mpm */ if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { /* check with the precalculated values from the sig */ if (s->mpm_content_maxlen > 0) { if ((*sgh)->mpm_content_maxlen == 0) (*sgh)->mpm_content_maxlen = s->mpm_content_maxlen; if ((*sgh)->mpm_content_maxlen > s->mpm_content_maxlen) (*sgh)->mpm_content_maxlen = s->mpm_content_maxlen; SCLogDebug("(%p)->mpm_content_maxlen %u", *sgh, (*sgh)->mpm_content_maxlen); } } if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { if (s->mpm_uricontent_maxlen > 0) { if ((*sgh)->mpm_uricontent_maxlen == 0) (*sgh)->mpm_uricontent_maxlen = s->mpm_uricontent_maxlen; if ((*sgh)->mpm_uricontent_maxlen > s->mpm_uricontent_maxlen) (*sgh)->mpm_uricontent_maxlen = s->mpm_uricontent_maxlen; SCLogDebug("(%p)->mpm_uricontent_maxlen %u", *sgh, (*sgh)->mpm_uricontent_maxlen); } } return 0; error: return -1; } /** * \brief Clears the bitarray holding the sids for this SigGroupHead. * * \param sgh Pointer to the SigGroupHead. * * \retval 0 Always. */ int SigGroupHeadClearSigs(SigGroupHead *sgh) { if (sgh == NULL) return 0; if (sgh->init->sig_array != NULL) memset(sgh->init->sig_array, 0, sgh->init->sig_size); sgh->sig_cnt = 0; return 0; } /** * \brief Copies the bitarray holding the sids from the source SigGroupHead to * the destination SigGroupHead. * * \param de_ctx Pointer to the detection engine context. * \param src Pointer to the source SigGroupHead. * \param dst Pointer to the destination SigGroupHead. * * \retval 0 On success. * \retval -1 On failure. */ int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst) { uint32_t idx = 0; if (src == NULL || de_ctx == NULL) return 0; if (*dst == NULL) { *dst = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1); if (*dst == NULL) goto error; } /* do the copy */ for (idx = 0; idx < src->init->sig_size; idx++) (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx]; if (src->mpm_content_maxlen != 0) { if ((*dst)->mpm_content_maxlen == 0) (*dst)->mpm_content_maxlen = src->mpm_content_maxlen; if ((*dst)->mpm_content_maxlen > src->mpm_content_maxlen) (*dst)->mpm_content_maxlen = src->mpm_content_maxlen; SCLogDebug("src (%p)->mpm_content_maxlen %u", src, src->mpm_content_maxlen); SCLogDebug("dst (%p)->mpm_content_maxlen %u", (*dst), (*dst)->mpm_content_maxlen); BUG_ON((*dst)->mpm_content_maxlen == 0); } if (src->mpm_uricontent_maxlen != 0) { if ((*dst)->mpm_uricontent_maxlen == 0) (*dst)->mpm_uricontent_maxlen = src->mpm_uricontent_maxlen; if ((*dst)->mpm_uricontent_maxlen > src->mpm_uricontent_maxlen) (*dst)->mpm_uricontent_maxlen = src->mpm_uricontent_maxlen; } return 0; error: return -1; } /** * \brief Updates the SigGroupHead->sig_cnt with the total count of all the * Signatures present in this SigGroupHead. * * \param sgh Pointer to the SigGroupHead. * \param max_idx Maximum sid of the all the Signatures present in this * SigGroupHead. */ void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx) { uint32_t sig; sgh->sig_cnt = 0; for (sig = 0; sig < max_idx + 1; sig++) { if (sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) sgh->sig_cnt++; } return; } /** * \brief Prints the memory statistics for the detect-engine-siggroup.[ch] module. */ void DetectSigGroupPrintMemory(void) { SCLogDebug(" * Sig group head memory stats (SigGroupHead %" PRIuMAX "):", (uintmax_t)sizeof(SigGroupHead)); SCLogDebug(" - detect_siggroup_head_memory %" PRIu32, detect_siggroup_head_memory); SCLogDebug(" - detect_siggroup_head_init_cnt %" PRIu32, detect_siggroup_head_init_cnt); SCLogDebug(" - detect_siggroup_head_free_cnt %" PRIu32, detect_siggroup_head_free_cnt); SCLogDebug(" - outstanding sig group heads %" PRIu32, detect_siggroup_head_init_cnt - detect_siggroup_head_free_cnt); SCLogDebug(" * Sig group head memory stats done"); SCLogDebug(" * Sig group head initdata memory stats (SigGroupHeadInitData %" PRIuMAX "):", (uintmax_t)sizeof(SigGroupHeadInitData)); SCLogDebug(" - detect_siggroup_head_initdata_memory %" PRIu32, detect_siggroup_head_initdata_memory); SCLogDebug(" - detect_siggroup_head_initdata_init_cnt %" PRIu32, detect_siggroup_head_initdata_init_cnt); SCLogDebug(" - detect_siggroup_head_initdata_free_cnt %" PRIu32, detect_siggroup_head_initdata_free_cnt); SCLogDebug(" - outstanding sig group head initdatas %" PRIu32, detect_siggroup_head_initdata_init_cnt - detect_siggroup_head_initdata_free_cnt); SCLogDebug(" * Sig group head memory initdata stats done"); SCLogDebug(" * Sig group sigarray memory stats:"); SCLogDebug(" - detect_siggroup_sigarray_memory %" PRIu32, detect_siggroup_sigarray_memory); SCLogDebug(" - detect_siggroup_sigarray_init_cnt %" PRIu32, detect_siggroup_sigarray_init_cnt); SCLogDebug(" - detect_siggroup_sigarray_free_cnt %" PRIu32, detect_siggroup_sigarray_free_cnt); SCLogDebug(" - outstanding sig group sigarrays %" PRIu32, (detect_siggroup_sigarray_init_cnt - detect_siggroup_sigarray_free_cnt)); SCLogDebug(" * Sig group sigarray memory stats done"); SCLogDebug(" * Sig group matcharray memory stats:"); SCLogDebug(" - detect_siggroup_matcharray_memory %" PRIu32, detect_siggroup_matcharray_memory); SCLogDebug(" - detect_siggroup_matcharray_init_cnt %" PRIu32, detect_siggroup_matcharray_init_cnt); SCLogDebug(" - detect_siggroup_matcharray_free_cnt %" PRIu32, detect_siggroup_matcharray_free_cnt); SCLogDebug(" - outstanding sig group matcharrays %" PRIu32, (detect_siggroup_matcharray_init_cnt - detect_siggroup_matcharray_free_cnt)); SCLogDebug(" * Sig group sigarray memory stats done"); SCLogDebug(" X Total %" PRIu32, (detect_siggroup_head_memory + detect_siggroup_sigarray_memory + detect_siggroup_matcharray_memory)); return; } /** * \brief Helper function used to print the list of sids for the Signatures * present in this SigGroupHead. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. */ void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); if (sgh == NULL) { SCReturn; } uint32_t u; SCLogDebug("The Signatures present in this SigGroupHead are: "); for (u = 0; u < (sgh->init->sig_size * 8); u++) { if (sgh->init->sig_array[u / 8] & (1 << (u % 8))) { SCLogDebug("%" PRIu32, u); printf("s->num %"PRIu16" ", u); } } SCReturn; } /** * \brief Helper function used to print the content ids of all the contents that * have been added to the bitarray of this SigGroupHead. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. */ void SigGroupHeadPrintContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); uint32_t i = 0; SCLogDebug("Contents with the following content ids are present in this " "SigGroupHead - "); for (i = 0; i < DetectContentMaxId(de_ctx); i++) { if (sgh->init->content_array[i / 8] & (1 << (i % 8))) SCLogDebug("%" PRIu32, i); } SCReturn; } /** * \brief Helper function used to print the total no of contents that have * been added to the bitarray for this SigGroupHead. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. */ void SigGroupHeadPrintContentCnt(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); uint32_t i = 0; uint32_t cnt = 0; for (i = 0; i < DetectContentMaxId(de_ctx); i++) { if (sgh->init->content_array[i / 8] & (1 << (i % 8))) cnt++; } SCLogDebug("Total contents added to the SigGroupHead content bitarray: " "%" PRIu32, cnt); SCReturn; } /** * \brief Loads all the content ids from all the contents belonging to all the * Signatures in this SigGroupHead, into a bitarray. A fast and an * efficient way of comparing pattern sets. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval 0 On success, i.e. on either the detection engine context being NULL * or on successfully allocating memory and updating it with relevant * data. * \retval -1 On failure. */ int SigGroupHeadLoadContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; SigMatch *sm = NULL; uint32_t sig = 0; DetectContentData *co = NULL; if (sgh == NULL) return 0; if (DetectContentMaxId(de_ctx) == 0) return 0; BUG_ON(sgh->init == NULL); sgh->init->content_size = (DetectContentMaxId(de_ctx) / 8) + 1; sgh->init->content_array = SCMalloc(sgh->init->content_size); if (sgh->init->content_array == NULL) return -1; memset(sgh->init->content_array,0, sgh->init->content_size); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; if (s->alproto != ALPROTO_UNKNOWN) continue; sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm == NULL) continue; for ( ;sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { co = (DetectContentData *)sm->ctx; sgh->init->content_array[co->id / 8] |= 1 << (co->id % 8); } } } return 0; } /** * \brief Clears the memory allocated by SigGroupHeadLoadContent() for the * bitarray to hold the content ids for a SigGroupHead. * * \param Pointer to the SigGroupHead whose content_array would to be cleared. * * \ret 0 Always. */ int SigGroupHeadClearContent(SigGroupHead *sh) { if (sh == NULL) return 0; if (sh->init->content_array != NULL) { SCFree(sh->init->content_array); sh->init->content_array = NULL; sh->init->content_size = 0; } return 0; } /** * \brief Loads all the uri content ids from all the uri contents belonging to * all the Signatures in this SigGroupHead, into a bitarray. A fast and * an efficient way of comparing pattern sets. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval 0 On success, i.e. on either the detection engine context being NULL * or on successfully allocating memory and updating it with relevant * data. * \retval -1 On failure. */ int SigGroupHeadLoadUricontent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; SigMatch *sm = NULL; uint32_t sig = 0; DetectContentData *co = NULL; if (sgh == NULL) return 0; if (DetectUricontentMaxId(de_ctx) == 0) return 0; BUG_ON(sgh->init == NULL); sgh->init->uri_content_size = (DetectUricontentMaxId(de_ctx) / 8) + 1; sgh->init->uri_content_array = SCMalloc(sgh->init->uri_content_size); if (sgh->init->uri_content_array == NULL) return -1; memset(sgh->init->uri_content_array, 0, sgh->init->uri_content_size); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; if (sm == NULL) continue; for ( ;sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { co = (DetectContentData *)sm->ctx; sgh->init->uri_content_array[co->id / 8] |= 1 << (co->id % 8); } } } return 0; } /** * \brief Clears the memory allocated by SigGroupHeadLoadUriContent() for the * bitarray to hold the uri content ids for a SigGroupHead. * * \param Pointer to the SigGroupHead whose uri_content_array would to be * cleared. * * \retval 0 Always. */ int SigGroupHeadClearUricontent(SigGroupHead *sh) { if (sh == NULL) return 0; if (sh->init->uri_content_array != NULL) { SCFree(sh->init->uri_content_array); sh->init->uri_content_array = NULL; sh->init->uri_content_size = 0; } return 0; } /** * \brief Loads all the content ids from all the contents belonging to all the * Signatures in this SigGroupHead, into a bitarray. A fast and an * efficient way of comparing pattern sets. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * * \retval 0 On success, i.e. on either the detection engine context being NULL * or on successfully allocating memory and updating it with relevant * data. * \retval -1 On failure. */ int SigGroupHeadLoadStreamContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); Signature *s = NULL; SigMatch *sm = NULL; uint32_t sig = 0; DetectContentData *co = NULL; if (sgh == NULL) { SCReturnInt(0); } if (DetectContentMaxId(de_ctx) == 0) { SCReturnInt(0); } BUG_ON(sgh->init == NULL); sgh->init->stream_content_size = (DetectContentMaxId(de_ctx) / 8) + 1; sgh->init->stream_content_array = SCMalloc(sgh->init->stream_content_size); if (sgh->init->stream_content_array == NULL) { SCReturnInt(-1); } memset(sgh->init->stream_content_array,0, sgh->init->stream_content_size); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; SCLogDebug("s %"PRIu32, s->id); if (s == NULL) continue; if (SignatureHasPacketContent(s)) { SCLogDebug("Sig has packet content"); continue; } sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm == NULL) continue; for ( ;sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { co = (DetectContentData *)sm->ctx; sgh->init->stream_content_array[co->id / 8] |= 1 << (co->id % 8); } } } SCReturnInt(0); } /** * \brief Clears the memory allocated by SigGroupHeadLoadContent() for the * bitarray to hold the content ids for a SigGroupHead. * * \param Pointer to the SigGroupHead whose content_array would to be cleared. * * \ret 0 Always. */ int SigGroupHeadClearStreamContent(SigGroupHead *sh) { if (sh == NULL) return 0; if (sh->init->stream_content_array != NULL) { SCFree(sh->init->stream_content_array); sh->init->stream_content_array = NULL; sh->init->stream_content_size = 0; } return 0; } /** * \brief Create an array with all the internal ids of the sigs that this * sig group head will check for. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * \param max_idx The maximum value of the sid in the SigGroupHead arg. * * \retval 0 success * \retval -1 error */ int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx) { Signature *s = NULL; uint32_t idx = 0; uint32_t sig = 0; if (sgh == NULL) return 0; BUG_ON(sgh->match_array != NULL); sgh->match_array = SCMalloc(sgh->sig_cnt * sizeof(Signature *)); if (sgh->match_array == NULL) return -1; memset(sgh->match_array,0, sgh->sig_cnt * sizeof(Signature *)); detect_siggroup_matcharray_init_cnt++; detect_siggroup_matcharray_memory += (sgh->sig_cnt * sizeof(Signature *)); for (sig = 0; sig < max_idx + 1; sig++) { if (!(sgh->init->sig_array[(sig / 8)] & (1 << (sig % 8))) ) continue; s = de_ctx->sig_array[sig]; if (s == NULL) continue; sgh->match_array[idx] = s; idx++; } return 0; } /** * \brief Set the need md5 flag in the sgh. * * \param de_ctx detection engine ctx for the signatures * \param sgh sig group head to set the flag in */ void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; uint32_t sig = 0; if (sgh == NULL) return; for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; if (SignatureIsFilemagicInspecting(s)) { sgh->flags |= SIG_GROUP_HEAD_HAVEFILEMAGIC; break; } } return; } /** * \brief Set the need size flag in the sgh. * * \param de_ctx detection engine ctx for the signatures * \param sgh sig group head to set the flag in */ void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; uint32_t sig = 0; if (sgh == NULL) return; for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; if (SignatureIsFilesizeInspecting(s)) { sgh->flags |= SIG_GROUP_HEAD_HAVEFILESIZE; break; } } return; } /** * \brief Set the need magic flag in the sgh. * * \param de_ctx detection engine ctx for the signatures * \param sgh sig group head to set the flag in */ void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; uint32_t sig = 0; if (sgh == NULL) return; for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; if (SignatureIsFileMd5Inspecting(s)) { sgh->flags |= SIG_GROUP_HEAD_HAVEFILEMD5; SCLogDebug("sgh %p has filemd5", sgh); break; } } return; } /** * \brief Set the filestore_cnt in the sgh. * * \param de_ctx detection engine ctx for the signatures * \param sgh sig group head to set the counter in */ void SigGroupHeadSetFilestoreCount(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; uint32_t sig = 0; if (sgh == NULL) return; for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; if (SignatureIsFilestoring(s)) { sgh->filestore_cnt++; } } return; } int SigGroupHeadBuildHeadArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; uint32_t idx = 0; uint32_t sig = 0; if (sgh == NULL) return 0; BUG_ON(sgh->head_array != NULL); #if defined(__SSE3__) BUG_ON(sgh->mask_array != NULL); /* mask array is 16 byte aligned for SIMD checking, also we always * alloc a multiple of 32/64 bytes */ int cnt = sgh->sig_cnt; #if __WORDSIZE == 32 if (cnt % 32 != 0) { cnt += (32 - (cnt % 32)); } #elif __WORDSIZE == 64 if (cnt % 64 != 0) { cnt += (64 - (cnt % 64)); } #endif /* __WORDSIZE */ sgh->mask_array = SCMallocAligned((cnt * sizeof(SignatureMask)), 16); if (sgh->mask_array == NULL) return -1; memset(sgh->mask_array, 0, (cnt * sizeof(SignatureMask))); #endif sgh->head_array = SCMalloc(sgh->sig_cnt * sizeof(SignatureHeader)); if (sgh->head_array == NULL) return -1; memset(sgh->head_array, 0, sgh->sig_cnt * sizeof(SignatureHeader)); detect_siggroup_matcharray_init_cnt++; detect_siggroup_matcharray_memory += (sgh->sig_cnt * sizeof(SignatureHeader *)); for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; sgh->head_array[idx].hdr_copy1 = s->hdr_copy1; sgh->head_array[idx].hdr_copy2 = s->hdr_copy2; sgh->head_array[idx].hdr_copy3 = s->hdr_copy3; sgh->head_array[idx].full_sig = s; #if defined(__SSE3__) sgh->mask_array[idx] = s->mask; #endif idx++; } return 0; } /** * \brief Check if a SigGroupHead contains a Signature, whose sid is sent as an * argument. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead that has to be checked for the * presence of a Signature. * \param sid The Signature id(sid) that has to be checked in the SigGroupHead. * * \retval 1 On successfully finding the sid in the SigGroupHead. * \retval 0 If the sid is not found in the SigGroupHead */ int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid) { SCEnter(); uint32_t sig = 0; Signature *s = NULL; uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx); if (sgh == NULL) { SCReturnInt(0); } for (sig = 0; sig < max_sid; sig++) { if (sgh->init->sig_array == NULL) { SCReturnInt(0); } /* Check if the SigGroupHead has an entry for the sid */ if ( !(sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) ) continue; /* If we have reached here, we have an entry for sid in the SigGrouHead. * Retrieve the Signature from the detection engine context */ s = de_ctx->sig_array[sig]; if (s == NULL) continue; /* If the retrieved Signature matches the sid arg, we have a match */ if (s->id == sid) { SCReturnInt(1); } } SCReturnInt(0); } /*----------------------------------Unittests---------------------------------*/ #ifdef UNITTESTS int SigAddressPrepareStage1(DetectEngineCtx *); /** * \test Check if a SigGroupHead mpm hash table is properly allocated and * deallocated when calling SigGroupHeadMpmHashInit() and * SigGroupHeadMpmHashFree() respectively. */ static int SigGroupHeadTest01(void) { int result = 1; DetectEngineCtx de_ctx; SigGroupHeadMpmHashInit(&de_ctx); result &= (de_ctx.sgh_mpm_hash_table != NULL); SigGroupHeadMpmHashFree(&de_ctx); result &= (de_ctx.sgh_mpm_hash_table == NULL); return result; } /** * \test Check if a SigGroupHead mpm uri hash table is properly allocated and * deallocated when calling SigGroupHeadMpmUriHashInit() and * SigGroupHeadMpmUriHashFree() respectively. */ static int SigGroupHeadTest02(void) { int result = 1; DetectEngineCtx de_ctx; SigGroupHeadMpmUriHashInit(&de_ctx); result &= (de_ctx.sgh_mpm_uri_hash_table != NULL); SigGroupHeadMpmUriHashFree(&de_ctx); result &= (de_ctx.sgh_mpm_uri_hash_table == NULL); return result; } /** * \test Check if a SigGroupHead hash table is properly allocated and * deallocated when calling SigGroupHeadHashInit() and * SigGroupHeadHashFree() respectively. */ static int SigGroupHeadTest03(void) { int result = 1; DetectEngineCtx de_ctx; SigGroupHeadHashInit(&de_ctx); result &= (de_ctx.sgh_hash_table != NULL); SigGroupHeadHashFree(&de_ctx); result &= (de_ctx.sgh_hash_table == NULL); return result; } /** * \test Check if a SigGroupHead dport hash table is properly allocated and * deallocated when calling SigGroupHeadDPortHashInit() and * SigGroupHeadDportHashFree() respectively. */ static int SigGroupHeadTest04(void) { int result = 1; DetectEngineCtx de_ctx; SigGroupHeadDPortHashInit(&de_ctx); result &= (de_ctx.sgh_dport_hash_table != NULL); SigGroupHeadDPortHashFree(&de_ctx); result &= (de_ctx.sgh_dport_hash_table == NULL); return result; } /** * \test Check if a SigGroupHead dport hash table is properly allocated and * deallocated when calling SigGroupHeadSPortHashInit() and * SigGroupHeadSportHashFree() respectively. */ static int SigGroupHeadTest05(void) { int result = 1; DetectEngineCtx de_ctx; SigGroupHeadSPortHashInit(&de_ctx); result &= (de_ctx.sgh_sport_hash_table != NULL); SigGroupHeadSPortHashFree(&de_ctx); result &= (de_ctx.sgh_sport_hash_table == NULL); return result; } /** * \test Check if a SigGroupHeadAppendSig() correctly appends a sid to a * SigGroupHead() and SigGroupHeadContainsSigId() correctly indicates * the presence of a sid. */ static int SigGroupHeadTest06(void) { int result = 1; SigGroupHead *sh = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature *prev_sig = NULL; if (de_ctx == NULL) return 0; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:0;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } prev_sig = de_ctx->sig_list; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:1;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:2;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:3;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:4;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; SigAddressPrepareStage1(de_ctx); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next); SigGroupHeadSetSigCnt(sh, 4); result &= (sh->sig_cnt == 3); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 0) == 1); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 1) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 2) == 1); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 3) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 4) == 1); SigGroupHeadFree(sh); end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if a SigGroupHeadAppendSig(), correctly appends a sid to a * SigGroupHead() and SigGroupHeadContainsSigId(), correctly indicates * the presence of a sid and SigGroupHeadClearSigs(), correctly clears * the SigGroupHead->sig_array and SigGroupHead->sig_cnt. */ static int SigGroupHeadTest07(void) { int result = 1; SigGroupHead *sh = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature *prev_sig = NULL; if (de_ctx == NULL) return 0; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:0;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } prev_sig = de_ctx->sig_list; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:1;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:2;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:3;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:4;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; SigAddressPrepareStage1(de_ctx); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next); SigGroupHeadSetSigCnt(sh, 4); result &= (sh->sig_cnt == 3); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 0) == 1); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 1) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 2) == 1); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 3) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 4) == 1); SigGroupHeadClearSigs(sh); result &= (sh->sig_cnt == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 0) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 1) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 2) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 3) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, sh, 4) == 0); SigGroupHeadFree(sh); end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if SigGroupHeadCopySigs(), correctly copies the sig_array from * the source to the destination SigGroupHead. */ static int SigGroupHeadTest08(void) { int result = 1; SigGroupHead *src_sh = NULL; SigGroupHead *dst_sh = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature *prev_sig = NULL; if (de_ctx == NULL) return 0; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:0;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } prev_sig = de_ctx->sig_list; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:1;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:2;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:3;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:4;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; SigAddressPrepareStage1(de_ctx); SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list); SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list->next->next); SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list->next->next->next->next); SigGroupHeadSetSigCnt(src_sh, 4); result &= (src_sh->sig_cnt == 3); result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 0) == 1); result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 1) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 2) == 1); result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 3) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 4) == 1); SigGroupHeadCopySigs(de_ctx, src_sh, &dst_sh); SigGroupHeadSetSigCnt(dst_sh, 4); result &= (dst_sh->sig_cnt == 3); result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 0) == 1); result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 1) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 2) == 1); result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 3) == 0); result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 4) == 1); SigGroupHeadFree(src_sh); SigGroupHeadFree(dst_sh); end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if SigGroupHeadBuildMatchArray(), correctly updates the * match array with the sids. */ static int SigGroupHeadTest09(void) { int result = 1; SigGroupHead *sh = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature *prev_sig = NULL; if (de_ctx == NULL) return 0; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:0;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } prev_sig = de_ctx->sig_list; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:1;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:2;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:3;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"SigGroupHead tests\"; content:\"test1\"; " "content:\"test2\"; content:\"test3\"; sid:4;)"); if (prev_sig->next == NULL) { result = 0; goto end; } prev_sig = prev_sig->next; SigAddressPrepareStage1(de_ctx); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next); SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next); SigGroupHeadSetSigCnt(sh, 4); SigGroupHeadBuildMatchArray(de_ctx, sh, 4); result &= (sh->match_array[0] == de_ctx->sig_list); result &= (sh->match_array[1] == de_ctx->sig_list->next->next); result &= (sh->match_array[2] == de_ctx->sig_list->next->next->next->next); SigGroupHeadFree(sh); end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test ICMP(?) sig grouping bug. */ static int SigGroupHeadTest10(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature *s = NULL; Packet *p = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; memset(&th_v, 0, sizeof(ThreadVars)); p = UTHBuildPacketSrcDst(NULL, 0, IPPROTO_ICMP, "192.168.1.1", "1.2.3.4"); p->icmpv4h->type = 5; p->icmpv4h->code = 1; /* originally ip's were p.src.addr_data32[0] = 0xe08102d3; p.dst.addr_data32[0] = 0x3001a8c0; */ if (de_ctx == NULL) return 0; s = DetectEngineAppendSig(de_ctx, "alert icmp 192.168.0.0/16 any -> any any (icode:>1; itype:11; sid:1; rev:1;)"); if (s == NULL) { goto end; } s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> 192.168.0.0/16 any (icode:1; itype:5; sid:2; rev:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); AddressDebugPrint(&p->dst); SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); return result; } /** * \test sig grouping bug. */ static int SigGroupHeadTest11(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature *s = NULL; Packet *p = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; memset(&th_v, 0, sizeof(ThreadVars)); p = UTHBuildPacketReal(NULL, 0, IPPROTO_TCP, "192.168.1.1", "1.2.3.4", 60000, 80); if (de_ctx == NULL || p == NULL) return 0; s = DetectEngineAppendSig(de_ctx, "alert tcp any 1024: -> any 1024: (content:\"abc\"; sid:1;)"); if (s == NULL) { goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"def\"; http_client_body; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); AddressDebugPrint(&p->dst); SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { goto end; } /* check if hcbd flag is set in sgh */ if (!(sgh->flags & SIG_GROUP_HEAD_MPM_HCBD)) { printf("sgh has not SIG_GROUP_HEAD_MPM_HCBD flag set: "); goto end; } /* check if sig 2 is part of the sgh */ result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); return result; } #endif void SigGroupHeadRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SigGroupHeadTest01", SigGroupHeadTest01, 1); UtRegisterTest("SigGroupHeadTest02", SigGroupHeadTest02, 1); UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03, 1); UtRegisterTest("SigGroupHeadTest04", SigGroupHeadTest04, 1); UtRegisterTest("SigGroupHeadTest05", SigGroupHeadTest05, 1); UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06, 1); UtRegisterTest("SigGroupHeadTest07", SigGroupHeadTest07, 1); UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08, 1); UtRegisterTest("SigGroupHeadTest09", SigGroupHeadTest09, 1); UtRegisterTest("SigGroupHeadTest10", SigGroupHeadTest10, 1); UtRegisterTest("SigGroupHeadTest11", SigGroupHeadTest11, 1); #endif } suricata-1.4.7/src/detect-pcre.h0000644000000000000000000000470712253546156013405 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_PCRE_H__ #define __DETECT_PCRE_H__ #define DETECT_PCRE_RELATIVE 0x00001 #define DETECT_PCRE_RAWBYTES 0x00002 #define DETECT_PCRE_URI 0x00004 #define DETECT_PCRE_CAPTURE_PKT 0x00008 #define DETECT_PCRE_CAPTURE_FLOW 0x00010 #define DETECT_PCRE_MATCH_LIMIT 0x00020 #define DETECT_PCRE_HTTP_CLIENT_BODY 0x00040 #define DETECT_PCRE_HTTP_SERVER_BODY 0x00080 #define DETECT_PCRE_RELATIVE_NEXT 0x00100 /* new modifiers 2.8.5.3 support */ #define DETECT_PCRE_HEADER 0x00200 #define DETECT_PCRE_RAW_HEADER 0x00400 #define DETECT_PCRE_COOKIE 0x00800 #define DETECT_PCRE_METHOD 0x01000 #define DETECT_PCRE_HTTP_RAW_URI 0x02000 #define DETECT_PCRE_HTTP_STAT_MSG 0x04000 #define DETECT_PCRE_HTTP_STAT_CODE 0x08000 #define DETECT_PCRE_HTTP_USER_AGENT 0x10000 #define DETECT_PCRE_HTTP_HOST 0x20000 #define DETECT_PCRE_HTTP_RAW_HOST 0x40000 #define DETECT_PCRE_NEGATE 0x80000 #define DETECT_PCRE_CASELESS 0x100000 typedef struct DetectPcreData_ { /* pcre options */ pcre *re; pcre_extra *sd; int opts; uint32_t flags; uint16_t capidx; char *capname; } DetectPcreData; /* prototypes */ int DetectPcrePayloadMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, Flow *, uint8_t *, uint32_t); int DetectPcrePacketPayloadMatch(DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectPcrePayloadDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, uint8_t *, uint16_t); void DetectPcreRegister (void); #endif /* __DETECT_PCRE_H__ */ suricata-1.4.7/src/detect-dce-iface.h0000644000000000000000000000245012253546156014245 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_DCE_IFACE_H__ #define __DETECT_DCE_IFACE_H__ typedef enum DetectDceIfaceOperators_ { DETECT_DCE_IFACE_OP_NONE = 0, DETECT_DCE_IFACE_OP_LT, DETECT_DCE_IFACE_OP_GT, DETECT_DCE_IFACE_OP_EQ, DETECT_DCE_IFACE_OP_NE, } DetectDceIfaceOperators; typedef struct DetectDceIfaceData_ { uint8_t uuid[16]; uint8_t op; uint16_t version; uint8_t any_frag; } DetectDceIfaceData; void DetectDceIfaceRegister(void); void DetectDceIfaceRegisterTests(void); #endif /* __DETECT_DCE_IFACE_H__ */ suricata-1.4.7/src/util-mem.h0000644000000000000000000002231112253546156012726 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * Utility Macros for memory management * * \todo Add wrappers for functions that allocate/free memory here. * Currently we have malloc, calloc, realloc, strdup and free, * but there are more. */ #ifndef __UTIL_MEM_H__ #define __UTIL_MEM_H__ #include "util-atomic.h" #if defined(_WIN32) || defined(__WIN32) #include "mm_malloc.h" #endif SC_ATOMIC_EXTERN(unsigned int, engine_stage); /* Use this only if you want to debug memory allocation and free() * It will log a lot of lines more, so think that is a performance killer */ /* Uncomment this if you want to print memory allocations and free's() */ //#define DBG_MEM_ALLOC #ifdef DBG_MEM_ALLOC /* Uncomment this if you want to print mallocs at the startup (recommended) */ #define DBG_MEM_ALLOC_SKIP_STARTUP #define SCMalloc(a) ({ \ void *ptrmem = NULL; \ extern size_t global_mem; \ extern uint8_t print_mem_flag; \ \ ptrmem = malloc((a)); \ if (ptrmem == NULL && (a) > 0) { \ SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)(a)); \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ \ global_mem += (a); \ if (print_mem_flag == 1) { \ SCLogInfo("SCMalloc return at %p of size %"PRIuMAX, \ ptrmem, (uintmax_t)(a)); \ } \ (void*)ptrmem; \ }) #define SCRealloc(x, a) ({ \ void *ptrmem = NULL; \ extern size_t global_mem; \ extern uint8_t print_mem_flag; \ \ ptrmem = realloc((x), (a)); \ if (ptrmem == NULL && (a) > 0) { \ SCLogError(SC_ERR_MEM_ALLOC, "SCRealloc failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)(a)); \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ \ global_mem += (a); \ if (print_mem_flag == 1) { \ SCLogInfo("SCRealloc return at %p (old:%p) of size %"PRIuMAX, \ ptrmem, (x), (uintmax_t)(a)); \ } \ (void*)ptrmem; \ }) #define SCCalloc(nm, a) ({ \ void *ptrmem = NULL; \ extern size_t global_mem; \ extern uint8_t print_mem_flag; \ \ ptrmem = calloc((nm), (a)); \ if (ptrmem == NULL && (a) > 0) { \ SCLogError(SC_ERR_MEM_ALLOC, "SCCalloc failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)a); \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ \ global_mem += (a)*(nm); \ if (print_mem_flag == 1) { \ SCLogInfo("SCCalloc return at %p of size %"PRIuMAX" (nm) %"PRIuMAX, \ ptrmem, (uintmax_t)(a), (uintmax_t)(nm)); \ } \ (void*)ptrmem; \ }) #define SCStrdup(a) ({ \ char *ptrmem = NULL; \ extern size_t global_mem; \ extern uint8_t print_mem_flag; \ size_t len = strlen((a)); \ \ ptrmem = strdup((a)); \ if (ptrmem == NULL) { \ SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)len); \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ \ global_mem += len; \ if (print_mem_flag == 1) { \ SCLogInfo("SCStrdup return at %p of size %"PRIuMAX, \ ptrmem, (uintmax_t)len); \ } \ (void*)ptrmem; \ }) #define SCFree(a) ({ \ extern uint8_t print_mem_flag; \ if (print_mem_flag == 1) { \ SCLogInfo("SCFree at %p", (a)); \ } \ free((a)); \ }) #else /* !DBG_MEM_ALLOC */ #define SCMalloc(a) ({ \ void *ptrmem = NULL; \ \ ptrmem = malloc((a)); \ if (ptrmem == NULL) { \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ uintmax_t scmalloc_size_ = (uintmax_t)(a); \ SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes", strerror(errno), scmalloc_size_); \ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ (void*)ptrmem; \ }) #define SCRealloc(x, a) ({ \ void *ptrmem = NULL; \ \ ptrmem = realloc((x), (a)); \ if (ptrmem == NULL) { \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ SCLogError(SC_ERR_MEM_ALLOC, "SCRealloc failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)(a)); \ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ (void*)ptrmem; \ }) #define SCCalloc(nm, a) ({ \ void *ptrmem = NULL; \ \ ptrmem = calloc((nm), (a)); \ if (ptrmem == NULL) { \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ SCLogError(SC_ERR_MEM_ALLOC, "SCCalloc failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)(a)); \ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ (void*)ptrmem; \ }) #define SCStrdup(a) ({ \ char *ptrmem = NULL; \ \ ptrmem = strdup((a)); \ if (ptrmem == NULL) { \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ size_t len = strlen((a)); \ SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)len); \ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ (void*)ptrmem; \ }) #define SCFree(a) ({ \ free(a); \ }) #if defined(__WIN32) || defined(_WIN32) /** \brief wrapper for allocing aligned mem * \param a size * \param b alignement */ #define SCMallocAligned(a, b) ({ \ void *ptrmem = NULL; \ \ ptrmem = _mm_malloc((a), (b)); \ if (ptrmem == NULL) { \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ SCLogError(SC_ERR_MEM_ALLOC, "SCMallocAligned(posix_memalign) failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes, alignment %"PRIuMAX, strerror(errno), (uintmax_t)(a), (uintmax_t)(b)); \ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ (void*)ptrmem; \ }) /** \brief Free aligned memory * * Not needed for mem alloc'd by posix_memalign, * but for possible future use of _mm_malloc needing * _mm_free. */ #define SCFreeAligned(a) ({ \ _mm_free(a); \ }) #else /* !win */ /** \brief wrapper for allocing aligned mem * \param a size * \param b alignement */ #define SCMallocAligned(a, b) ({ \ void *ptrmem = NULL; \ \ ptrmem = _mm_malloc((a), (b)); \ if (ptrmem == NULL) { \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ SCLogError(SC_ERR_MEM_ALLOC, "SCMallocAligned(posix_memalign) failed: %s, while trying " \ "to allocate %"PRIuMAX" bytes, alignment %"PRIuMAX, strerror(errno), (uintmax_t)a, (uintmax_t)b); \ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ } \ (void*)ptrmem; \ }) /** \brief Free aligned memory * * Not needed for mem alloc'd by posix_memalign, * but for possible future use of _mm_malloc needing * _mm_free. */ #define SCFreeAligned(a) ({ \ _mm_free((a)); \ }) #endif /* __WIN32 */ #endif /* DBG_MEM_ALLOC */ #endif /* __UTIL_MEM_H__ */ suricata-1.4.7/src/detect.h0000644000000000000000000010611012253546156012445 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_H__ #define __DETECT_H__ #include #include "flow.h" #include "detect-engine-proto.h" #include "detect-reference.h" #include "packet-queue.h" #include "util-mpm.h" #include "util-hash.h" #include "util-hashlist.h" #include "util-debug.h" #include "util-error.h" #include "util-radix-tree.h" #include "util-file.h" #include "detect-mark.h" #define COUNTER_DETECT_ALERTS 1 /* forward declarations for the structures from detect-engine-sigorder.h */ struct SCSigOrderFunc_; struct SCSigSignatureWrapper_; /* The detection engine groups similar signatures/rules together. Internally a tree of different types of data is created on initialization. This is it's global layout: For TCP/UDP - Flow direction -- Protocol -=- Src address -==- Dst address -===- Src port -====- Dst port For the other protocols - Flow direction -- Protocol -=- Src address -==- Dst address */ /* * DETECT ADDRESS */ /* holds the values for different possible lists in struct Signature. * These codes are access points to particular lists in the array * Signature->sm_lists[DETECT_SM_LIST_MAX] */ enum { DETECT_SM_LIST_MATCH = 0, DETECT_SM_LIST_PMATCH, /* list for http_uri keyword and the ones relative to it */ DETECT_SM_LIST_UMATCH, DETECT_SM_LIST_AMATCH, DETECT_SM_LIST_DMATCH, DETECT_SM_LIST_TMATCH, /* list for http_client_body keyword and the ones relative to it */ DETECT_SM_LIST_HCBDMATCH, /* list for http_server_body keyword and the ones relative to it */ DETECT_SM_LIST_HSBDMATCH, /* list for http_header keyword and the ones relative to it */ DETECT_SM_LIST_HHDMATCH, /* list for http_raw_header keyword and the ones relative to it */ DETECT_SM_LIST_HRHDMATCH, /* list for http_method keyword and the ones relative to it */ DETECT_SM_LIST_HMDMATCH, /* list for http_cookie keyword and the ones relative to it */ DETECT_SM_LIST_HCDMATCH, /* list for http_raw_uri keyword and the ones relative to it */ DETECT_SM_LIST_HRUDMATCH, /* list for http_stat_msg keyword and the ones relative to it */ DETECT_SM_LIST_HSMDMATCH, /* list for http_stat_code keyword and the ones relative to it */ DETECT_SM_LIST_HSCDMATCH, /* list for http_user_agent keyword and the ones relative to it */ DETECT_SM_LIST_HUADMATCH, /* list for http_host keyword and the ones relative to it */ DETECT_SM_LIST_HHHDMATCH, /* list for http_raw_host keyword and the ones relative to it */ DETECT_SM_LIST_HRHHDMATCH, DETECT_SM_LIST_FILEMATCH, /* list for post match actions: flowbit set, flowint increment, etc */ DETECT_SM_LIST_POSTMATCH, /* list for alert thresholding */ DETECT_SM_LIST_THRESHOLD, DETECT_SM_LIST_MAX, }; /* a is ... than b */ enum { ADDRESS_ER = -1, /**< error e.g. compare ipv4 and ipv6 */ ADDRESS_LT, /**< smaller [aaa] [bbb] */ ADDRESS_LE, /**< smaller with overlap [aa[bab]bb] */ ADDRESS_EQ, /**< exactly equal [abababab] */ ADDRESS_ES, /**< within [bb[aaa]bb] and [[abab]bbb] and [bbb[abab]] */ ADDRESS_EB, /**< completely overlaps [aa[bbb]aa] and [[baba]aaa] and [aaa[baba]] */ ADDRESS_GE, /**< bigger with overlap [bb[aba]aa] */ ADDRESS_GT, /**< bigger [bbb] [aaa] */ }; #define ADDRESS_FLAG_ANY 0x01 /**< address is "any" */ #define ADDRESS_FLAG_NOT 0x02 /**< address is negated */ #define ADDRESS_SIGGROUPHEAD_COPY 0x04 /**< sgh is a ptr to another sgh */ #define ADDRESS_PORTS_COPY 0x08 /**< ports are a ptr to other ports */ #define ADDRESS_PORTS_NOTUNIQ 0x10 #define ADDRESS_HAVEPORT 0x20 /**< address has a ports ptr */ /** \brief address structure for use in the detection engine. * * Contains the address information and matching information. */ typedef struct DetectAddress_ { /** address data for this group */ Address ip; Address ip2; // uint8_t family; /**< address family, AF_INET (IPv4) or AF_INET6 (IPv6) */ // uint32_t ip[4]; /**< the address, or lower end of a range */ // uint32_t ip2[4]; /**< higher end of a range */ /** ptr to the next address (dst addr in that case) or to the src port */ union { struct DetectAddressHead_ *dst_gh; /**< destination address */ struct DetectPort_ *port; /**< source port */ }; /** signatures that belong in this group */ struct SigGroupHead_ *sh; /** flags affecting this address */ uint8_t flags; /** ptr to the previous address in the list */ struct DetectAddress_ *prev; /** ptr to the next address in the list */ struct DetectAddress_ *next; uint32_t cnt; } DetectAddress; /** Signature grouping head. Here 'any', ipv4 and ipv6 are split out */ typedef struct DetectAddressHead_ { DetectAddress *any_head; DetectAddress *ipv4_head; DetectAddress *ipv6_head; } DetectAddressHead; #include "detect-threshold.h" typedef struct DetectMatchAddressIPv4_ { uint32_t ip; /**< address in host order, start of range */ uint32_t ip2; /**< address in host order, end of range */ } DetectMatchAddressIPv4; typedef struct DetectMatchAddressIPv6_ { uint32_t ip[4]; uint32_t ip2[4]; } DetectMatchAddressIPv6; /* * DETECT PORT */ /* a is ... than b */ enum { PORT_ER = -1, /* error e.g. compare ipv4 and ipv6 */ PORT_LT, /* smaller [aaa] [bbb] */ PORT_LE, /* smaller with overlap [aa[bab]bb] */ PORT_EQ, /* exactly equal [abababab] */ PORT_ES, /* within [bb[aaa]bb] and [[abab]bbb] and [bbb[abab]] */ PORT_EB, /* completely overlaps [aa[bbb]aa] and [[baba]aaa] and [aaa[baba]] */ PORT_GE, /* bigger with overlap [bb[aba]aa] */ PORT_GT, /* bigger [bbb] [aaa] */ }; #define PORT_FLAG_ANY 0x01 /**< 'any' special port */ #define PORT_FLAG_NOT 0x02 /**< negated port */ #define PORT_SIGGROUPHEAD_COPY 0x04 /**< sgh is a ptr copy */ #define PORT_GROUP_PORTS_COPY 0x08 /**< dst_ph is a ptr copy */ /** \brief Port structure for detection engine */ typedef struct DetectPort_ { uint16_t port; uint16_t port2; /* signatures that belong in this group */ struct SigGroupHead_ *sh; struct DetectPort_ *dst_ph; /* double linked list */ union { struct DetectPort_ *prev; struct DetectPort_ *hnext; /* hash next */ }; struct DetectPort_ *next; uint32_t cnt; uint8_t flags; /**< flags for this port */ } DetectPort; /* Signature flags */ #define SIG_FLAG_SRC_ANY (1) /**< source is any */ #define SIG_FLAG_DST_ANY (1<<1) /**< destination is any */ #define SIG_FLAG_SP_ANY (1<<2) /**< source port is any */ #define SIG_FLAG_DP_ANY (1<<3) /**< destination port is any */ #define SIG_FLAG_NOALERT (1<<4) /**< no alert flag is set */ #define SIG_FLAG_DSIZE (1<<5) /**< signature has a dsize setting */ #define SIG_FLAG_APPLAYER (1<<6) /**< signature applies to app layer instead of packets */ #define SIG_FLAG_IPONLY (1<<7) /**< ip only signature */ #define SIG_FLAG_STATE_MATCH (1<<8) /**< signature has matches that require stateful inspection */ #define SIG_FLAG_REQUIRE_PACKET (1<<9) /**< signature is requiring packet match */ #define SIG_FLAG_REQUIRE_STREAM (1<<10) /**< signature is requiring stream match */ #define SIG_FLAG_MPM_PACKET (1<<11) #define SIG_FLAG_MPM_PACKET_NEG (1<<12) #define SIG_FLAG_MPM_STREAM (1<<13) #define SIG_FLAG_MPM_STREAM_NEG (1<<14) #define SIG_FLAG_MPM_HTTP (1<<15) #define SIG_FLAG_MPM_HTTP_NEG (1<<16) #define SIG_FLAG_REQUIRE_FLOWVAR (1<<17) /**< signature can only match if a flowbit, flowvar or flowint is available. */ #define SIG_FLAG_FILESTORE (1<<18) /**< signature has filestore keyword */ #define SIG_FLAG_TOSERVER (1<<19) #define SIG_FLAG_TOCLIENT (1<<20) #define SIG_FLAG_TLSSTORE (1<<21) /* signature init flags */ #define SIG_FLAG_INIT_DEONLY 1 /**< decode event only signature */ #define SIG_FLAG_INIT_PACKET (1<<1) /**< signature has matches against a packet (as opposed to app layer) */ #define SIG_FLAG_INIT_FLOW (1<<2) /**< signature has a flow setting */ #define SIG_FLAG_INIT_BIDIREC (1<<3) /**< signature has bidirectional operator */ #define SIG_FLAG_INIT_PAYLOAD (1<<4) /**< signature is inspecting the packet payload */ #define SIG_FLAG_INIT_FILE_DATA (1<<5) /**< file_data set */ /* signature mask flags */ #define SIG_MASK_REQUIRE_PAYLOAD (1<<0) #define SIG_MASK_REQUIRE_FLOW (1<<1) #define SIG_MASK_REQUIRE_FLAGS_INITDEINIT (1<<2) /* SYN, FIN, RST */ #define SIG_MASK_REQUIRE_FLAGS_UNUSUAL (1<<3) /* URG, ECN, CWR */ #define SIG_MASK_REQUIRE_NO_PAYLOAD (1<<4) #define SIG_MASK_REQUIRE_HTTP_STATE (1<<5) #define SIG_MASK_REQUIRE_DCE_STATE (1<<6) #define SIG_MASK_REQUIRE_ENGINE_EVENT (1<<7) /* for now a uint8_t is enough */ #define SignatureMask uint8_t #define DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET 0x0001 #define DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM 0x0002 #define DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH 0x0004 #define FILE_SIG_NEED_FILE 0x01 #define FILE_SIG_NEED_FILENAME 0x02 #define FILE_SIG_NEED_TYPE 0x04 #define FILE_SIG_NEED_MAGIC 0x08 /**< need the start of the file */ #define FILE_SIG_NEED_FILECONTENT 0x10 #define FILE_SIG_NEED_MD5 0x20 #define FILE_SIG_NEED_SIZE 0x40 /* Detection Engine flags */ #define DE_QUIET 0x01 /**< DE is quiet (esp for unittests) */ typedef struct IPOnlyCIDRItem_ { /* address data for this item */ uint8_t family; uint32_t ip[4]; /* netmask in CIDR values (ex. /16 /18 /24..) */ uint8_t netmask; /* If this host or net is negated for the signum */ uint8_t negated; SigIntId signum; /**< our internal id */ /* linked list, the header should be the biggest network */ struct IPOnlyCIDRItem_ *next; } IPOnlyCIDRItem; /** \brief Subset of the Signature for cache efficient prefiltering */ typedef struct SignatureHeader_ { union { struct { uint32_t flags; uint16_t alproto; uint16_t dsize_low; }; uint64_t hdr_copy1; }; union { struct { uint16_t dsize_high; uint16_t mpm_pattern_id_div_8; }; uint32_t hdr_copy2; }; union { struct { uint8_t mpm_pattern_id_mod_8; SignatureMask mask; SigIntId num; /**< signature number, internal id */ }; uint32_t hdr_copy3; }; /** pointer to the full signature */ struct Signature_ *full_sig; } SignatureHeader; /** \brief a single match condition for a signature */ typedef struct SigMatch_ { uint16_t idx; /**< position in the signature */ uint8_t type; /**< match type */ void *ctx; /**< plugin specific data */ struct SigMatch_ *next; struct SigMatch_ *prev; } SigMatch; /** \brief Signature container */ typedef struct Signature_ { union { struct { uint32_t flags; uint16_t alproto; uint16_t dsize_low; }; uint64_t hdr_copy1; }; union { struct { uint16_t dsize_high; uint16_t mpm_pattern_id_div_8; }; uint32_t hdr_copy2; }; union { struct { uint8_t mpm_pattern_id_mod_8; SignatureMask mask; SigIntId num; /**< signature number, internal id */ }; uint32_t hdr_copy3; }; /** inline -- action */ uint8_t action; uint8_t file_flags; /** ipv4 match arrays */ uint16_t addr_dst_match4_cnt; uint16_t addr_src_match4_cnt; DetectMatchAddressIPv4 *addr_dst_match4; DetectMatchAddressIPv4 *addr_src_match4; /** ipv6 match arrays */ DetectMatchAddressIPv6 *addr_dst_match6; DetectMatchAddressIPv6 *addr_src_match6; uint16_t addr_dst_match6_cnt; uint16_t addr_src_match6_cnt; uint32_t id; /**< sid, set by the 'sid' rule keyword */ /** port settings for this signature */ DetectPort *sp, *dp; /** addresses, ports and proto this sig matches on */ DetectProto proto; /** classification id **/ uint8_t class; uint32_t gid; /**< generator id */ /** netblocks and hosts specified at the sid, in CIDR format */ IPOnlyCIDRItem *CidrSrc, *CidrDst; uint32_t rev; int prio; char *msg; /** classification message */ char *class_msg; /** Reference */ DetectReference *references; /* Be careful, this pointer is only valid while parsing the sig, * to warn the user about any possible problem */ char *sig_str; #ifdef PROFILING uint16_t profiling_id; #endif /* holds all sm lists */ struct SigMatch_ *sm_lists[DETECT_SM_LIST_MAX]; /* holds all sm lists' tails */ struct SigMatch_ *sm_lists_tail[DETECT_SM_LIST_MAX]; /** address settings for this signature */ DetectAddressHead src, dst; /* used to hold flags that are predominantly used during init */ uint32_t init_flags; /** number of sigmatches in the match and pmatch list */ uint16_t sm_cnt; SigMatch *dsize_sm; SigMatch *filestore_sm; /* the fast pattern added from this signature */ SigMatch *mpm_sm; /* helper for init phase */ uint16_t mpm_content_maxlen; uint16_t mpm_uricontent_maxlen; /** ptr to the next sig in the list */ struct Signature_ *next; } Signature; typedef struct DetectReplaceList_ { struct DetectContentData_ *cd; uint8_t *found; struct DetectReplaceList_ *next; } DetectReplaceList; /** list for flowvar store candidates, to be stored from * post-match function */ typedef struct DetectFlowvarList_ { uint16_t idx; /**< flowvar name idx */ uint16_t len; /**< data len */ uint8_t *buffer; /**< alloc'd buffer, may be freed by post-match, post-non-match */ struct DetectFlowvarList_ *next; } DetectFlowvarList; typedef struct DetectEngineIPOnlyThreadCtx_ { uint8_t *sig_match_array; /* bit array of sig nums */ uint32_t sig_match_size; /* size in bytes of the array */ } DetectEngineIPOnlyThreadCtx; /** \brief IP only rules matching ctx. * \todo a radix tree would be great here */ typedef struct DetectEngineIPOnlyCtx_ { /* lookup hashes */ HashListTable *ht16_src, *ht16_dst; HashListTable *ht24_src, *ht24_dst; /* Lookup trees */ SCRadixTree *tree_ipv4src, *tree_ipv4dst; SCRadixTree *tree_ipv6src, *tree_ipv6dst; /* Used to build the radix trees */ IPOnlyCIDRItem *ip_src, *ip_dst; /* counters */ uint32_t a_src_uniq16, a_src_total16; uint32_t a_dst_uniq16, a_dst_total16; uint32_t a_src_uniq24, a_src_total24; uint32_t a_dst_uniq24, a_dst_total24; uint32_t max_idx; uint8_t *sig_init_array; /* bit array of sig nums */ uint32_t sig_init_size; /* size in bytes of the array */ /* number of sigs in this head */ uint32_t sig_cnt; uint32_t *match_array; } DetectEngineIPOnlyCtx; typedef struct DetectEngineLookupFlow_ { DetectAddressHead *src_gh[256]; /* a head for each protocol */ DetectAddressHead *tmp_gh[256]; } DetectEngineLookupFlow; /* Flow status * * to server * to client */ #define FLOW_STATES 2 /* mpm pattern id api */ typedef struct MpmPatternIdStore_ { HashTable *hash; PatIntId max_id; uint32_t unique_patterns; uint32_t shared_patterns; } MpmPatternIdStore; /** \brief threshold ctx */ typedef struct ThresholdCtx_ { SCMutex threshold_table_lock; /**< Mutex for hash table */ /** to support rate_filter "by_rule" option */ DetectThresholdEntry **th_entry; uint32_t th_size; } ThresholdCtx; typedef struct DetectEngineThreadKeywordCtxItem_ { void *(*InitFunc)(void *); void (*FreeFunc)(void *); void *data; struct DetectEngineThreadKeywordCtxItem_ *next; int id; const char *name; /* keyword name, for error printing */ } DetectEngineThreadKeywordCtxItem; /** \brief main detection engine ctx */ typedef struct DetectEngineCtx_ { uint8_t flags; int failure_fatal; Signature *sig_list; uint32_t sig_cnt; /* version of the srep data */ uint32_t srep_version; Signature **sig_array; uint32_t sig_array_size; /* size in bytes */ uint32_t sig_array_len; /* size in array members */ uint32_t signum; /* used by the signature ordering module */ struct SCSigOrderFunc_ *sc_sig_order_funcs; struct SCSigSignatureWrapper_ *sc_sig_sig_wrapper; /* hash table used for holding the classification config info */ HashTable *class_conf_ht; /* hash table used for holding the reference config info */ HashTable *reference_conf_ht; /* main sigs */ DetectEngineLookupFlow flow_gh[FLOW_STATES]; uint32_t mpm_unique, mpm_reuse, mpm_none, mpm_uri_unique, mpm_uri_reuse, mpm_uri_none; uint32_t gh_unique, gh_reuse; uint32_t mpm_max_patcnt, mpm_min_patcnt, mpm_tot_patcnt, mpm_uri_max_patcnt, mpm_uri_min_patcnt, mpm_uri_tot_patcnt; /* init phase vars */ HashListTable *sgh_hash_table; HashListTable *sgh_mpm_hash_table; HashListTable *sgh_mpm_uri_hash_table; HashListTable *sgh_mpm_stream_hash_table; HashListTable *sgh_sport_hash_table; HashListTable *sgh_dport_hash_table; HashListTable *sport_hash_table; HashListTable *dport_hash_table; HashListTable *variable_names; HashListTable *variable_idxs; uint16_t variable_names_idx; /* hash table used to cull out duplicate sigs */ HashListTable *dup_sig_hash_table; /* memory counters */ uint32_t mpm_memory_size; DetectEngineIPOnlyCtx io_ctx; ThresholdCtx ths_ctx; uint16_t mpm_matcher; /**< mpm matcher this ctx uses */ #ifdef __SC_CUDA_SUPPORT__ /* cuda rules content module handle. Holds the handler serivice's * (util-cuda-handler.c) handle for a module. This module would * hold the cuda context for all the rules content */ int cuda_rc_mod_handle; #endif /* Config options */ uint16_t max_uniq_toclient_src_groups; uint16_t max_uniq_toclient_dst_groups; uint16_t max_uniq_toclient_sp_groups; uint16_t max_uniq_toclient_dp_groups; uint16_t max_uniq_toserver_src_groups; uint16_t max_uniq_toserver_dst_groups; uint16_t max_uniq_toserver_sp_groups; uint16_t max_uniq_toserver_dp_groups; /* uint16_t max_uniq_small_toclient_src_groups; uint16_t max_uniq_small_toclient_dst_groups; uint16_t max_uniq_small_toclient_sp_groups; uint16_t max_uniq_small_toclient_dp_groups; uint16_t max_uniq_small_toserver_src_groups; uint16_t max_uniq_small_toserver_dst_groups; uint16_t max_uniq_small_toserver_sp_groups; uint16_t max_uniq_small_toserver_dp_groups; */ /* specify the configuration for mpm context factory */ uint8_t sgh_mpm_context; /** hash table for looking up patterns for * id sharing and id tracking. */ MpmPatternIdStore *mpm_pattern_id_store; MpmCtxFactoryContainer *mpm_ctx_factory_container; /* maximum recursion depth for content inspection */ int inspection_recursion_limit; /* conf parameter that limits the length of the http request body inspected */ int hcbd_buffer_limit; /* conf parameter that limits the length of the http response body inspected */ int hsbd_buffer_limit; /* array containing all sgh's in use so we can loop * through it in Stage4. */ struct SigGroupHead_ **sgh_array; uint32_t sgh_array_cnt; uint32_t sgh_array_size; int32_t sgh_mpm_context_proto_tcp_packet; int32_t sgh_mpm_context_proto_udp_packet; int32_t sgh_mpm_context_proto_other_packet; int32_t sgh_mpm_context_stream; int32_t sgh_mpm_context_uri; int32_t sgh_mpm_context_hcbd; int32_t sgh_mpm_context_hsbd; int32_t sgh_mpm_context_hhd; int32_t sgh_mpm_context_hrhd; int32_t sgh_mpm_context_hmd; int32_t sgh_mpm_context_hcd; int32_t sgh_mpm_context_hrud; int32_t sgh_mpm_context_hsmd; int32_t sgh_mpm_context_hscd; int32_t sgh_mpm_context_huad; int32_t sgh_mpm_context_hhhd; int32_t sgh_mpm_context_hrhhd; int32_t sgh_mpm_context_app_proto_detect; /* the max local id used amongst all sigs */ int32_t byte_extract_max_local_id; /* id used by every detect engine ctx instance */ uint32_t id; /** sgh for signatures that match against invalid packets. In those cases * we can't lookup by proto, address, port as we don't have these */ struct SigGroupHead_ *decoder_event_sgh; /** Store rule file and line so that parsers can use them in errors. */ char *rule_file; int rule_line; /** Is detect engine using a delayed init */ int delayed_detect; /** list of keywords that need thread local ctxs */ DetectEngineThreadKeywordCtxItem *keyword_list; int keyword_id; int detect_luajit_instances; #ifdef PROFILING struct SCProfileDetectCtx_ *profile_ctx; #endif } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ enum { ENGINE_PROFILE_UNKNOWN, ENGINE_PROFILE_LOW, ENGINE_PROFILE_MEDIUM, ENGINE_PROFILE_HIGH, ENGINE_PROFILE_CUSTOM, ENGINE_PROFILE_MAX }; /* Siggroup mpm context profile */ enum { ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL, ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE, ENGINE_SGH_MPM_FACTORY_CONTEXT_AUTO }; typedef struct HttpReassembledBody_ { uint8_t *buffer; uint32_t buffer_size; /**< size of the buffer itself */ uint32_t buffer_len; /**< data len in the buffer */ uint64_t offset; /**< data offset */ } HttpReassembledBody; #define DETECT_FILESTORE_MAX 15 /** * Detection engine thread data. */ typedef struct DetectionEngineThreadCtx_ { /* the thread to which this detection engine thread belongs */ ThreadVars *tv; /* detection engine variables */ /** offset into the payload of the last match by: * content, pcre, etc */ uint32_t buffer_offset; /* used by pcre match function alone */ uint32_t pcre_match_start_offset; /* counter for the filestore array below -- up here for cache reasons. */ uint16_t filestore_cnt; HttpReassembledBody *hsbd; int hsbd_start_tx_id; uint16_t hsbd_buffers_size; uint16_t hsbd_buffers_list_len; HttpReassembledBody *hcbd; int hcbd_start_tx_id; uint16_t hcbd_buffers_size; uint16_t hcbd_buffers_list_len; uint8_t **hhd_buffers; uint32_t *hhd_buffers_len; uint16_t hhd_buffers_size; uint16_t hhd_buffers_list_len; int hhd_start_tx_id; /** id for alert counter */ uint16_t counter_alerts; /* used to discontinue any more matching */ uint16_t discontinue_matching; uint16_t flags; /** ID of the transaction currently being inspected. */ uint16_t tx_id; SC_ATOMIC_DECLARE(uint16_t, so_far_used_by_detect); /* holds the current recursion depth on content inspection */ int inspection_recursion_counter; /** array of signature pointers we're going to inspect in the detection * loop. */ Signature **match_array; /** size of the array in items (mem size if * sizeof(Signature *) * Only used during initialization. */ uint32_t match_array_len; /** size in use */ SigIntId match_array_cnt; /** Array of sigs that had a state change */ SigIntId de_state_sig_array_len; uint8_t *de_state_sig_array; struct SigGroupHead_ *sgh; /** pointer to the current mpm ctx that is stored * in a rule group head -- can be either a content * or uricontent ctx. */ MpmThreadCtx mtc; /**< thread ctx for the mpm */ MpmThreadCtx mtcu; /**< thread ctx for uricontent mpm */ MpmThreadCtx mtcs; /**< thread ctx for stream mpm */ PatternMatcherQueue pmq; PatternMatcherQueue smsg_pmq[256]; /** ip only rules ctx */ DetectEngineIPOnlyThreadCtx io_ctx; /* byte jump values */ uint64_t *bj_values; /* string to replace */ DetectReplaceList *replist; /* flowvars to store in post match function */ DetectFlowvarList *flowvarlist; /* Array in which the filestore keyword stores file id and tx id. If the * full signature matches, these are processed by a post-match filestore * function to finalize the store. */ struct { uint16_t file_id; uint16_t tx_id; } filestore[DETECT_FILESTORE_MAX]; DetectEngineCtx *de_ctx; #ifdef __SC_CUDA_SUPPORT__ /* each detection thread would have it's own queue where the cuda dispatcher * thread can dump the packets once it has processed them */ Tmq *cuda_mpm_rc_disp_outq; #endif /** store for keyword contexts that need a per thread storage because of * thread safety issues */ void **keyword_ctxs_array; int keyword_ctxs_size; #ifdef PROFILING struct SCProfileData_ *rule_perf_data; int rule_perf_data_size; #endif } DetectEngineThreadCtx; /** \brief element in sigmatch type table. * \note FileMatch pointer below takes a locked flow, AppLayerMatch an unlocked flow */ typedef struct SigTableElmt_ { /** Packet match function pointer */ int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); /** AppLayer match function pointer */ int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, Signature *, SigMatch *); /** File match function pointer */ int (*FileMatch)(ThreadVars *, /**< thread local vars */ DetectEngineThreadCtx *, Flow *, /**< *LOCKED* flow */ uint8_t flags, File *, Signature *, SigMatch *); /** app layer proto from app-layer-protos.h this match applies to */ uint16_t alproto; /** keyword setup function pointer */ int (*Setup)(DetectEngineCtx *, Signature *, char *); void (*Free)(void *); void (*RegisterTests)(void); uint8_t flags; char *name; char *desc; char *url; } SigTableElmt; #define SIG_GROUP_HEAD_MPM_COPY (1) #define SIG_GROUP_HEAD_MPM_URI_COPY (1 << 1) #define SIG_GROUP_HEAD_MPM_STREAM_COPY (1 << 2) #define SIG_GROUP_HEAD_FREE (1 << 3) #define SIG_GROUP_HEAD_MPM_PACKET (1 << 4) #define SIG_GROUP_HEAD_MPM_STREAM (1 << 5) #define SIG_GROUP_HEAD_MPM_URI (1 << 6) #define SIG_GROUP_HEAD_MPM_HCBD (1 << 7) #define SIG_GROUP_HEAD_MPM_HHD (1 << 8) #define SIG_GROUP_HEAD_MPM_HRHD (1 << 9) #define SIG_GROUP_HEAD_MPM_HMD (1 << 10) #define SIG_GROUP_HEAD_MPM_HCD (1 << 11) #define SIG_GROUP_HEAD_MPM_HRUD (1 << 12) #define SIG_GROUP_HEAD_REFERENCED (1 << 13) /**< sgh is being referenced by others, don't clear */ #define SIG_GROUP_HEAD_HAVEFILEMAGIC (1 << 14) #define SIG_GROUP_HEAD_MPM_HSBD (1 << 15) #define SIG_GROUP_HEAD_MPM_HSMD (1 << 16) #define SIG_GROUP_HEAD_MPM_HSCD (1 << 17) #define SIG_GROUP_HEAD_MPM_HUAD (1 << 18) #define SIG_GROUP_HEAD_MPM_HHHD (1 << 19) #define SIG_GROUP_HEAD_MPM_HRHHD (1 << 20) #define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21) #define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22) typedef struct SigGroupHeadInitData_ { /* list of content containers * XXX move into a separate data struct * with only a ptr to it. Saves some memory * after initialization */ uint8_t *content_array; uint32_t content_size; uint8_t *uri_content_array; uint32_t uri_content_size; uint8_t *stream_content_array; uint32_t stream_content_size; /* "Normal" detection uses these only at init, but ip-only * uses it during runtime as well, thus not in init... */ uint8_t *sig_array; /**< bit array of sig nums (internal id's) */ uint32_t sig_size; /**< size in bytes */ /* port ptr */ struct DetectPort_ *port; } SigGroupHeadInitData; /** \brief Container for matching data for a signature group */ typedef struct SigGroupHead_ { uint32_t flags; /* number of sigs in this head */ SigIntId sig_cnt; uint16_t mpm_content_maxlen; /** array of masks, used to check multiple masks against * a packet using SIMD. */ #if defined(__SSE3__) SignatureMask *mask_array; #endif /** chunk of memory containing the "header" part of each * signature ordered as an array. Used to pre-filter the * signatures to be inspected in a cache efficient way. */ SignatureHeader *head_array; /* pattern matcher instances */ MpmCtx *mpm_proto_other_ctx; MpmCtx *mpm_proto_tcp_ctx_ts; MpmCtx *mpm_proto_udp_ctx_ts; MpmCtx *mpm_stream_ctx_ts; MpmCtx *mpm_uri_ctx_ts; MpmCtx *mpm_hcbd_ctx_ts; MpmCtx *mpm_hsbd_ctx_ts; MpmCtx *mpm_hhd_ctx_ts; MpmCtx *mpm_hrhd_ctx_ts; MpmCtx *mpm_hmd_ctx_ts; MpmCtx *mpm_hcd_ctx_ts; MpmCtx *mpm_hrud_ctx_ts; MpmCtx *mpm_hsmd_ctx_ts; MpmCtx *mpm_hscd_ctx_ts; MpmCtx *mpm_huad_ctx_ts; MpmCtx *mpm_hhhd_ctx_ts; MpmCtx *mpm_hrhhd_ctx_ts; MpmCtx *mpm_proto_tcp_ctx_tc; MpmCtx *mpm_proto_udp_ctx_tc; MpmCtx *mpm_stream_ctx_tc; MpmCtx *mpm_uri_ctx_tc; MpmCtx *mpm_hcbd_ctx_tc; MpmCtx *mpm_hsbd_ctx_tc; MpmCtx *mpm_hhd_ctx_tc; MpmCtx *mpm_hrhd_ctx_tc; MpmCtx *mpm_hmd_ctx_tc; MpmCtx *mpm_hcd_ctx_tc; MpmCtx *mpm_hrud_ctx_tc; MpmCtx *mpm_hsmd_ctx_tc; MpmCtx *mpm_hscd_ctx_tc; MpmCtx *mpm_huad_ctx_tc; MpmCtx *mpm_hhhd_ctx_tc; MpmCtx *mpm_hrhhd_ctx_tc; uint16_t mpm_uricontent_maxlen; /** the number of signatures in this sgh that have the filestore keyword * set. */ uint16_t filestore_cnt; /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ Signature **match_array; /* ptr to our init data we only use at... init :) */ SigGroupHeadInitData *init; } SigGroupHead; /** sigmatch has no options, so the parser shouldn't expect any */ #define SIGMATCH_NOOPT (1 << 0) /** sigmatch is compatible with a ip only rule */ #define SIGMATCH_IPONLY_COMPAT (1 << 1) /** sigmatch is compatible with a decode event only rule */ #define SIGMATCH_DEONLY_COMPAT (1 << 2) /**< Flag to indicate that the signature inspects the packet payload */ #define SIGMATCH_PAYLOAD (1 << 3) /**< Flag to indicate that the signature is not built-in */ #define SIGMATCH_NOT_BUILT (1 << 4) /** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */ enum { DETECT_SID, DETECT_PRIORITY, DETECT_REV, DETECT_CLASSTYPE, DETECT_THRESHOLD, DETECT_METADATA, DETECT_REFERENCE, DETECT_TAG, DETECT_MSG, DETECT_CONTENT, DETECT_URICONTENT, DETECT_PCRE, DETECT_ACK, DETECT_SEQ, DETECT_DEPTH, DETECT_DISTANCE, DETECT_WITHIN, DETECT_OFFSET, DETECT_REPLACE, DETECT_NOCASE, DETECT_FAST_PATTERN, DETECT_RAWBYTES, DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_SAMEIP, DETECT_GEOIP, DETECT_IPPROTO, DETECT_FLOW, DETECT_WINDOW, DETECT_FTPBOUNCE, DETECT_ISDATAAT, DETECT_ID, DETECT_RPC, DETECT_DSIZE, DETECT_FLOWVAR, DETECT_FLOWVAR_POSTMATCH, DETECT_FLOWINT, DETECT_PKTVAR, DETECT_NOALERT, DETECT_FLOWBITS, DETECT_FLOWALERTSID, DETECT_IPV4_CSUM, DETECT_TCPV4_CSUM, DETECT_TCPV6_CSUM, DETECT_UDPV4_CSUM, DETECT_UDPV6_CSUM, DETECT_ICMPV4_CSUM, DETECT_ICMPV6_CSUM, DETECT_STREAM_SIZE, DETECT_TTL, DETECT_ITYPE, DETECT_ICODE, DETECT_TOS, DETECT_ICMP_ID, DETECT_ICMP_SEQ, DETECT_DETECTION_FILTER, DETECT_DECODE_EVENT, DETECT_IPOPTS, DETECT_FLAGS, DETECT_FRAGBITS, DETECT_FRAGOFFSET, DETECT_GID, DETECT_MARK, DETECT_AL_TLS_VERSION, DETECT_AL_TLS_SUBJECT, DETECT_AL_TLS_ISSUERDN, DETECT_AL_TLS_FINGERPRINT, DETECT_AL_TLS_STORE, DETECT_AL_HTTP_COOKIE, DETECT_AL_HTTP_METHOD, DETECT_AL_URILEN, DETECT_AL_HTTP_CLIENT_BODY, DETECT_AL_HTTP_SERVER_BODY, DETECT_AL_HTTP_HEADER, DETECT_AL_HTTP_RAW_HEADER, DETECT_AL_HTTP_URI, DETECT_AL_HTTP_RAW_URI, DETECT_AL_HTTP_STAT_MSG, DETECT_AL_HTTP_STAT_CODE, DETECT_AL_HTTP_USER_AGENT, DETECT_AL_HTTP_HOST, DETECT_AL_HTTP_RAW_HOST, DETECT_AL_SSH_PROTOVERSION, DETECT_AL_SSH_SOFTWAREVERSION, DETECT_AL_SSL_VERSION, DETECT_AL_SSL_STATE, DETECT_BYTE_EXTRACT, DETECT_FILE_DATA, DETECT_PKT_DATA, DETECT_AL_APP_LAYER_EVENT, DETECT_DCE_IFACE, DETECT_DCE_OPNUM, DETECT_DCE_STUB_DATA, DETECT_ASN1, DETECT_ENGINE_EVENT, DETECT_STREAM_EVENT, DETECT_FILENAME, DETECT_FILEEXT, DETECT_FILESTORE, DETECT_FILEMAGIC, DETECT_FILEMD5, DETECT_FILESIZE, DETECT_L3PROTO, DETECT_LUAJIT, DETECT_IPREP, /* make sure this stays last */ DETECT_TBLSIZE, }; /* Table with all SigMatch registrations */ SigTableElmt sigmatch_table[DETECT_TBLSIZE]; /* detection api */ SigMatch *SigMatchAlloc(void); Signature *SigFindSignatureBySidGid(DetectEngineCtx *, uint32_t, uint32_t); void SigMatchFree(SigMatch *sm); void SigCleanSignatures(DetectEngineCtx *); void SigTableRegisterTests(void); void SigRegisterTests(void); void TmModuleDetectRegister (void); int SigGroupBuild(DetectEngineCtx *); int SigGroupCleanup (DetectEngineCtx *de_ctx); void SigAddressPrepareBidirectionals (DetectEngineCtx *); char *DetectLoadCompleteSigPath(char *sig_file); int SigLoadSignatures (DetectEngineCtx *, char *, int); void SigTableList(const char *keyword); void SigTableSetup(void); int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p); int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s); SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p); Signature *DetectGetTagSignature(void); int SignatureIsFilestoring(Signature *); int SignatureIsFilemagicInspecting(Signature *); int SignatureIsFileMd5Inspecting(Signature *); int SignatureIsFilesizeInspecting(Signature *); int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int); void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *, int); #endif /* __DETECT_H__ */ suricata-1.4.7/src/detect-engine-hhhd.h0000644000000000000000000000233212253546156014622 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HHHD_H__ #define __DETECT_ENGINE_HHHD_H__ #include "app-layer-htp.h" int DetectEngineInspectHttpHH(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *, Flow *, HtpState *, uint8_t); void DetectEngineHttpHHRegisterTests(void); #endif /* __DETECT_ENGINE_HHHD_H__ */ suricata-1.4.7/src/detect-ftpbounce.c0000644000000000000000000004056112253546156014432 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * * ftpbounce keyword, part of the detection engine. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "app-layer.h" #include "app-layer-ftp.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "threads.h" #include "detect-ftpbounce.h" #include "stream-tcp.h" #include "util-byte.h" int DetectFtpbounceMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectFtpbounceALMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectFtpbounceSetup(DetectEngineCtx *, Signature *, char *); int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, uint32_t ip_orig, uint16_t offset); void DetectFtpbounceRegisterTests(void); void DetectFtpbounceFree(void *); /** * \brief Registration function for ftpbounce: keyword * \todo add support for no_stream and stream_only */ void DetectFtpbounceRegister(void) { sigmatch_table[DETECT_FTPBOUNCE].name = "ftpbounce"; sigmatch_table[DETECT_FTPBOUNCE].Setup = DetectFtpbounceSetup; sigmatch_table[DETECT_FTPBOUNCE].Match = NULL; sigmatch_table[DETECT_FTPBOUNCE].AppLayerMatch = DetectFtpbounceALMatch; sigmatch_table[DETECT_FTPBOUNCE].alproto = ALPROTO_FTP; sigmatch_table[DETECT_FTPBOUNCE].Free = NULL; sigmatch_table[DETECT_FTPBOUNCE].RegisterTests = DetectFtpbounceRegisterTests; return; } /** * \brief This function is used to match ftpbounce attacks * * \param payload Payload of the PORT command * \param payload_len Length of the payload * \param ip_orig IP source to check the ftpbounce condition * \param offset offset to the arguments of the PORT command * * \retval 1 if ftpbounce detected, 0 if not */ int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, uint32_t ip_orig, uint16_t offset) { SCEnter(); SCLogDebug("Checking ftpbounce condition"); char *c = NULL; uint16_t i = 0; int octet = 0; int octet_ascii_len = 0; int noctet = 0; uint32_t ip = 0; /* PrintRawDataFp(stdout, payload, payload_len); */ if (payload_len < 7) { /* we need at least a differet ip address * in the format 1,2,3,4,x,y where x,y is the port * in two byte representation so let's look at * least for the IP octets in comma separated */ return 0; } if (offset + 7 >= payload_len) return 0; c =(char*) payload; if (c == NULL) { SCLogDebug("No payload to check"); return 0; } i = offset; /* Search for the first IP octect(Skips "PORT ") */ while (i < payload_len && !isdigit((unsigned char)c[i])) i++; for (;i < payload_len && octet_ascii_len < 4 ;i++) { if (isdigit((unsigned char)c[i])) { octet =(c[i] - '0') + octet * 10; octet_ascii_len++; } else { if (octet > 256) { SCLogDebug("Octet not in ip format"); return 0; } if (isspace((unsigned char)c[i])) while (i < payload_len && isspace((unsigned char)c[i]) ) i++; if (i < payload_len && c[i] == ',') { /* we have an octet */ noctet++; octet_ascii_len = 0; ip =(ip << 8) + octet; octet = 0; } else { SCLogDebug("Unrecognized character '%c'", c[i]); return 0; } if (noctet == 4) { /* Different IP than src, ftp bounce scan */ ip = SCByteSwap32(ip); if (ip != ip_orig) { SCLogDebug("Different ip, so Matched ip:%d <-> ip_orig:%d", ip, ip_orig); return 1; } SCLogDebug("Same ip, so no match here"); return 0; } } } SCLogDebug("No match"); return 0; } /** * \brief This function is used to check matches from the FTP App Layer Parser * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch but we don't use it since ftpbounce * has no options * \retval 0 no match * \retval 1 match */ int DetectFtpbounceALMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); FtpState *ftp_state =(FtpState *)state; if (ftp_state == NULL) { SCLogDebug("no ftp state, no match"); SCReturnInt(0); } int ret = 0; FLOWLOCK_RDLOCK(f); if (ftp_state->command == FTP_COMMAND_PORT) { ret = DetectFtpbounceMatchArgs(ftp_state->port_line, ftp_state->port_line_len, f->src.address.address_un_data32[0], ftp_state->arg_offset); } FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief This function is used to match ftpbounce attacks * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch but we don't use it since ftpbounce * has no options * \retval 0 no match, 1 if match */ int DetectFtpbounceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { /** \todo VJ broken and no longer used */ #if 0 SCEnter(); uint16_t offset = 0; if (!(PKT_IS_TCP(p))) return 0; SigMatch *sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (sm == NULL) return 0; DetectContentData *co = sm->ctx; if (co == NULL) return 0; MpmMatch *mm = det_ctx->mtc.match[co->id].top; SCLogDebug("Starting Offset: %u",mm->offset + co->content_len); offset = mm->offset + co->content_len; SCLogDebug("Payload: \"%s\"\nLen: %u Offset: %u\n", p->payload, p->payload_len, offset); return DetectFtpbounceMatchArgs(p->payload, p->payload_len, p->src.addr_data32[0], offset); #endif return 0; } /** * \brief this function is used to add the parsed ftpbounce * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param m pointer to the Current SigMatch * \param ftpbouncestr pointer to the user provided ftpbounce options * currently there are no options. * * \retval 0 on Success * \retval -1 on Failure */ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbouncestr) { SCEnter(); SigMatch *sm = NULL; sm = SigMatchAlloc(); if (sm == NULL) { goto error;; } sm->type = DETECT_FTPBOUNCE; /* We don't need to allocate any data for ftpbounce here. * * TODO: As a suggestion, maybe we can add a flag in the flow * to set the stream as "bounce detected" for fast Match. * When you do a ftp bounce attack you usually use the same * communication control stream to "setup" various destinations * whithout breaking the connection, so I guess we can make it a bit faster * with a flow flag set lookup in the Match function. */ sm->ctx = NULL; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_FTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_FTP; SCReturnInt(0); error: if (sm != NULL) { SigMatchFree(sm); } SCReturnInt(-1); } #ifdef UNITTESTS /** * \test DetectFtpbounceTestSetup01 is a test for the Setup ftpbounce */ int DetectFtpbounceTestSetup01(void) { int res = 0; DetectEngineCtx *de_ctx = NULL; Signature *s = SigAlloc(); if (s == NULL) return 0; /* ftpbounce doesn't accept options so the str is NULL */ res = !DetectFtpbounceSetup(de_ctx, s, NULL); res &= s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL && s->sm_lists[DETECT_SM_LIST_AMATCH]->type & DETECT_FTPBOUNCE; SigFree(s); return res; } #include "stream-tcp-reassemble.h" /** * \test Check the ftpbounce match, send a get request in three chunks * + more data. * \brief This test tests the ftpbounce condition match, based on the * ftp layer parser */ static int DetectFtpbounceTestALMatch02(void) { int result = 0; uint8_t ftpbuf1[] = { 'P','O' }; uint32_t ftplen1 = sizeof(ftpbuf1); uint8_t ftpbuf2[] = { 'R', 'T' }; uint32_t ftplen2 = sizeof(ftpbuf2); uint8_t ftpbuf3[] = { ' ', '8','0',',','5' }; uint32_t ftplen3 = sizeof(ftpbuf3); uint8_t ftpbuf4[] = "8,0,33,10,20\r\n"; uint32_t ftplen4 = sizeof(ftpbuf4); TcpSession ssn; Flow f; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacketSrcDst(NULL, 0, IPPROTO_TCP, "1.2.3.4", "5.6.7.8"); FLOW_INITIALIZE(&f); f.src.address.address_un_data32[0]=0x01020304; f.protoctx =(void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_FTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " "(msg:\"Ftp Bounce\"; ftpbounce; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *)de_ctx,(void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf4, ftplen4); if (r != 0) { SCLogDebug("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { SCLogDebug("no ftp state: "); result = 0; goto end; } if (ftp_state->command != FTP_COMMAND_PORT) { SCLogDebug("expected command port not detected"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v,(void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Check the ftpbounce match * \brief This test tests the ftpbounce condition match, based on * the ftp layer parser */ static int DetectFtpbounceTestALMatch03(void) { int result = 0; uint8_t ftpbuf1[] = { 'P','O' }; uint32_t ftplen1 = sizeof(ftpbuf1); uint8_t ftpbuf2[] = { 'R', 'T' }; uint32_t ftplen2 = sizeof(ftpbuf2); uint8_t ftpbuf3[] = { ' ', '1',',','2',',' }; uint32_t ftplen3 = sizeof(ftpbuf3); uint8_t ftpbuf4[] = "3,4,10,20\r\n"; uint32_t ftplen4 = sizeof(ftpbuf4); TcpSession ssn; Flow f; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = 0x04030201; p->payload = NULL; p->payload_len = 0; p->proto = IPPROTO_TCP; FLOW_INITIALIZE(&f); f.src.address.address_un_data32[0]=0x04030201; f.protoctx =(void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_FTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " "(msg:\"Ftp Bounce\"; ftpbounce; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *)de_ctx,(void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf4, ftplen4); if (r != 0) { SCLogDebug("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { SCLogDebug("no ftp state: "); result = 0; goto end; } if (ftp_state->command != FTP_COMMAND_PORT) { SCLogDebug("expected command port not detected"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* It should not match */ if (!(PacketAlertCheck(p, 1))) { result = 1; } else { SCLogDebug("It should not match here!"); } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v,(void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SCFree(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectFtpbounce */ void DetectFtpbounceRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectFtpbounceTestSetup01", DetectFtpbounceTestSetup01, 1); UtRegisterTest("DetectFtpbounceTestALMatch02", DetectFtpbounceTestALMatch02, 1); UtRegisterTest("DetectFtpbounceTestALMatch03", DetectFtpbounceTestALMatch03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-error.h0000644000000000000000000002002312253546156013277 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __ERROR_H__ #define __ERROR_H__ /* different error types */ typedef enum { SC_OK, SC_ERR_MEM_ALLOC, SC_ERR_PCRE_MATCH, SC_ERR_ACTION_ORDER, SC_ERR_PCRE_GET_SUBSTRING, SC_ERR_PCRE_COMPILE, SC_ERR_PCRE_STUDY, SC_ERR_PCRE_PARSE, SC_ERR_LOG_MODULE_NOT_INIT, SC_ERR_LOG_FG_FILTER_MATCH, SC_ERR_COUNTER_EXCEEDED, SC_ERR_INVALID_CHECKSUM, SC_ERR_SPRINTF, SC_ERR_INVALID_ARGUMENT, SC_ERR_SPINLOCK, SC_ERR_INVALID_ENUM_MAP, SC_ERR_INVALID_IP_NETBLOCK, SC_ERR_INVALID_IPV4_ADDR, SC_ERR_INVALID_IPV6_ADDR, SC_ERR_INVALID_RUNMODE, SC_ERR_PCAP_DISPATCH, SC_ERR_PCAP_CREATE, SC_ERR_PCAP_SET_SNAPLEN, SC_ERR_PCAP_SET_PROMISC, SC_ERR_PCAP_SET_TIMEOUT, SC_ERR_PCAP_OPEN_LIVE, SC_ERR_PCAP_OPEN_OFFLINE, SC_ERR_PCAP_ACTIVATE_HANDLE, SC_ERR_PCAP_SET_BUFF_SIZE, SC_ERR_NO_PCAP_SET_BUFFER_SIZE, SC_ERR_NO_PF_RING, SC_ERR_PF_RING_RECV, SC_ERR_PF_RING_GET_CLUSTERID_FAILED, SC_ERR_PF_RING_GET_INTERFACE_FAILED, SC_ERR_PF_RING_OPEN, SC_ERR_GET_CLUSTER_TYPE_FAILED, SC_ERR_INVALID_CLUSTER_TYPE, SC_ERR_PF_RING_SET_CLUSTER_FAILED, SC_ERR_DATALINK_UNIMPLEMENTED, SC_ERR_INVALID_SIGNATURE, SC_ERR_OPENING_FILE, SC_ERR_OPENING_RULE_FILE, SC_ERR_NO_RULES, SC_ERR_NO_RULES_LOADED, SC_ERR_FOPEN, SC_ERR_INITIALIZATION, SC_ERR_THREAD_SPAWN, SC_ERR_THREAD_NICE_PRIO, SC_ERR_THREAD_CREATE, SC_ERR_THREAD_INIT, /**< thread's initialization function failed */ SC_ERR_SYSCALL, SC_ERR_SYSCONF, SC_ERR_INVALID_ARGUMENTS, SC_ERR_PERF_STATS_NOT_INIT, SC_ERR_COMPLETE_PORT_SPACE_NEGATED, SC_ERR_NO_PORTS_LEFT_AFTER_MERGE, SC_ERR_NEGATED_VALUE_IN_PORT_RANGE, SC_ERR_PORT_PARSE_INSERT_STRING, SC_ERR_UNREACHABLE_CODE_REACHED, SC_ERR_ALPARSER, SC_ERR_INVALID_NUMERIC_VALUE, SC_ERR_NUMERIC_VALUE_ERANGE, SC_ERR_INVALID_NUM_BYTES, SC_ERR_ARG_LEN_LONG, SC_ERR_POOL_EMPTY, SC_ERR_REASSEMBLY, SC_ERR_POOL_INIT, SC_ERR_NFQ_NOSUPPORT, SC_ERR_NFQ_OPEN, SC_ERR_NFQ_BIND, SC_ERR_NFQ_UNBIND, SC_ERR_NFQ_MAXLEN, SC_ERR_NFQ_CREATE_QUEUE, SC_ERR_NFQ_SET_MODE, SC_ERR_NFQ_SETSOCKOPT, SC_ERR_NFQ_RECV, SC_ERR_NFQ_HANDLE_PKT, SC_ERR_NFQ_SET_VERDICT, SC_ERR_NFQ_THREAD_INIT, SC_ERR_IPFW_NOSUPPORT, SC_ERR_IPFW_BIND, SC_ERR_IPFW_SOCK, SC_ERR_IPFW_NOPORT, SC_WARN_IPFW_RECV, SC_WARN_IPFW_XMIT, SC_WARN_IPFW_SETSOCKOPT, SC_WARN_IPFW_UNBIND, SC_ERR_DAEMON, SC_ERR_UNIMPLEMENTED, SC_ERR_ADDRESS_ENGINE_GENERIC, SC_ERR_PORT_ENGINE_GENERIC, SC_ERR_IPONLY_RADIX, SC_ERR_FAST_LOG_GENERIC, SC_ERR_DEBUG_LOG_GENERIC, SC_ERR_UNIFIED_LOG_GENERIC, SC_ERR_HTTP_LOG_GENERIC, SC_ERR_TLS_LOG_GENERIC, SC_ERR_UNIFIED_ALERT_GENERIC, SC_ERR_UNIFIED2_ALERT_GENERIC, SC_ERR_FWRITE, SC_ERR_THRESHOLD_HASH_ADD, SC_ERR_UNDEFINED_VAR, SC_ERR_RULE_KEYWORD_UNKNOWN, SC_ERR_FLAGS_MODIFIER, SC_ERR_DISTANCE_MISSING_CONTENT, SC_ERR_WITHIN_MISSING_CONTENT, SC_ERR_WITHIN_INVALID, SC_ERR_OFFSET_MISSING_CONTENT, SC_ERR_DEPTH_MISSING_CONTENT, SC_ERR_BYTETEST_MISSING_CONTENT, SC_ERR_BYTEJUMP_MISSING_CONTENT, SC_ERR_NOCASE_MISSING_PATTERN, SC_ERR_RAWBYTES_MISSING_CONTENT, SC_ERR_NO_URICONTENT_NEGATION, SC_ERR_HASH_TABLE_INIT, SC_ERR_STAT, SC_ERR_LOGDIR_CONFIG, SC_ERR_LOGDIR_CMDLINE, SC_ERR_MISSING_CONFIG_PARAM, SC_ERR_RADIX_TREE_GENERIC, SC_ERR_MISSING_QUOTE, SC_ERR_MUTEX, SC_ERR_REPUTATION_INVALID_OPERATION, SC_ERR_REPUTATION_INVALID_TYPE, SC_ERR_UNKNOWN_PROTOCOL, /**< signature contains invalid protocol */ SC_ERR_UNKNOWN_RUN_MODE, SC_ERR_MULTIPLE_RUN_MODE, SC_ERR_BPF, SC_ERR_BYTE_EXTRACT_FAILED, SC_ERR_UNKNOWN_VALUE, SC_ERR_INVALID_VALUE, SC_ERR_UNKNOWN_REGEX_MOD, SC_ERR_INVALID_OPERATOR, SC_ERR_PCAP_RECV_INIT, SC_ERR_CUDA_ERROR, SC_ERR_CUDA_HANDLER_ERROR, SC_ERR_TM_THREADS_ERROR, SC_ERR_TM_MODULES_ERROR, SC_ERR_B2G_CUDA_ERROR, SC_ERR_INVALID_YAML_CONF_ENTRY, SC_ERR_TMQ_ALREADY_REGISTERED, SC_ERR_CONFLICTING_RULE_KEYWORDS, SC_ERR_INVALID_ACTION, SC_ERR_LIBNET_REQUIRED_FOR_ACTION, SC_ERR_LIBNET_INIT, SC_ERR_LIBNET_INVALID_DIR, SC_ERR_LIBNET_BUILD_FAILED, SC_ERR_LIBNET_WRITE_FAILED, SC_ERR_LIBNET_NOT_ENABLED, SC_ERR_UNIFIED_LOG_FILE_HEADER, /**< Error to indicate the unified file header writing function has been failed */ SC_ERR_REFERENCE_UNKNOWN, /**< unknown reference key (cve, url, etc) */ SC_ERR_PIDFILE_SNPRINTF, SC_ERR_PIDFILE_OPEN, SC_ERR_PIDFILE_WRITE, SC_ERR_PIDFILE_DAEMON, SC_ERR_UID_FAILED, SC_ERR_GID_FAILED, SC_ERR_CHANGING_CAPS_FAILED, SC_ERR_LIBCAP_NG_REQUIRED, SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG, SC_WARN_FLOW_EMERGENCY, SC_WARN_COMPATIBILITY, SC_ERR_SVC, SC_ERR_ERF_DAG_OPEN_FAILED, SC_ERR_ERF_DAG_STREAM_OPEN_FAILED, SC_ERR_ERF_DAG_STREAM_START_FAILED, SC_ERR_ERF_DAG_STREAM_SET_FAILED, SC_ERR_ERF_DAG_STREAM_READ_FAILED, SC_WARN_ERF_DAG_REC_LEN_CHANGED, SC_ERR_DAG_REQUIRED, SC_ERR_DAG_NOSUPPORT, /**< no ERF/DAG support compiled in */ SC_ERR_FATAL, SC_ERR_DCERPC, SC_ERR_DETECT_PREPARE, /**< preparing the detection engine failed */ SC_ERR_AHO_CORASICK, SC_ERR_REFERENCE_CONFIG, SC_ERR_DUPLICATE_SIG, /**< Error to indicate that signature is duplicate */ SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, SC_ERR_HTTP_METHOD_NEEDS_PRECEEDING_CONTENT, SC_ERR_HTTP_METHOD_INCOMPATIBLE_WITH_RAWBYTES, SC_ERR_HTTP_METHOD_RELATIVE_MISSING, SC_ERR_HTTP_COOKIE_NEEDS_PRECEEDING_CONTENT, SC_ERR_HTTP_COOKIE_INCOMPATIBLE_WITH_RAWBYTES, SC_ERR_HTTP_COOKIE_RELATIVE_MISSING, SC_ERR_LOGPCAP_SGUIL_BASE_DIR_MISSING, SC_ERR_UNKNOWN_DECODE_EVENT, SC_ERR_RUNMODE, SC_ERR_SHUTDOWN, SC_ERR_INVALID_DIRECTION, SC_ERR_AFP_CREATE, SC_ERR_AFP_READ, SC_ERR_AFP_DISPATCH, SC_ERR_NO_AF_PACKET, SC_ERR_PCAP_FILE_DELETE_FAILED, SC_ERR_CMD_LINE, SC_ERR_MAGIC_OPEN, SC_ERR_MAGIC_LOAD, SC_ERR_SIZE_PARSE, SC_ERR_RAWBYTES_FILE_DATA, SC_ERR_SOCKET, SC_ERR_PCAP_TRANSLATE, /* failed to translate ip to dev */ SC_WARN_OUTDATED_LIBHTP, SC_WARN_DEPRECATED, SC_WARN_PROFILE, SC_ERR_FLOW_INIT, SC_ERR_HOST_INIT, SC_ERR_MEM_BUFFER_API, SC_ERR_INVALID_MD5, SC_ERR_NO_MD5_SUPPORT, SC_ERR_EVENT_ENGINE, SC_ERR_NO_LUAJIT_SUPPORT, SC_ERR_LUAJIT_ERROR, SC_ERR_DEFRAG_INIT, SC_ERR_NAPATECH_OPEN_FAILED, SC_ERR_NAPATECH_STREAM_NEXT_FAILED, SC_ERR_NAPATECH_NOSUPPORT, SC_ERR_NAPATECH_REQUIRED, SC_ERR_NAPATECH_TIMESTAMP_TYPE_NOT_SUPPORTED, SC_ERR_NAPATECH_INIT_FAILED, SC_ERR_NAPATECH_CONFIG_STREAM, SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, SC_ERR_NAPATECH_STAT_DROPS_FAILED, SC_ERR_NAPATECH_PARSE_CONFIG, SC_ERR_NO_REPUTATION, SC_ERR_NOT_SUPPORTED, SC_ERR_IPFW_SETSOCKOPT, SC_ERR_NO_GEOIP_SUPPORT, SC_ERR_GEOIP_ERROR, SC_WARN_UNCOMMON, SC_ERR_THRESHOLD_SETUP, } SCError; const char *SCErrorToString(SCError); #endif /* __ERROR_H__ */ suricata-1.4.7/src/tmqh-simple.h0000644000000000000000000000202512253546156013435 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __TMQH_SIMPLE_H__ #define __TMQH_SIMPLE_H__ #include "data-queue.h" SCDQGenericQData *TmqhInputSimpleOnQ(SCDQDataQueue *); void TmqhOutputSimpleOnQ(SCDQDataQueue *, SCDQGenericQData *); void TmqhSimpleRegister (void); #endif /* __TMQH_SIMPLE_H__ */ suricata-1.4.7/src/util-threshold-config.c0000644000000000000000000022331212253546156015406 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup threshold * @{ */ /** * \file * * \author Breno Silva Pinto * * \todo Need to support suppress * * Implements Threshold support */ #include "suricata-common.h" #include "host.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-address.h" #include "detect-threshold.h" #include "detect-parse.h" #include "conf.h" #include "util-threshold-config.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-byte.h" #include "util-time.h" #include "util-error.h" #include "util-debug.h" #include "util-fmemopen.h" typedef enum ThresholdRuleType { THRESHOLD_TYPE_EVENT_FILTER, THRESHOLD_TYPE_THRESHOLD, THRESHOLD_TYPE_RATE, THRESHOLD_TYPE_SUPPRESS, } ThresholdRuleType; /* File descriptor for unittests */ /* common base for all options */ #define DETECT_BASE_REGEX "^\\s*(event_filter|threshold|rate_filter|suppress)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(\\d+)\\s*(.*)\\s*$" #define DETECT_THRESHOLD_REGEX "^,\\s*type\\s*(limit|both|threshold)\\s*,\\s*track\\s*(by_dst|by_src)\\s*,\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*$" /* TODO: "apply_to" */ #define DETECT_RATE_REGEX "^,\\s*track\\s*(by_dst|by_src|by_rule)\\s*,\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*,\\s*new_action\\s*(alert|drop|pass|log|sdrop|reject)\\s*,\\s*timeout\\s*(\\d+)\\s*$" /* * suppress has two form: * suppress gen_id 0, sig_id 0, track by_dst, ip 10.88.0.14 * suppress gen_id 1, sig_id 2000328 * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10 */ #define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src)\\s*,\\s*ip\\s*([\\da-fA-F.:/]+)*\\s*$" /* Default path for the threshold.config file */ #if defined OS_WIN32 || defined __CYGWIN__ #define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "\\\\threshold.config" #else #define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/threshold.config" #endif static pcre *regex_base = NULL; static pcre_extra *regex_base_study = NULL; static pcre *regex_threshold = NULL; static pcre_extra *regex_threshold_study = NULL; static pcre *regex_rate = NULL; static pcre_extra *regex_rate_study = NULL; static pcre *regex_suppress = NULL; static pcre_extra *regex_suppress_study = NULL; /** * \brief Returns the path for the Threshold Config file. We check if we * can retrieve the path from the yaml conf file. If it is not present, * return the default path for the threshold file which is * "./threshold.config". * * \retval log_filename Pointer to a string containing the path for the * Threshold Config file. */ char *SCThresholdConfGetConfFilename(void) { char *log_filename = NULL; if (ConfGet("threshold-file", &log_filename) != 1) { log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; } return log_filename; } /** * \brief Inits the context to be used by the Threshold Config parsing API. * * This function initializes the hash table to be used by the Detection * Engine Context to hold the data from the threshold.config file, * obtains the file desc to parse the threshold.config file, and * inits the regex used to parse the lines from threshold.config * file. * * \param de_ctx Pointer to the Detection Engine Context. * \param utfd Pointer for unit test file descriptor. * * \retval 0 On success. * \retval -1 On failure. */ int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) { char *filename = NULL; const char *eb = NULL; FILE *fd = utfd; int eo; int opts = 0; if (fd == NULL) { filename = SCThresholdConfGetConfFilename(); if ( (fd = fopen(filename, "r")) == NULL) { SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } } regex_base = pcre_compile(DETECT_BASE_REGEX, opts, &eb, &eo, NULL); if (regex_base == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s",DETECT_BASE_REGEX, eo, eb); goto error; } regex_base_study = pcre_study(regex_base, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } regex_threshold = pcre_compile(DETECT_THRESHOLD_REGEX, opts, &eb, &eo, NULL); if (regex_threshold == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s",DETECT_THRESHOLD_REGEX, eo, eb); goto error; } regex_threshold_study = pcre_study(regex_threshold, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } regex_rate = pcre_compile(DETECT_RATE_REGEX, opts, &eb, &eo, NULL); if (regex_rate == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s",DETECT_RATE_REGEX, eo, eb); goto error; } regex_rate_study = pcre_study(regex_rate, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } regex_suppress = pcre_compile(DETECT_SUPPRESS_REGEX, opts, &eb, &eo, NULL); if (regex_suppress == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s",DETECT_SUPPRESS_REGEX, eo, eb); goto error; } regex_suppress_study = pcre_study(regex_suppress, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } SCThresholdConfParseFile(de_ctx, fd); SCThresholdConfDeInitContext(de_ctx, fd); SCLogDebug("Global thresholding options defined"); return 0; error: SCThresholdConfDeInitContext(de_ctx, fd); return -1; } /** * \brief Releases resources used by the Threshold Config API. * * \param de_ctx Pointer to the Detection Engine Context. * \param fd Pointer to file descriptor. */ void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) { if (fd != NULL) fclose(fd); if (regex_base != NULL) { pcre_free(regex_base); regex_base = NULL; } if (regex_base_study != NULL) { pcre_free(regex_base_study); regex_base_study = NULL; } if (regex_threshold != NULL) { pcre_free(regex_threshold); regex_threshold = NULL; } if (regex_threshold_study != NULL) { pcre_free(regex_threshold_study); regex_threshold_study = NULL; } if (regex_rate != NULL) { pcre_free(regex_rate); regex_rate = NULL; } if (regex_rate_study != NULL) { pcre_free(regex_rate_study); regex_rate_study = NULL; } if (regex_suppress != NULL) { pcre_free(regex_suppress); regex_suppress = NULL; } if (regex_suppress_study != NULL) { pcre_free(regex_suppress_study); regex_suppress_study = NULL; } return; } /** * \brief Parses a line from the threshold file and adds it to Thresholdtype * * \param rawstr Pointer to the string to be parsed. * \param de_ctx Pointer to the Detection Engine Context. * * \retval 0 On success. * \retval -1 On failure. */ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) { const char *th_rule_type = NULL; const char *th_gid = NULL; const char *th_sid = NULL; const char *th_type = NULL; const char *th_track = NULL; const char *th_count = NULL; const char *th_seconds = NULL; const char *th_new_action= NULL; const char *th_timeout = NULL; const char *th_ip = NULL; const char *rule_extend = NULL; uint8_t parsed_type = 0; uint8_t parsed_track = 0; uint8_t parsed_new_action = 0; uint32_t parsed_count = 0; uint32_t parsed_seconds = 0; uint32_t parsed_timeout = 0; Signature *sig = NULL; Signature *s = NULL, *ns = NULL; DetectThresholdData *de = NULL; SigMatch *sm = NULL; SigMatch *m = NULL; #define MAX_SUBSTRINGS 30 int ret = 0; int ov[MAX_SUBSTRINGS]; uint32_t id = 0, gid = 0; ThresholdRuleType rule_type; int fret = -1; if (de_ctx == NULL) return -1; ret = pcre_exec(regex_base, regex_base_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); goto error; } /* retrieve the classtype name */ ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &th_rule_type); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* retrieve the classtype name */ ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &th_gid); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &th_sid); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rawstr, ov, 30, 4, &rule_extend); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* get type of rule */ if (strncasecmp(th_rule_type,"event_filter",strlen("event_filter")) == 0) { rule_type = THRESHOLD_TYPE_EVENT_FILTER; } else if (strncasecmp(th_rule_type,"threshold",strlen("threshold")) == 0) { rule_type = THRESHOLD_TYPE_THRESHOLD; } else if (strncasecmp(th_rule_type,"rate",strlen("rate")) == 0) { rule_type = THRESHOLD_TYPE_RATE; } else if (strncasecmp(th_rule_type,"suppress",strlen("suppress")) == 0) { rule_type = THRESHOLD_TYPE_SUPPRESS; } else { SCLogError(SC_ERR_INVALID_VALUE, "rule type %s is unknown", th_rule_type); goto error; } /* get end of rule */ switch(rule_type) { case THRESHOLD_TYPE_EVENT_FILTER: case THRESHOLD_TYPE_THRESHOLD: if (strlen(rule_extend) > 0) { ret = pcre_exec(regex_threshold, regex_threshold_study, rule_extend, strlen(rule_extend), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rule_extend); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, 30, 1, &th_type); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, 30, 2, &th_track); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, 30, 3, &th_count); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, 30, 4, &th_seconds); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (strcasecmp(th_type,"limit") == 0) parsed_type = TYPE_LIMIT; else if (strcasecmp(th_type,"both") == 0) parsed_type = TYPE_BOTH; else if (strcasecmp(th_type,"threshold") == 0) parsed_type = TYPE_THRESHOLD; else { SCLogError(SC_ERR_INVALID_ARGUMENTS, "limit type not supported: %s", th_type); goto error; } } else { SCLogError(SC_ERR_INVALID_ARGUMENTS, "rule invalid: %s", rawstr); goto error; } break; case THRESHOLD_TYPE_SUPPRESS: if (strlen(rule_extend) > 0) { ret = pcre_exec(regex_suppress, regex_suppress_study, rule_extend, strlen(rule_extend), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rule_extend); goto error; } /* retrieve the track mode */ ret = pcre_get_substring((char *)rule_extend, ov, 30, 1, &th_track); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* retrieve the IP */ ret = pcre_get_substring((char *)rule_extend, ov, 30, 2, &th_ip); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } } else { parsed_track = TRACK_RULE; } parsed_type = TYPE_SUPPRESS; break; case THRESHOLD_TYPE_RATE: if (strlen(rule_extend) > 0) { ret = pcre_exec(regex_rate, regex_rate_study, rule_extend, strlen(rule_extend), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 5) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rule_extend); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 1, &th_track); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 2, &th_count); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 3, &th_seconds); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 4, &th_new_action); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 5, &th_timeout); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* TODO: implement option "apply_to" */ if (ByteExtractStringUint32(&parsed_timeout, 10, strlen(th_timeout), th_timeout) <= 0) { goto error; } /* Get the new action to take */ if (strcasecmp(th_new_action, "alert") == 0) parsed_new_action = TH_ACTION_ALERT; if (strcasecmp(th_new_action, "drop") == 0) parsed_new_action = TH_ACTION_DROP; if (strcasecmp(th_new_action, "pass") == 0) parsed_new_action = TH_ACTION_PASS; if (strcasecmp(th_new_action, "reject") == 0) parsed_new_action = TH_ACTION_REJECT; if (strcasecmp(th_new_action, "log") == 0) { SCLogInfo("log action for rate_filter not supported yet"); parsed_new_action = TH_ACTION_LOG; } if (strcasecmp(th_new_action, "sdrop") == 0) { SCLogInfo("sdrop action for rate_filter not supported yet"); parsed_new_action = TH_ACTION_SDROP; } parsed_type = TYPE_RATE; } else { SCLogError(SC_ERR_INVALID_ARGUMENTS, "rule invalid: %s", rawstr); goto error; } break; default: SCLogError(SC_ERR_PCRE_MATCH, "unable to find rule type for string %s", rawstr); goto error; } switch (rule_type) { /* This part is common to threshold/event_filter/rate_filter */ case THRESHOLD_TYPE_EVENT_FILTER: case THRESHOLD_TYPE_THRESHOLD: case THRESHOLD_TYPE_RATE: if (strcasecmp(th_track,"by_dst") == 0) parsed_track = TRACK_DST; else if (strcasecmp(th_track,"by_src") == 0) parsed_track = TRACK_SRC; else if (strcasecmp(th_track,"by_rule") == 0) parsed_track = TRACK_RULE; else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rawstr); goto error; } if (ByteExtractStringUint32(&parsed_count, 10, strlen(th_count), th_count) <= 0) { goto error; } if (parsed_count == 0) { SCLogError(SC_ERR_INVALID_VALUE, "rate filter count should be > 0"); goto error; } if (ByteExtractStringUint32(&parsed_seconds, 10, strlen(th_seconds), th_seconds) <= 0) { goto error; } break; case THRESHOLD_TYPE_SUPPRESS: /* need to get IP if extension is provided */ if (th_track != NULL) { if (strcasecmp(th_track,"by_dst") == 0) parsed_track = TRACK_DST; else if (strcasecmp(th_track,"by_src") == 0) parsed_track = TRACK_SRC; else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rule_extend); goto error; } } break; } if (ByteExtractStringUint32(&id, 10, strlen(th_sid), th_sid) <= 0) { goto error; } if (ByteExtractStringUint32(&gid, 10, strlen(th_gid), th_gid) <= 0) { goto error; } /* Install it */ if (id == 0 && gid == 0) { for (s = de_ctx->sig_list; s != NULL;) { ns = s->next; if (parsed_type != TYPE_SUPPRESS) { m = SigMatchGetLastSMFromLists(s, 2, DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); if (m != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " "given precedence over the threshold.conf one. " "We'll change this in the future though.", s->id); goto end; } m = SigMatchGetLastSMFromLists(s, 2, DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); if (m != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " "given precedence over the threshold.conf one. " "We'll change this in the future though.", s->id); goto end; } } de = SCMalloc(sizeof(DetectThresholdData)); if (unlikely(de == NULL)) goto error; memset(de,0,sizeof(DetectThresholdData)); de->type = parsed_type; de->track = parsed_track; de->count = parsed_count; de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; de->addr = NULL; if ((parsed_type == TYPE_SUPPRESS) && (parsed_track != TRACK_RULE)) { de->addr = DetectAddressInit(); if (de->addr == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); goto error; } if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); goto error; } } sm = SigMatchAlloc(); if (sm == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); goto error; } if (parsed_type == TYPE_RATE) sm->type = DETECT_DETECTION_FILTER; else sm->type = DETECT_THRESHOLD; sm->ctx = (void *)de; if (parsed_track == TRACK_RULE) { de_ctx->ths_ctx.th_entry = SCRealloc(de_ctx->ths_ctx.th_entry, (de_ctx->ths_ctx.th_size + 1) * sizeof(DetectThresholdEntry *)); if (de_ctx->ths_ctx.th_entry == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for threshold config" " (tried to allocate %"PRIu32"th_entrys for rule tracking with rate_filter)", de_ctx->ths_ctx.th_size + 1); } else { de_ctx->ths_ctx.th_entry[de_ctx->ths_ctx.th_size] = NULL; de_ctx->ths_ctx.th_size++; } } SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); s = ns; } } else if (id == 0 && gid > 0) { for (s = de_ctx->sig_list; s != NULL;) { ns = s->next; if(s->gid == gid) { if (parsed_type != TYPE_SUPPRESS) { m = SigMatchGetLastSMFromLists(s, 2, DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); if (m != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " "given precedence over the threshold.conf one. " "We'll change this in the future though.", id); goto end; } m = SigMatchGetLastSMFromLists(s, 2, DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); if (m != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " "given precedence over the threshold.conf one. " "We'll change this in the future though.", id); goto end; } } de = SCMalloc(sizeof(DetectThresholdData)); if (unlikely(de == NULL)) goto error; memset(de,0,sizeof(DetectThresholdData)); de->type = parsed_type; de->track = parsed_track; de->count = parsed_count; de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; de->addr = NULL; if ((parsed_type == TYPE_SUPPRESS) && (parsed_track != TRACK_RULE)) { de->addr = DetectAddressInit(); if (de->addr == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); goto error; } if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); goto error; } } sm = SigMatchAlloc(); if (sm == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); goto error; } if (parsed_type == TYPE_RATE) sm->type = DETECT_DETECTION_FILTER; else sm->type = DETECT_THRESHOLD; sm->ctx = (void *)de; if (parsed_track == TRACK_RULE) { de_ctx->ths_ctx.th_entry = SCRealloc(de_ctx->ths_ctx.th_entry, (de_ctx->ths_ctx.th_size + 1) * sizeof(DetectThresholdEntry *)); if (de_ctx->ths_ctx.th_entry == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for threshold config" " (tried to allocate %"PRIu32"th_entrys for rule tracking with rate_filter)", de_ctx->ths_ctx.th_size + 1); } else { de_ctx->ths_ctx.th_entry[de_ctx->ths_ctx.th_size] = NULL; de_ctx->ths_ctx.th_size++; } } SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); } s = ns; } } else if (id > 0 && gid == 0) { SCLogError(SC_ERR_INVALID_VALUE, "Can't use a event config that has " "sid > 0 and gid == 0. Please fix this " "in your threshold.conf file"); } else { sig = SigFindSignatureBySidGid(de_ctx,id,gid); if(sig != NULL) { if ((parsed_type == TYPE_SUPPRESS) && (parsed_track == TRACK_RULE)) { sig->flags |= SIG_FLAG_NOALERT; goto end; } if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD && parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT) { m = SigMatchGetLastSMFromLists(sig, 2, DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if (m != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "a threshold set. The signature event var is " "given precedence over the threshold.conf one. " "Bug #425.", sig->id); goto end; } m = SigMatchGetLastSMFromLists(sig, 2, DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if (m != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "a detection_filter set. The signature event var is " "given precedence over the threshold.conf one. " "Bug #425.", sig->id); goto end; } /* replace threshold on sig if we have a global override for it */ } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) { m = SigMatchGetLastSMFromLists(sig, 2, DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if (m == NULL) { m = SigMatchGetLastSMFromLists(sig, 2, DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); } if (m != NULL) { SigMatchRemoveSMFromList(sig, m, DETECT_SM_LIST_THRESHOLD); SigMatchFree(m); m = NULL; } } de = SCMalloc(sizeof(DetectThresholdData)); if (unlikely(de == NULL)) goto error; memset(de,0,sizeof(DetectThresholdData)); de->type = parsed_type; de->track = parsed_track; de->count = parsed_count; de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; de->addr = NULL; if ((parsed_type == TYPE_SUPPRESS) && (parsed_track != TRACK_RULE)) { de->addr = DetectAddressInit(); if (de->addr == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); goto error; } if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); goto error; } } sm = SigMatchAlloc(); if (sm == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); goto error; } if (parsed_type == TYPE_RATE) sm->type = DETECT_DETECTION_FILTER; else sm->type = DETECT_THRESHOLD; sm->ctx = (void *)de; if (parsed_track == TRACK_RULE) { de_ctx->ths_ctx.th_entry = SCRealloc(de_ctx->ths_ctx.th_entry, (de_ctx->ths_ctx.th_size + 1) * sizeof(DetectThresholdEntry *)); if (de_ctx->ths_ctx.th_entry == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for threshold config" " (tried to allocate %"PRIu32"th_entrys for rule tracking with rate_filter)", de_ctx->ths_ctx.th_size + 1); } else { de_ctx->ths_ctx.th_entry[de_ctx->ths_ctx.th_size] = NULL; de_ctx->ths_ctx.th_size++; } } SigMatchAppendSMToList(sig, sm, DETECT_SM_LIST_THRESHOLD); } } end: fret = 0; error: if (fret == -1) { if (de != NULL) { if (de->addr != NULL) DetectAddressFree(de->addr); SCFree(de); } } if(th_rule_type != NULL) SCFree((char *)th_rule_type); if(th_sid != NULL) SCFree((char *)th_sid); if(th_gid != NULL) SCFree((char *)th_gid); if(th_track != NULL) SCFree((char *)th_track); if(th_count != NULL) SCFree((char *)th_count); if(th_seconds != NULL) SCFree((char *)th_seconds); if(th_type != NULL) SCFree((char *)th_type); if(th_ip != NULL) SCFree((char *)th_ip); if(rule_extend != NULL) SCFree((char *)rule_extend); return fret; } /** * \brief Checks if a string is a comment or a blank line. * * Comments lines are lines of the following format - * "# This is a comment string" or * " # This is a comment string". * * \param line String that has to be checked * * \retval 1 On the argument string being a comment or blank line * \retval 0 Otherwise */ int SCThresholdConfIsLineBlankOrComment(char *line) { while (*line != '\0') { /* we have a comment */ if (*line == '#') return 1; /* this line is neither a comment line, nor a blank line */ if (!isspace((unsigned char)*line)) return 0; line++; } /* we have a blank line */ return 1; } /** * \brief Checks if the rule is multiline, by searching an ending slash * * \param line String that has to be checked * * \retval the position of the slash making it multiline * \retval 0 Otherwise */ int SCThresholdConfLineIsMultiline(char *line) { int flag = 0; char *rline = line; int len = strlen(line); while (line < rline + len && *line != '\n') { /* we have a comment */ if (*line == '\\') flag = line - rline; else if (!isspace((unsigned char)*line)) flag = 0; line++; } /* we have a blank line */ return flag; } /** * \brief Get the config line length to allocate the buffer needed * * \param fd Pointer to file descriptor. * \retval int of the line length */ int SCThresholdConfLineLength(FILE *fd) { long pos = ftell(fd); int len = 0; int c; while ( (c = fgetc(fd)) && (char)c != '\n' && c != EOF && !feof(fd)) len++; if (pos < 0) pos = 0; if (fseek(fd, pos, SEEK_SET) < 0) { SCLogError(SC_ERR_THRESHOLD_SETUP, "threshold fseek failure: %s", strerror(errno)); return -1; } return len; } /** * \brief Parses the Threshold Config file * * \param de_ctx Pointer to the Detection Engine Context. * \param fd Pointer to file descriptor. */ void SCThresholdConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) { char *line = NULL; int len = 0; int rule_num = 0; /* position of "\", on multiline rules */ int esc_pos = 0; if (fd == NULL) return; while (!feof(fd)) { len = SCThresholdConfLineLength(fd); if (len > 0) { if (line == NULL) line = SCRealloc(line, len + 1); else line = SCRealloc(line, strlen(line) + len + 1); if (line == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); break; } if (fgets(line + esc_pos, len + 1, fd) == NULL) break; /* Skip EOL to inspect the next line (or read EOF) */ (void)fgetc(fd); if (SCThresholdConfIsLineBlankOrComment(line)) { continue; } esc_pos = SCThresholdConfLineIsMultiline(line); if (esc_pos == 0) { rule_num++; SCLogDebug("Adding threshold.config rule num %"PRIu32"( %s )", rule_num, line); SCThresholdConfAddThresholdtype(line, de_ctx); } } else { /* Skip EOL to inspect the next line (or read EOF) */ (void)fgetc(fd); if (feof(fd)) break; } } SCLogInfo("Threshold config parsed: %d rule(s) found", rule_num); /* Free the last line */ SCFree(line); return; } #ifdef UNITTESTS /** * \brief Creates a dummy threshold file, with all valid options, for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD01() { FILE *fd = NULL; const char *buffer = "event_filter gen_id 1, sig_id 10, type limit, track by_src, count 1, seconds 60\n" "threshold gen_id 1, sig_id 100, type both, track by_dst, count 10, seconds 60\n" "event_filter gen_id 1, sig_id 1000, type threshold, track by_src, count 100, seconds 60\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with some valid options and a couple of invalid options. * For testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateInValidDummyFD02() { FILE *fd; const char *buffer = "event_filter gen_id 1, sig_id 1000, type invalid, track by_src, count 100, seconds 60\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD03() { FILE *fd; const char *buffer = "event_filter gen_id 0, sig_id 0, type threshold, track by_src, count 100, seconds 60\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, but * with splitted rules (multiline), for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD04() { FILE *fd = NULL; const char *buffer = "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 1, seconds 60\n" "threshold gen_id 1, \\\nsig_id 100, type both\\\n, track by_dst, count 10, \\\n seconds 60\n" "event_filter gen_id 1, sig_id 1000, \\\ntype threshold, track \\\nby_src, count 100, seconds 60\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD05() { FILE *fd = NULL; const char *buffer = "rate_filter gen_id 1, sig_id 10, track by_src, count 1, seconds 60, new_action drop, timeout 10\n" "rate_filter gen_id 1, sig_id 100, track by_dst, count 10, seconds 60, new_action pass, timeout 5\n" "rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, new_action alert, timeout 30\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, but * with splitted rules (multiline), for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD06() { FILE *fd = NULL; const char *buffer = "rate_filter \\\ngen_id 1, sig_id 10, track by_src, count 1, seconds 60\\\n, new_action drop, timeout 10\n" "rate_filter gen_id 1, \\\nsig_id 100, track by_dst, \\\ncount 10, seconds 60, new_action pass, timeout 5\n" "rate_filter gen_id 1, sig_id 1000, \\\ntrack by_rule, count 100, seconds 60, new_action alert, timeout 30\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, but * with splitted rules (multiline), for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD07() { FILE *fd = NULL; const char *buffer = "rate_filter gen_id 1, sig_id 10, track by_src, count 3, seconds 3, new_action drop, timeout 10\n" "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, new_action drop, timeout 5\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, but * with splitted rules (multiline), for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD08() { FILE *fd = NULL; const char *buffer = "rate_filter gen_id 1, sig_id 10, track by_rule, count 3, seconds 3, new_action drop, timeout 10\n" "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, new_action drop, timeout 5\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, but * with splitted rules (multiline), for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD09() { FILE *fd = NULL; const char *buffer = "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 2, seconds 60\n" "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 3, \\\n seconds 60\n" "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 2, seconds 60\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, but * with splitted rules (multiline), for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD10() { FILE *fd = NULL; const char *buffer = "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 5, seconds 2\n" "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 5, \\\n seconds 2\n" "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 5, seconds 2\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \brief Creates a dummy threshold file, with all valid options, for testing purposes. * * \retval fd Pointer to file descriptor. */ FILE *SCThresholdConfGenerateValidDummyFD11() { FILE *fd = NULL; const char *buffer = "suppress gen_id 1, sig_id 10000\n" "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); return fd; } /** * \test Check if the threshold file is loaded and well parsed * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD01(); SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m != NULL) { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) result = 1; } end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the threshold file is loaded and well parsed * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD01(); SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m != NULL) { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60)) result = 1; } end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the threshold file is loaded and well parsed * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest03(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD01(); SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m != NULL) { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60)) result = 1; } end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the threshold file is loaded and well parsed * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest04(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateInValidDummyFD02(); SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m != NULL) { de = (DetectThresholdData *)m->ctx; if(de == NULL) return result; else result = 1; } end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); return result; } /** * \test Check if the threshold file is loaded and well parsed * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest05(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; Signature *s = NULL, *ns = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)"); if (sig == NULL) { goto end; } sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)"); if (sig == NULL) { goto end; } sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD03(); SCThresholdConfInitContext(de_ctx,fd); for (s = de_ctx->sig_list; s != NULL;) { ns = s->next; if(s->id == 1 || s->id == 10 || s->id == 100) { m = SigMatchGetLastSMFromLists(s, 2, DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m == NULL) { goto end; } else { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60)) result++; } } s = ns; } if(result == 3) result = 1; end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the threshold file is loaded and well parsed * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest06(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD04(); SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m != NULL) { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) result = 1; } end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the rate_filter rules are loaded and well parsed * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest07(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD05(); SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m != NULL) { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) result = 1; } end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the rate_filter rules are loaded and well parsed * with multilines * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest08(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD06(); SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m != NULL) { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) result = 1; } end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the rate_filter rules work * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest09(void) { Signature *sig = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL || p == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD07(); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { result = 0; goto end; } p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { result = 0; goto end; } p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { result = 0; goto end; } TimeSetIncrementTime(2); TimeGet(&p->ts); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))) { result = 0; goto end; } TimeSetIncrementTime(3); TimeGet(&p->ts); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))) { result = 0; goto end; } TimeSetIncrementTime(10); TimeGet(&p->ts); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { result = 0; goto end; } p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { result = 0; goto end; } result = 1; end: UTHFreePacket(p); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } /** * \test Check if the rate_filter rules work with track by_rule * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest10(void) { Signature *sig = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int alerts = 0; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL || p == NULL || p2 == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD08(); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); alerts += PacketAlertCheck(p2, 10); if (alerts > 0) { result = 0; goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); if (alerts != 1) { result = 0; goto end; } TimeSetIncrementTime(2); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); alerts += PacketAlertCheck(p2, 10); if (alerts != 2) { result = 0; goto end; } TimeSetIncrementTime(10); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); if (alerts == 2) result = 1; /* Ensure that a Threshold entry was installed at the sig */ if (de_ctx->ths_ctx.th_entry[sig->num] == NULL) { result = 0; goto end; } end: UTHFreePacket(p); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } /** * \test Check if the rate_filter rules work * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest11(void) { Signature *sig = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int alerts10 = 0; int alerts11 = 0; int alerts12 = 0; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL || p == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD09(); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); TimeSetIncrementTime(100); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); TimeSetIncrementTime(10); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); if (alerts10 == 4) result = 1; /* One on the first interval, another on the second */ if (alerts11 == 2) result = 1; if (alerts12 == 2) result = 1; end: UTHFreePacket(p); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } /** * \test Check if the rate_filter rules work * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest12(void) { Signature *sig = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int alerts10 = 0; int alerts11 = 0; int alerts12 = 0; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL || p == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD10(); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); TimeSetIncrementTime(100); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); TimeSetIncrementTime(10); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); /* Yes, none of the alerts will be out of the count of the given interval for type limit */ if (alerts10 == 10) result = 1; /* One on the first interval, another on the second */ if (alerts11 == 1) result = 1; if (alerts12 == 1) result = 1; end: UTHFreePacket(p); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } /** * \test Check if the threshold file is loaded and well parsed * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest13(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectThresholdData *de = NULL; Signature *sig = NULL; SigMatch *m = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); if (de_ctx == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD11(); SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); if(m != NULL) { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) result = 1; } end: SigGroupBuild(de_ctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } /** * \test Check if the suppress rules work * * \retval 1 on succces * \retval 0 on failure */ int SCThresholdConfTest14(void) { Signature *sig = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", "192.168.0.100", 1234, 24); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL || p == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)"); sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)"); sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD11(); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p, 10000) == 0) && (PacketAlertCheck(p, 10) == 1) && (PacketAlertCheck(p, 1000) == 1) && (PacketAlertCheck(p1, 1000) == 0)) result = 1; end: UTHFreePacket(p); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } /** * \test Check if the suppress rules work * * \retval 1 on succces * \retval 0 on failure */ static int SCThresholdConfTest15(void) { Signature *sig = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL || p == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD11(); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* 10000 shouldn't match */ if (PacketAlertCheck(p, 10000) != 0) { printf("sid 10000 should not have alerted: "); goto end; } /* however, it should have set the drop flag */ if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { printf("sid 10000 should have set DROP flag even if suppressed: "); goto end; } result = 1; end: UTHFreePacket(p); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } /** * \test Check if the suppress rules work * * \retval 1 on succces * \retval 0 on failure */ static int SCThresholdConfTest16(void) { Signature *sig = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", "192.168.0.100", 1234, 24); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL || p == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD11(); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* 10000 shouldn't match */ if (PacketAlertCheck(p, 1000) != 0) { printf("sid 1000 should not have alerted: "); goto end; } /* however, it should have set the drop flag */ if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { printf("sid 1000 should have set DROP flag even if suppressed: "); goto end; } result = 1; end: UTHFreePacket(p); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } /** * \test Check if the suppress rules work - ip only rule * * \retval 1 on succces * \retval 0 on failure */ static int SCThresholdConfTest17(void) { Signature *sig = NULL; int result = 0; FILE *fd = NULL; HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL || p == NULL) return result; de_ctx->flags |= DE_QUIET; sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)"); if (sig == NULL) { goto end; } fd = SCThresholdConfGenerateValidDummyFD11(); SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* 10000 shouldn't match */ if (PacketAlertCheck(p, 10000) != 0) { printf("sid 10000 should not have alerted: "); goto end; } /* however, it should have set the drop flag */ if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { printf("sid 10000 should have set DROP flag even if suppressed: "); goto end; } result = 1; end: UTHFreePacket(p); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); return result; } #endif /* UNITTESTS */ /** * \brief This function registers unit tests for Classification Config API. */ void SCThresholdConfRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01, 1); UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02, 1); UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03, 1); UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04, 0); UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05, 1); UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06, 1); UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07, 1); UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08, 1); UtRegisterTest("SCThresholdConfTest09 - rate_filter", SCThresholdConfTest09, 1); UtRegisterTest("SCThresholdConfTest10 - rate_filter", SCThresholdConfTest10, 1); UtRegisterTest("SCThresholdConfTest11 - event_filter", SCThresholdConfTest11, 1); UtRegisterTest("SCThresholdConfTest12 - event_filter", SCThresholdConfTest12, 1); UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13, 1); UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14, 1); UtRegisterTest("SCThresholdConfTest15 - suppress drop", SCThresholdConfTest15, 1); UtRegisterTest("SCThresholdConfTest16 - suppress drop", SCThresholdConfTest16, 1); UtRegisterTest("SCThresholdConfTest17 - suppress drop", SCThresholdConfTest17, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/detect-engine-address-ipv6.c0000644000000000000000000021360612253546156016221 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * IPV6 Address part of the detection engine. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "flow-var.h" #include "util-cidr.h" #include "util-unittest.h" #include "detect-engine-address.h" #include "detect-engine-siggroup.h" #include "detect-engine-port.h" #include "util-debug.h" /** * \brief Compares 2 ipv6 addresses and returns if the first address(a) is less * than the second address(b) or not. * * \param a The first ipv6 address to be compared. * \param b The second ipv6 address to be compared. * * \retval 1 If a < b. * \retval 0 Otherwise, i.e. a >= b. */ int AddressIPv6Lt(Address *a, Address *b) { int i = 0; for (i = 0; i < 4; i++) { if (ntohl(a->addr_data32[i]) < ntohl(b->addr_data32[i])) return 1; if (ntohl(a->addr_data32[i]) > ntohl(b->addr_data32[i])) break; } return 0; } int AddressIPv6LtU32(uint32_t *a, uint32_t *b) { int i = 0; for (i = 0; i < 4; i++) { if (ntohl(a[i]) < ntohl(b[i])) return 1; if (ntohl(a[i]) > ntohl(b[i])) break; } return 0; } /** * \brief Compares 2 ipv6 addresses and returns if the first address(a) is * greater than the second address(b) or not. * * \param a The first ipv6 address to be compared. * \param b The second ipv6 address to be compared. * * \retval 1 If a > b. * \retval 0 Otherwise, i.e. a <= b. */ int AddressIPv6Gt(Address *a, Address *b) { int i = 0; for (i = 0; i < 4; i++) { if (ntohl(a->addr_data32[i]) > ntohl(b->addr_data32[i])) return 1; if (ntohl(a->addr_data32[i]) < ntohl(b->addr_data32[i])) break; } return 0; } int AddressIPv6GtU32(uint32_t *a, uint32_t *b) { int i = 0; for (i = 0; i < 4; i++) { if (ntohl(a[i]) > ntohl(b[i])) return 1; if (ntohl(a[i]) < ntohl(b[i])) break; } return 0; } /** * \brief Compares 2 ipv6 addresses and returns if the addresses are equal * or not. * * \param a The first ipv6 address to be compared. * \param b The second ipv6 address to be compared. * * \retval 1 If a == b. * \retval 0 Otherwise. */ int AddressIPv6Eq(Address *a, Address *b) { int i = 0; for (i = 0; i < 4; i++) { if (a->addr_data32[i] != b->addr_data32[i]) return 0; } return 1; } int AddressIPv6EqU32(uint32_t *a, uint32_t *b) { int i = 0; for (i = 0; i < 4; i++) { if (a[i] != b[i]) return 0; } return 1; } /** * \brief Compares 2 ipv6 addresses and returns if the first address(a) is less * than or equal to the second address(b) or not. * * \param a The first ipv6 address to be compared. * \param b The second ipv6 address to be compared. * * \retval 1 If a <= b. * \retval 0 Otherwise, i.e. a > b. */ int AddressIPv6Le(Address *a, Address *b) { if (AddressIPv6Eq(a, b) == 1) return 1; if (AddressIPv6Lt(a, b) == 1) return 1; return 0; } int AddressIPv6LeU32(uint32_t *a, uint32_t *b) { if (AddressIPv6EqU32(a, b) == 1) return 1; if (AddressIPv6LtU32(a, b) == 1) return 1; return 0; } /** * \brief Compares 2 ipv6 addresses and returns if the first address(a) is * greater than or equal to the second address(b) or not. * * \param a The first ipv6 address to be compared. * \param b The second ipv6 address to be compared. * * \retval 1 If a >= b. * \retval 0 Otherwise, i.e. a < b. */ int AddressIPv6Ge(Address *a, Address *b) { if (AddressIPv6Eq(a, b) == 1) return 1; if (AddressIPv6Gt(a, b) == 1) return 1; return 0; } int AddressIPv6GeU32(uint32_t *a, uint32_t *b) { if (AddressIPv6EqU32(a, b) == 1) return 1; if (AddressIPv6GtU32(a, b) == 1) return 1; return 0; } /** * \brief Compares 2 addresses(address ranges) and returns the relationship * between the 2 addresses. * * \param a Pointer to the first address instance to be compared. * \param b Pointer to the second address instance to be compared. * * \retval ADDRESS_EQ If the 2 address ranges a and b, are equal. * \retval ADDRESS_ES b encapsulates a. b_ip1[...a_ip1...a_ip2...]b_ip2. * \retval ADDRESS_EB a encapsulates b. a_ip1[...b_ip1....b_ip2...]a_ip2. * \retval ADDRESS_LE a_ip1(...b_ip1==a_ip2...)b_ip2 * \retval ADDRESS_LT a_ip1(...b_ip1...a_ip2...)b_ip2 * \retval ADDRESS_GE b_ip1(...a_ip1==b_ip2...)a_ip2 * \retval ADDRESS_GT a_ip1 > b_ip2, i.e. the address range for 'a' starts only * after the end of the address range for 'b' */ int DetectAddressCmpIPv6(DetectAddress *a, DetectAddress *b) { if (AddressIPv6Eq(&a->ip, &b->ip) == 1 && AddressIPv6Eq(&a->ip2, &b->ip2) == 1) { return ADDRESS_EQ; } else if (AddressIPv6Ge(&a->ip, &b->ip) == 1 && AddressIPv6Le(&a->ip, &b->ip2) == 1 && AddressIPv6Le(&a->ip2, &b->ip2) == 1) { return ADDRESS_ES; } else if (AddressIPv6Le(&a->ip, &b->ip) == 1 && AddressIPv6Ge(&a->ip2, &b->ip2) == 1) { return ADDRESS_EB; } else if (AddressIPv6Lt(&a->ip, &b->ip) == 1 && AddressIPv6Lt(&a->ip2, &b->ip2) == 1 && AddressIPv6Ge(&a->ip2, &b->ip) == 1) { return ADDRESS_LE; } else if (AddressIPv6Lt(&a->ip, &b->ip) == 1 && AddressIPv6Lt(&a->ip2, &b->ip2) == 1) { return ADDRESS_LT; } else if (AddressIPv6Gt(&a->ip, &b->ip) == 1 && AddressIPv6Le(&a->ip, &b->ip2) == 1 && AddressIPv6Gt(&a->ip2, &b->ip2) == 1) { return ADDRESS_GE; } else if (AddressIPv6Gt(&a->ip, &b->ip2) == 1) { return ADDRESS_GT; } else { /* should be unreachable */ SCLogDebug("Internal Error: should be unreachable\n"); } return ADDRESS_ER; } /** * \brief Takes an IPv6 address in a, and returns in b an IPv6 address which is * one less than the IPv6 address in a. The address sent in a is in host * order, and the address in b will be returned in network order! * * \param a Pointer to an IPv6 address in host order. * \param b Pointer to an IPv6 address store in memory which has to be updated * with the new address(a - 1). */ static void AddressCutIPv6CopySubOne(uint32_t *a, uint32_t *b) { uint32_t t = a[3]; b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; b[3] = a[3]; b[3]--; if (b[3] > t) { t = b[2]; b[2]--; if (b[2] > t) { t = b[1]; b[1]--; if (b[1] > t) b[0]--; } } b[0] = htonl(b[0]); b[1] = htonl(b[1]); b[2] = htonl(b[2]); b[3] = htonl(b[3]); return; } /** * \brief Takes an IPv6 address in a, and returns in b an IPv6 address which is * one more than the IPv6 address in a. The address sent in a is in host * order, and the address in b will be returned in network order! * * \param a Pointer to an IPv6 address in host order. * \param b Pointer to an IPv6 address store in memory which has to be updated * with the new address(a + 1). */ static void AddressCutIPv6CopyAddOne(uint32_t *a, uint32_t *b) { uint32_t t = a[3]; b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; b[3] = a[3]; b[3]++; if (b[3] < t) { t = b[2]; b[2]++; if (b[2] < t) { t = b[1]; b[1]++; if (b[1] < t) b[0]++; } } b[0] = htonl(b[0]); b[1] = htonl(b[1]); b[2] = htonl(b[2]); b[3] = htonl(b[3]); return; } /** * \brief Copies an IPv6 address in a to the b. The address in a is in host * order and will be copied in network order to b! * * \param a Pointer to the IPv6 address to be copied. * \param b Pointer to an IPv6 address in memory which will be updated with the * address in a. */ static void AddressCutIPv6Copy(uint32_t *a, uint32_t *b) { b[0] = htonl(a[0]); b[1] = htonl(a[1]); b[2] = htonl(a[2]); b[3] = htonl(a[3]); return; } int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, DetectAddress *b, DetectAddress **c) { uint32_t a_ip1[4] = { ntohl(a->ip.addr_data32[0]), ntohl(a->ip.addr_data32[1]), ntohl(a->ip.addr_data32[2]), ntohl(a->ip.addr_data32[3]) }; uint32_t a_ip2[4] = { ntohl(a->ip2.addr_data32[0]), ntohl(a->ip2.addr_data32[1]), ntohl(a->ip2.addr_data32[2]), ntohl(a->ip2.addr_data32[3]) }; uint32_t b_ip1[4] = { ntohl(b->ip.addr_data32[0]), ntohl(b->ip.addr_data32[1]), ntohl(b->ip.addr_data32[2]), ntohl(b->ip.addr_data32[3]) }; uint32_t b_ip2[4] = { ntohl(b->ip2.addr_data32[0]), ntohl(b->ip2.addr_data32[1]), ntohl(b->ip2.addr_data32[2]), ntohl(b->ip2.addr_data32[3]) }; DetectPort *port = NULL; DetectAddress *tmp = NULL; /* default to NULL */ *c = NULL; int r = DetectAddressCmpIPv6(a, b); if (r != ADDRESS_ES && r != ADDRESS_EB && r != ADDRESS_LE && r != ADDRESS_GE) { goto error; } /* get a place to temporary put sigs lists */ tmp = DetectAddressInit(); if (tmp == NULL) goto error; memset(tmp,0,sizeof(DetectAddress)); /* we have 3 parts: [aaa[abab]bbb] * part a: a_ip1 <-> b_ip1 - 1 * part b: b_ip1 <-> a_ip2 * part c: a_ip2 + 1 <-> b_ip2 */ if (r == ADDRESS_LE) { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); AddressCutIPv6Copy(b_ip1, b->ip.addr_data32); AddressCutIPv6Copy(a_ip2, b->ip2.addr_data32); DetectAddress *tmp_c; tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(a_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(b_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; /* copy old b to c */ SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); /* copy old b to a */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp_c->port, port); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &b->port, port); tmp_c->cnt += b->cnt; b->cnt += a->cnt; /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 * part c: b_ip2 + 1 <-> a_ip2 */ } else if (r == ADDRESS_GE) { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); AddressCutIPv6Copy(a_ip1, b->ip.addr_data32); AddressCutIPv6Copy(b_ip2, b->ip2.addr_data32); DetectAddress *tmp_c; tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(b_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(a_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; /* 'a' gets clean and then 'b' sigs * 'b' gets clean, then 'a' then 'b' sigs * 'c' gets 'a' sigs */ /* store old a list */ SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); /* clean a list */ SigGroupHeadClearSigs(a->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx, tmp->sh, &tmp_c->sh); /* copy old b to a */ SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); /* prepend old a before b */ SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); /* clean tmp list */ SigGroupHeadClearSigs(tmp->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&tmp->port, port); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&a->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&b->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&tmp_c->port, port); tmp->cnt += a->cnt; a->cnt = 0; tmp_c->cnt += tmp->cnt; a->cnt += b->cnt; b->cnt += tmp->cnt; tmp->cnt = 0; /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] * part a: a_ip1 <-> a_ip2 * part b: a_ip2 + 1 <-> b_ip2 * * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> a_ip2 * * 3 part [bbb[aaa]bbb] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> a_ip2 * part c: a_ip2 + 1 <-> b_ip2 */ } else if (r == ADDRESS_ES) { if (AddressIPv6EqU32(a_ip1, b_ip1) == 1) { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6Copy(a_ip2, a->ip2.addr_data32); AddressCutIPv6CopyAddOne(a_ip2, b->ip.addr_data32); AddressCutIPv6Copy(b_ip2, b->ip2.addr_data32); /* 'b' overlaps 'a' so 'a' needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&a->port, port); a->cnt += b->cnt; } else if (AddressIPv6EqU32(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); AddressCutIPv6Copy(a_ip1, b->ip.addr_data32); AddressCutIPv6Copy(a_ip2, b->ip2.addr_data32); SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadClearSigs(a->sh); SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&tmp->port, a->port); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&a->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&b->port, port); tmp->cnt += a->cnt; a->cnt = 0; a->cnt += b->cnt; b->cnt += tmp->cnt; tmp->cnt = 0; } else { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); AddressCutIPv6Copy(a_ip1, b->ip.addr_data32); AddressCutIPv6Copy(a_ip2, b->ip2.addr_data32); DetectAddress *tmp_c; tmp_c = DetectAddressInit(); if (tmp_c == NULL) { goto error; } tmp_c->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(a_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(b_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; /* 'a' gets clean and then 'b' sigs * 'b' gets clean, then 'a' then 'b' sigs * 'c' gets 'b' sigs */ /* store old a list */ SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); /* clean a list */ SigGroupHeadClearSigs(a->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); /* copy old b to a */ SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); /* prepend old a before b */ SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); /* clean tmp list */ SigGroupHeadClearSigs(tmp->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&tmp->port, port); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&tmp_c->port, port); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&a->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&b->port, port); tmp->cnt += a->cnt; a->cnt = 0; tmp_c->cnt += b->cnt; a->cnt += b->cnt; b->cnt += tmp->cnt; tmp->cnt = 0; } /* we have 2 or three parts: * * 2 part: [[baba]aaa] or [aaa[abab]] * part a: b_ip1 <-> b_ip2 * part b: b_ip2 + 1 <-> a_ip2 * * part a: a_ip1 <-> b_ip1 - 1 * part b: b_ip1 <-> b_ip2 * * 3 part [aaa[bbb]aaa] * part a: a_ip1 <-> b_ip2 - 1 * part b: b_ip1 <-> b_ip2 * part c: b_ip2 + 1 <-> a_ip2 */ } else if (r == ADDRESS_EB) { if (AddressIPv6EqU32(a_ip1, b_ip1) == 1) { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6Copy(b_ip2, a->ip2.addr_data32); AddressCutIPv6CopyAddOne(b_ip2, b->ip.addr_data32); AddressCutIPv6Copy(a_ip2, b->ip2.addr_data32); /* 'b' overlaps 'a' so a needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); SigGroupHeadClearSigs(b->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&tmp->port, b->port); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&b->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&a->port, port); tmp->cnt += b->cnt; b->cnt = 0; b->cnt += a->cnt; a->cnt += tmp->cnt; tmp->cnt = 0; } else if (AddressIPv6EqU32(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); AddressCutIPv6Copy(b_ip1, b->ip.addr_data32); AddressCutIPv6Copy(b_ip2, b->ip2.addr_data32); /* 'a' overlaps 'b' so a needs the 'a' sigs */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&b->port, port); b->cnt += a->cnt; } else { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); AddressCutIPv6Copy(b_ip1, b->ip.addr_data32); AddressCutIPv6Copy(b_ip2, b->ip2.addr_data32); DetectAddress *tmp_c; tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(b_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(a_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; /* 'a' stays the same wrt sigs * 'b' keeps it's own sigs and gets a's sigs prepended * 'c' gets 'a' sigs */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&b->port, port); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx,&tmp_c->port, port); b->cnt += a->cnt; tmp_c->cnt += a->cnt; } } if (tmp != NULL) DetectAddressFree(tmp); return 0; error: if (tmp != NULL) DetectAddressFree(tmp); return -1; } #if 0 int DetectAddressCutIPv6(DetectAddressData *a, DetectAddressData *b, DetectAddressData **c) { uint32_t a_ip1[4] = { ntohl(a->ip[0]), ntohl(a->ip[1]), ntohl(a->ip[2]), ntohl(a->ip[3]) }; uint32_t a_ip2[4] = { ntohl(a->ip2[0]), ntohl(a->ip2[1]), ntohl(a->ip2[2]), ntohl(a->ip2[3]) }; uint32_t b_ip1[4] = { ntohl(b->ip[0]), ntohl(b->ip[1]), ntohl(b->ip[2]), ntohl(b->ip[3]) }; uint32_t b_ip2[4] = { ntohl(b->ip2[0]), ntohl(b->ip2[1]), ntohl(b->ip2[2]), ntohl(b->ip2[3]) }; /* default to NULL */ *c = NULL; int r = DetectAddressCmpIPv6(a, b); if (r != ADDRESS_ES && r != ADDRESS_EB && r != ADDRESS_LE && r != ADDRESS_GE) { goto error; } /* we have 3 parts: [aaa[abab]bbb] * part a: a_ip1 <-> b_ip1 - 1 * part b: b_ip1 <-> a_ip2 * part c: a_ip2 + 1 <-> b_ip2 */ if (r == ADDRESS_LE) { AddressCutIPv6Copy(a_ip1, a->ip); AddressCutIPv6CopySubOne(b_ip1, a->ip2); AddressCutIPv6Copy(b_ip1, b->ip); AddressCutIPv6Copy(a_ip2, b->ip2); DetectAddressData *tmp_c; tmp_c = DetectAddressDataInit(); if (tmp_c == NULL) goto error; tmp_c->family = AF_INET6; AddressCutIPv6CopyAddOne(a_ip2, tmp_c->ip); AddressCutIPv6Copy(b_ip2, tmp_c->ip2); *c = tmp_c; /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 * part c: b_ip2 + 1 <-> a_ip2 */ } else if (r == ADDRESS_GE) { AddressCutIPv6Copy(b_ip1, a->ip); AddressCutIPv6CopySubOne(a_ip1, a->ip2); AddressCutIPv6Copy(a_ip1, b->ip); AddressCutIPv6Copy(b_ip2, b->ip2); DetectAddressData *tmp_c; tmp_c = DetectAddressDataInit(); if (tmp_c == NULL) goto error; tmp_c->family = AF_INET6; AddressCutIPv6CopyAddOne(b_ip2, tmp_c->ip); AddressCutIPv6Copy(a_ip2, tmp_c->ip2); *c = tmp_c; /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] * part a: a_ip1 <-> a_ip2 * part b: a_ip2 + 1 <-> b_ip2 * * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> a_ip2 * * 3 part [bbb[aaa]bbb] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> a_ip2 * part c: a_ip2 + 1 <-> b_ip2 */ } else if (r == ADDRESS_ES) { if (AddressIPv6Eq(a_ip1,b_ip1) == 1) { AddressCutIPv6Copy(a_ip1, a->ip); AddressCutIPv6Copy(a_ip2, a->ip2); AddressCutIPv6CopyAddOne(a_ip2, b->ip); AddressCutIPv6Copy(b_ip2, b->ip2); } else if (AddressIPv6Eq(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(b_ip1, a->ip); AddressCutIPv6CopySubOne(a_ip1, a->ip2); AddressCutIPv6Copy(a_ip1, b->ip); AddressCutIPv6Copy(a_ip2, b->ip2); } else { AddressCutIPv6Copy(b_ip1, a->ip); AddressCutIPv6CopySubOne(a_ip1, a->ip2); AddressCutIPv6Copy(a_ip1, b->ip); AddressCutIPv6Copy(a_ip2, b->ip2); DetectAddressData *tmp_c; tmp_c = DetectAddressDataInit(); if (tmp_c == NULL) goto error; tmp_c->family = AF_INET6; AddressCutIPv6CopyAddOne(a_ip2, tmp_c->ip); AddressCutIPv6Copy(b_ip2, tmp_c->ip2); *c = tmp_c; } /* we have 2 or three parts: * * 2 part: [[baba]aaa] or [aaa[abab]] * part a: b_ip1 <-> b_ip2 * part b: b_ip2 + 1 <-> a_ip2 * * part a: a_ip1 <-> b_ip1 - 1 * part b: b_ip1 <-> b_ip2 * * 3 part [aaa[bbb]aaa] * part a: a_ip1 <-> b_ip2 - 1 * part b: b_ip1 <-> b_ip2 * part c: b_ip2 + 1 <-> a_ip2 */ } else if (r == ADDRESS_EB) { if (AddressIPv6Eq(a_ip1, b_ip1) == 1) { AddressCutIPv6Copy(b_ip1, a->ip); AddressCutIPv6Copy(b_ip2, a->ip2); AddressCutIPv6CopyAddOne(b_ip2, b->ip); AddressCutIPv6Copy(a_ip2, b->ip2); } else if (AddressIPv6Eq(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(a_ip1, a->ip); AddressCutIPv6CopySubOne(b_ip1, a->ip2); AddressCutIPv6Copy(b_ip1, b->ip); AddressCutIPv6Copy(b_ip2, b->ip2); } else { AddressCutIPv6Copy(a_ip1, a->ip); AddressCutIPv6CopySubOne(b_ip1, a->ip2); AddressCutIPv6Copy(b_ip1, b->ip); AddressCutIPv6Copy(b_ip2, b->ip2); DetectAddressData *tmp_c; tmp_c = DetectAddressDataInit(); if (tmp_c == NULL) goto error; tmp_c->family = AF_INET6; AddressCutIPv6CopyAddOne(b_ip2, tmp_c->ip); AddressCutIPv6Copy(a_ip2, tmp_c->ip2); *c = tmp_c; } } return 0; error: return -1; } #endif /** * \brief Cuts and returns an address range, which is the complement of the * address range that is supplied as the argument. * * For example: * * If a = ::-2000::, * then a = 2000::1-FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF and b = NULL * If a = 2000::1-FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF, * then a = ::-2000:: and b = NULL * If a = 2000::1-20FF::2, * then a = ::-2000:: and * b = 20FF::3-FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF * * \param a Pointer to an address range (DetectAddress) instance whose complement * has to be returned in a and b. * \param b Pointer to DetectAddress pointer, that will be supplied back with a * new DetectAddress instance, if the complement demands so. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressCutNotIPv6(DetectAddress *a, DetectAddress **b) { uint32_t a_ip1[4] = { ntohl(a->ip.addr_data32[0]), ntohl(a->ip.addr_data32[1]), ntohl(a->ip.addr_data32[2]), ntohl(a->ip.addr_data32[3]) }; uint32_t a_ip2[4] = { ntohl(a->ip2.addr_data32[0]), ntohl(a->ip2.addr_data32[1]), ntohl(a->ip2.addr_data32[2]), ntohl(a->ip2.addr_data32[3]) }; uint32_t ip_nul[4] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; uint32_t ip_max[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; /* default to NULL */ *b = NULL; if (!(a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && a_ip1[2] == 0x00000000 && a_ip1[3] == 0x00000000) && !(a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && a_ip2[2] == 0xFFFFFFFF && a_ip2[3] == 0xFFFFFFFF)) { AddressCutIPv6Copy(ip_nul, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); DetectAddress *tmp_b = DetectAddressInit(); if (tmp_b == NULL) goto error; tmp_b->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(a_ip2, tmp_b->ip.addr_data32); AddressCutIPv6Copy(ip_max, tmp_b->ip2.addr_data32); *b = tmp_b; } else if ((a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && a_ip1[2] == 0x00000000 && a_ip1[3] == 0x00000000) && !(a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && a_ip2[2] == 0xFFFFFFFF && a_ip2[3] == 0xFFFFFFFF)) { AddressCutIPv6CopyAddOne(a_ip2, a->ip.addr_data32); AddressCutIPv6Copy(ip_max, a->ip2.addr_data32); } else if (!(a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && a_ip1[2] == 0x00000000 && a_ip1[3] == 0x00000000) && (a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && a_ip2[2] == 0xFFFFFFFF && a_ip2[3] == 0xFFFFFFFF)) { AddressCutIPv6Copy(ip_nul, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); } else { goto error; } return 0; error: return -1; } /** * \brief Extends a target address range if the the source address range is * wider than the target address range on either sides. * * Every address is a range, i.e. address->ip1....address->ip2. For * example 2000::-2010:: * if source->ip1 is smaller than target->ip1, it indicates that the * source's left address limit is greater(range wise) than the target's * left address limit, and hence we reassign the target's left address * limit to source's left address limit. * Similary if source->ip2 is greater than target->ip2, it indicates that * the source's right address limit is greater(range wise) than the * target's right address limit, and hence we reassign the target's right * address limit to source's right address limit. * * \param de_ctx Pointer to the detection engine context. * \param target Pointer to the target DetectAddress instance that has to be * updated. * \param source Pointer to the source DetectAddress instance that is used * to decided whether we extend the target's address range. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressJoinIPv6(DetectEngineCtx *de_ctx, DetectAddress *target, DetectAddress *source) { if (AddressIPv6Lt(&source->ip, &target->ip)) { COPY_ADDRESS(&source->ip, &target->ip); } if (AddressIPv6Gt(&source->ip, &target->ip)) { COPY_ADDRESS(&source->ip2, &target->ip2); } return 0; } /***************************************Unittests******************************/ #ifdef UNITTESTS int AddressTestIPv6Gt01(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 0, 2, 3, 4 }; if (AddressIPv6GtU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Gt02(void) { int result = 0; uint32_t a[4] = { 0, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6GtU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Gt03(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6GtU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Gt04(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 5 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6GtU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Lt01(void) { int result = 0; uint32_t a[4] = { 0, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6LtU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Lt02(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 0, 2, 3, 4 }; if (AddressIPv6LtU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Lt03(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6LtU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Lt04(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 5 }; if (AddressIPv6LtU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Eq01(void) { int result = 0; uint32_t a[4] = { 0, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6EqU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Eq02(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 0, 2, 3, 4 }; if (AddressIPv6EqU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Eq03(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6EqU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Eq04(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 5 }; if (AddressIPv6EqU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Le01(void) { int result = 0; uint32_t a[4] = { 0, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6LeU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Le02(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 0, 2, 3, 4 }; if (AddressIPv6LeU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Le03(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6LeU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Le04(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 5 }; if (AddressIPv6LeU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Le05(void) { int result = 0; uint32_t a[4]; uint32_t b[4]; struct in6_addr in6; if (inet_pton(AF_INET6, "1999:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &in6) != 1) return 0; memcpy(&a, &in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) return 0; memcpy(&b, &in6.s6_addr, sizeof(in6.s6_addr)); if (AddressIPv6LeU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Ge01(void) { int result = 0; uint32_t a[4] = { 0, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6GeU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Ge02(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 0, 2, 3, 4 }; if (AddressIPv6GeU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Ge03(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 4 }; if (AddressIPv6GeU32(a, b) == 1) result = 1; return result; } int AddressTestIPv6Ge04(void) { int result = 0; uint32_t a[4] = { 1, 2, 3, 4 }; uint32_t b[4] = { 1, 2, 3, 5 }; if (AddressIPv6GeU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6Ge05(void) { int result = 0; uint32_t a[4]; uint32_t b[4]; struct in6_addr in6; if (inet_pton(AF_INET6, "1999:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &in6) != 1) return 0; memcpy(&a, &in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) return 0; memcpy(&b, &in6.s6_addr, sizeof(in6.s6_addr)); if (AddressIPv6GeU32(a, b) == 0) result = 1; return result; } int AddressTestIPv6SubOne01(void) { int result = 0; uint32_t a[4], b[4]; struct in6_addr in6; if (inet_pton(AF_INET6, "2000::1", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); a[0] = ntohl(a[0]); a[1] = ntohl(a[1]); a[2] = ntohl(a[2]); a[3] = ntohl(a[3]); AddressCutIPv6CopySubOne(a, b); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); if (b[0] == a[0] && b[1] == a[1] && b[2] == a[2] && b[3] == a[3]) { result = 1; } return result; } int AddressTestIPv6SubOne02(void) { int result = 0; uint32_t a[4], b[4]; struct in6_addr in6; if (inet_pton(AF_INET6, "2000::0", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); a[0] = ntohl(a[0]); a[1] = ntohl(a[1]); a[2] = ntohl(a[2]); a[3] = ntohl(a[3]); AddressCutIPv6CopySubOne(a, b); if (inet_pton(AF_INET6, "1FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); if (b[0] == a[0] && b[1] == a[1] && b[2] == a[2] && b[3] == a[3]) { result = 1; } return result; } int AddressTestIPv6AddOne01(void) { int result = 0; uint32_t a[4], b[4]; struct in6_addr in6; if (inet_pton(AF_INET6, "2000::0", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); a[0] = ntohl(a[0]); a[1] = ntohl(a[1]); a[2] = ntohl(a[2]); a[3] = ntohl(a[3]); AddressCutIPv6CopyAddOne(a, b); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); if (b[0] == a[0] && b[1] == a[1] && b[2] == a[2] && b[3] == a[3]) { result = 1; } return result; } int AddressTestIPv6AddOne02(void) { int result = 0; uint32_t a[4], b[4]; struct in6_addr in6; if (inet_pton(AF_INET6, "1FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); a[0] = ntohl(a[0]); a[1] = ntohl(a[1]); a[2] = ntohl(a[2]); a[3] = ntohl(a[3]); AddressCutIPv6CopyAddOne(a, b); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); if (b[0] == a[0] && b[1] == a[1] && b[2] == a[2] && b[3] == a[3]) { result = 1; } return result; } static int AddressTestIPv6AddressCmp01(void) { DetectAddress *a = DetectAddressInit(); DetectAddress *b = DetectAddressInit(); struct in6_addr in6; int result = 1; if (a == NULL || b == NULL) goto error; if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_EQ); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_ES); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::11", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_ES); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_ES); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::11", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_ES); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::11", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_ES); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::11", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_EB); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_EB); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::11", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_EB); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::11", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_EB); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_LE); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_LE); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_LE); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_LE); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_LE); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_LT); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); /* we could get a LE */ result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_LT); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); /* we could get a LE */ result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_LT); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::19", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_LT); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_LT); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_LT); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_GE); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_GE); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_GE); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_GE); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::19", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_GE); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_GE); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) == ADDRESS_GT); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_GT); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&b->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&b->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCmpIPv6(a, b) != ADDRESS_GT); if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return result; error: if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return 0; } static int AddressTestIPv6CutNot01(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; struct in6_addr in6; int result = 1; if ( (a = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "::", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCutNotIPv6(a, &b) == -1); if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return result; error: if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return 0; } static int AddressTestIPv6CutNot02(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; DetectAddress *temp = NULL; struct in6_addr in6; int result = 1; if ( (a = DetectAddressInit()) == NULL) goto error; if ( (temp = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "::", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCutNotIPv6(a, &b) == 0); result &= (b == NULL); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(a, temp) == ADDRESS_EQ); if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); if (temp != NULL) DetectAddressFree(temp); return result; error: if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); if (temp != NULL) DetectAddressFree(temp); return 0; } static int AddressTestIPv6CutNot03(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; DetectAddress *temp = NULL; struct in6_addr in6; int result = 1; if ( (a = DetectAddressInit()) == NULL) goto error; if ( (temp = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCutNotIPv6(a, &b) == 0); result &= (b == NULL); if (inet_pton(AF_INET6, "::", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(a, temp) == ADDRESS_EQ); if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); if (temp != NULL) DetectAddressFree(temp); return result; error: if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); if (temp != NULL) DetectAddressFree(temp); return 0; } static int AddressTestIPv6CutNot04(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; DetectAddress *temp = NULL; struct in6_addr in6; int result = 1; if ( (a = DetectAddressInit()) == NULL) goto error; if ( (temp = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCutNotIPv6(a, &b) == 0); if (inet_pton(AF_INET6, "::", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(a, temp) == ADDRESS_EQ); result &= (b != NULL); if (result == 0) goto error; if (inet_pton(AF_INET6, "2000::2", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(b, temp) == ADDRESS_EQ); if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); if (temp != NULL) DetectAddressFree(temp); return result; error: if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); if (temp != NULL) DetectAddressFree(temp); return 0; } static int AddressTestIPv6CutNot05(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; DetectAddress *temp = NULL; struct in6_addr in6; int result = 1; if ( (a = DetectAddressInit()) == NULL) goto error; if ( (temp = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&a->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&a->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressCutNotIPv6(a, &b) == 0); if (inet_pton(AF_INET6, "::", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::0", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(a, temp) == ADDRESS_EQ); result &= (b != NULL); if (result == 0) goto error; if (inet_pton(AF_INET6, "2000::21", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(b, temp) == ADDRESS_EQ); if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); if (temp != NULL) DetectAddressFree(temp); return result; error: if (a != NULL) DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); if (temp != NULL) DetectAddressFree(temp); return 0; } static int AddressTestIPv6Join01(void) { DetectAddress *source = DetectAddressInit(); DetectAddress *target = DetectAddressInit(); DetectAddress *temp = DetectAddressInit(); struct in6_addr in6; int result = 1; if (source == NULL || target == NULL || temp == NULL) goto error; /* case 1 */ if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&target->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&target->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&source->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&source->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressJoinIPv6(NULL, target, source) == 0); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(target, temp) == ADDRESS_EQ); /* case 2 */ if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&target->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&target->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::2", &in6) != 1) goto error; memcpy(&source->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::19", &in6) != 1) goto error; memcpy(&source->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressJoinIPv6(NULL, target, source) == 0); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(target, temp) == ADDRESS_EQ); /* case 3 */ if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&target->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::15", &in6) != 1) goto error; memcpy(&target->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&source->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&source->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressJoinIPv6(NULL, target, source) == 0); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(target, temp) == ADDRESS_EQ); /* case 4 */ if (inet_pton(AF_INET6, "2000::10", &in6) != 1) goto error; memcpy(&target->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&target->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&source->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&source->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressJoinIPv6(NULL, target, source) == 0); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(target, temp) == ADDRESS_EQ); /* case 5 */ if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&target->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&target->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&source->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&source->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result &= (DetectAddressJoinIPv6(NULL, target, source) == 0); if (inet_pton(AF_INET6, "2000::1", &in6) != 1) goto error; memcpy(&temp->ip.address, in6.s6_addr, sizeof(in6.s6_addr)); if (inet_pton(AF_INET6, "2000::20", &in6) != 1) goto error; memcpy(&temp->ip2.address, in6.s6_addr, sizeof(in6.s6_addr)); result = (DetectAddressCmpIPv6(target, temp) == ADDRESS_EQ); if (source != NULL) DetectAddressFree(source); if (target != NULL) DetectAddressFree(target); if (temp != NULL) DetectAddressFree(temp); return result; error: if (source != NULL) DetectAddressFree(source); if (target != NULL) DetectAddressFree(target); if (temp != NULL) DetectAddressFree(temp); return 0; } #endif /* UNITTESTS */ void DetectAddressIPv6Tests(void) { #ifdef UNITTESTS UtRegisterTest("AddressTestIPv6Gt01", AddressTestIPv6Gt01, 1); UtRegisterTest("AddressTestIPv6Gt02", AddressTestIPv6Gt02, 1); UtRegisterTest("AddressTestIPv6Gt03", AddressTestIPv6Gt03, 1); UtRegisterTest("AddressTestIPv6Gt04", AddressTestIPv6Gt04, 1); UtRegisterTest("AddressTestIPv6Lt01", AddressTestIPv6Lt01, 1); UtRegisterTest("AddressTestIPv6Lt02", AddressTestIPv6Lt02, 1); UtRegisterTest("AddressTestIPv6Lt03", AddressTestIPv6Lt03, 1); UtRegisterTest("AddressTestIPv6Lt04", AddressTestIPv6Lt04, 1); UtRegisterTest("AddressTestIPv6Eq01", AddressTestIPv6Eq01, 1); UtRegisterTest("AddressTestIPv6Eq02", AddressTestIPv6Eq02, 1); UtRegisterTest("AddressTestIPv6Eq03", AddressTestIPv6Eq03, 1); UtRegisterTest("AddressTestIPv6Eq04", AddressTestIPv6Eq04, 1); UtRegisterTest("AddressTestIPv6Le01", AddressTestIPv6Le01, 1); UtRegisterTest("AddressTestIPv6Le02", AddressTestIPv6Le02, 1); UtRegisterTest("AddressTestIPv6Le03", AddressTestIPv6Le03, 1); UtRegisterTest("AddressTestIPv6Le04", AddressTestIPv6Le04, 1); UtRegisterTest("AddressTestIPv6Le05", AddressTestIPv6Le05, 1); UtRegisterTest("AddressTestIPv6Ge01", AddressTestIPv6Ge01, 1); UtRegisterTest("AddressTestIPv6Ge02", AddressTestIPv6Ge02, 1); UtRegisterTest("AddressTestIPv6Ge03", AddressTestIPv6Ge03, 1); UtRegisterTest("AddressTestIPv6Ge04", AddressTestIPv6Ge04, 1); UtRegisterTest("AddressTestIPv6Ge05", AddressTestIPv6Ge05, 1); UtRegisterTest("AddressTestIPv6SubOne01", AddressTestIPv6SubOne01, 1); UtRegisterTest("AddressTestIPv6SubOne02", AddressTestIPv6SubOne02, 1); UtRegisterTest("AddressTestIPv6AddOne01", AddressTestIPv6AddOne01, 1); UtRegisterTest("AddressTestIPv6AddOne02", AddressTestIPv6AddOne02, 1); UtRegisterTest("AddressTestIPv6AddressCmp01", AddressTestIPv6AddressCmp01, 1); UtRegisterTest("AddressTestIPv6CutNot01", AddressTestIPv6CutNot01, 1); UtRegisterTest("AddressTestIPv6CutNot02", AddressTestIPv6CutNot02, 1); UtRegisterTest("AddressTestIPv6CutNot03", AddressTestIPv6CutNot03, 1); UtRegisterTest("AddressTestIPv6CutNot04", AddressTestIPv6CutNot04, 1); UtRegisterTest("AddressTestIPv6CutNot05", AddressTestIPv6CutNot05, 1); UtRegisterTest("AddressTestIPv6Join01", AddressTestIPv6Join01, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/detect-engine-event.h0000644000000000000000000002346312253546156015040 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DETECT_ENGINE_EVENT_H__ #define __DETECT_ENGINE_EVENT_H__ #include "decode-events.h" typedef struct DetectEngineEventData_ { uint8_t event; } DetectEngineEventData; /* prototypes */ void DetectEngineEventRegister (void); /* supported decoder events */ #ifdef DETECT_EVENTS struct DetectEngineEvents_ { char *event_name; uint8_t code; } DEvents[] = { { "ipv4.pkt_too_small", IPV4_PKT_TOO_SMALL, }, { "ipv4.hlen_too_small", IPV4_HLEN_TOO_SMALL, }, { "ipv4.iplen_smaller_than_hlen", IPV4_IPLEN_SMALLER_THAN_HLEN, }, { "ipv4.trunc_pkt", IPV4_TRUNC_PKT, }, { "ipv4.opt_invalid", IPV4_OPT_INVALID, }, { "ipv4.opt_invalid_len", IPV4_OPT_INVALID_LEN, }, { "ipv4.opt_malformed", IPV4_OPT_MALFORMED, }, { "ipv4.opt_pad_required", IPV4_OPT_PAD_REQUIRED, }, { "ipv4.opt_eol_required", IPV4_OPT_EOL_REQUIRED, }, { "ipv4.opt_duplicate", IPV4_OPT_DUPLICATE, }, { "ipv4.opt_unknown", IPV4_OPT_UNKNOWN, }, { "ipv4.wrong_ip_version", IPV4_WRONG_IP_VER, }, { "ipv6.pkt_too_small", IPV6_PKT_TOO_SMALL, }, { "ipv6.trunc_pkt", IPV6_TRUNC_PKT, }, { "ipv6.trunc_exthdr", IPV6_TRUNC_EXTHDR, }, { "ipv6.exthdr_dupl_fh", IPV6_EXTHDR_DUPL_FH, }, { "ipv6.exthdr_useless_fh", IPV6_EXTHDR_USELESS_FH, }, { "ipv6.exthdr_dupl_rh", IPV6_EXTHDR_DUPL_RH, }, { "ipv6.exthdr_dupl_hh", IPV6_EXTHDR_DUPL_HH, }, { "ipv6.exthdr_dupl_dh", IPV6_EXTHDR_DUPL_DH, }, { "ipv6.exthdr_dupl_ah", IPV6_EXTHDR_DUPL_AH, }, { "ipv6.exthdr_dupl_eh", IPV6_EXTHDR_DUPL_EH, }, { "ipv6.exthdr_invalid_optlen", IPV6_EXTHDR_INVALID_OPTLEN, }, { "ipv6.wrong_ip_version", IPV6_WRONG_IP_VER, }, { "ipv6.exthdr_ah_res_not_null", IPV6_EXTHDR_AH_RES_NOT_NULL, }, { "ipv6.hopopts_unknown_opt", IPV6_HOPOPTS_UNKNOWN_OPT, }, { "ipv6.hopopts_only_padding", IPV6_HOPOPTS_ONLY_PADDING, }, { "ipv6.dstopts_unknown_opt", IPV6_DSTOPTS_UNKNOWN_OPT, }, { "ipv6.dstopts_only_padding", IPV6_DSTOPTS_ONLY_PADDING, }, { "ipv6.icmpv4", IPV6_WITH_ICMPV4, }, { "icmpv4.pkt_too_small", ICMPV4_PKT_TOO_SMALL, }, { "icmpv4.unknown_type", ICMPV4_UNKNOWN_TYPE, }, { "icmpv4.unknown_code", ICMPV4_UNKNOWN_CODE, }, { "icmpv4.ipv4_trunc_pkt", ICMPV4_IPV4_TRUNC_PKT, }, { "icmpv4.ipv4_unknown_ver", ICMPV4_IPV4_UNKNOWN_VER, }, { "icmpv6.unknown_type", ICMPV6_UNKNOWN_TYPE,}, { "icmpv6.unknown_code", ICMPV6_UNKNOWN_CODE,}, { "icmpv6.pkt_too_small", ICMPV6_PKT_TOO_SMALL,}, { "icmpv6.ipv6_unknown_version", ICMPV6_IPV6_UNKNOWN_VER,}, { "icmpv6.ipv6_trunc_pkt", ICMPV6_IPV6_TRUNC_PKT,}, { "tcp.pkt_too_small", TCP_PKT_TOO_SMALL, }, { "tcp.hlen_too_small", TCP_HLEN_TOO_SMALL, }, { "tcp.invalid_optlen", TCP_INVALID_OPTLEN, }, { "tcp.opt_invalid_len", TCP_OPT_INVALID_LEN, }, { "tcp.opt_duplicate", TCP_OPT_DUPLICATE, }, { "udp.pkt_too_small", UDP_PKT_TOO_SMALL, }, { "udp.hlen_too_small", UDP_HLEN_TOO_SMALL, }, { "udp.hlen_invalid", UDP_HLEN_INVALID, }, { "sll.pkt_too_small", SLL_PKT_TOO_SMALL, }, { "ethernet.pkt_too_small", ETHERNET_PKT_TOO_SMALL, }, { "ppp.pkt_too_small", PPP_PKT_TOO_SMALL, }, { "ppp.vju_pkt_too_small", PPPVJU_PKT_TOO_SMALL, }, { "ppp.ip4_pkt_too_small", PPPIPV4_PKT_TOO_SMALL, }, { "ppp.ip6_pkt_too_small", PPPIPV6_PKT_TOO_SMALL, }, { "ppp.wrong_type", PPP_WRONG_TYPE, }, /** unknown & invalid protocol */ { "ppp.unsup_proto", PPP_UNSUP_PROTO, }, /** unsupported but valid protocol */ { "pppoe.pkt_too_small", PPPOE_PKT_TOO_SMALL, }, { "pppoe.wrong_code", PPPOE_WRONG_CODE, }, { "pppoe.malformed_tags", PPPOE_MALFORMED_TAGS, }, { "gre.pkt_too_small", GRE_PKT_TOO_SMALL, }, { "gre.wrong_version", GRE_WRONG_VERSION, }, { "gre.version0_recur", GRE_VERSION0_RECUR, }, { "gre.version0_flags", GRE_VERSION0_FLAGS, }, { "gre.version0_hdr_too_big", GRE_VERSION0_HDR_TOO_BIG, }, { "gre.version0_malformed_sre_hdr", GRE_VERSION0_MALFORMED_SRE_HDR, }, { "gre.version1_chksum", GRE_VERSION1_CHKSUM, }, { "gre.version1_route", GRE_VERSION1_ROUTE, }, { "gre.version1_ssr", GRE_VERSION1_SSR, }, { "gre.version1_recur", GRE_VERSION1_RECUR, }, { "gre.version1_flags", GRE_VERSION1_FLAGS, }, { "gre.version1_no_key", GRE_VERSION1_NO_KEY, }, { "gre.version1_wrong_protocol", GRE_VERSION1_WRONG_PROTOCOL, }, { "gre.version1_malformed_sre_hdr", GRE_VERSION1_MALFORMED_SRE_HDR, }, { "gre.version1_hdr_too_big", GRE_VERSION1_HDR_TOO_BIG, }, { "ipraw.invalid_ip_version",IPRAW_INVALID_IPV, }, { "vlan.header_too_small",VLAN_HEADER_TOO_SMALL, }, { "vlan.unknown_type",VLAN_UNKNOWN_TYPE, }, { "ipv4.frag_too_large", IPV4_FRAG_PKT_TOO_LARGE, }, { "ipv4.frag_overlap", IPV4_FRAG_OVERLAP, }, { "ipv6.frag_too_large", IPV6_FRAG_PKT_TOO_LARGE, }, { "ipv6.frag_overlap", IPV6_FRAG_OVERLAP, }, { "ipv6.ipv4_in_ipv6_too_small", IPV4_IN_IPV6_PKT_TOO_SMALL, }, { "ipv6.ipv4_in_ipv6_wrong_version", IPV4_IN_IPV6_WRONG_IP_VER, }, { "ipv6.ipv6_in_ipv6_too_small", IPV6_IN_IPV6_PKT_TOO_SMALL, }, { "ipv6.ipv6_in_ipv6_wrong_version", IPV6_IN_IPV6_WRONG_IP_VER, }, { "stream.3whs_ack_in_wrong_dir", STREAM_3WHS_ACK_IN_WRONG_DIR, }, { "stream.3whs_async_wrong_seq", STREAM_3WHS_ASYNC_WRONG_SEQ, }, { "stream.3whs_right_seq_wrong_ack_evasion", STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION, }, { "stream.3whs_synack_in_wrong_direction", STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION, }, { "stream.3whs_synack_resend_with_different_ack", STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, { "stream.3whs_synack_resend_with_diff_seq", STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ, }, { "stream.3whs_synack_toserver_on_syn_recv", STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV, }, { "stream.3whs_synack_with_wrong_ack", STREAM_3WHS_SYNACK_WITH_WRONG_ACK, }, { "stream.3whs_syn_resend_diff_seq_on_syn_recv", STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV, }, { "stream.3whs_syn_toclient_on_syn_recv", STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV, }, { "stream.3whs_wrong_seq_wrong_ack", STREAM_3WHS_WRONG_SEQ_WRONG_ACK, }, { "stream.4whs_synack_with_wrong_ack", STREAM_4WHS_SYNACK_WITH_WRONG_ACK, }, { "stream.4whs_synack_with_wrong_syn", STREAM_4WHS_SYNACK_WITH_WRONG_SYN, }, { "stream.4whs_wrong_seq", STREAM_4WHS_WRONG_SEQ, }, { "stream.4whs_invalid_ack", STREAM_4WHS_INVALID_ACK, }, { "stream.closewait_ack_out_of_window", STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW, }, { "stream.closewait_fin_out_of_window", STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, }, { "stream.closewait_pkt_before_last_ack", STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK, }, { "stream.closewait_invalid_ack", STREAM_CLOSEWAIT_INVALID_ACK, }, { "stream.closing_ack_wrong_seq", STREAM_CLOSING_ACK_WRONG_SEQ, }, { "stream.closing_invalid_ack", STREAM_CLOSING_INVALID_ACK, }, { "stream.est_packet_out_of_window", STREAM_EST_PACKET_OUT_OF_WINDOW, }, { "stream.est_pkt_before_last_ack", STREAM_EST_PKT_BEFORE_LAST_ACK, }, { "stream.est_synack_resend", STREAM_EST_SYNACK_RESEND, }, { "stream.est_synack_resend_with_different_ack", STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, { "stream.est_synack_resend_with_diff_seq", STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ, }, { "stream.est_synack_toserver", STREAM_EST_SYNACK_TOSERVER, }, { "stream.est_syn_resend", STREAM_EST_SYN_RESEND, }, { "stream.est_syn_resend_diff_seq", STREAM_EST_SYN_RESEND_DIFF_SEQ, }, { "stream.est_syn_toclient", STREAM_EST_SYN_TOCLIENT, }, { "stream.est_invalid_ack", STREAM_EST_INVALID_ACK, }, { "stream.fin_invalid_ack", STREAM_FIN_INVALID_ACK, }, { "stream.fin1_ack_wrong_seq", STREAM_FIN1_ACK_WRONG_SEQ, }, { "stream.fin1_fin_wrong_seq", STREAM_FIN1_FIN_WRONG_SEQ, }, { "stream.fin1_invalid_ack", STREAM_FIN1_INVALID_ACK, }, { "stream.fin2_ack_wrong_seq", STREAM_FIN2_ACK_WRONG_SEQ, }, { "stream.fin2_fin_wrong_seq", STREAM_FIN2_FIN_WRONG_SEQ, }, { "stream.fin2_invalid_ack", STREAM_FIN2_INVALID_ACK, }, { "stream.fin_but_no_session", STREAM_FIN_BUT_NO_SESSION, }, { "stream.fin_out_of_window", STREAM_FIN_OUT_OF_WINDOW, }, { "stream.lastack_ack_wrong_seq", STREAM_LASTACK_ACK_WRONG_SEQ, }, { "stream.lastack_invalid_ack", STREAM_LASTACK_INVALID_ACK, }, { "stream.rst_but_no_session", STREAM_RST_BUT_NO_SESSION, }, { "stream.timewait_ack_wrong_seq", STREAM_TIMEWAIT_ACK_WRONG_SEQ, }, { "stream.timewait_invalid_ack", STREAM_TIMEWAIT_INVALID_ACK, }, { "stream.pkt_invalid_timestamp", STREAM_PKT_INVALID_TIMESTAMP, }, { "stream.pkt_invalid_ack", STREAM_PKT_INVALID_ACK, }, { "stream.pkt_broken_ack", STREAM_PKT_BROKEN_ACK, }, { "stream.rst_invalid_ack", STREAM_RST_INVALID_ACK, }, { "stream.shutdown_syn_resend", STREAM_SHUTDOWN_SYN_RESEND, }, { "stream.pkt_retransmission", STREAM_PKT_RETRANSMISSION, }, { "stream.reassembly_segment_before_base_seq", STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ, }, { "stream.reassembly_no_segment", STREAM_REASSEMBLY_NO_SEGMENT, }, { "stream.reassembly_seq_gap", STREAM_REASSEMBLY_SEQ_GAP, }, { "stream.reassembly_overlap_different_data", STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, }, { NULL, 0 }, }; #endif /* DETECT_EVENTS */ #endif /*__DETECT_ENGINE_EVENT_H__ */ suricata-1.4.7/src/util-time.c0000644000000000000000000000554412253546156013112 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Time keeping for offline (non-live) packet handling (pcap files) */ #include "suricata-common.h" #include "detect.h" #include "threads.h" #include "util-debug.h" static struct timeval current_time = { 0, 0 }; //static SCMutex current_time_mutex = PTHREAD_MUTEX_INITIALIZER; static SCSpinlock current_time_spinlock; static char live = TRUE; void TimeInit(void) { SCSpinInit(¤t_time_spinlock, 0); } void TimeDeinit(void) { SCSpinDestroy(¤t_time_spinlock); } void TimeModeSetLive(void) { live = TRUE; SCLogDebug("live time mode enabled"); } void TimeModeSetOffline (void) { live = FALSE; SCLogDebug("offline time mode enabled"); } void TimeSet(struct timeval *tv) { if (live == TRUE) return; if (tv == NULL) return; SCSpinLock(¤t_time_spinlock); current_time.tv_sec = tv->tv_sec; current_time.tv_usec = tv->tv_usec; SCLogDebug("time set to %" PRIuMAX " sec, %" PRIuMAX " usec", (uintmax_t)current_time.tv_sec, (uintmax_t)current_time.tv_usec); SCSpinUnlock(¤t_time_spinlock); } /** \brief set the time to "gettimeofday" meant for testing */ void TimeSetToCurrentTime(void) { struct timeval tv; memset(&tv, 0x00, sizeof(tv)); gettimeofday(&tv, NULL); TimeSet(&tv); } void TimeGet(struct timeval *tv) { if (tv == NULL) return; if (live == TRUE) { gettimeofday(tv, NULL); } else { SCSpinLock(¤t_time_spinlock); tv->tv_sec = current_time.tv_sec; tv->tv_usec = current_time.tv_usec; SCSpinUnlock(¤t_time_spinlock); } SCLogDebug("time we got is %" PRIuMAX " sec, %" PRIuMAX " usec", (uintmax_t)tv->tv_sec, (uintmax_t)tv->tv_usec); } /** \brief increment the time in the engine * \param tv_sec seconds to increment the time with */ void TimeSetIncrementTime(uint32_t tv_sec) { struct timeval tv; memset(&tv, 0x00, sizeof(tv)); TimeGet(&tv); tv.tv_sec += tv_sec; TimeSet(&tv); } struct tm *SCLocalTime(time_t timep, struct tm *result) { return localtime_r(&timep, result); } suricata-1.4.7/src/util-reference-config.c0000644000000000000000000005455212253546156015360 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "detect.h" #include "detect-engine.h" #include "util-hash.h" #include "util-reference-config.h" #include "conf.h" #include "util-unittest.h" #include "util-error.h" #include "util-debug.h" #include "util-fmemopen.h" /* Regex to parse each line from reference.config file. The first substring * is for the system name and the second for the url */ /*-----------------------------------------------------------system-------------------url----*/ #define SC_RCONF_REGEX "^\\s*config\\s+reference\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s+(.+)\\s*$" /* Default path for the reference.conf file */ #define SC_RCONF_DEFAULT_FILE_PATH CONFIG_DIR "/reference.config" /* Holds a pointer to the default path for the reference.config file */ static const char *file_path = SC_RCONF_DEFAULT_FILE_PATH; static FILE *fd = NULL; static pcre *regex = NULL; static pcre_extra *regex_study = NULL; /* the hash functions */ uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen); char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2); void SCRConfReferenceHashFree(void *ch); /* used to get the reference.config file path */ static char *SCRConfGetConfFilename(void); /** * \brief Inits the context to be used by the Reference Config parsing API. * * This function initializes the hash table to be used by the Detection * Engine Context to hold the data from reference.config file, * obtains the file descriptor to parse the reference.config file, and * inits the regex used to parse the lines from reference.config file. * * \param de_ctx Pointer to the Detection Engine Context. * * \retval 0 On success. * \retval -1 On failure. */ static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) { char *filename = NULL; const char *eb = NULL; int eo; int opts = 0; /* init the hash table to be used by the reference config references */ de_ctx->reference_conf_ht = HashTableInit(128, SCRConfReferenceHashFunc, SCRConfReferenceHashCompareFunc, SCRConfReferenceHashFree); if (de_ctx->reference_conf_ht == NULL) { SCLogError(SC_ERR_HASH_TABLE_INIT, "Error initializing the hash " "table"); goto error; } /* if it is not NULL, use the file descriptor. The hack so that we can * avoid using a dummy reference file for testing purposes and * instead use an input stream against a buffer containing the * reference strings */ if (fd == NULL) { filename = SCRConfGetConfFilename(); if ((fd = fopen(filename, "r")) == NULL) { SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } } regex = pcre_compile(SC_RCONF_REGEX, opts, &eb, &eo, NULL); if (regex == NULL) { SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", SC_RCONF_REGEX, eo, eb); goto error; } regex_study = pcre_study(regex, 0, &eb); if (eb != NULL) { SCLogDebug("pcre study failed: %s", eb); goto error; } return 0; error: if (de_ctx->reference_conf_ht != NULL) { HashTableFree(de_ctx->reference_conf_ht); de_ctx->reference_conf_ht = NULL; } if (fd != NULL) { fclose(fd); fd = NULL; } if (regex != NULL) { pcre_free(regex); regex = NULL; } if (regex_study != NULL) { pcre_free(regex_study); regex_study = NULL; } return -1; } /** * \brief Returns the path for the Reference Config file. We check if we * can retrieve the path from the yaml conf file. If it is not present, * return the default path for the reference.config file which is * "./reference.config". * * \retval log_filename Pointer to a string containing the path for the * reference.config file. */ static char *SCRConfGetConfFilename(void) { char *path = NULL; if (ConfGet("reference-config-file", &path) != 1) { return (char *)file_path; } return path; } /** * \brief Releases local resources used by the Reference Config API. */ static void SCRConfDeInitLocalResources(DetectEngineCtx *de_ctx) { if (fd != NULL) fclose(fd); file_path = SC_RCONF_DEFAULT_FILE_PATH; fd = NULL; if (regex != NULL) { pcre_free(regex); regex = NULL; } if (regex_study != NULL) { pcre_free(regex_study); regex_study = NULL; } return; } /** * \brief Releases de_ctx resources related to Reference Config API. */ void SCRConfDeInitContext(DetectEngineCtx *de_ctx) { if (de_ctx->reference_conf_ht != NULL) HashTableFree(de_ctx->reference_conf_ht); de_ctx->reference_conf_ht = NULL; return; } /** * \brief Converts a string to lowercase. * * \param str Pointer to the string to be converted. */ static char *SCRConfStringToLowercase(const char *str) { char *new_str = NULL; char *temp_str = NULL; if ((new_str = SCStrdup(str)) == NULL) { return NULL; } temp_str = new_str; while (*temp_str != '\0') { *temp_str = tolower((unsigned char)*temp_str); temp_str++; } return new_str; } /** * \brief Parses a line from the reference config file and adds it to Reference * Config hash table DetectEngineCtx->reference_conf_ht. * * \param rawstr Pointer to the string to be parsed. * \param de_ctx Pointer to the Detection Engine Context. * * \retval 0 On success. * \retval -1 On failure. */ static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx) { const char *system = NULL; const char *url = NULL; SCRConfReference *ref_new = NULL; SCRConfReference *ref_lookup = NULL; #define MAX_SUBSTRINGS 30 int ret = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30); if (ret < 0) { SCLogError(SC_ERR_REFERENCE_CONFIG, "Invalid Reference Config in " "reference.config file"); goto error; } /* retrieve the reference system */ ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &system); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring() failed"); goto error; } /* retrieve the reference url */ ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &url); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring() failed"); goto error; } /* Create a new instance of the parsed Reference string */ ref_new = SCRConfAllocSCRConfReference(system, url); /* Check if the Reference is present in the HashTable. In case it's present * ignore it, as it's a duplicate. If not present, add it to the table */ ref_lookup = HashTableLookup(de_ctx->reference_conf_ht, ref_new, 0); if (ref_lookup == NULL) { if (HashTableAdd(de_ctx->reference_conf_ht, ref_new, 0) < 0) { SCLogDebug("HashTable Add failed"); } } else { SCLogDebug("Duplicate reference found inside reference.config"); SCRConfDeAllocSCRConfReference(ref_new); } /* free the substrings */ pcre_free_substring(system); pcre_free_substring(url); return 0; error: if (system) pcre_free_substring(system); if (url) pcre_free_substring(url); return -1; } /** * \brief Checks if a string is a comment or a blank line. * * Comments lines are lines of the following format - * "# This is a comment string" or * " # This is a comment string". * * \param line String that has to be checked. * * \retval 1 On the argument string being a comment or blank line. * \retval 0 Otherwise. */ static int SCRConfIsLineBlankOrComment(char *line) { while (*line != '\0') { /* we have a comment */ if (*line == '#') return 1; /* this line is neither a comment line, nor a blank line */ if (!isspace((unsigned char)*line)) return 0; line++; } /* we have a blank line */ return 1; } /** * \brief Parses the Reference Config file and updates the * DetectionEngineCtx->reference_conf_ht with the Reference information. * * \param de_ctx Pointer to the Detection Engine Context. */ static void SCRConfParseFile(DetectEngineCtx *de_ctx) { char line[1024]; uint8_t i = 1; while (fgets(line, sizeof(line), fd) != NULL) { if (SCRConfIsLineBlankOrComment(line)) continue; SCRConfAddReference(line, de_ctx); i++; } #ifdef UNITTESTS SCLogInfo("Added \"%d\" reference types from the reference.config file", de_ctx->reference_conf_ht->count); #endif /* UNITTESTS */ return; } /** * \brief Returns a new SCRConfReference instance. The reference string * is converted into lowercase, before being assigned to the instance. * * \param system Pointer to the system. * \param url Pointer to the reference url. * * \retval ref Pointer to the new instance of SCRConfReference. */ SCRConfReference *SCRConfAllocSCRConfReference(const char *system, const char *url) { SCRConfReference *ref = NULL; if (system == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid arguments. system NULL"); return NULL; } if ((ref = SCMalloc(sizeof(SCRConfReference))) == NULL) { return NULL; } memset(ref, 0, sizeof(SCRConfReference)); if ((ref->system = SCRConfStringToLowercase(system)) == NULL) { SCFree(ref); return NULL; } if (url != NULL && (ref->url = SCStrdup(url)) == NULL) { SCFree(ref->system); SCFree(ref); return NULL; } return ref; } /** * \brief Frees a SCRConfReference instance. * * \param Pointer to the SCRConfReference instance that has to be freed. */ void SCRConfDeAllocSCRConfReference(SCRConfReference *ref) { if (ref != NULL) { if (ref->system != NULL) SCFree(ref->system); if (ref->url != NULL) SCFree(ref->url); SCFree(ref); } return; } /** * \brief Hashing function to be used to hash the Reference name. Would be * supplied as an argument to the HashTableInit function for * DetectEngineCtx->reference_conf_ht. * * \param ht Pointer to the HashTable. * \param data Pointer to the data to be hashed. In this case, the data * would be a pointer to a SCRConfReference instance. * \param datalen Not used by this function. */ uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen) { SCRConfReference *ref = (SCRConfReference *)data; uint32_t hash = 0; int i = 0; int len = strlen(ref->system); for (i = 0; i < len; i++) hash += tolower((unsigned char)ref->system[i]); hash = hash % ht->array_size; return hash; } /** * \brief Used to compare two References that have been stored in the HashTable. * This function is supplied as an argument to the HashTableInit function * for DetectionEngineCtx->reference_conf_ct. * * \param data1 Pointer to the first SCRConfReference to be compared. * \param len1 Not used by this function. * \param data2 Pointer to the second SCRConfReference to be compared. * \param len2 Not used by this function. * * \retval 1 On data1 and data2 being equal. * \retval 0 On data1 and data2 not being equal. */ char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) { SCRConfReference *ref1 = (SCRConfReference *)data1; SCRConfReference *ref2 = (SCRConfReference *)data2; int len1 = 0; int len2 = 0; if (ref1 == NULL || ref2 == NULL) return 0; if (ref1->system == NULL || ref2->system == NULL) return 0; len1 = strlen(ref1->system); len2 = strlen(ref2->system); if (len1 == len2 && memcmp(ref1->system, ref2->system, len1) == 0) { SCLogDebug("Match found inside Reference-Config hash function"); return 1; } return 0; } /** * \brief Used to free the Reference Config Hash Data that was stored in * DetectEngineCtx->reference_conf_ht Hashtable. * * \param data Pointer to the data that has to be freed. */ void SCRConfReferenceHashFree(void *data) { SCRConfDeAllocSCRConfReference(data); return; } /** * \brief Loads the Reference info from the reference.config file. * * The reference.config file contains references that can be used in * Signatures. Each line of the file should have the following format - * config reference: system_name, reference_url. * * \param de_ctx Pointer to the Detection Engine Context that should be updated * with reference information. * * \retval 0 On success. * \retval -1 On failure. */ int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx) { if (SCRConfInitContextAndLocalResources(de_ctx) == -1) { SCLogInfo("Please check the \"reference-config-file\" option in your suricata.yaml file"); exit(EXIT_FAILURE); } SCRConfParseFile(de_ctx); SCRConfDeInitLocalResources(de_ctx); return 0; } /** * \brief Gets the refernce config from the corresponding hash table stored * in the Detection Engine Context's reference conf ht, given the * reference name. * * \param ct_name Pointer to the reference name that has to be looked up. * \param de_ctx Pointer to the Detection Engine Context. * * \retval lookup_rconf_info Pointer to the SCRConfReference instance from * the hash table on success; NULL on failure. */ SCRConfReference *SCRConfGetReference(const char *rconf_name, DetectEngineCtx *de_ctx) { SCRConfReference *ref_conf = SCRConfAllocSCRConfReference(rconf_name, NULL); if (ref_conf == NULL) exit(EXIT_FAILURE); SCRConfReference *lookup_ref_conf = HashTableLookup(de_ctx->reference_conf_ht, ref_conf, 0); SCRConfDeAllocSCRConfReference(ref_conf); return lookup_ref_conf; } /*----------------------------------Unittests---------------------------------*/ #ifdef UNITTESTS /** * \brief Creates a dummy reference config, with all valid references, for * testing purposes. */ void SCRConfGenerateValidDummyReferenceConfigFD01(void) { const char *buffer = "config reference: one http://www.one.com\n" "config reference: two http://www.two.com\n" "config reference: three http://www.three.com\n" "config reference: one http://www.one.com\n" "config reference: three http://www.three.com\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); return; } /** * \brief Creates a dummy reference config, with some valid references and a * couple of invalid references, for testing purposes. */ void SCRConfGenerateInValidDummyReferenceConfigFD02(void) { const char *buffer = "config reference: one http://www.one.com\n" "config_ reference: two http://www.two.com\n" "config reference_: three http://www.three.com\n" "config reference: four\n" "config reference five http://www.five.com\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); return; } /** * \brief Creates a dummy reference config, with all invalid references, for * testing purposes. */ void SCRConfGenerateInValidDummyReferenceConfigFD03(void) { const char *buffer = "config reference one http://www.one.com\n" "config_ reference: two http://www.two.com\n" "config reference_: three http://www.three.com\n" "config reference: four\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); return; } /** * \brief Deletes the FD, if set by the other testing functions. */ void SCRConfDeleteDummyReferenceConfigFD(void) { if (fd != NULL) { fclose(fd); fd = NULL; } return; } /** * \test Check that the reference file is loaded and the detection engine * content reference_conf_ht loaded with the reference data. */ int SCRConfTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 0; if (de_ctx == NULL) return result; SCRConfGenerateValidDummyReferenceConfigFD01(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); if (de_ctx->reference_conf_ht == NULL) goto end; result = (de_ctx->reference_conf_ht->count == 3); if (result == 0) printf("FAILED: de_ctx->reference_conf_ht->count %u: ", de_ctx->reference_conf_ht->count); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Check that invalid references present in the reference.config file * aren't loaded. */ int SCRConfTest02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 0; if (de_ctx == NULL) return result; SCRConfGenerateInValidDummyReferenceConfigFD03(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); if (de_ctx->reference_conf_ht == NULL) goto end; result = (de_ctx->reference_conf_ht->count == 0); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Check that only valid references are loaded into the hash table from * the reference.config file. */ int SCRConfTest03(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 0; if (de_ctx == NULL) return result; SCRConfGenerateInValidDummyReferenceConfigFD02(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); if (de_ctx->reference_conf_ht == NULL) goto end; result = (de_ctx->reference_conf_ht->count == 1); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the reference info from the reference.config file have * been loaded into the hash table. */ int SCRConfTest04(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 1; if (de_ctx == NULL) return 0; SCRConfGenerateValidDummyReferenceConfigFD01(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); if (de_ctx->reference_conf_ht == NULL) goto end; result = (de_ctx->reference_conf_ht->count == 3); result &= (SCRConfGetReference("one", de_ctx) != NULL); result &= (SCRConfGetReference("two", de_ctx) != NULL); result &= (SCRConfGetReference("three", de_ctx) != NULL); result &= (SCRConfGetReference("four", de_ctx) == NULL); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the reference info from the invalid reference.config file * have not been loaded into the hash table, and cross verify to check * that the hash table contains no reference data. */ int SCRConfTest05(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 1; if (de_ctx == NULL) return 0; SCRConfGenerateInValidDummyReferenceConfigFD03(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); if (de_ctx->reference_conf_ht == NULL) goto end; result = (de_ctx->reference_conf_ht->count == 0); result &= (SCRConfGetReference("one", de_ctx) == NULL); result &= (SCRConfGetReference("two", de_ctx) == NULL); result &= (SCRConfGetReference("three", de_ctx) == NULL); result &= (SCRConfGetReference("four", de_ctx) == NULL); result &= (SCRConfGetReference("five", de_ctx) == NULL); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Check if the reference info from the reference.config file have * been loaded into the hash table. */ int SCRConfTest06(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); int result = 1; if (de_ctx == NULL) return 0; SCRConfGenerateInValidDummyReferenceConfigFD02(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); if (de_ctx->reference_conf_ht == NULL) goto end; result = (de_ctx->reference_conf_ht->count == 1); result &= (SCRConfGetReference("one", de_ctx) != NULL); result &= (SCRConfGetReference("two", de_ctx) == NULL); result &= (SCRConfGetReference("three", de_ctx) == NULL); result &= (SCRConfGetReference("four", de_ctx) == NULL); result &= (SCRConfGetReference("five", de_ctx) == NULL); end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ /** * \brief This function registers unit tests for Reference Config API. */ void SCRConfRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCRConfTest01", SCRConfTest01, 1); UtRegisterTest("SCRConfTest02", SCRConfTest02, 1); UtRegisterTest("SCRConfTest03", SCRConfTest03, 1); UtRegisterTest("SCRConfTest04", SCRConfTest04, 1); UtRegisterTest("SCRConfTest05", SCRConfTest05, 1); UtRegisterTest("SCRConfTest06", SCRConfTest06, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/util-hash-lookup3.c0000644000000000000000000010477412253546156014476 00000000000000/* ------------------------------------------------------------------------------- lookup3.c, by Bob Jenkins, May 2006, Public Domain. These are functions for producing 32-bit hashes for hash table lookup. hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() are externally useful functions. Routines to test the hash are included if SELF_TEST is defined. You can use this free for any purpose. It's in the public domain. It has no warranty. You probably want to use hashlittle(). hashlittle() and hashbig() hash byte arrays. hashlittle() is is faster than hashbig() on little-endian machines. Intel and AMD are little-endian machines. On second thought, you probably want hashlittle2(), which is identical to hashlittle() except it returns two 32-bit hashes for the price of one. You could implement hashbig2() if you wanted but I haven't bothered here. If you want to find a hash of, say, exactly 7 integers, do a = i1; b = i2; c = i3; mix(a,b,c); a += i4; b += i5; c += i6; mix(a,b,c); a += i7; final(a,b,c); then use c as the hash value. If you have a variable length array of 4-byte integers to hash, use hashword(). If you have a byte array (like a character string), use hashlittle(). If you have several byte arrays, or a mix of things, see the comments above hashlittle(). Why is this so big? I read 12 bytes at a time into 3 4-byte integers, then mix those integers. This is fast (you can do a lot more thorough mixing with 12*3 instructions on 3 integers than you can with 3 instructions on 1 byte), but shoehorning those bytes into integers efficiently is messy. ------------------------------------------------------------------------------- */ //#define SELF_TEST 1 #include /* defines printf for tests */ #include /* defines time_t for timings in the test */ #include /* defines uint32_t etc */ #include /* attempt to define endianness */ #ifdef linux # include /* attempt to define endianness */ #endif /* * My best guess at if you are big-endian or little-endian. This may * need adjustment. */ #if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ __BYTE_ORDER == __LITTLE_ENDIAN) || \ (defined(i386) || defined(__i386__) || defined(__i486__) || \ defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) # define HASH_LITTLE_ENDIAN 1 # define HASH_BIG_ENDIAN 0 #elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ __BYTE_ORDER == __BIG_ENDIAN) || \ (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 1 #else # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 0 #endif #define hashsize(n) ((uint32_t)1<<(n)) #define hashmask(n) (hashsize(n)-1) #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) /* ------------------------------------------------------------------------------- mix -- mix 3 32-bit values reversibly. This is reversible, so any information in (a,b,c) before mix() is still in (a,b,c) after mix(). If four pairs of (a,b,c) inputs are run through mix(), or through mix() in reverse, there are at least 32 bits of the output that are sometimes the same for one pair and different for another pair. This was tested for: * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that satisfy this are 4 6 8 16 19 4 9 15 3 18 27 15 14 9 3 7 17 3 Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" defined as + with a one-bit base and a two-bit delta. I used http://burtleburtle.net/bob/hash/avalanche.html to choose the operations, constants, and arrangements of the variables. This does not achieve avalanche. There are input bits of (a,b,c) that fail to affect some output bits of (a,b,c), especially of a. The most thoroughly mixed value is c, but it doesn't really even achieve avalanche in c. This allows some parallelism. Read-after-writes are good at doubling the number of bits affected, so the goal of mixing pulls in the opposite direction as the goal of parallelism. I did what I could. Rotates seem to cost as much as shifts on every machine I could lay my hands on, and rotates are much kinder to the top and bottom bits, so I used rotates. ------------------------------------------------------------------------------- */ #define mix(a,b,c) \ { \ a -= c; a ^= rot(c, 4); c += b; \ b -= a; b ^= rot(a, 6); a += c; \ c -= b; c ^= rot(b, 8); b += a; \ a -= c; a ^= rot(c,16); c += b; \ b -= a; b ^= rot(a,19); a += c; \ c -= b; c ^= rot(b, 4); b += a; \ } /* ------------------------------------------------------------------------------- final -- final mixing of 3 32-bit values (a,b,c) into c Pairs of (a,b,c) values differing in only a few bits will usually produce values of c that look totally different. This was tested for * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. These constants passed: 14 11 25 16 4 14 24 12 14 25 16 4 14 24 and these came close: 4 8 15 26 3 22 24 10 8 15 26 3 22 24 11 8 15 26 3 22 24 ------------------------------------------------------------------------------- */ #define final(a,b,c) \ { \ c ^= b; c -= rot(b,14); \ a ^= c; a -= rot(c,11); \ b ^= a; b -= rot(a,25); \ c ^= b; c -= rot(b,16); \ a ^= c; a -= rot(c,4); \ b ^= a; b -= rot(a,14); \ c ^= b; c -= rot(b,24); \ } /* -------------------------------------------------------------------- This works on all machines. To be useful, it requires -- that the key be an array of uint32_t's, and -- that the length be the number of uint32_t's in the key The function hashword() is identical to hashlittle() on little-endian machines, and identical to hashbig() on big-endian machines, except that the length has to be measured in uint32_ts rather than in bytes. hashlittle() is more complicated than hashword() only because hashlittle() has to dance around fitting the key bytes into registers. -------------------------------------------------------------------- */ uint32_t hashword( const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t initval) /* the previous hash, or an arbitrary value */ { uint32_t a,b,c; /* Set up the internal state */ a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval; /*------------------------------------------------- handle most of the key */ while (length > 3) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 3; k += 3; } /*------------------------------------------- handle the last 3 uint32_t's */ switch(length) /* all the case statements fall through */ { case 3 : c+=k[2]; case 2 : b+=k[1]; case 1 : a+=k[0]; final(a,b,c); case 0: /* case 0: nothing left to add */ break; } /*------------------------------------------------------ report the result */ return c; } /* -------------------------------------------------------------------- hashword2() -- same as hashword(), but take two seeds and return two 32-bit values. pc and pb must both be nonnull, and *pc and *pb must both be initialized with seeds. If you pass in (*pb)==0, the output (*pc) will be the same as the return value from hashword(). -------------------------------------------------------------------- */ void hashword2 ( const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t *pc, /* IN: seed OUT: primary hash value */ uint32_t *pb) /* IN: more seed OUT: secondary hash value */ { uint32_t a,b,c; /* Set up the internal state */ a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc; c += *pb; /*------------------------------------------------- handle most of the key */ while (length > 3) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 3; k += 3; } /*------------------------------------------- handle the last 3 uint32_t's */ switch(length) /* all the case statements fall through */ { case 3 : c+=k[2]; case 2 : b+=k[1]; case 1 : a+=k[0]; final(a,b,c); case 0: /* case 0: nothing left to add */ break; } /*------------------------------------------------------ report the result */ *pc=c; *pb=b; } /* ------------------------------------------------------------------------------- hashlittle() -- hash a variable-length key into a 32-bit value k : the key (the unaligned variable-length array of bytes) length : the length of the key, counting by bytes initval : can be any 4-byte value Returns a 32-bit value. Every bit of the key affects every bit of the return value. Two keys differing by one or two bits will have totally different hash values. The best hash table sizes are powers of 2. There is no need to do mod a prime (mod is sooo slow!). If you need less than 32 bits, use a bitmask. For example, if you need only 10 bits, do h = (h & hashmask(10)); In which case, the hash table should have hashsize(10) elements. If you are hashing n strings (uint8_t **)k, do it like this: for (i=0, h=0; i 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff; a+=k[0]; break; case 6 : b+=k[1]&0xffff; a+=k[0]; break; case 5 : b+=k[1]&0xff; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff; break; case 2 : a+=k[0]&0xffff; break; case 1 : a+=k[0]&0xff; break; case 0 : return c; /* zero length strings require no mixing */ } #else /* make valgrind happy */ const uint8_t *k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : return c; } #endif /* !valgrind */ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : return c; /* zero length requires no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; case 11: c+=((uint32_t)k[10])<<16; case 10: c+=((uint32_t)k[9])<<8; case 9 : c+=k[8]; case 8 : b+=((uint32_t)k[7])<<24; case 7 : b+=((uint32_t)k[6])<<16; case 6 : b+=((uint32_t)k[5])<<8; case 5 : b+=k[4]; case 4 : a+=((uint32_t)k[3])<<24; case 3 : a+=((uint32_t)k[2])<<16; case 2 : a+=((uint32_t)k[1])<<8; case 1 : a+=k[0]; break; case 0 : return c; } } final(a,b,c); return c; } /* * hashlittle2: return 2 32-bit hash values * * This is identical to hashlittle(), except it returns two 32-bit hash * values instead of just one. This is good enough for hash table * lookup with 2^^64 buckets, or if you want a second hash if you're not * happy with the first, or if you want a probably-unique 64-bit ID for * the key. *pc is better mixed than *pb, so use *pc first. If you want * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". */ void hashlittle2( const void *key, /* the key to hash */ size_t length, /* length of the key */ uint32_t *pc, /* IN: primary initval, OUT: primary hash */ uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ { uint32_t a,b,c; /* internal state */ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ /* Set up the internal state */ a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc; c += *pb; u.ptr = key; if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff; a+=k[0]; break; case 6 : b+=k[1]&0xffff; a+=k[0]; break; case 5 : b+=k[1]&0xff; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff; break; case 2 : a+=k[0]&0xffff; break; case 1 : a+=k[0]&0xff; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } #else /* make valgrind happy */ const uint8_t *k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } #endif /* !valgrind */ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; case 11: c+=((uint32_t)k[10])<<16; case 10: c+=((uint32_t)k[9])<<8; case 9 : c+=k[8]; case 8 : b+=((uint32_t)k[7])<<24; case 7 : b+=((uint32_t)k[6])<<16; case 6 : b+=((uint32_t)k[5])<<8; case 5 : b+=k[4]; case 4 : a+=((uint32_t)k[3])<<24; case 3 : a+=((uint32_t)k[2])<<16; case 2 : a+=((uint32_t)k[1])<<8; case 1 : a+=k[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } } final(a,b,c); *pc=c; *pb=b; } /* * hashbig(): * This is the same as hashword() on big-endian machines. It is different * from hashlittle() on all machines. hashbig() takes advantage of * big-endian byte ordering. */ uint32_t hashbig( const void *key, size_t length, uint32_t initval) { uint32_t a,b,c; union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ /* Set up the internal state */ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; u.ptr = key; if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]<<8" actually reads beyond the end of the string, but * then shifts out the part it's not allowed to read. Because the * string is aligned, the illegal read is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; case 5 : b+=k[1]&0xff000000; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff00; break; case 2 : a+=k[0]&0xffff0000; break; case 1 : a+=k[0]&0xff000000; break; case 0 : return c; /* zero length strings require no mixing */ } #else /* make valgrind happy */ const uint8_t *k8 = (const uint8_t *)k; switch(length) /* all the case statements fall through */ { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ case 1 : a+=((uint32_t)k8[0])<<24; break; case 0 : return c; } #endif /* !VALGRIND */ } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += ((uint32_t)k[0])<<24; a += ((uint32_t)k[1])<<16; a += ((uint32_t)k[2])<<8; a += ((uint32_t)k[3]); b += ((uint32_t)k[4])<<24; b += ((uint32_t)k[5])<<16; b += ((uint32_t)k[6])<<8; b += ((uint32_t)k[7]); c += ((uint32_t)k[8])<<24; c += ((uint32_t)k[9])<<16; c += ((uint32_t)k[10])<<8; c += ((uint32_t)k[11]); mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=k[11]; case 11: c+=((uint32_t)k[10])<<8; case 10: c+=((uint32_t)k[9])<<16; case 9 : c+=((uint32_t)k[8])<<24; case 8 : b+=k[7]; case 7 : b+=((uint32_t)k[6])<<8; case 6 : b+=((uint32_t)k[5])<<16; case 5 : b+=((uint32_t)k[4])<<24; case 4 : a+=k[3]; case 3 : a+=((uint32_t)k[2])<<8; case 2 : a+=((uint32_t)k[1])<<16; case 1 : a+=((uint32_t)k[0])<<24; break; case 0 : return c; } } final(a,b,c); return c; } #ifdef SELF_TEST /* used for timings */ void driver1() { uint8_t buf[256]; uint32_t i; uint32_t h=0; time_t a,z; time(&a); for (i=0; i<256; ++i) buf[i] = 'x'; for (i=0; i<1; ++i) { h = hashlittle(&buf[0],1,h); } time(&z); if (z-a > 0) printf("time %d %.8x\n", z-a, h); } /* check that every input bit changes every output bit half the time */ #define HASHSTATE 1 #define HASHLEN 1 #define MAXPAIR 60 #define MAXLEN 70 void driver2() { uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; uint32_t x[HASHSTATE],y[HASHSTATE]; uint32_t hlen; printf("No more than %d trials should ever be needed \n",MAXPAIR/2); for (hlen=0; hlen < MAXLEN; ++hlen) { z=0; for (i=0; i>(8-j)); c[0] = hashlittle(a, hlen, m); b[i] ^= ((k+1)<>(8-j)); d[0] = hashlittle(b, hlen, m); /* check every bit is 1, 0, set, and not set at least once */ for (l=0; lz) z=k; if (k==MAXPAIR) { printf("Some bit didn't change: "); printf("%.8x %.8x %.8x %.8x %.8x %.8x ", e[0],f[0],g[0],h[0],x[0],y[0]); printf("i %d j %d m %d len %d\n", i, j, m, hlen); } if (z==MAXPAIR) goto done; } } } done: if (z < MAXPAIR) { printf("Mix success %2d bytes %2d initvals ",i,m); printf("required %d trials\n", z/2); } } printf("\n"); } /* Check for reading beyond the end of the buffer and alignment problems */ void driver3() { uint8_t buf[MAXLEN+20], *b; uint32_t len; uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; uint32_t h; uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; uint32_t i; uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; uint32_t j; uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; uint32_t ref,x,y; uint8_t *p; printf("Endianness. These lines should all be the same (for values filled in):\n"); printf("%.8x %.8x %.8x\n", hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13), hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13), hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13)); p = q; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qq[1]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qqq[2]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qqqq[3]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); printf("\n"); /* check that hashlittle2 and hashlittle produce the same results */ i=47; j=0; hashlittle2(q, sizeof(q), &i, &j); if (hashlittle(q, sizeof(q), 47) != i) printf("hashlittle2 and hashlittle mismatch\n"); /* check that hashword2 and hashword produce the same results */ len = 0xdeadbeef; i=47, j=0; hashword2(&len, 1, &i, &j); if (hashword(&len, 1, 47) != i) printf("hashword2 and hashword mismatch %x %x\n", i, hashword(&len, 1, 47)); /* check hashlittle doesn't read before or after the ends of the string */ for (h=0, b=buf+1; h<8; ++h, ++b) { for (i=0; i * */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-spm-bm.h" #include "util-unittest.h" #include "util-unittest-helper.h" static int DetectPktDataSetup (DetectEngineCtx *, Signature *, char *); static void DetectPktDataTestRegister(void); /** * \brief Registration function for keyword: file_data */ void DetectPktDataRegister(void) { sigmatch_table[DETECT_PKT_DATA].name = "pkt_data"; sigmatch_table[DETECT_PKT_DATA].Match = NULL; sigmatch_table[DETECT_PKT_DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_PKT_DATA].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_PKT_DATA].Setup = DetectPktDataSetup; sigmatch_table[DETECT_PKT_DATA].Free = NULL; sigmatch_table[DETECT_PKT_DATA].RegisterTests = DetectPktDataTestRegister; } /** * \brief this function is used to parse pkt_data options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param str pointer to the user provided "filestore" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectPktDataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); s->init_flags &= (~SIG_FLAG_INIT_FILE_DATA); return 0; } #ifdef UNITTESTS /************************************Unittests*********************************/ static int DetectPktDataTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; SigMatch *sm = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; Signature *sig = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"in file data\";" " pkt_data; content:\"in pkt data\";)"); de_ctx->sig_list = sig; if (de_ctx->sig_list == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE,"could not load test signature"); goto end; } /* sm should be in the MATCH list */ sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; if (sm == NULL) { printf("sm not in DETECT_SM_LIST_HSBDMATCH: "); goto end; } sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm == NULL) { printf("sm not in DETECT_SM_LIST_PMATCH: "); goto end; } if (sm->type != DETECT_CONTENT) { printf("sm type not DETECT_AL_HTTP_SERVER_BODY: "); goto end; } if (sm->next != NULL) { goto end; } if (sig->init_flags & SIG_FLAG_INIT_FILE_DATA) { printf("sm init_flags SIG_FLAG_INIT_FILE_DATA set: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif static void DetectPktDataTestRegister(void){ #ifdef UNITTESTS UtRegisterTest("DetectPktDataTest01", DetectPktDataTest01, 1); #endif } suricata-1.4.7/src/detect-content.h0000644000000000000000000000724212253546156014123 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_CONTENT_H__ #define __DETECT_CONTENT_H__ /* Flags affecting this content */ #define DETECT_CONTENT_NOCASE (1) #define DETECT_CONTENT_DISTANCE (1 << 1) #define DETECT_CONTENT_WITHIN (1 << 2) #define DETECT_CONTENT_OFFSET (1 << 3) #define DETECT_CONTENT_DEPTH (1 << 4) #define DETECT_CONTENT_FAST_PATTERN (1 << 5) #define DETECT_CONTENT_FAST_PATTERN_ONLY (1 << 6) #define DETECT_CONTENT_FAST_PATTERN_CHOP (1 << 7) /** content applies to a "raw"/undecoded field if applicable */ #define DETECT_CONTENT_RAWBYTES (1 << 8) /** content is negated */ #define DETECT_CONTENT_NEGATED (1 << 9) /** a relative match to this content is next, used in matching phase */ #define DETECT_CONTENT_RELATIVE_NEXT (1 << 10) /* BE - byte extract */ #define DETECT_CONTENT_OFFSET_BE (1 << 11) #define DETECT_CONTENT_DEPTH_BE (1 << 12) #define DETECT_CONTENT_DISTANCE_BE (1 << 13) #define DETECT_CONTENT_WITHIN_BE (1 << 14) /* replace data */ #define DETECT_CONTENT_REPLACE (1 << 15) /* this flag is set during the staging phase. It indicates that a content * has been added to the mpm phase and requires no further inspection inside * the inspection phase */ #define DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED (1 << 16) #define DETECT_CONTENT_IS_SINGLE(c) (!( ((c)->flags & DETECT_CONTENT_DISTANCE) || \ ((c)->flags & DETECT_CONTENT_WITHIN) || \ ((c)->flags & DETECT_CONTENT_RELATIVE_NEXT) || \ ((c)->flags & DETECT_CONTENT_DEPTH) || \ ((c)->flags & DETECT_CONTENT_OFFSET) )) #include "util-spm-bm.h" typedef struct DetectContentData_ { uint8_t *content; uint8_t content_len; /* would want to move PatIntId here and flags down to remove the padding * gap, but I think the first four members was used as a template for * casting. \todo check this and fix it if posssible */ uint32_t flags; PatIntId id; uint16_t depth; uint16_t offset; int32_t distance; int32_t within; /* Boyer Moore context (for spm search) */ BmCtx *bm_ctx; /* for chopped fast pattern, the offset */ uint16_t fp_chop_offset; /* for chopped fast pattern, the length */ uint16_t fp_chop_len; /* pointer to replacement data */ uint8_t *replace; uint8_t replace_len; } DetectContentData; /* prototypes */ void DetectContentRegister (void); uint32_t DetectContentMaxId(DetectEngineCtx *); DetectContentData *DetectContentParse (char *contentstr); int DetectContentDataParse(char *keyword, char *contentstr, char** pstr, uint16_t *plen, int *flags); DetectContentData *DetectContentParseEncloseQuotes(char *); void DetectContentPrint(DetectContentData *); void DetectContentFree(void *); #endif /* __DETECT_CONTENT_H__ */ suricata-1.4.7/src/util-crypt.c0000644000000000000000000002011412253546156013303 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Roliers Jean-Paul * * Implements cryptographic functions. * Based on the libtomcrypt library ( http://libtom.org/?page=features&newsitems=5&whatfile=crypt ) * * Implementation of function using NSS is not linked with libtomcrypt. */ #include "suricata-common.h" #include "suricata.h" #include "util-crypt.h" #ifdef HAVE_NSS #include #endif #ifndef HAVE_NSS #define F0(x,y,z) (z ^ (x & (y ^ z))) #define F1(x,y,z) (x ^ y ^ z) #define F2(x,y,z) ((x & y) | (z & (x | y))) #define F3(x,y,z) (x ^ y ^ z) static int Sha1Compress(HashState *md, unsigned char *buf) { uint32_t a,b,c,d,e,W[80],i; /* copy the state into 512-bits into W[0..15] */ for (i = 0; i < 16; i++) { LOAD32H(W[i], buf + (4*i)); } /* copy state */ a = md->sha1.state[0]; b = md->sha1.state[1]; c = md->sha1.state[2]; d = md->sha1.state[3]; e = md->sha1.state[4]; /* expand it */ for (i = 16; i < 80; i++) { W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); } /* compress */ /* round one */ #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30); #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30); #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30); #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30); for (i = 0; i < 20; ) { FF0(a,b,c,d,e,i++); FF0(e,a,b,c,d,i++); FF0(d,e,a,b,c,i++); FF0(c,d,e,a,b,i++); FF0(b,c,d,e,a,i++); } /* round two */ for (; i < 40; ) { FF1(a,b,c,d,e,i++); FF1(e,a,b,c,d,i++); FF1(d,e,a,b,c,i++); FF1(c,d,e,a,b,i++); FF1(b,c,d,e,a,i++); } /* round three */ for (; i < 60; ) { FF2(a,b,c,d,e,i++); FF2(e,a,b,c,d,i++); FF2(d,e,a,b,c,i++); FF2(c,d,e,a,b,i++); FF2(b,c,d,e,a,i++); } /* round four */ for (; i < 80; ) { FF3(a,b,c,d,e,i++); FF3(e,a,b,c,d,i++); FF3(d,e,a,b,c,i++); FF3(c,d,e,a,b,i++); FF3(b,c,d,e,a,i++); } #undef FF0 #undef FF1 #undef FF2 #undef FF3 /* store */ md->sha1.state[0] = md->sha1.state[0] + a; md->sha1.state[1] = md->sha1.state[1] + b; md->sha1.state[2] = md->sha1.state[2] + c; md->sha1.state[3] = md->sha1.state[3] + d; md->sha1.state[4] = md->sha1.state[4] + e; return SC_SHA_1_OK; } static int Sha1Init(HashState * md) { if(md == NULL) { return SC_SHA_1_NOK; } md->sha1.state[0] = 0x67452301UL; md->sha1.state[1] = 0xefcdab89UL; md->sha1.state[2] = 0x98badcfeUL; md->sha1.state[3] = 0x10325476UL; md->sha1.state[4] = 0xc3d2e1f0UL; md->sha1.curlen = 0; md->sha1.length = 0; return SC_SHA_1_OK; } static int Sha1Process (HashState * md, const unsigned char *in, unsigned long inlen) { if(md == NULL || in == NULL) { return SC_SHA_1_INVALID_ARG; } unsigned long n; int err; if (md->sha1.curlen > sizeof(md->sha1.buf)) { return SC_SHA_1_INVALID_ARG; } while (inlen > 0) { if (md-> sha1.curlen == 0 && inlen >= 64) { if ((err = Sha1Compress(md, (unsigned char *)in)) != SC_SHA_1_OK) { return err; } md-> sha1 .length += 64 * 8; in += 64; inlen -= 64; } else { n = MIN(inlen, (64 - md-> sha1 .curlen)); memcpy(md-> sha1 .buf + md-> sha1.curlen, in, (size_t)n); md-> sha1 .curlen += n; in += n; inlen -= n; if (md-> sha1 .curlen == 64) { if ((err = Sha1Compress(md, md-> sha1 .buf)) != SC_SHA_1_OK) { return err; } md-> sha1 .length += 8*64; md-> sha1 .curlen = 0; } } } return SC_SHA_1_OK; } static int Sha1Done(HashState * md, unsigned char *out) { int i; if (md == NULL || out == NULL) { return SC_SHA_1_NOK; } if (md->sha1.curlen >= sizeof(md->sha1.buf)) { return SC_SHA_1_INVALID_ARG; } /* increase the length of the message */ md->sha1.length += md->sha1.curlen * 8; /* append the '1' bit */ md->sha1.buf[md->sha1.curlen++] = (unsigned char)0x80; /* if the length is currently above 56 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->sha1.curlen > 56) { while (md->sha1.curlen < 64) { md->sha1.buf[md->sha1.curlen++] = (unsigned char)0; } Sha1Compress(md, md->sha1.buf); md->sha1.curlen = 0; } /* pad upto 56 bytes of zeroes */ while (md->sha1.curlen < 56) { md->sha1.buf[md->sha1.curlen++] = (unsigned char)0; } /* store length */ STORE64H(md->sha1.length, md->sha1.buf+56); Sha1Compress(md, md->sha1.buf); /* copy output */ for (i = 0; i < 5; i++) { STORE32H(md->sha1.state[i], out+(4*i)); } memset(md, 0, sizeof(HashState)); return SC_SHA_1_OK; } unsigned char* ComputeSHA1(unsigned char* buff, int bufflen) { HashState md; unsigned char* lResult = (unsigned char*) SCMalloc((sizeof(unsigned char) * 20)); if (lResult == NULL) return NULL; Sha1Init(&md); Sha1Process(&md, buff, bufflen); Sha1Done(&md, lResult); return lResult; } #else /* HAVE_NSS */ unsigned char* ComputeSHA1(unsigned char* buff, int bufflen) { HASHContext *sha1_ctx = HASH_Create(HASH_AlgSHA1); unsigned char* lResult = NULL; unsigned int rlen; if (sha1_ctx == NULL) { return NULL; } lResult = (unsigned char*) SCMalloc((sizeof(unsigned char) * 20)); if (lResult == NULL) { HASH_Destroy(sha1_ctx); return NULL; } HASH_Begin(sha1_ctx); HASH_Update(sha1_ctx, buff, bufflen); HASH_End(sha1_ctx, lResult, &rlen, (sizeof(unsigned char) * 20)); HASH_Destroy(sha1_ctx); return lResult; } #endif /* HAVE_NSS */ static const char *b64codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int Base64Encode(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen) { unsigned long i, len2, leven; unsigned char *p; if(in == NULL || out == NULL || outlen == NULL) { return SC_BASE64_INVALID_ARG; } /* valid output size ? */ len2 = 4 * ((inlen + 2) / 3); if (*outlen < len2 + 1) { *outlen = len2 + 1; return SC_BASE64_OVERFLOW; } p = out; leven = 3*(inlen / 3); for (i = 0; i < leven; i += 3) { *p++ = b64codes[(in[0] >> 2) & 0x3F]; *p++ = b64codes[(((in[0] & 3) << 4) + (in[1] >> 4)) & 0x3F]; *p++ = b64codes[(((in[1] & 0xf) << 2) + (in[2] >> 6)) & 0x3F]; *p++ = b64codes[in[2] & 0x3F]; in += 3; } /* Pad it if necessary... */ if (i < inlen) { unsigned a = in[0]; unsigned b = (i+1 < inlen) ? in[1] : 0; *p++ = b64codes[(a >> 2) & 0x3F]; *p++ = b64codes[(((a & 3) << 4) + (b >> 4)) & 0x3F]; *p++ = (i+1 < inlen) ? b64codes[(((b & 0xf) << 2)) & 0x3F] : '='; *p++ = '='; } /* append a NULL byte */ *p = '\0'; /* return ok */ *outlen = p - out; return SC_BASE64_OK; } suricata-1.4.7/src/detect-engine-sigorder.h0000644000000000000000000000512212253546156015525 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_SIGORDER_H__ #define __DETECT_ENGINE_SIGORDER_H__ /** * \brief Different kinds of helper data that can be used by the signature * ordering module. Used by the "user" field in SCSigSignatureWrapper */ typedef enum{ SC_RADIX_USER_DATA_FLOWBITS, SC_RADIX_USER_DATA_FLOWVAR, SC_RADIX_USER_DATA_PKTVAR, SC_RADIX_USER_DATA_FLOWINT, SC_RADIX_USER_DATA_MAX } SCRadixUserDataType; /** * \brief Signature wrapper used by signature ordering module while ordering * signatures */ typedef struct SCSigSignatureWrapper_ { /* the wrapped signature */ Signature *sig; /* used as the lower limit SCSigSignatureWrapper that is used by the next * ordering function, which will order the incoming Sigwrapper after this * (min) wrapper */ struct SCSigSignatureWrapper_ *min; /* used as the upper limit SCSigSignatureWrapper that is used by the next * ordering function, which will order the incoming Sigwrapper below this * (max) wrapper */ struct SCSigSignatureWrapper_ *max; /* user data that is to be associated with this sigwrapper */ int **user; struct SCSigSignatureWrapper_ *next; struct SCSigSignatureWrapper_ *prev; } SCSigSignatureWrapper; /** * \brief Structure holding the signature ordering function used by the * signature ordering module */ typedef struct SCSigOrderFunc_ { /* Pointer to the Signature Ordering function */ int (*SWCompare)(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2); struct SCSigOrderFunc_ *next; } SCSigOrderFunc; void SCSigOrderSignatures(DetectEngineCtx *); void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *); void SCSigRegisterSignatureOrderingTests(void); void SCSigSignatureOrderingModuleCleanup(DetectEngineCtx *); #endif /* __DETECT_ENGINE_SIGORDER_H__ */ suricata-1.4.7/src/detect-geoip.h0000644000000000000000000000244412253546156013553 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Ignacio Sanchez */ #ifndef __DETECT_GEOIP_H__ #define __DETECT_GEOIP_H__ #ifdef HAVE_GEOIP #include #include "util-spm-bm.h" #define GEOOPTION_MAXSIZE 3 /* Country Code (2 chars) + NULL */ #define GEOOPTION_MAXLOCATIONS 64 typedef struct DetectGeoipData_ { uint8_t location[GEOOPTION_MAXLOCATIONS][GEOOPTION_MAXSIZE]; /** country code for now, null term.*/ int nlocations; /** number of location strings parsed */ uint32_t flags; GeoIP *geoengine; } DetectGeoipData; #endif void DetectGeoipRegister(void); #endif suricata-1.4.7/src/app-layer-smtp.h0000644000000000000000000000622412253546156014055 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __APP_LAYER_SMTP_H__ #define __APP_LAYER_SMTP_H__ #include "decode-events.h" enum { SMTP_DECODER_EVENT_INVALID_REPLY, SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST, SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED, SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE, SMTP_DECODER_EVENT_TLS_REJECTED, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED, }; typedef struct SMTPState_ { /* current input that is being parsed */ uint8_t *input; int32_t input_len; uint8_t direction; /* --parser details-- */ /** current line extracted by the parser from the call to SMTPGetline() */ uint8_t *current_line; /** length of the line in current_line. Doesn't include the delimiter */ int32_t current_line_len; uint8_t current_line_delimiter_len; PatternMatcherQueue *thread_local_data; /** used to indicate if the current_line buffer is a malloced buffer. We * use a malloced buffer, if a line is fragmented */ uint8_t *tc_db; int32_t tc_db_len; uint8_t tc_current_line_db; /** we have see LF for the currently parsed line */ uint8_t tc_current_line_lf_seen; /** used to indicate if the current_line buffer is a malloced buffer. We * use a malloced buffer, if a line is fragmented */ uint8_t *ts_db; int32_t ts_db_len; uint8_t ts_current_line_db; /** we have see LF for the currently parsed line */ uint8_t ts_current_line_lf_seen; /** var to indicate parser state */ uint8_t parser_state; /** current command in progress */ uint8_t current_command; /** bdat chunk len */ uint32_t bdat_chunk_len; /** bdat chunk idx */ uint32_t bdat_chunk_idx; /* the request commands are store here and the reply handler uses these * stored command in the buffer to match the reply(ies) with the command */ /** the command buffer */ uint8_t *cmds; /** the buffer length */ uint16_t cmds_buffer_len; /** no of commands stored in the above buffer */ uint16_t cmds_cnt; /** index of the command in the buffer, currently in inspection by reply * handler */ uint16_t cmds_idx; } SMTPState; void RegisterSMTPParsers(void); void SMTPParserRegisterTests(void); #endif /* __APP_LAYER_SMTP_H__ */ suricata-1.4.7/src/detect-filemagic.h0000644000000000000000000000247612253546156014375 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_FILEMAGIC_H__ #define __DETECT_FILEMAGIC_H__ #include "util-spm-bm.h" #include typedef struct DetectFilemagicThreadData { magic_t ctx; } DetectFilemagicThreadData; typedef struct DetectFilemagicData { int thread_ctx_id; uint8_t *name; /** name of the file to match */ BmCtx *bm_ctx; /** BM context */ uint16_t len; /** name length */ uint32_t flags; } DetectFilemagicData; /* prototypes */ void DetectFilemagicRegister (void); int FilemagicGlobalLookup(File *file); #endif /* __DETECT_FILEMAGIC_H__ */ suricata-1.4.7/src/util-ringbuffer.c0000644000000000000000000006520712253546156014307 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Ringbuffer implementation that is lockless for the most part IF atomic * operations are available. * * Two sizes are implemented currently: 256 and 65536. Those sizes are chosen * for simplicity when working with the read and write indexes. Both can just * wrap around. * * Implemented are: * Single reader, single writer (lockless) * Single reader, multi writer (partly locked) * Multi reader, single writer (lockless) * Multi reader, multi writer (partly locked) */ #include "suricata-common.h" #include "suricata.h" #include "util-ringbuffer.h" #include "util-atomic.h" #include "util-unittest.h" #define USLEEP_TIME 5 /** \brief wait function for condition where ringbuffer is either * full or empty. * * \param rb ringbuffer * * Based on RINGBUFFER_MUTEX_WAIT define, we either sleep and spin * or use thread condition to wait. */ static inline void RingBuffer8DoWait(RingBuffer8 *rb) { #ifdef RINGBUFFER_MUTEX_WAIT SCMutexLock(&rb->wait_mutex); SCCondWait(&rb->wait_cond, &rb->wait_mutex); SCMutexUnlock(&rb->wait_mutex); #else usleep(USLEEP_TIME); #endif } /** \brief wait function for condition where ringbuffer is either * full or empty. * * \param rb ringbuffer * * Based on RINGBUFFER_MUTEX_WAIT define, we either sleep and spin * or use thread condition to wait. */ static inline void RingBufferDoWait(RingBuffer16 *rb) { #ifdef RINGBUFFER_MUTEX_WAIT SCMutexLock(&rb->wait_mutex); SCCondWait(&rb->wait_cond, &rb->wait_mutex); SCMutexUnlock(&rb->wait_mutex); #else usleep(USLEEP_TIME); #endif } /** \brief wait function for condition where ringbuffer is either * full or empty. * * \param rb ringbuffer * * Based on RINGBUFFER_MUTEX_WAIT define, we either sleep and spin * or use thread condition to wait. */ void RingBufferWait(RingBuffer16 *rb) { RingBufferDoWait(rb); } /** \brief tell the ringbuffer to shut down * * \param rb ringbuffer */ void RingBuffer8Shutdown(RingBuffer8 *rb) { rb->shutdown = 1; #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif } /** \brief check the ringbuffer is empty (no data in it) * * \param rb ringbuffer * * \retval 1 empty * \retval 0 not empty */ int RingBuffer8IsEmpty(RingBuffer8 *rb) { if (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { return 1; } return 0; } /** \brief check the ringbuffer is full (no more data will fit) * * \param rb ringbuffer * * \retval 1 empty * \retval 0 not empty */ int RingBuffer8IsFull(RingBuffer8 *rb) { if ((unsigned char)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { return 1; } return 0; } /** \brief tell the ringbuffer to shut down * * \param rb ringbuffer */ void RingBufferShutdown(RingBuffer16 *rb) { rb->shutdown = 1; #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif } /** \brief get number of items in the ringbuffer */ uint16_t RingBufferSize(RingBuffer16 *rb) { SCEnter(); uint16_t size = (uint16_t)(SC_ATOMIC_GET(rb->write) - SC_ATOMIC_GET(rb->read)); SCReturnUInt(size); } /** \brief check the ringbuffer is empty (no data in it) * * \param rb ringbuffer * * \retval 1 empty * \retval 0 not empty */ int RingBufferIsEmpty(RingBuffer16 *rb) { if (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { return 1; } return 0; } /** \brief check the ringbuffer is full (no more data will fit) * * \param rb ringbuffer * * \retval 1 empty * \retval 0 not empty */ int RingBufferIsFull(RingBuffer16 *rb) { if ((unsigned short)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { return 1; } return 0; } /* Single Reader, Single Writer, 8 bits */ void *RingBufferSrSw8Get(RingBuffer8 *rb) { void *ptr = NULL; /* buffer is empty, wait... */ while (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return NULL; RingBuffer8DoWait(rb); } ptr = rb->array[SC_ATOMIC_GET(rb->read)]; (void) SC_ATOMIC_ADD(rb->read, 1); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return ptr; } int RingBufferSrSw8Put(RingBuffer8 *rb, void *ptr) { /* buffer is full, wait... */ while ((unsigned char)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return -1; RingBuffer8DoWait(rb); } rb->array[SC_ATOMIC_GET(rb->write)] = ptr; (void) SC_ATOMIC_ADD(rb->write, 1); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return 0; } /* Single Reader, Multi Writer, 8 bites */ void *RingBufferSrMw8Get(RingBuffer8 *rb) { void *ptr = NULL; /* buffer is empty, wait... */ while (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return NULL; RingBuffer8DoWait(rb); } ptr = rb->array[SC_ATOMIC_GET(rb->read)]; (void) SC_ATOMIC_ADD(rb->read, 1); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return ptr; } /** * \brief put a ptr in the RingBuffer. * * As we support multiple writers we need to protect 2 things: * 1. writing the ptr to the array * 2. incrementing the rb->write idx * * We can't do both at the same time in one atomic operation, so * we need to (spin) lock it. We do increment rb->write atomically * after that, so that we don't need to use the lock in our *Get * function. * * \param rb the ringbuffer * \param ptr ptr to store * * \retval 0 ok * \retval -1 wait loop interrupted because of engine flags */ int RingBufferSrMw8Put(RingBuffer8 *rb, void *ptr) { SCLogDebug("ptr %p", ptr); /* buffer is full, wait... */ retry: while ((unsigned char)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return -1; RingBuffer8DoWait(rb); } /* get our lock */ SCSpinLock(&rb->spin); /* if while we got our lock the buffer changed, we need to retry */ if ((unsigned char)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { SCSpinUnlock(&rb->spin); goto retry; } SCLogDebug("rb->write %u, ptr %p", SC_ATOMIC_GET(rb->write), ptr); /* update the ring buffer */ rb->array[SC_ATOMIC_GET(rb->write)] = ptr; (void) SC_ATOMIC_ADD(rb->write, 1); SCSpinUnlock(&rb->spin); SCLogDebug("ptr %p, done", ptr); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return 0; } /* Multi Reader, Single Writer, 8 bits */ /** * \brief get the next ptr from the ring buffer * * Because we allow for multiple readers we take great care in making sure * that the threads don't interfere with one another. * */ void *RingBufferMrSw8Get(RingBuffer8 *rb) { void *ptr; /** local pointer for data races. If SCAtomicCompareAndSwap (CAS) * fails we increase our local array idx to try the next array member * until we succeed. Or when the buffer is empty again we jump back * to the waiting loop. */ unsigned char readp; /* buffer is empty, wait... */ retry: while (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return NULL; RingBuffer8DoWait(rb); } /* atomically update rb->read */ readp = SC_ATOMIC_GET(rb->read) - 1; do { /* with multiple readers we can get in the situation that we exitted * from the wait loop but the rb is empty again once we get here. */ if (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) goto retry; readp++; ptr = rb->array[readp]; } while (!(SC_ATOMIC_CAS(&rb->read, readp, (readp + 1)))); SCLogDebug("ptr %p", ptr); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return ptr; } /** * \brief put a ptr in the RingBuffer */ int RingBufferMrSw8Put(RingBuffer8 *rb, void *ptr) { SCLogDebug("ptr %p", ptr); /* buffer is full, wait... */ while ((unsigned char)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return -1; RingBuffer8DoWait(rb); } rb->array[SC_ATOMIC_GET(rb->write)] = ptr; (void) SC_ATOMIC_ADD(rb->write, 1); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return 0; } /* Multi Reader, Single Writer */ /** * \brief get the next ptr from the ring buffer * * Because we allow for multiple readers we take great care in making sure * that the threads don't interfere with one another. * */ void *RingBufferMrSwGet(RingBuffer16 *rb) { void *ptr; /** local pointer for data races. If SCAtomicCompareAndSwap (CAS) * fails we increase our local array idx to try the next array member * until we succeed. Or when the buffer is empty again we jump back * to the waiting loop. */ unsigned short readp; /* buffer is empty, wait... */ retry: while (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return NULL; RingBufferDoWait(rb); } /* atomically update rb->read */ readp = SC_ATOMIC_GET(rb->read) - 1; do { /* with multiple readers we can get in the situation that we exitted * from the wait loop but the rb is empty again once we get here. */ if (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) goto retry; readp++; ptr = rb->array[readp]; } while (!(SC_ATOMIC_CAS(&rb->read, readp, (readp + 1)))); SCLogDebug("ptr %p", ptr); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return ptr; } /** * \brief put a ptr in the RingBuffer */ int RingBufferMrSwPut(RingBuffer16 *rb, void *ptr) { SCLogDebug("ptr %p", ptr); /* buffer is full, wait... */ while ((unsigned short)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return -1; RingBufferDoWait(rb); } rb->array[SC_ATOMIC_GET(rb->write)] = ptr; (void) SC_ATOMIC_ADD(rb->write, 1); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return 0; } /* Single Reader, Single Writer */ void *RingBufferSrSwGet(RingBuffer16 *rb) { void *ptr = NULL; /* buffer is empty, wait... */ while (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return NULL; RingBufferDoWait(rb); } ptr = rb->array[SC_ATOMIC_GET(rb->read)]; (void) SC_ATOMIC_ADD(rb->read, 1); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return ptr; } int RingBufferSrSwPut(RingBuffer16 *rb, void *ptr) { /* buffer is full, wait... */ while ((unsigned short)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return -1; RingBufferDoWait(rb); } rb->array[SC_ATOMIC_GET(rb->write)] = ptr; (void) SC_ATOMIC_ADD(rb->write, 1); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return 0; } /* Multi Reader, Multi Writer, 8 bits */ RingBuffer8 *RingBuffer8Init(void) { RingBuffer8 *rb = SCMalloc(sizeof(RingBuffer8)); if (unlikely(rb == NULL)) { return NULL; } memset(rb, 0x00, sizeof(RingBuffer8)); SC_ATOMIC_INIT(rb->write); SC_ATOMIC_INIT(rb->read); SCSpinInit(&rb->spin, 0); #ifdef RINGBUFFER_MUTEX_WAIT SCMutexInit(&rb->wait_mutex, NULL); SCCondInit(&rb->wait_cond, NULL); #endif return rb; } void RingBuffer8Destroy(RingBuffer8 *rb) { if (rb != NULL) { SC_ATOMIC_DESTROY(rb->write); SC_ATOMIC_DESTROY(rb->read); SCSpinDestroy(&rb->spin); #ifdef RINGBUFFER_MUTEX_WAIT SCMutexDestroy(&rb->wait_mutex); SCCondDestroy(&rb->wait_cond); #endif SCFree(rb); } } /** * \brief get the next ptr from the ring buffer * * Because we allow for multiple readers we take great care in making sure * that the threads don't interfere with one another. * */ void *RingBufferMrMw8Get(RingBuffer8 *rb) { void *ptr; /** local pointer for data races. If SCAtomicCompareAndSwap (CAS) * fails we increase our local array idx to try the next array member * until we succeed. Or when the buffer is empty again we jump back * to the waiting loop. */ unsigned char readp; /* buffer is empty, wait... */ retry: while (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return NULL; RingBuffer8DoWait(rb); } /* atomically update rb->read */ readp = SC_ATOMIC_GET(rb->read) - 1; do { /* with multiple readers we can get in the situation that we exitted * from the wait loop but the rb is empty again once we get here. */ if (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) goto retry; readp++; ptr = rb->array[readp]; } while (!(SC_ATOMIC_CAS(&rb->read, readp, (readp + 1)))); SCLogDebug("ptr %p", ptr); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return ptr; } /** * \brief put a ptr in the RingBuffer. * * As we support multiple writers we need to protect 2 things: * 1. writing the ptr to the array * 2. incrementing the rb->write idx * * We can't do both at the same time in one atomic operation, so * we need to (spin) lock it. We do increment rb->write atomically * after that, so that we don't need to use the lock in our *Get * function. * * \param rb the ringbuffer * \param ptr ptr to store * * \retval 0 ok * \retval -1 wait loop interrupted because of engine flags */ int RingBufferMrMw8Put(RingBuffer8 *rb, void *ptr) { SCLogDebug("ptr %p", ptr); /* buffer is full, wait... */ retry: while ((unsigned char)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return -1; RingBuffer8DoWait(rb); } /* get our lock */ SCSpinLock(&rb->spin); /* if while we got our lock the buffer changed, we need to retry */ if ((unsigned char)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { SCSpinUnlock(&rb->spin); goto retry; } SCLogDebug("rb->write %u, ptr %p", SC_ATOMIC_GET(rb->write), ptr); /* update the ring buffer */ rb->array[SC_ATOMIC_GET(rb->write)] = ptr; (void) SC_ATOMIC_ADD(rb->write, 1); SCSpinUnlock(&rb->spin); SCLogDebug("ptr %p, done", ptr); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return 0; } /* Multi Reader, Multi Writer, 16 bits */ RingBuffer16 *RingBufferInit(void) { RingBuffer16 *rb = SCMalloc(sizeof(RingBuffer16)); if (unlikely(rb == NULL)) { return NULL; } memset(rb, 0x00, sizeof(RingBuffer16)); SC_ATOMIC_INIT(rb->write); SC_ATOMIC_INIT(rb->read); SCSpinInit(&rb->spin, 0); #ifdef RINGBUFFER_MUTEX_WAIT SCMutexInit(&rb->wait_mutex, NULL); SCCondInit(&rb->wait_cond, NULL); #endif return rb; } void RingBufferDestroy(RingBuffer16 *rb) { if (rb != NULL) { SC_ATOMIC_DESTROY(rb->write); SC_ATOMIC_DESTROY(rb->read); SCSpinDestroy(&rb->spin); #ifdef RINGBUFFER_MUTEX_WAIT SCMutexDestroy(&rb->wait_mutex); SCCondDestroy(&rb->wait_cond); #endif SCFree(rb); } } /** * \brief get the next ptr from the ring buffer * * Because we allow for multiple readers we take great care in making sure * that the threads don't interfere with one another. * */ void *RingBufferMrMwGet(RingBuffer16 *rb) { void *ptr; /** local pointer for data races. If SCAtomicCompareAndSwap (CAS) * fails we increase our local array idx to try the next array member * until we succeed. Or when the buffer is empty again we jump back * to the waiting loop. */ unsigned short readp; /* buffer is empty, wait... */ retry: while (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return NULL; RingBufferDoWait(rb); } /* atomically update rb->read */ readp = SC_ATOMIC_GET(rb->read) - 1; do { /* with multiple readers we can get in the situation that we exitted * from the wait loop but the rb is empty again once we get here. */ if (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) goto retry; readp++; ptr = rb->array[readp]; } while (!(SC_ATOMIC_CAS(&rb->read, readp, (readp + 1)))); SCLogDebug("ptr %p", ptr); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return ptr; } /** * \brief get the next ptr from the ring buffer * * Because we allow for multiple readers we take great care in making sure * that the threads don't interfere with one another. * * This version does NOT enter a wait if the buffer is empty loop. * * \retval ptr pointer to the data, or NULL if buffer is empty */ void *RingBufferMrMwGetNoWait(RingBuffer16 *rb) { void *ptr; /** local pointer for data races. If SCAtomicCompareAndSwap (CAS) * fails we increase our local array idx to try the next array member * until we succeed. Or when the buffer is empty again we jump back * to the waiting loop. */ unsigned short readp; /* buffer is empty, wait... */ retry: while (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) { /* break if buffer is empty */ return NULL; } /* atomically update rb->read */ readp = SC_ATOMIC_GET(rb->read) - 1; do { /* with multiple readers we can get in the situation that we exitted * from the wait loop but the rb is empty again once we get here. */ if (SC_ATOMIC_GET(rb->write) == SC_ATOMIC_GET(rb->read)) goto retry; readp++; ptr = rb->array[readp]; } while (!(SC_ATOMIC_CAS(&rb->read, readp, (readp + 1)))); SCLogDebug("ptr %p", ptr); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return ptr; } /** * \brief put a ptr in the RingBuffer. * * As we support multiple writers we need to protect 2 things: * 1. writing the ptr to the array * 2. incrementing the rb->write idx * * We can't do both at the same time in one atomic operation, so * we need to (spin) lock it. We do increment rb->write atomically * after that, so that we don't need to use the lock in our *Get * function. * * \param rb the ringbuffer * \param ptr ptr to store * * \retval 0 ok * \retval -1 wait loop interrupted because of engine flags */ int RingBufferMrMwPut(RingBuffer16 *rb, void *ptr) { SCLogDebug("ptr %p", ptr); /* buffer is full, wait... */ retry: while ((unsigned short)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { /* break out if the engine wants to shutdown */ if (rb->shutdown != 0) return -1; RingBufferDoWait(rb); } /* get our lock */ SCSpinLock(&rb->spin); /* if while we got our lock the buffer changed, we need to retry */ if ((unsigned short)(SC_ATOMIC_GET(rb->write) + 1) == SC_ATOMIC_GET(rb->read)) { SCSpinUnlock(&rb->spin); goto retry; } SCLogDebug("rb->write %u, ptr %p", SC_ATOMIC_GET(rb->write), ptr); /* update the ring buffer */ rb->array[SC_ATOMIC_GET(rb->write)] = ptr; (void) SC_ATOMIC_ADD(rb->write, 1); SCSpinUnlock(&rb->spin); SCLogDebug("ptr %p, done", ptr); #ifdef RINGBUFFER_MUTEX_WAIT SCCondSignal(&rb->wait_cond); #endif return 0; } #ifdef UNITTESTS static int RingBuffer8SrSwInit01 (void) { int result = 0; RingBuffer8 *rb = NULL; rb = RingBuffer8Init(); if (rb == NULL) { printf("rb == NULL: "); goto end; } int r = SCSpinLock(&rb->spin); if (r != 0) { printf("r = %d, expected %d: ", r, 0); goto end; } SCSpinUnlock(&rb->spin); if (SC_ATOMIC_GET(rb->read) != 0) { printf("read %u, expected 0: ", SC_ATOMIC_GET(rb->read)); goto end; } if (SC_ATOMIC_GET(rb->write) != 0) { printf("write %u, expected 0: ", SC_ATOMIC_GET(rb->write)); goto end; } result = 1; end: if (rb != NULL) { RingBuffer8Destroy(rb); } return result; } static int RingBuffer8SrSwPut01 (void) { int result = 0; RingBuffer8 *rb = NULL; rb = RingBuffer8Init(); if (rb == NULL) { printf("rb == NULL: "); goto end; } if (SC_ATOMIC_GET(rb->read) != 0) { printf("read %u, expected 0: ", SC_ATOMIC_GET(rb->read)); goto end; } if (SC_ATOMIC_GET(rb->write) != 0) { printf("write %u, expected 0: ", SC_ATOMIC_GET(rb->write)); goto end; } void *ptr = &result; RingBufferSrSw8Put(rb, ptr); if (SC_ATOMIC_GET(rb->read) != 0) { printf("read %u, expected 0: ", SC_ATOMIC_GET(rb->read)); goto end; } if (SC_ATOMIC_GET(rb->write) != 1) { printf("write %u, expected 1: ", SC_ATOMIC_GET(rb->write)); goto end; } if (rb->array[0] != ptr) { printf("ptr is %p, expected %p: ", rb->array[0], ptr); goto end; } result = 1; end: if (rb != NULL) { RingBuffer8Destroy(rb); } return result; } static int RingBuffer8SrSwPut02 (void) { int result = 0; RingBuffer8 *rb = NULL; int array[255]; int cnt = 0; for (cnt = 0; cnt < 255; cnt++) { array[cnt] = cnt; } rb = RingBuffer8Init(); if (rb == NULL) { printf("rb == NULL: "); goto end; } for (cnt = 0; cnt < 255; cnt++) { RingBufferSrSw8Put(rb, (void *)&array[cnt]); if (SC_ATOMIC_GET(rb->read) != 0) { printf("read %u, expected 0: ", SC_ATOMIC_GET(rb->read)); goto end; } if (SC_ATOMIC_GET(rb->write) != (unsigned char)(cnt+1)) { printf("write %u, expected %u: ", SC_ATOMIC_GET(rb->write), (unsigned char)(cnt+1)); goto end; } if (rb->array[cnt] != (void *)&array[cnt]) { printf("ptr is %p, expected %p: ", rb->array[cnt], (void *)&array[cnt]); goto end; } } if (!(RingBuffer8IsFull(rb))) { printf("ringbuffer should be full, isn't: "); goto end; } result = 1; end: if (rb != NULL) { RingBuffer8Destroy(rb); } return result; } static int RingBuffer8SrSwGet01 (void) { int result = 0; RingBuffer8 *rb = NULL; rb = RingBuffer8Init(); if (rb == NULL) { printf("rb == NULL: "); goto end; } void *ptr = &result; RingBufferSrSw8Put(rb, ptr); void *ptr2 = RingBufferSrSw8Get(rb); if (ptr != ptr2) { printf("ptr %p != ptr2 %p: ", ptr, ptr2); goto end; } if (SC_ATOMIC_GET(rb->read) != 1) { printf("read %u, expected 1: ", SC_ATOMIC_GET(rb->read)); goto end; } if (SC_ATOMIC_GET(rb->write) != 1) { printf("write %u, expected 1: ", SC_ATOMIC_GET(rb->write)); goto end; } result = 1; end: if (rb != NULL) { RingBuffer8Destroy(rb); } return result; } static int RingBuffer8SrSwGet02 (void) { int result = 0; RingBuffer8 *rb = NULL; int array[255]; int cnt = 0; for (cnt = 0; cnt < 255; cnt++) { array[cnt] = cnt; } rb = RingBuffer8Init(); if (rb == NULL) { printf("rb == NULL: "); goto end; } for (cnt = 0; cnt < 255; cnt++) { RingBufferSrSw8Put(rb, (void *)&array[cnt]); if (SC_ATOMIC_GET(rb->read) != 0) { printf("read %u, expected 0: ", SC_ATOMIC_GET(rb->read)); goto end; } if (SC_ATOMIC_GET(rb->write) != (unsigned char)(cnt+1)) { printf("write %u, expected %u: ", SC_ATOMIC_GET(rb->write), (unsigned char)(cnt+1)); goto end; } if (rb->array[cnt] != (void *)&array[cnt]) { printf("ptr is %p, expected %p: ", rb->array[cnt], (void *)&array[cnt]); goto end; } } if (!(RingBuffer8IsFull(rb))) { printf("ringbuffer should be full, isn't: "); goto end; } for (cnt = 0; cnt < 255; cnt++) { void *ptr = RingBufferSrSw8Get(rb); if (SC_ATOMIC_GET(rb->read) != (unsigned char)(cnt+1)) { printf("read %u, expected %u: ", SC_ATOMIC_GET(rb->read), (unsigned char)(cnt+1)); goto end; } if (SC_ATOMIC_GET(rb->write) != 255) { printf("write %u, expected %u: ", SC_ATOMIC_GET(rb->write), 255); goto end; } if (ptr != (void *)&array[cnt]) { printf("ptr is %p, expected %p: ", ptr, (void *)&array[cnt]); goto end; } } if (!(RingBuffer8IsEmpty(rb))) { printf("ringbuffer should be empty, isn't: "); goto end; } result = 1; end: if (rb != NULL) { RingBuffer8Destroy(rb); } return result; } #endif /* UNITTESTS */ void DetectRingBufferRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("RingBuffer8SrSwInit01", RingBuffer8SrSwInit01, 1); UtRegisterTest("RingBuffer8SrSwPut01", RingBuffer8SrSwPut01, 1); UtRegisterTest("RingBuffer8SrSwPut02", RingBuffer8SrSwPut02, 1); UtRegisterTest("RingBuffer8SrSwGet01", RingBuffer8SrSwGet01, 1); UtRegisterTest("RingBuffer8SrSwGet02", RingBuffer8SrSwGet02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/pkt-var.c0000644000000000000000000000617312253546156012564 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements per packet vars * * \todo move away from a linked list implementation * \todo use different datatypes, such as string, int, etc. * \todo have more than one instance of the same var, and be able to match on a * specific one, or one all at a time. So if a certain capture matches * multiple times, we can operate on all of them. */ #include "suricata-common.h" #include "decode.h" #include "pkt-var.h" #include "util-debug.h" /* puts a new value into a pktvar */ void PktVarUpdate(PktVar *pv, uint8_t *value, uint16_t size) { if (pv->value) SCFree(pv->value); pv->value = value; pv->value_len = size; } /* get the pktvar with name 'name' from the pkt * * name is a normal string*/ PktVar *PktVarGet(Packet *p, char *name) { PktVar *pv = p->pktvar; for (;pv != NULL; pv = pv->next) { if (pv->name && strcmp(pv->name, name) == 0) return pv; } return NULL; } /* add a pktvar to the pkt, or update it */ void PktVarAdd(Packet *p, char *name, uint8_t *value, uint16_t size) { //printf("Adding packet var \"%s\" with value(%" PRId32 ") \"%s\"\n", name, size, value); PktVar *pv = PktVarGet(p, name); if (pv == NULL) { pv = SCMalloc(sizeof(PktVar)); if (unlikely(pv == NULL)) return; pv->name = name; pv->value = value; pv->value_len = size; pv->next = NULL; PktVar *tpv = p->pktvar; if (p->pktvar == NULL) p->pktvar = pv; else { while(tpv) { if (tpv->next == NULL) { tpv->next = pv; return; } tpv = tpv->next; } } } else { PktVarUpdate(pv, value, size); } } void PktVarFree(PktVar *pv) { if (pv == NULL) return; pv->name = NULL; if (pv->value != NULL) SCFree(pv->value); PktVar *pv_next = pv->next; SCFree(pv); if (pv_next != NULL) PktVarFree(pv_next); } void PktVarPrint(PktVar *pv) { uint16_t i; if (pv == NULL) return; printf("Name \"%s\", Value \"", pv->name); for (i = 0; i < pv->value_len; i++) { if (isprint(pv->value[i])) printf("%c", pv->value[i]); else printf("\\%02X", pv->value[i]); } printf("\", Len \"%" PRIu32 "\"\n", pv->value_len); PktVarPrint(pv->next); } suricata-1.4.7/src/decode-ethernet.c0000644000000000000000000001062212253546156014231 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Victor Julien * * Decode Ethernet */ #include "suricata-common.h" #include "decode.h" #include "decode-ethernet.h" #include "decode-events.h" #include "util-unittest.h" #include "util-debug.h" void DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_eth, tv->sc_perf_pca); if (len < ETHERNET_HEADER_LEN) { ENGINE_SET_EVENT(p,ETHERNET_PKT_TOO_SMALL); return; } p->ethh = (EthernetHdr *)pkt; if (p->ethh == NULL) return; SCLogDebug("p %p pkt %p ether type %04x", p, pkt, ntohs(p->ethh->eth_type)); switch (ntohs(p->ethh->eth_type)) { case ETHERNET_TYPE_IP: //printf("DecodeEthernet ip4\n"); DecodeIPV4(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_IPV6: //printf("DecodeEthernet ip6\n"); DecodeIPV6(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_SESS: //printf("DecodeEthernet PPPOE Session\n"); DecodePPPOESession(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_DISC: //printf("DecodeEthernet PPPOE Discovery\n"); DecodePPPOEDiscovery(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_VLAN: DecodeVLAN(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; default: SCLogDebug("p %p pkt %p ether type %04x not supported", p, pkt, ntohs(p->ethh->eth_type)); } return; } #ifdef UNITTESTS /** DecodeEthernettest01 * \brief Valid Ethernet packet * \retval 0 Expected test value */ static int DecodeEthernetTest01 (void) { /* ICMP packet wrapped in PPPOE */ uint8_t raw_eth[] = { 0x00, 0x10, 0x94, 0x55, 0x00, 0x01, 0x00, 0x10, 0x94, 0x56, 0x00, 0x01, 0x88, 0x64, 0x11, 0x00, 0x00, 0x01, 0x00, 0x68, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x64, 0x00, 0x1e, 0x00, 0x00, 0xff, 0x01, 0xa7, 0x78, 0x0a, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x00, 0x4a, 0x61, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3b, 0xd4, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth), NULL); SCFree(p); return 0; } #endif /* UNITTESTS */ /** * \brief Registers Ethernet unit tests * \todo More Ethernet tests */ void DecodeEthernetRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeEthernetTest01", DecodeEthernetTest01, 0); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/app-layer-smb.c0000644000000000000000000026043612253546156013655 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Kirby Kuehl * * \brief SMBv1 parser/decoder */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "util-debug.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-detect-proto.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "util-spm.h" #include "util-unittest.h" #include "util-memcmp.h" #include "app-layer-smb.h" enum { SMB_FIELD_NONE = 0, SMB_PARSE_NBSS_HEADER, SMB_PARSE_SMB_HEADER, SMB_PARSE_GET_WORDCOUNT, SMB_PARSE_WORDCOUNT, SMB_PARSE_GET_BYTECOUNT, SMB_PARSE_BYTECOUNT, /* must be last */ SMB_FIELD_MAX, }; /** * \brief SMB Write AndX Request Parsing */ /* For WriteAndX we need to get writeandxdataoffset */ static uint32_t SMBParseWriteAndX(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; switch (sstate->andx.andxbytesprocessed) { case 0: sstate->andx.paddingparsed = 0; if (input_len >= 28) { sstate->andx.andxcommand = *p; sstate->andx.andxoffset = *(p + 2); sstate->andx.andxoffset |= *(p + 3) << 8; sstate->andx.datalengthhigh = *(p + 18); sstate->andx.datalengthhigh |= *(p + 19) << 8; sstate->andx.datalength = *(p + 20); sstate->andx.datalength |= *(p + 21) << 8; sstate->andx.dataoffset = *(p + 22); sstate->andx.dataoffset |= *(p + 23) << 8; sstate->andx.dataoffset |= (uint64_t) *(p + 24) << 56; sstate->andx.dataoffset |= (uint64_t) *(p + 25) << 48; sstate->andx.dataoffset |= (uint64_t) *(p + 26) << 40; sstate->andx.dataoffset |= (uint64_t) *(p + 27) << 32; sstate->bytesprocessed += 28; SCReturnUInt(28U); } else { sstate->andx.andxcommand = *(p++); if (!(--input_len)) break; } case 1: p++; // Reserved if (!(--input_len)) break; case 2: sstate->andx.andxoffset = *(p++) << 8; if (!(--input_len)) break; case 3: sstate->andx.andxoffset |= *(p++); if (!(--input_len)) break; case 4: // SMB_COM_WRITE_ANDX Fid 1 p++; if (!(--input_len)) break; case 5: // SMB_COM_WRITE_ANDX Fid 2 p++; if (!(--input_len)) break; case 6: // SMB_COM_WRITE_ANDX Offset 1 p++; if (!(--input_len)) break; case 7: // SMB_COM_WRITE_ANDX Offset 2 p++; if (!(--input_len)) break; case 8: // SMB_COM_WRITE_ANDX Offset 3 p++; if (!(--input_len)) break; case 9: // SMB_COM_WRITE_ANDX Offset 4 p++; if (!(--input_len)) break; case 10: // SMB_COM_WRITE_ANDX Reserved 1 p++; if (!(--input_len)) break; case 11: // SMB_COM_WRITE_ANDX Reserved 2 p++; if (!(--input_len)) break; case 12: // SMB_COM_WRITE_ANDX Reserved 3 p++; if (!(--input_len)) break; case 13: // SMB_COM_WRITE_ANDX Reserved 4 p++; if (!(--input_len)) break; case 14: // SMB_COM_WRITE_ANDX WriteMode 1 p++; if (!(--input_len)) break; case 15: // SMB_COM_WRITE_ANDX WriteMode 2 p++; if (!(--input_len)) break; case 16: // SMB_COM_WRITE_ANDX BytesRemaining 1 p++; if (!(--input_len)) break; case 17: // SMB_COM_WRITE_ANDX BytesRemaining 2 p++; if (!(--input_len)) break; case 18: // DataLengthHigh 1 sstate->andx.datalengthhigh = *(p++); if (!(--input_len)) break; case 19: // DataLengthHigh 2 sstate->andx.datalengthhigh |= *(p++) << 8; if (!(--input_len)) break; case 20: // DataLength 1 sstate->andx.datalength = *(p++); if (!(--input_len)) break; case 21: // DataLength 2 sstate->andx.datalength |= *(p++) << 8; if (!(--input_len)) break; case 22: sstate->andx.dataoffset = *(p++) << 8; if (!(--input_len)) break; case 23: sstate->andx.dataoffset |= *(p++); if (!(--input_len)) break; case 24: sstate->andx.dataoffset |= (uint64_t) *(p++) << 56; if (!(--input_len)) break; case 25: sstate->andx.dataoffset |= (uint64_t) *(p++) << 48; if (!(--input_len)) break; case 26: sstate->andx.dataoffset |= (uint64_t) *(p++) << 40; if (!(--input_len)) break; case 27: sstate->andx.dataoffset |= (uint64_t) *(p++) << 32; --input_len; break; default: sstate->bytesprocessed++; SCReturnUInt(1); break; } sstate->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } /** * \brief SMB Read AndX Response Parsing */ static uint32_t SMBParseReadAndX(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; switch (sstate->andx.andxbytesprocessed) { case 0: sstate->andx.paddingparsed = 0; if (input_len >= 24) { sstate->andx.andxcommand = *p; sstate->andx.andxoffset = *(p + 2); sstate->andx.andxoffset |= *(p + 3) << 8; sstate->andx.datalength = *(p + 10); sstate->andx.datalength |= *(p + 11) << 8; sstate->andx.dataoffset = *(p + 12); sstate->andx.dataoffset |= *(p + 13) << 8; sstate->andx.datalength |= (uint64_t) *(p + 14) << 32; sstate->andx.datalength |= (uint64_t) *(p + 15) << 40; sstate->andx.datalength |= (uint64_t) *(p + 16) << 48; sstate->andx.datalength |= (uint64_t) *(p + 17) << 56; sstate->bytesprocessed += 24; SCReturnUInt(24U); } else { sstate->andx.andxcommand = *(p++); if (!(--input_len)) break; } case 1: p++; // Reserved if (!(--input_len)) break; case 2: sstate->andx.andxoffset |= *(p++); if (!(--input_len)) break; case 3: sstate->andx.andxoffset |= *(p++) << 8; if (!(--input_len)) break; case 4: // SMB_COM_READ_ANDX Remaining Reserved must be 0xff p++; if (!(--input_len)) break; case 5: // SMB_COM_READ_ANDX Remaining Reserved must be 0xff p++; if (!(--input_len)) break; case 6: // SMB_COM_READ_ANDX DataCompactionMode 1 p++; if (!(--input_len)) break; case 7: // SMB_COM_READ_ANDX DataCompactionMode 1 p++; if (!(--input_len)) break; case 8: // SMB_COM_READ_ANDX Reserved p++; if (!(--input_len)) break; case 9: // SMB_COM_READ_ANDX Reserved p++; if (!(--input_len)) break; case 10: sstate->andx.datalength = *(p++); if (!(--input_len)) break; case 11: sstate->andx.datalength |= *(p++) << 8; if (!(--input_len)) break; case 12: sstate->andx.dataoffset = *(p++); if (!(--input_len)) break; case 13: sstate->andx.dataoffset |= *(p++) << 8; if (!(--input_len)) break; case 14: sstate->andx.datalength |= *(p++) << 16; if (!(--input_len)) break; case 15: sstate->andx.datalength |= *(p++) << 24; if (!(--input_len)) break; case 16: // SMB_COM_READ_ANDX Reserved p++; if (!(--input_len)) break; case 17: // SMB_COM_READ_ANDX Reserved p++; if (!(--input_len)) break; case 18: // SMB_COM_READ_ANDX Reserved p++; --input_len; break; default: sstate->bytesprocessed++; SCReturnUInt(1); break; } sstate->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } static uint32_t SMBParseTransact(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; switch (sstate->andx.andxbytesprocessed) { case 0: sstate->andx.paddingparsed = 0; if (input_len >= sstate->wordcount.wordcount) { sstate->andx.datalength = *(p + 22); sstate->andx.datalength |= *(p + 23) << 8; sstate->andx.dataoffset = *(p + 24); sstate->andx.dataoffset |= *(p + 25) << 8; sstate->andx.datalength |= (uint64_t) *(p + 14) << 56; sstate->andx.datalength |= (uint64_t) *(p + 15) << 48; sstate->andx.datalength |= (uint64_t) *(p + 16) << 40; sstate->andx.datalength |= (uint64_t) *(p + 17) << 32; sstate->bytesprocessed += sstate->wordcount.wordcount; sstate->andx.andxbytesprocessed += sstate->wordcount.wordcount; SCReturnUInt(sstate->wordcount.wordcount); } else { /* total parameter count 1 */ p++; if (!(--input_len)) break; } case 1: /* total parameter count 2 */ p++; if (!(--input_len)) break; case 2: /* total data count 1 */ p++; if (!(--input_len)) break; case 3: /* total data count 2 */ p++; if (!(--input_len)) break; case 4: /* max parameter count 1 */ p++; if (!(--input_len)) break; case 5: /* max parameter count 2 */ p++; if (!(--input_len)) break; case 6: /* max data count 1 */ p++; if (!(--input_len)) break; case 7: /* max data count 2 */ p++; if (!(--input_len)) break; case 8: /* max setup count */ p++; if (!(--input_len)) break; case 9: /* Reserved */ p++; if (!(--input_len)) break; case 10: /* Flags */ p++; if (!(--input_len)) break; case 11: /* Flags */ p++; if (!(--input_len)) break; case 12: /* Timeout */ p++; if (!(--input_len)) break; case 13: /* Timeout */ p++; if (!(--input_len)) break; case 14: /* Timeout */ p++; if (!(--input_len)) break; case 15: /* Timeout */ p++; if (!(--input_len)) break; case 16: /* Reserved */ p++; if (!(--input_len)) break; case 17: /* Reserved */ p++; if (!(--input_len)) break; case 18: /* Parameter Count */ p++; if (!(--input_len)) break; case 19: /* Parameter Count */ p++; if (!(--input_len)) break; case 20: /* Parameter Offset */ p++; if (!(--input_len)) break; case 21: /* Parameter Offset */ p++; if (!(--input_len)) break; case 22: /* Data Count */ sstate->andx.datalength = *(p++); if (!(--input_len)) break; case 23: /* Data Count */ sstate->andx.datalength |= *(p++) << 8; if (!(--input_len)) break; case 24: /* Data Offset */ sstate->andx.dataoffset = *(p++); if (!(--input_len)) break; case 25: /* Data Offset */ sstate->andx.dataoffset |= *(p++) << 8; if (!(--input_len)) break; case 26: /* Setup Count */ p++; if (!(--input_len)) break; case 27: /* Reserved */ p++; if (!(--input_len)) break; case 28: p++; if (!(--input_len)) break; case 29: p++; if (!(--input_len)) break; case 30: p++; if (!(--input_len)) break; case 31: p++; --input_len; break; default: SCLogDebug("SMB_COM_TRANSACTION AndX bytes processed is greater than 31 %u", sstate->andx.andxbytesprocessed); sstate->bytesprocessed++; sstate->andx.andxbytesprocessed++; SCReturnUInt(1); break; } sstate->bytesprocessed += (p - input); sstate->andx.andxbytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } /** * Handle variable length padding for WriteAndX and ReadAndX */ static uint32_t PaddingParser(void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; /* Check for validity of dataoffset */ if ((uint64_t)(sstate->bytesprocessed - NBSS_HDR_LEN) > sstate->andx.dataoffset) { sstate->andx.paddingparsed = 1; SCReturnUInt((uint32_t)(p - input)); } while (((uint64_t)(sstate->bytesprocessed - NBSS_HDR_LEN) + (p - input)) < sstate->andx.dataoffset && sstate->bytecount.bytecountleft-- && input_len--) { SCLogDebug("0x%02x ", *p); p++; } if (((uint64_t)(sstate->bytesprocessed - NBSS_HDR_LEN) + (p - input)) == sstate->andx.dataoffset) { sstate->andx.paddingparsed = 1; } sstate->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } /** * \brief Parse WriteAndX and ReadAndX Data * \retval -1 f DCERPCParser does not validate * \retval Number of bytes processed */ static int32_t DataParser(void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; int32_t parsed = 0; if (sstate->andx.paddingparsed) { parsed = DCERPCParser(&sstate->dcerpc, input, input_len); if (parsed == -1 || parsed > sstate->bytecount.bytecountleft || parsed > (int32_t)input_len) { SCReturnInt(-1); } else { sstate->dcerpc_present = 1; sstate->bytesprocessed += parsed; sstate->bytecount.bytecountleft -= parsed; input_len -= parsed; } } SCReturnInt(parsed); } /** * \brief Obtain SMB WordCount which is 2 times the value. * Reset bytecount.bytecountbytes to 0. * Determine if this is an SMB AndX Command */ static uint32_t SMBGetWordCount(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); if (input_len > 0) { SMBState *sstate = (SMBState *) smb_state; sstate->wordcount.wordcount = *(input) * 2; sstate->wordcount.wordcountleft = sstate->wordcount.wordcount; sstate->bytesprocessed++; sstate->bytecount.bytecountbytes = 0; sstate->andx.isandx = isAndX(sstate); SCLogDebug("Wordcount (%u):", sstate->wordcount.wordcount); SCReturnUInt(1U); } SCReturnUInt(0); } /* * Obtain SMB Bytecount. Handle the corner obfuscation case where a packet boundary * is after the first bytecount byte. */ static uint32_t SMBGetByteCount(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; if (input_len && sstate->bytesprocessed == NBSS_HDR_LEN + SMB_HDR_LEN + 1 + sstate->wordcount.wordcount) { sstate->bytecount.bytecount = *(p++); sstate->bytesprocessed++; --input_len; } if (input_len && sstate->bytesprocessed == NBSS_HDR_LEN + SMB_HDR_LEN + 2 + sstate->wordcount.wordcount) { sstate->bytecount.bytecount |= *(p++) << 8; sstate->bytecount.bytecountleft = sstate->bytecount.bytecount; sstate->bytesprocessed++; SCLogDebug("Bytecount %u", sstate->bytecount.bytecount); --input_len; } SCReturnUInt((uint32_t)(p - input)); } /** * \brief SMBParseWordCount parses the SMB Wordcount portion of the SMB Transaction. * until sstate->wordcount.wordcount bytes are parsed. */ static uint32_t SMBParseWordCount(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; uint32_t retval = 0; if ((sstate->smb.flags & SMB_FLAGS_SERVER_TO_REDIR) && sstate->smb.command == SMB_COM_READ_ANDX) { retval = SMBParseReadAndX(f, sstate, pstate, input, input_len, output); if (retval <= sstate->wordcount.wordcountleft) { sstate->wordcount.wordcountleft -= retval; SCLogDebug("SMB_COM_READ_ANDX returned %d - %u bytes at offset %"PRIu64"", retval, sstate->andx.datalength, sstate->andx.dataoffset); SCReturnUInt(retval); } else { SCReturnUInt(0U); } } else if (((sstate->smb.flags & SMB_FLAGS_SERVER_TO_REDIR) == 0) && sstate->smb.command == SMB_COM_WRITE_ANDX) { retval = SMBParseWriteAndX(f, sstate, pstate, input, input_len, output); if (retval <= sstate->wordcount.wordcountleft) { sstate->wordcount.wordcountleft -= retval; SCLogDebug("SMB_COM_WRITE_ANDX returned %d - %u bytes at offset %"PRIu64"", retval, sstate->andx.datalength, sstate->andx.dataoffset); SCReturnUInt(retval); } else { SCReturnUInt(0U); } } else if (sstate->smb.command == SMB_COM_TRANSACTION) { retval = SMBParseTransact(f, sstate, pstate, input, input_len, output); if (retval <= sstate->wordcount.wordcountleft) { sstate->wordcount.wordcountleft -= retval; SCLogDebug("SMB_COM_TRANSACTION returned %d - %u bytes at offset %"PRIu64"", retval, sstate->andx.datalength, sstate->andx.dataoffset); SCReturnUInt(retval); } else { SCReturnUInt(0U); } } else { /* Generic WordCount Handler */ while (sstate->wordcount.wordcountleft-- && input_len--) { SCLogDebug("0x%02x wordcount %u/%u input_len %u", *p, sstate->wordcount.wordcountleft, sstate->wordcount.wordcount, input_len); p++; } sstate->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } } /** * \brief SMBParseByteCount parses the SMB ByteCount portion of the SMB Transaction. * until sstate->bytecount.bytecount bytes are parsed. */ static uint32_t SMBParseByteCount(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; uint32_t ures = 0; /* unsigned */ int32_t sres = 0; /* signed */ uint32_t parsed = 0; if (((sstate->smb.flags & SMB_FLAGS_SERVER_TO_REDIR) && sstate->smb.command == SMB_COM_READ_ANDX) || (((sstate->smb.flags & SMB_FLAGS_SERVER_TO_REDIR) == 0) && sstate->smb.command == SMB_COM_WRITE_ANDX) || (sstate->smb.command == SMB_COM_TRANSACTION)) { if (sstate->andx.paddingparsed == 0) { ures = PaddingParser(sstate, pstate, input + parsed, input_len, output); if (ures <= input_len) { parsed += ures; input_len -= ures; } else { SCReturnUInt(0U); } } if (sstate->andx.datalength && input_len) { /* Uncomment the next line to help debug DCERPC over SMB */ //hexdump(f, input + parsed, input_len); sres = DataParser(sstate, pstate, input + parsed, input_len, output); if (sres != -1 && sres <= (int32_t)input_len) { parsed += (uint32_t)sres; input_len -= (uint32_t)sres; } else { /* Did not Validate as DCERPC over SMB */ while (sstate->bytecount.bytecountleft-- && input_len--) { SCLogDebug("0x%02x bytecount %"PRIu16"/%"PRIu16" input_len %"PRIu32, *p, sstate->bytecount.bytecountleft, sstate->bytecount.bytecount, input_len); p++; } sstate->bytesprocessed += (p - input); SCReturnUInt((p - input)); } } SCReturnUInt(ures); } while (sstate->bytecount.bytecountleft-- && input_len--) { SCLogDebug("0x%02x bytecount %u/%u input_len %u", *p, sstate->bytecount.bytecountleft, sstate->bytecount.bytecount, input_len); p++; } sstate->bytesprocessed += (p - input); SCReturnUInt((p - input)); } /** * \brief Parse a NBSS header. * * \retval 4 parsing of the header is done * \retval 3 parsing partially done * \retval 2 parsing partially done * \retval 1 parsing partially done * \retval 0 no input or already done */ static uint32_t NBSSParseHeader(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; if (input_len > 0 && sstate->bytesprocessed < (NBSS_HDR_LEN - 1)) { switch (sstate->bytesprocessed) { case 0: /* Initialize */ sstate->andx.andxcommand = SMB_NO_SECONDARY_ANDX_COMMAND; sstate->andx.maxchainedandx = 5; /* fast track for having all bytes (common case) */ if (input_len >= NBSS_HDR_LEN) { sstate->nbss.type = *p; sstate->nbss.length = (*(p + 1) & 0x01) << 16; sstate->nbss.length |= *(p + 2) << 8; sstate->nbss.length |= *(p + 3); sstate->bytesprocessed += NBSS_HDR_LEN; SCReturnUInt(4U); } else { sstate->nbss.type = *(p++); if (!(--input_len)) break; } case 1: sstate->nbss.length = (*(p++) & 0x01) << 16; if (!(--input_len)) break; case 2: sstate->nbss.length |= *(p++) << 8; if (!(--input_len)) break; case 3: sstate->nbss.length |= *(p++); --input_len; break; } sstate->bytesprocessed += (p - input); } SCReturnUInt((uint32_t)(p - input)); } /** * \brief parse and validate the 32 byte SMB Header * * \retval 32 parsing done * \retval >0<32 parsing in progress * \retval 0 no input or already fully parsed * \retval -1 error */ static int SMBParseHeader(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint8_t *p = input; if (input_len > 0) { switch (sstate->bytesprocessed) { case 4: // fallthrough /* above statement to prevent coverity FPs from the switch * fall through */ if (input_len >= SMB_HDR_LEN) { if (SCMemcmp(p, "\xff\x53\x4d\x42", 4) != 0) { SCLogDebug("SMB Header did not validate"); SCReturnInt(-1); } sstate->smb.command = *(p + 4); sstate->smb.status = *(p + 5) << 24; sstate->smb.status |= *(p + 6) << 16; sstate->smb.status |= *(p + 7) << 8; sstate->smb.status |= *(p + 8); sstate->smb.flags = *(p + 9); sstate->smb.flags2 = *(p + 10) << 8; sstate->smb.flags2 |= *(p + 11); sstate->smb.pidhigh = *(p + 12) << 8; sstate->smb.pidhigh |= *(p + 13); sstate->smb.securitysignature = (uint64_t) *(p + 14) << 56; sstate->smb.securitysignature |= (uint64_t) *(p + 15) << 48; sstate->smb.securitysignature |= (uint64_t) *(p + 16) << 40; sstate->smb.securitysignature |= (uint64_t) *(p + 17) << 32; sstate->smb.securitysignature |= (uint64_t) *(p + 18) << 24; sstate->smb.securitysignature |= (uint64_t) *(p + 19) << 16; sstate->smb.securitysignature |= (uint64_t) *(p + 20) << 8; sstate->smb.securitysignature |= (uint64_t) *(p + 21); sstate->smb.tid = *(p + 24) << 8; sstate->smb.tid |= *(p + 25); sstate->smb.pid = *(p + 26) << 8; sstate->smb.pid |= *(p + 27); sstate->smb.uid = *(p + 28) << 8; sstate->smb.uid |= *(p + 29); sstate->smb.mid = *(p + 30) << 8; sstate->smb.mid |= *(p + 31); sstate->bytesprocessed += SMB_HDR_LEN; SCReturnInt(32); break; } else { if (*(p++) != 0xff) { SCLogDebug("SMB Header did not validate"); SCReturnInt(-1); } if (!(--input_len)) break; /* We fall through to the next case if we still have input. * Same applies for other cases as well */ } case 5: if (*(p++) != 'S') { SCLogDebug("SMB Header did not validate"); SCReturnInt(-1); } if (!(--input_len)) break; case 6: if (*(p++) != 'M') { SCLogDebug("SMB Header did not validate"); SCReturnInt(-1); } if (!(--input_len)) break; case 7: if (*(p++) != 'B') { SCLogDebug("SMB Header did not validate"); SCReturnInt(-1); } if (!(--input_len)) break; case 8: sstate->smb.command = *(p++); if (!(--input_len)) break; case 9: sstate->smb.status = *(p++) << 24; if (!(--input_len)) break; case 10: sstate->smb.status |= *(p++) << 16; if (!(--input_len)) break; case 11: sstate->smb.status |= *(p++) << 8; if (!(--input_len)) break; case 12: sstate->smb.status |= *(p++); if (!(--input_len)) break; case 13: sstate->smb.flags = *(p++); if (!(--input_len)) break; case 14: sstate->smb.flags2 = *(p++) << 8; if (!(--input_len)) break; case 15: sstate->smb.flags2 |= *(p++); if (!(--input_len)) break; case 16: sstate->smb.pidhigh = *(p++) << 8; if (!(--input_len)) break; case 17: sstate->smb.pidhigh |= *(p++); if (!(--input_len)) break; case 18: sstate->smb.securitysignature = (uint64_t) *(p++) << 56; if (!(--input_len)) break; case 19: sstate->smb.securitysignature |= (uint64_t) *(p++) << 48; if (!(--input_len)) break; case 20: sstate->smb.securitysignature |= (uint64_t) *(p++) << 40; if (!(--input_len)) break; case 21: sstate->smb.securitysignature |= (uint64_t) *(p++) << 32; if (!(--input_len)) break; case 22: sstate->smb.securitysignature |= (uint64_t) *(p++) << 24; if (!(--input_len)) break; case 23: sstate->smb.securitysignature |= (uint64_t) *(p++) << 16; if (!(--input_len)) break; case 24: sstate->smb.securitysignature |= (uint64_t) *(p++) << 8; if (!(--input_len)) break; case 25: sstate->smb.securitysignature |= (uint64_t) *(p++); if (!(--input_len)) break; case 26: p++; // UNUSED if (!(--input_len)) break; case 27: p++; // UNUSED if (!(--input_len)) break; case 28: sstate->smb.tid = *(p++) << 8; if (!(--input_len)) break; case 29: sstate->smb.tid |= *(p++); if (!(--input_len)) break; case 30: sstate->smb.pid = *(p++) << 8; if (!(--input_len)) break; case 31: sstate->smb.pid |= *(p++); if (!(--input_len)) break; case 32: sstate->smb.uid = *(p++) << 8; if (!(--input_len)) break; case 33: sstate->smb.uid |= *(p++); if (!(--input_len)) break; case 34: sstate->smb.mid = *(p++) << 8; if (!(--input_len)) break; case 35: sstate->smb.mid |= *(p++); --input_len; break; } } sstate->bytesprocessed += (p - input); SCReturnInt((p - input)); } static int SMBParse(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output, uint8_t dir) { SCEnter(); SMBState *sstate = (SMBState *) smb_state; uint64_t retval = 0; uint64_t parsed = 0; int hdrretval = 0; int counter = 0; if (pstate == NULL) { SCLogDebug("pstate == NULL"); SCReturnInt(0); } if (sstate->bytesprocessed != 0 && sstate->data_needed_for_dir != dir) { SCReturnInt(-1); } while (input_len) { /* till we clear corner cases */ if (counter++ == 30) { SCLogDebug("Somehow seem to be stuck inside the smb " "parser for quite sometime. Let's get out of here."); sstate->bytesprocessed = 0; SCReturnInt(0); } while (input_len && sstate->bytesprocessed < NBSS_HDR_LEN) { retval = NBSSParseHeader(f, smb_state, pstate, input + parsed, input_len, output); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; SCLogDebug("[1] NBSS Header (%u/%u) Type 0x%02x Length 0x%04x " "parsed %"PRIu64" input_len %u", sstate->bytesprocessed, NBSS_HDR_LEN, sstate->nbss.type, sstate->nbss.length, parsed, input_len); } else if (input_len) { SCLogDebug("Error parsing NBSS Header"); sstate->bytesprocessed = 0; SCReturnInt(0); } } switch (sstate->nbss.type) { case NBSS_SESSION_MESSAGE: while (input_len && (sstate->bytesprocessed >= NBSS_HDR_LEN && sstate->bytesprocessed < NBSS_HDR_LEN + SMB_HDR_LEN)) { /* inside while */ hdrretval = SMBParseHeader(f, smb_state, pstate, input + parsed, input_len, output); if (hdrretval == -1 || hdrretval > (int32_t)input_len) { SCLogDebug("Error parsing SMB Header"); sstate->bytesprocessed = 0; SCReturnInt(0); } else { parsed += hdrretval; input_len -= hdrretval; SCLogDebug("[2] SMB Header (%u/%u) Command 0x%02x " "parsed %"PRIu64" input_len %u", sstate->bytesprocessed, NBSS_HDR_LEN + SMB_HDR_LEN, sstate->smb.command, parsed, input_len); } } /* while */ do { if (input_len && (sstate->bytesprocessed == NBSS_HDR_LEN + SMB_HDR_LEN)) { /* inside if */ retval = SMBGetWordCount(f, smb_state, pstate, input + parsed, input_len, output); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; } else if (input_len) { SCLogDebug("Error parsing SMB Word Count"); sstate->bytesprocessed = 0; SCReturnInt(0); } SCLogDebug("[3] WordCount (%u/%u) WordCount %u parsed " "%"PRIu64" input_len %u", sstate->bytesprocessed, NBSS_HDR_LEN + SMB_HDR_LEN + 1, sstate->wordcount.wordcount, parsed, input_len); } /* if (input_len && ..) */ while (input_len && (sstate->bytesprocessed >= NBSS_HDR_LEN + SMB_HDR_LEN + 1 && sstate->bytesprocessed < (NBSS_HDR_LEN + SMB_HDR_LEN + 1 + sstate->wordcount.wordcount))) { /* inside while */ retval = SMBParseWordCount(f, smb_state, pstate, input + parsed, input_len, output); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; } else if (input_len) { SCLogDebug("Error parsing SMB Word Count Data retval " "%"PRIu64" input_len %u", retval, input_len); sstate->bytesprocessed = 0; SCReturnInt(0); } SCLogDebug("[4] Parsing WordCount (%u/%u) WordCount %u " "parsed %"PRIu64" input_len %u", sstate->bytesprocessed, NBSS_HDR_LEN + SMB_HDR_LEN + 1 + sstate->wordcount.wordcount, sstate->wordcount.wordcount, parsed, input_len); } /* while (input_len && ..) */ while (input_len && (sstate->bytesprocessed >= (NBSS_HDR_LEN + SMB_HDR_LEN + 1 + sstate->wordcount.wordcount) && sstate->bytesprocessed < (NBSS_HDR_LEN + SMB_HDR_LEN + 3 + sstate->wordcount.wordcount))) { /* inside while */ retval = SMBGetByteCount(f, smb_state, pstate, input + parsed, input_len, output); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; } else if (input_len) { SCLogDebug("Error parsing SMB Byte Count"); sstate->bytesprocessed = 0; SCReturnInt(0); } SCLogDebug("[5] ByteCount (%u/%u) ByteCount %u parsed " "%"PRIu64" input_len %u", sstate->bytesprocessed, NBSS_HDR_LEN + SMB_HDR_LEN + 3, sstate->bytecount.bytecount, parsed, input_len); if (sstate->bytecount.bytecount == 0) { sstate->bytesprocessed = 0; input_len = 0; } } /* while (input_len && ..) */ while (input_len && (sstate->bytesprocessed >= (NBSS_HDR_LEN + SMB_HDR_LEN + 3 + sstate->wordcount.wordcount)) && (sstate->bytesprocessed < (NBSS_HDR_LEN + SMB_HDR_LEN + 3 + sstate->wordcount.wordcount + sstate->bytecount.bytecount))) { /* inside while */ retval = SMBParseByteCount(f, smb_state, pstate, input + parsed, input_len, output); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; } else if (input_len) { SCLogDebug("Error parsing SMB Byte Count Data"); sstate->bytesprocessed = 0; SCReturnInt(0); } SCLogDebug("[6] Parsing ByteCount (%u/%u) ByteCount %u " "parsed %"PRIu64" input_len %u", sstate->bytesprocessed, NBSS_HDR_LEN + SMB_HDR_LEN + 1 + sstate->wordcount.wordcount + 2 + sstate->bytecount.bytecount, sstate->bytecount.bytecount, parsed, input_len); } /* while (input_len && ..) */ } while (sstate->andx.andxcommand != SMB_NO_SECONDARY_ANDX_COMMAND && input_len && sstate->andx.maxchainedandx--); if (sstate->bytesprocessed >= sstate->nbss.length + NBSS_HDR_LEN || sstate->andx.maxchainedandx == 0) { /* inside if */ sstate->bytesprocessed = 0; sstate->transaction_id++; input_len = 0; } break; case NBSS_SESSION_REQUEST: case NBSS_POSITIVE_SESSION_RESPONSE: case NBSS_NEGATIVE_SESSION_RESPONSE: case NBSS_RETARGET_SESSION_RESPONSE: case NBSS_SESSION_KEEP_ALIVE: if (sstate->bytesprocessed < (sstate->nbss.length + NBSS_HDR_LEN)) { if (input_len >= (sstate->nbss.length + NBSS_HDR_LEN - sstate->bytesprocessed)) { /* inside if */ input_len -= (sstate->nbss.length + NBSS_HDR_LEN - sstate->bytesprocessed); parsed += (sstate->nbss.length + NBSS_HDR_LEN - sstate->bytesprocessed); sstate->bytesprocessed = 0; } else { sstate->bytesprocessed += input_len; input_len = 0; } } else { sstate->bytesprocessed = 0; } break; default: sstate->bytesprocessed = 0; break; } /* switch */ } /* while (input_len) */ pstate->parse_field = 0; sstate->data_needed_for_dir = dir; SCReturnInt(1); } static int SMBParseRequest(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { return SMBParse(f, smb_state, pstate, input, input_len, local_data, output, 0); } static int SMBParseResponse(Flow *f, void *smb_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { return SMBParse(f, smb_state, pstate, input, input_len, local_data, output, 1); } /** * \brief determines if the SMB command is an ANDX command * \retval 1 if smb command is an AndX command * \retval 0 if smb command is not an AndX command */ int isAndX(SMBState *smb_state) { SCEnter(); switch (smb_state->smb.command) { case SMB_NO_SECONDARY_ANDX_COMMAND: case SMB_COM_LOCKING_ANDX: case SMB_COM_OPEN_ANDX: case SMB_COM_READ_ANDX: case SMB_COM_WRITE_ANDX: case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_LOGOFF_ANDX: case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_NT_CREATE_ANDX: smb_state->andx.andxbytesprocessed = 0; SCReturnInt(1); default: SCReturnInt(0); } } /** \internal * \brief Allocate a SMBState * \retval s State, or NULL in case of error */ static void *SMBStateAlloc(void) { SCEnter(); void *s = SCMalloc(sizeof(SMBState)); if (unlikely(s == NULL)) { SCReturnPtr(NULL, "void"); } memset(s, 0, sizeof(SMBState)); SCReturnPtr(s, "void"); } /** \internal * \brief Free a SMBState */ static void SMBStateFree(void *s) { SCEnter(); SMBState *sstate = (SMBState *) s; DCERPCUuidEntry *item; while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.uuid_list))) { //printUUID("Free", item); TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.uuid_list, item, next); SCFree(item); } if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; sstate->dcerpc.dcerpcrequest.stub_data_buffer_len = 0; } if (sstate->dcerpc.dcerpcresponse.stub_data_buffer != NULL) { SCFree(sstate->dcerpc.dcerpcresponse.stub_data_buffer); sstate->dcerpc.dcerpcresponse.stub_data_buffer = NULL; sstate->dcerpc.dcerpcresponse.stub_data_buffer_len = 0; } if (s) { SCFree(s); s = NULL; } SCReturn; } /** * \brief Update the transaction id based on the SMB state */ void SMBUpdateTransactionId(void *state, uint16_t *id) { SCEnter(); SMBState *s = (SMBState *)state; SCLogDebug("original id %"PRIu16, *id); (*id) = s->transaction_id; SCLogDebug("updated id %"PRIu16, *id); SCReturn; } #define SMB_PROBING_PARSER_MIN_DEPTH 8 static uint16_t SMBProbingParser(uint8_t *input, uint32_t ilen) { int32_t len; int32_t input_len = ilen; while (input_len >= SMB_PROBING_PARSER_MIN_DEPTH) { switch (input[0]) { case NBSS_SESSION_MESSAGE: if (input[4] == 0xFF && input[5] == 'S' && input[6] == 'M' && input[7] == 'B') { return ALPROTO_SMB; } case NBSS_SESSION_REQUEST: case NBSS_POSITIVE_SESSION_RESPONSE: case NBSS_NEGATIVE_SESSION_RESPONSE: case NBSS_RETARGET_SESSION_RESPONSE: case NBSS_SESSION_KEEP_ALIVE: len = (input[1] & 0x01) << 16; len = input[2] << 8; len |= input[3]; break; default: /* -1 indicates a stream where the probing parser would be * unable to find nbss, even if it exists. This should * prevent the probing parser from beig invoked henceforth */ return ALPROTO_FAILED; } input_len -= 4; if (len >= input_len) { return ALPROTO_UNKNOWN; } input_len -= len; input += 4 + len; } return ALPROTO_UNKNOWN; } void RegisterSMBParsers(void) { char *proto_name = "smb"; /** SMB */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_SMB, "|ff|SMB", 8, 4, STREAM_TOSERVER); /** SMB2 */ AlpProtoAdd(&alp_proto_ctx, "smb2", IPPROTO_TCP, ALPROTO_SMB2, "|fe|SMB", 8, 4, STREAM_TOSERVER); AppLayerRegisterProto(proto_name, ALPROTO_SMB, STREAM_TOSERVER, SMBParseRequest); AppLayerRegisterProto(proto_name, ALPROTO_SMB, STREAM_TOCLIENT, SMBParseResponse); AppLayerRegisterStateFuncs(ALPROTO_SMB, SMBStateAlloc, SMBStateFree); AppLayerRegisterTransactionIdFuncs(ALPROTO_SMB, SMBUpdateTransactionId, NULL); AppLayerRegisterProbingParser(&alp_proto_ctx, 139, IPPROTO_TCP, "smb", ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, SMBProbingParser); return; } /* UNITTESTS */ #ifdef UNITTESTS /** * \test SMBParserTest01 tests the NBSS and SMB header decoding */ int SMBParserTest01(void) { int result = 0; Flow f; uint8_t smbbuf[] = "\x00\x00\x00\x85" // NBSS "\xff\x53\x4d\x42\x72\x00\x00\x00" // SMB "\x00\x18\x53\xc8\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\xff\xfe\x00\x00\x00\x00" "\x00" // WordCount "\x62\x00" // ByteCount "\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20" "\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73" "\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c" "\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54" "\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"; uint32_t smblen = sizeof(smbbuf) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } SMBState *smb_state = f.alstate; if (smb_state == NULL) { printf("no smb state: "); goto end; } if (smb_state->nbss.type != NBSS_SESSION_MESSAGE) { printf("expected nbss type 0x%02x , got 0x%02x : ", NBSS_SESSION_MESSAGE, smb_state->nbss.type); goto end; } if (smb_state->nbss.length != 133) { printf("expected nbss length 0x%02x , got 0x%02x : ", 133, smb_state->nbss.length); goto end; } if (smb_state->smb.command != SMB_COM_NEGOTIATE) { printf("expected SMB command 0x%02x , got 0x%02x : ", SMB_COM_NEGOTIATE, smb_state->smb.command); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** * \test SMBParserTest02 tests the NBSS, SMB, and DCERPC over SMB header decoding */ int SMBParserTest02(void) { int result = 0; Flow f; uint8_t smbbuf[] = { 0x00, 0x00, 0x00, 0x92, 0xff, 0x53, 0x4d, 0x42, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x64, 0x05, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x48, 0x00, 0x00, 0x04, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x48, 0x00, 0x4a, 0x00, 0x02, 0x00, 0x26, 0x00, 0x00, 0x40, 0x4f, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x00, 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0xfd, 0x2c, 0x34, 0x6c, 0x3c, 0xce, 0x11, 0xa8, 0x93, 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t smblen = sizeof(smbbuf); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } SMBState *smb_state = f.alstate; if (smb_state == NULL) { printf("no smb state: "); goto end; } if (smb_state->nbss.type != NBSS_SESSION_MESSAGE) { printf("expected nbss type 0x%02x , got 0x%02x : ", NBSS_SESSION_MESSAGE, smb_state->nbss.type); goto end; } if (smb_state->nbss.length != 146) { printf("expected nbss length 0x%02x , got 0x%02x : ", 146, smb_state->nbss.length); goto end; } if (smb_state->smb.command != SMB_COM_TRANSACTION) { printf("expected SMB command 0x%02x , got 0x%02x : ", SMB_COM_TRANSACTION, smb_state->smb.command); goto end; } printUUID("BIND", smb_state->dcerpc.dcerpcbindbindack.uuid_entry); result = 1; end: StreamTcpFreeConfig(TRUE); return result; } int SMBParserTest03(void) { int result = 0; Flow f; uint8_t smbbuf1[] = { 0x00, 0x00, 0x07, 0x57, 0xff, 0x53, 0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7f, 0x13, 0x01, 0x08, 0xc9, 0x29, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x49, 0x07, 0x00, 0x00, 0x00, 0x00, 0x18, 0x07, 0xcc, 0x1b, 0x19, 0xb8, 0x75, 0x2c, 0x85, 0x52, 0x39, 0x72, 0xfa, 0x9c, 0x5f, 0x5a, 0xb7, 0x59, 0xa1, 0x83, 0xba, 0x87, 0xd3, 0xc3, 0xbf, 0xf4, 0x5d, 0x08, 0x32, 0x22, 0x33, 0x2e, 0x62, 0x46, 0x4d, 0x03, 0x48, 0x1f, 0xea, 0x7c, 0x65, 0x3e, 0x71, 0xf8, 0xea, 0x20, 0x85, 0x29, 0x6f, 0x3c, 0xf2, 0x19, 0xb5, 0x65, 0xb0, 0xce, 0x06, 0xcc, 0x90, 0x86, 0x20, 0x77, 0xf5, 0xa0, 0xbc, 0x45, 0x9d, 0x4e, 0x92, 0xb4, 0x24, 0xc8, 0x58, 0x4a, 0xc3, 0x4e, 0xb8, 0x95, 0x8d, 0x93, 0x0c, 0xce, 0xe0, 0xf9, 0x7d, 0x7e, 0xd3, 0x46, 0x53, 0x32, 0x95, 0x7d, 0x22, 0x76, 0x0e, 0x95, 0x23, 0x2e, 0xa6, 0x58, 0x1a, 0xb6, 0x74, 0x54, 0x4f, 0x37, 0x5c, 0x60, 0x00, 0xb4, 0x55, 0x5b, 0xda, 0xea, 0x2c, 0xf3, 0x9b, 0x91, 0x6f, 0xa8, 0x20, 0xd3, 0x40, 0x0c, 0x7c, 0xc7, 0x85, 0x8c, 0x44, 0x76, 0xbc, 0x22, 0x9d, 0xfd, 0x8e, 0x21, 0x46, 0x05, 0x41, 0x73, 0x0c, 0x88, 0x62, 0xdc, 0x62, 0xc1, 0xc8, 0x14, 0xbb, 0x96, 0x60, 0x77, 0x6c, 0x5c, 0x31, 0x2a, 0xaa, 0x87, 0x69, 0x99, 0xaa, 0x83, 0x5e, 0x71, 0x11, 0x2a, 0x85, 0xca, 0x5d, 0xe1, 0x67, 0x4f, 0xa2, 0x3e, 0x4e, 0x94, 0xe7, 0xa3, 0xe6, 0xa0, 0xdb, 0xc2, 0x05, 0x01, 0x4f, 0xf5, 0xe9, 0xfc, 0xa2, 0x2a, 0x1c, 0x63, 0x21, 0xd5, 0x27, 0x98, 0x86, 0x9c, 0x66, 0x5e, 0xf1, 0x97, 0xb0, 0x86, 0x58, 0x5b, 0x94, 0x51, 0xfd, 0xb9, 0x83, 0x4c, 0xc4, 0x0f, 0x5f, 0xdd, 0xc8, 0xce, 0x43, 0xed, 0xe8, 0xae, 0xbc, 0x52, 0x73, 0xf6, 0x0f, 0x0d, 0xb4, 0xd6, 0xa7, 0xcf, 0xef, 0x0e, 0x72, 0x34, 0xff, 0x2b, 0x50, 0x71, 0x2a, 0x98, 0xf0, 0x60, 0x58, 0xde, 0x1d, 0x96, 0x50, 0xd8, 0xec, 0xeb, 0x40, 0xcb, 0x4c, 0x3b, 0x2c, 0xee, 0x76, 0xd6, 0x97, 0x1c, 0x69, 0x61, 0x89, 0xc1, 0x9b, 0x03, 0xda, 0x08, 0x0b, 0x15, 0xba, 0xd3, 0x3d, 0x8c, 0xea, 0xf7, 0x17, 0xc3, 0x77, 0xf8, 0x04, 0xca, 0x72, 0xed, 0xfe, 0xd0, 0x02, 0x73, 0x1b, 0x71, 0x72, 0x17, 0x9f, 0x14, 0x96, 0xe2, 0x5f, 0xae, 0x5b, 0x7d, 0x7f, 0xc9, 0x72, 0x9f, 0xd5, 0x32, 0xf4, 0xf3, 0x39, 0x89, 0x36, 0x00, 0x44, 0xa9, 0x18, 0x21, 0x4b, 0x26, 0xf2, 0x5a, 0x2a, 0x80, 0xea, 0x6b, 0x3e, 0x68, 0x27, 0xd0, 0xa0, 0x84, 0x81, 0xb5, 0xa6, 0x3b, 0xd5, 0xdc, 0xdd, 0xd1, 0xd4, 0x5b, 0xad, 0x80, 0x91, 0xf2, 0x30, 0x5e, 0x90, 0x17, 0x35, 0x59, 0xad, 0x34, 0x65, 0x54, 0x04, 0x5a, 0x3c, 0xe4, 0x68, 0xa7, 0x30, 0x06, 0x7a, 0x85, 0xe7, 0xf4, 0x20, 0xe3, 0xd7, 0xa5, 0x8b, 0x60, 0xfe, 0x51, 0xad, 0xda, 0xe2, 0xd1, 0x4f, 0xfb, 0x94, 0xc9, 0xba, 0xa4, 0x09, 0x5c, 0xde, 0x78, 0xdc, 0x78, 0x36, 0x96, 0x8b, 0xd6, 0x72, 0xc4, 0xa7, 0x1c, 0xde, 0x45, 0x85, 0xdf, 0x84, 0xb1, 0x3f, 0x2b, 0x3f, 0xfe, 0x56, 0x80, 0x8d, 0x26, 0x4a, 0x39, 0x22, 0x1f, 0x10, 0x89, 0x2e, 0x4e, 0x87, 0xf5, 0x9c, 0x0e, 0xd9, 0xdd, 0xb2, 0xc9, 0x9c, 0x3f, 0xc5, 0xe3, 0xab, 0xdc, 0x85, 0x1c, 0xf9, 0xda, 0xbb, 0x36, 0x9b, 0xe7, 0x21, 0x58, 0x44, 0xee, 0xb3, 0xe7, 0x37, 0xd3, 0xc3, 0x76, 0x09, 0x79, 0xe2, 0xf4, 0xf1, 0x27, 0x6b, 0x74, 0xc4, 0x5f, 0x06, 0x76, 0x78, 0x56, 0xb9, 0x80, 0x7f, 0x63, 0x53, 0xa2, 0xd1, 0xfc, 0xfb, 0x69, 0x38, 0x0c, 0x13, 0x6e, 0x9e, 0xea, 0x79, 0xc9, 0x6d, 0x45, 0x6b, 0xa3, 0xa8, 0x20, 0x21, 0x24, 0xff, 0x0d, 0x8d, 0xd9, 0x0a, 0x9e, 0xf4, 0x3f, 0xf5, 0x18, 0x39, 0xdd, 0x9f, 0xed, 0xd6, 0x2b, 0xb1, 0x4b, 0x3f, 0x24, 0x7e, 0x11, 0x79, 0x37, 0x01, 0x10, 0xe7, 0x34, 0x1d, 0x36, 0x5f, 0x26, 0x99, 0x5a, 0x4d, 0xe9, 0x1a, 0x89, 0x24, 0xf8, 0xea, 0xca, 0x16, 0x19, 0x6c, 0x3b, 0x8e, 0x44, 0x70, 0x20, 0x5f, 0x46, 0x3c, 0x60, 0xbe, 0x03, 0xfc, 0x99, 0x29, 0xd7, 0x30, 0x5e, 0xbe, 0x5b, 0x17, 0x4f, 0xfe, 0x3f, 0xe0, 0x50, 0xa0, 0x1b, 0x1a, 0x6b, 0x17, 0xf3, 0xf9, 0x01, 0xe8, 0xc6, 0xc8, 0x0f, 0x81, 0xbd, 0x2d, 0xc5, 0x8c, 0xa1, 0xab, 0x9d, 0x13, 0xce, 0x73, 0x14, 0x56, 0x56, 0xb4, 0x68, 0xac, 0x35, 0xf8, 0x6a, 0x55, 0x3e, 0x50, 0x34, 0x5a, 0x66, 0x17, 0x98, 0x4d, 0xd1, 0xa7, 0xdf, 0x57, 0xd6, 0xd4, 0x44, 0x64, 0xa7, 0x74, 0x18, 0x0a, 0x4f, 0xa9, 0xe4, 0xb4, 0x0f, 0x89, 0xa2, 0xc5, 0xb8, 0xa7, 0x20, 0xa2, 0xb1, 0xf8, 0x70, 0xaf, 0xee, 0x6e, 0x62, 0xa5, 0x89, 0x5d, 0xc9, 0x8a, 0xb9, 0x87, 0xac, 0x4d, 0x4d, 0x81, 0x1c, 0x62, 0xd3, 0xbf, 0x83, 0x79, 0x98, 0x81, 0xbd, 0xcc, 0x1f, 0x76, 0xc8, 0x7e, 0x2c, 0xec, 0xdb, 0xa7, 0xa5, 0xea, 0x05, 0x94, 0x3f, 0xef, 0x66, 0x1c, 0x5d, 0xc4, 0xbd, 0x73, 0x53, 0x1f, 0xf3, 0xac, 0x1f, 0xa4, 0xb9, 0x78, 0x1b, 0x93, 0xcb, 0x17, 0xb6, 0xda, 0xbb, 0x45, 0x21, 0xfa, 0x52, 0xc7, 0x71, 0x05, 0xb3, 0xeb, 0x82, 0x09, 0x99, 0x90, 0x5d, 0xa9, 0x76, 0xd1, 0x63, 0x6a, 0x14, 0x99, 0xe9, 0xa5, 0x98, 0x5d, 0xe0, 0xb5, 0x2a, 0xd1, 0xf1, 0x2e, 0xe7, 0x85, 0xdb, 0x42, 0xfc, 0x61, 0x09, 0x14, 0xe5, 0x8e, 0x92, 0x70, 0x91, 0x15, 0x74, 0x2c, 0x16, 0x30, 0xc4, 0xb0, 0xf1, 0x61, 0xd5, 0x55, 0xa8, 0xa3, 0xca, 0x88, 0xe6, 0xb1, 0x58, 0x76, 0xa5, 0x4c, 0x48, 0xe3, 0xdd, 0x7a, 0x5e, 0x0a, 0x86, 0xfd, 0xd6, 0xe8, 0xc0, 0x47, 0x27, 0x1a, 0x58, 0x92, 0xad, 0xa6, 0x51, 0x32, 0x4d, 0x0d, 0x29, 0xd3, 0xcf, 0xf1, 0xcc, 0x29, 0x1a, 0xfe, 0xf6, 0xa0, 0xf3, 0xdd, 0x98, 0x73, 0xcb, 0xbb, 0x8a, 0xe9, 0x55, 0xba, 0x89, 0x2d, 0x31, 0x9b, 0x3d, 0x04, 0x1f, 0xb5, 0x1c, 0x84, 0x63, 0xca, 0xde, 0x75, 0xac, 0x91, 0x78, 0x1f, 0x8b, 0x37, 0x8d, 0x46, 0xaa, 0x79, 0x51, 0xbf, 0x30, 0xfa, 0x3d, 0x9b, 0xd9, 0x20, 0x25, 0x18, 0x46, 0xb6, 0xe7, 0x8e, 0xf7, 0x5e, 0x7d, 0xf8, 0xd3, 0x01, 0x39, 0xe5, 0x9d, 0x46, 0x6b, 0x8c, 0xcf, 0x9d, 0xc6, 0xb9, 0xe8, 0xd8, 0x25, 0x2d, 0x96, 0x07, 0xc7, 0x4e, 0xa3, 0x3a, 0x9a, 0xbc, 0x9d, 0x80, 0xa6, 0x5d, 0xb1, 0xc0, 0x3e, 0x81, 0xe0, 0x52, 0x8f, 0x9a, 0x1a, 0xc2, 0xdb, 0x9f, 0x91, 0x85, 0x56, 0xdb, 0xb8, 0x69, 0x10, 0x35, 0xe4, 0xc4, 0xaf, 0xb6, 0x13, 0xf8, 0x86, 0xe1, 0x2d, 0x3c, 0xf8, 0x94, 0x60, 0xb7, 0xa1, 0xde, 0x25, 0x51, 0x7d, 0xff, 0xff, 0xa6, 0x23, 0x68, 0x28, 0x1f, 0x79, 0x33, 0x60, 0x86, 0xe9, 0x2c, 0x3a, 0xb9, 0x3c, 0x70, 0xb3, 0xe0, 0x4c, 0x8c, 0x7e, 0x06, 0xdf, 0x4d, 0xf6, 0x88, 0xda, 0x9e, 0x4f, 0x5b, 0xd2, 0x2e, 0x28, 0xb8, 0xe0, 0x27, 0x7a, 0x43, 0xfb, 0x23, 0x4b, 0x8a, 0xd9, 0x4f, 0x29, 0x53, 0x5d, 0x75, 0xc6, 0xfc }; uint8_t smbbuf2[] = { 0x0a, 0x30, 0xe0, 0x74, 0x3c, 0x23, 0xc3, 0x11, 0x95, 0x25, 0x04, 0xe4, 0x2d, 0x7b, 0x29, 0xa1, 0x75, 0x69, 0x3f, 0x49, 0x9c, 0xfa, 0x66, 0x78, 0x3c, 0xf1, 0xab, 0xee, 0xab, 0x9a, 0x75, 0x63, 0x54, 0x80, 0x2b, 0x5c, 0x07, 0xf7, 0xec, 0x72, 0xfb, 0xd0, 0x52, 0x5e, 0x7e, 0x99, 0xf5, 0x3b, 0xc4, 0x77, 0x96, 0x12, 0xb8, 0x36, 0xb2, 0xcf, 0xab, 0xf5, 0xd3, 0xf3, 0x19, 0x77, 0xbb, 0x03, 0xdb, 0xf7, 0x4d, 0x81, 0xe3, 0xe8, 0x6c, 0x23, 0x02, 0xe0, 0xcf, 0x24, 0xc1, 0xd5, 0x3d, 0x42, 0xa4, 0xbc, 0x97, 0xf4, 0x83, 0xee, 0xff, 0x85, 0x2c, 0xfd, 0xdd, 0xdc, 0x23, 0x1c, 0x87, 0x0c, 0xe4, 0xd5, 0xfc, 0xc3, 0x8b, 0x10, 0xa5, 0x42, 0x0f, 0x14, 0xd1, 0x89, 0xa6, 0xaf, 0xaa, 0x77, 0xfc, 0x3b, 0xce, 0x6c, 0xbe, 0x62, 0xc9, 0xdd, 0x16, 0xc6, 0x14, 0xc2, 0xa6, 0x13, 0x12, 0xfa, 0x5a, 0x8b, 0x05, 0x88, 0x06, 0xf9, 0xef, 0x9c, 0xce, 0xf7, 0x27, 0x46, 0x1d, 0x50, 0xe2, 0xeb, 0x49, 0xb2, 0xb1, 0x7c, 0x6b, 0xaf, 0xe9, 0xc7, 0xdd, 0x59, 0x8c, 0xda, 0x32, 0x55, 0xb5, 0xfe, 0xdc, 0xe0, 0x47, 0xf4, 0xa0, 0xe7, 0xaa, 0x47, 0x49, 0xdf, 0xcf, 0x9c, 0xd6, 0xfa, 0xd2, 0xca, 0x55, 0xa7, 0x3f, 0x62, 0x14, 0x6c, 0xc8, 0x7f, 0xad, 0x7c, 0xb1, 0x70, 0x88, 0xb3, 0x51, 0x13, 0x2c, 0x3b, 0x78, 0x1d, 0xa2, 0x5e, 0xf7, 0x83, 0x62, 0x6a, 0x51, 0xbd, 0xe9, 0x77, 0x62, 0xc6, 0x06, 0x06, 0x51, 0x9d, 0x03, 0x95, 0x51, 0x7c, 0xd3, 0x73, 0x50, 0x9b, 0x36, 0x5a, 0x28, 0x52, 0xc0, 0x05, 0xee, 0xd5, 0x2d, 0xd5, 0x77, 0x52, 0xab, 0x7c, 0x4a, 0x4c, 0x7e, 0xf6, 0xba, 0x52, 0xc5, 0x4d, 0xb5, 0x74, 0x83, 0x77, 0x5f, 0xaa, 0xba, 0x86, 0x94, 0xd2, 0x19, 0xca, 0xef, 0xc9, 0x6e, 0x5b, 0x50, 0xee, 0x2c, 0xdd, 0x67, 0xc8, 0xfd, 0xc3, 0xa4, 0x80, 0x63, 0x1d, 0xa2, 0x07, 0x1e, 0x1a, 0x9d, 0x70, 0xe4, 0xab, 0x34, 0x7a, 0xfb, 0x08, 0x82, 0x85, 0xec, 0x2d, 0x25, 0x3e, 0x70, 0x22, 0x6e, 0x9d, 0x0f, 0xed, 0x60, 0x8f, 0xc5, 0x06, 0x66, 0x42, 0x95, 0xcc, 0x77, 0xbe, 0x4d, 0x19, 0x7c, 0xd1, 0x31, 0x26, 0xfb, 0x52, 0xad, 0xbd, 0x19, 0x1d, 0x68, 0x56, 0x2c, 0xb9, 0x5b, 0xaa, 0x92, 0x48, 0xcf, 0xdf, 0x65, 0x2d, 0xdb, 0x87, 0x06, 0xbe, 0x51, 0x61, 0x6b, 0xf6, 0x87, 0xdc, 0xbb, 0xa5, 0x48, 0x81, 0xaf, 0xd7, 0xfc, 0x15, 0xf7, 0x41, 0xde, 0xe3, 0xe9, 0xd4, 0xad, 0x5d, 0x64, 0x8f, 0x13, 0x68, 0xe5, 0x2b, 0x4d, 0x87, 0x59, 0x7e, 0xcb, 0x2b, 0xbf, 0xbc, 0xaa, 0xd2, 0xc7, 0x60, 0xef, 0xe1, 0x25, 0xe2, 0x89, 0xb4, 0x78, 0x24, 0x52, 0xb4, 0x54, 0xe3, 0xf0, 0xe5, 0x81, 0xba, 0xe3, 0x00, 0x62, 0x09, 0x8a, 0x19, 0x7b, 0x9b, 0x0f, 0x50, 0x91, 0xa7, 0x80, 0xdb, 0x0e, 0x68, 0xe1, 0x22, 0x54, 0x89, 0x07, 0xc7, 0x39, 0x38, 0xca, 0xae, 0xbf, 0x5b, 0xbb, 0xe4, 0x70, 0x28, 0xc5, 0x18, 0x98, 0xea }; uint8_t smbbuf3[] = { 0x39, 0x99, 0x97, 0x1f, 0xf1, 0x6a, 0x72, 0x0d, 0x35, 0xd5, 0x33, 0x42, 0x5a, 0x9f, 0xea, 0x0f, 0x6f, 0x3b, 0xc7, 0xb9, 0xd3, 0x04, 0xdf, 0x44, 0x45, 0xc7, 0xc6, 0x06, 0x0b, 0x77, 0x8e, 0x8e, 0x9a, 0x3c, 0xa4, 0x15, 0x85, 0x80, 0xce, 0xd0, 0x8c, 0x54, 0x60, 0xf9, 0x1f, 0xb3, 0x3e, 0xed, 0x21, 0x3e, 0xfa, 0x30, 0xf4, 0x50, 0x2b, 0x00, 0x00, 0xea, 0xd1, 0xb3, 0xd2, 0x7e, 0x6c, 0x14, 0xe5, 0xf0, 0xf4, 0x9c, 0xb4, 0x2e, 0x32, 0x41, 0x20, 0x2a, 0x18, 0x78, 0x1a, 0xed, 0x04, 0x94, 0x83, 0xd1, 0x87, 0x39, 0xf6, 0xcb, 0xf4, 0xc1, 0xc7, 0xe0, 0x50, 0x87, 0x65, 0x4f, 0x36, 0x73, 0x70, 0xf5, 0x0a, 0xaa, 0x2b, 0x28, 0xad, 0x05, 0x28, 0x8d, 0x3b, 0x42, 0xfb, 0xe2, 0xd3, 0xb8, 0x82, 0x71, 0x25, 0xcd, 0xa2, 0xf2, 0x4b, 0x62, 0xeb, 0x14, 0x3b, 0x81, 0xaf, 0xd4, 0x68, 0x5a, 0xae, 0x8e, 0x10, 0x9a, 0x17, 0x4c, 0xf1, 0x3d, 0x43, 0xb9, 0xd2, 0xd5, 0x86, 0xee, 0x3a, 0xf3, 0xe5, 0x41, 0xe5, 0x52, 0xda, 0x61, 0xf3, 0x20, 0x30, 0x5b, 0xe5, 0x1f, 0xe2, 0x4e, 0x9d, 0xd6, 0xd6, 0x2e, 0x2a, 0x63, 0xbc, 0xf6, 0xb9, 0xc2, 0xec, 0xd0, 0xe9, 0xfd, 0x07, 0xfb, 0x2d, 0x8e, 0xbc, 0x43, 0xcb, 0x7e, 0x55, 0x63, 0x9f, 0xb6, 0xf8, 0x8b, 0x4c, 0xcd, 0x4b, 0x28, 0x47, 0x56, 0xc9, 0xd2, 0xfe, 0x0e, 0x63, 0x11, 0x09, 0xd9, 0xd9, 0x97, 0x0a, 0x5a, 0x21, 0xad, 0xdb, 0x53, 0x24, 0xee, 0x62, 0x4a, 0xaa, 0x49, 0x14, 0xdf, 0xc0, 0x61, 0x85, 0x11, 0x57, 0x6e, 0x3b, 0x8c, 0x37, 0x24, 0x13, 0xde, 0xc7, 0xf3, 0x44, 0x54, 0x8a, 0x69, 0x78, 0x0c, 0xf3, 0xd1, 0xcd, 0xc5, 0xad, 0x45, 0xc6, 0x06, 0x56, 0x0b, 0x53, 0x40, 0x79, 0x12, 0x90, 0x6b, 0xdf, 0xc5, 0x80, 0xde, 0x9c, 0x8e, 0xe1, 0x73, 0xdc, 0x92, 0xc2, 0xf1, 0xeb, 0xd9, 0x66, 0x0a, 0x12, 0xd2, 0x3f, 0x04, 0x03, 0xaa, 0x6f, 0xd0, 0x90, 0xfa, 0xb0, 0x6b, 0x7d, 0xfc, 0x76, 0xf9, 0xe3, 0xa2, 0x17, 0x28, 0x4e, 0x9d, 0x2d, 0xa6, 0x7e, 0xfa, 0x19, 0x91, 0xeb, 0xe5, 0xe4, 0xca, 0x09, 0x77, 0xfe, 0xc0, 0x1c, 0xaa, 0xc4, 0x7c, 0xc2, 0x6a, 0x0e, 0xf3, 0x4e, 0x79, 0x9b, 0x82, 0x2a, 0x4b, 0xd3, 0x35, 0x1d, 0x92, 0x6c, 0x3f, 0x85, 0x57, 0x5a, 0x16, 0xa1, 0x0d, 0xc7, 0x64, 0xb8, 0x46, 0x73, 0xbf, 0x91, 0x5f, 0x10, 0x2a, 0x2b, 0x51, 0x49, 0xe1, 0xea, 0xda, 0x2f, 0x41, 0x7b, 0x96, 0xa3, 0xd2, 0x7b, 0x72, 0xc0, 0x88, 0x84, 0xcb, 0xe0, 0xb7, 0xae, 0x74, 0xc9, 0x78, 0x82, 0x47, 0xf3, 0x19, 0x21, 0x53, 0xe6, 0xe1, 0x67, 0xbb, 0x39, 0x05, 0x6e, 0x1c, 0x38, 0x33, 0x10, 0x60, 0x24, 0x48, 0xb2, 0x7a, 0xb9, 0x4e, 0x8d, 0x36, 0xcf, 0xce, 0xf6, 0x31, 0x3b, 0xa3, 0x18, 0x78, 0x49, 0x91, 0xef, 0xed, 0x86, 0x2c, 0x98, 0x00, 0x18, 0x49, 0x73, 0xb8, 0xe5, 0x2f, 0xc1, 0x58, 0xe0, 0x47, 0x2b, 0x16, 0x41, 0xc3, 0x41, 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x00, 0x00 }; uint32_t smblen1 = sizeof(smbbuf1); uint32_t smblen2 = sizeof(smbbuf2); uint32_t smblen3 = sizeof(smbbuf3); TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } SMBState *smb_state = f.alstate; if (smb_state == NULL) { printf("no smb state: "); goto end; } if (smb_state->smb.command != SMB_COM_WRITE_ANDX) { printf("expected SMB command 0x%02x , got 0x%02x : ", SMB_COM_WRITE_ANDX, smb_state->smb.command); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf3, smblen3); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } printUUID("BIND", smb_state->dcerpc.dcerpcbindbindack.uuid_entry); result = 1; end: StreamTcpFreeConfig(TRUE); return result; } int SMBParserTest04(void) { int result = 0; Flow f; uint8_t smbbuf1[] = { 0x00, 0x00, 0x00, 0x88, 0xff, 0x53, 0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18, 0x07, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7c, 0x05, 0x00, 0x08, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0xab, 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x78, 0x56, 0x34, 0x12, 0x34, 0x12, 0xcd, 0xab, 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint8_t smbbuf2[] = { 0x00, 0x00, 0x00, 0x2f, 0xff, 0x53, 0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x98, 0x07, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7c, 0x05, 0x00, 0x08, 0x00, 0x00, 0x06, 0xff, 0x00, 0x2f, 0x00, 0x48, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t smbbuf3[] = { 0x00, 0x00, 0x00, 0x3b, 0xff, 0x53, 0x4d, 0x42, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7c, 0x05, 0x00, 0x08, 0x00, 0x00, 0x0c, 0xff, 0x00, 0xde, 0xde, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t smbbuf4[] = { 0x00, 0x00, 0x00, 0x80, 0xff, 0x53, 0x4d, 0x42, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x98, 0x03, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7c, 0x05, 0x00, 0x08, 0x00, 0x00, 0x0c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x5d, 0xe0, 0x00, 0x00, 0x0e, 0x00, 0x5c, 0x70, 0x69, 0x70, 0x65, 0x5c, 0x73, 0x70, 0x6f, 0x6f, 0x6c, 0x73, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t smblen1 = sizeof(smbbuf1); uint32_t smblen2 = sizeof(smbbuf2); uint32_t smblen3 = sizeof(smbbuf3); uint32_t smblen4 = sizeof(smbbuf4); TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } SMBState *smb_state = f.alstate; if (smb_state == NULL) { printf("no smb state: "); goto end; } if (smb_state->smb.command != SMB_COM_WRITE_ANDX) { printf("expected SMB command 0x%02x , got 0x%02x : ", SMB_COM_WRITE_ANDX, smb_state->smb.command); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf3, smblen3); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf4, smblen4); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } int SMBParserTest05(void) { uint8_t smbbuf1[] = { /* session request */ 0x81, 0x00, 0x00, 0x44, 0x20, 0x43, 0x4b, 0x46, 0x44, 0x45, 0x4e, 0x45, 0x43, 0x46, 0x44, 0x45, 0x46, 0x46, 0x43, 0x46, 0x47, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x00, 0x20, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41, 0x41, 0x00 }; uint32_t smblen1 = sizeof(smbbuf1); uint8_t smbbuf2[] = { /* session request */ 0x81, 0x00, 0x00, 0x44, 0x20, 0x43, 0x4b, 0x46, 0x44, 0x45, 0x4e, 0x45, 0x43, 0x46, 0x44, 0x45, 0x46, 0x46, 0x43, 0x46, 0x47, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x00, 0x20, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41, 0x41, 0x00, /* session message */ 0x00, 0x00, 0x00, 0x60, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x2d, 0x00, 0x00, 0xdd, 0xca, 0x00, 0x3d, 0x00, 0x02, 0x4d, 0x45, 0x54, 0x41, 0x53, 0x50, 0x4c, 0x4f, 0x49, 0x54, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x4e, 0x54, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4e, 0x54, 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00 }; uint32_t smblen2 = sizeof(smbbuf2); int result = 0; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; uint16_t alproto; Flow f; memset(&f, 0, sizeof(f)); f.dp = 139; AlpProtoInit(&ctx); /** SMB */ AlpProtoAdd(&ctx, "smb", IPPROTO_TCP, ALPROTO_SMB, "|ff|SMB", 8, 4, STREAM_TOCLIENT); AlpProtoAdd(&ctx, "smb", IPPROTO_TCP, ALPROTO_SMB, "|ff|SMB", 8, 4, STREAM_TOSERVER); /** SMB2 */ AlpProtoAdd(&ctx, "smb2", IPPROTO_TCP, ALPROTO_SMB2, "|fe|SMB", 8, 4, STREAM_TOCLIENT); AlpProtoAdd(&ctx, "smb2", IPPROTO_TCP, ALPROTO_SMB2, "|fe|SMB", 8, 4, STREAM_TOSERVER); AppLayerRegisterProbingParser(&ctx, f.dp, IPPROTO_TCP, "smb", ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, SMBProbingParser); AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); alproto = AppLayerDetectGetProto(&ctx, &tctx, &f, smbbuf1, smblen1, STREAM_TOSERVER, IPPROTO_TCP); if (alproto != ALPROTO_UNKNOWN) { printf("alproto is %"PRIu16 ". Should be ALPROTO_UNKNOWN\n", alproto); goto end; } alproto = AppLayerDetectGetProto(&ctx, &tctx, &f, smbbuf2, smblen2, STREAM_TOSERVER, IPPROTO_TCP); if (alproto != ALPROTO_SMB) { printf("alproto is %"PRIu16 ". Should be ALPROTO_SMB\n", alproto); goto end; } result = 1; end: AlpProtoTestDestroy(&ctx); PmqFree(&tctx.toclient.pmq); PmqFree(&tctx.toserver.pmq); return result; } int SMBParserTest06(void) { uint8_t smbbuf1[] = { /* session request */ 0x83, 0x00, 0x00, 0x01, 0x82 }; uint32_t smblen1 = sizeof(smbbuf1); uint8_t smbbuf2[] = { /* session request */ 0x83, 0x00, 0x00, 0x01, 0x82, /* session message */ 0x00, 0x00, 0x00, 0x55, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, 0x0a, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe3, 0x00, 0x80, 0xb8, 0xcb, 0x22, 0x5f, 0xfd, 0xeb, 0xc3, 0x01, 0x68, 0x01, 0x00, 0x10, 0x00, 0x50, 0xb5, 0xc3, 0x62, 0x59, 0x02, 0xd1, 0x4d, 0x99, 0x6d, 0x85, 0x7d, 0xfa, 0x93, 0x2d, 0xbb }; uint32_t smblen2 = sizeof(smbbuf2); int result = 0; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; uint16_t alproto; Flow f; memset(&f, 0, sizeof(f)); f.dp = 139; AlpProtoInit(&ctx); /** SMB */ AlpProtoAdd(&ctx, "smb", IPPROTO_TCP, ALPROTO_SMB, "|ff|SMB", 8, 4, STREAM_TOCLIENT); AlpProtoAdd(&ctx, "smb", IPPROTO_TCP, ALPROTO_SMB, "|ff|SMB", 8, 4, STREAM_TOSERVER); /** SMB2 */ AlpProtoAdd(&ctx, "smb2", IPPROTO_TCP, ALPROTO_SMB2, "|fe|SMB", 8, 4, STREAM_TOCLIENT); AlpProtoAdd(&ctx, "smb2", IPPROTO_TCP, ALPROTO_SMB2, "|fe|SMB", 8, 4, STREAM_TOSERVER); AppLayerRegisterProbingParser(&ctx, f.dp, IPPROTO_TCP, "smb", ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, APP_LAYER_PROBING_PARSER_PRIORITY_HIGH, 1, SMBProbingParser); AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); alproto = AppLayerDetectGetProto(&ctx, &tctx, &f, smbbuf1, smblen1, STREAM_TOSERVER, IPPROTO_TCP); if (alproto != ALPROTO_UNKNOWN) { printf("alproto is %"PRIu16 ". Should be ALPROTO_UNKNOWN\n", alproto); goto end; } alproto = AppLayerDetectGetProto(&ctx, &tctx, &f, smbbuf2, smblen2, STREAM_TOSERVER, IPPROTO_TCP); if (alproto != ALPROTO_SMB) { printf("alproto is %"PRIu16 ". Should be ALPROTO_SMB\n", alproto); goto end; } result = 1; end: AlpProtoTestDestroy(&ctx); PmqFree(&tctx.toclient.pmq); PmqFree(&tctx.toserver.pmq); return result; } int SMBParserTest07(void) { int result = 0; Flow f; uint8_t smbbuf1[] = { /* negative session response */ 0x83, 0x00, 0x00, 0x01, 0x82 }; uint32_t smblen1 = sizeof(smbbuf1); TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } SMBState *smb_state = f.alstate; if (smb_state == NULL) { printf("no smb state: "); goto end; } if (smb_state->smb.command != 0) { printf("we shouldn't have any smb state as yet\n"); goto end; } if (smb_state->nbss.length != 1 || smb_state->nbss.type != NBSS_NEGATIVE_SESSION_RESPONSE) { printf("something wrong with nbss parsing\n"); goto end; } if (smb_state->bytesprocessed != 0) { printf("smb parser bytesprocessed should be 0, but it is not\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } int SMBParserTest08(void) { int result = 0; Flow f; uint8_t smbbuf1[] = { /* positive session response */ 0x82, 0x00, 0x00, 0x00 }; uint8_t smbbuf2[] = { /* negotiate protocol */ 0x00, 0x00, 0x00, 0x55, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, 0x0a, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe3, 0x00, 0x80, 0x40, 0x8a, 0x57, 0x5c, 0xfd, 0xeb, 0xc3, 0x01, 0x68, 0x01, 0x00, 0x10, 0x00, 0x50, 0xb5, 0xc3, 0x62, 0x59, 0x02, 0xd1, 0x4d, 0x99, 0x6d, 0x85, 0x7d, 0xfa, 0x93, 0x2d, 0xbb }; uint32_t smblen1 = sizeof(smbbuf1); uint32_t smblen2 = sizeof(smbbuf2); TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } SMBState *smb_state = f.alstate; if (smb_state == NULL) { printf("no smb state: "); goto end; } if (smb_state->smb.command != 0) { printf("we shouldn't have any smb state as yet\n"); goto end; } if (smb_state->nbss.length != 0 || smb_state->nbss.type != NBSS_POSITIVE_SESSION_RESPONSE) { printf("something wrong with nbss parsing\n"); goto end; } if (smb_state->bytesprocessed != 0) { printf("smb parser bytesprocessed should be 0, but it is not\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOCLIENT, smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } if (smb_state->smb.command != SMB_COM_NEGOTIATE) { printf("we should expect SMB command 0x%02x , got 0x%02x : ", SMB_COM_NEGOTIATE, smb_state->smb.command); goto end; } if (smb_state->nbss.length != 85 || smb_state->nbss.type != NBSS_SESSION_MESSAGE) { printf("something wrong with nbss parsing\n"); goto end; } if (smb_state->bytesprocessed != 0) { printf("smb parser bytesprocessed should be 0, but it is not\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } int SMBParserTest09(void) { int result = 0; Flow f; uint8_t smbbuf1[] = { /* session request */ 0x81, 0x00, 0x00, 0x44, 0x20, 0x45, 0x44, 0x45, 0x4a, 0x46, 0x44, 0x45, 0x44, 0x45, 0x50, 0x43, 0x4e, 0x46, 0x48, 0x44, 0x43, 0x45, 0x4c, 0x43, 0x4e, 0x46, 0x43, 0x46, 0x45, 0x45, 0x4e, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x00, 0x20, 0x45, 0x44, 0x45, 0x4a, 0x46, 0x44, 0x45, 0x44, 0x45, 0x50, 0x43, 0x4e, 0x46, 0x49, 0x46, 0x41, 0x43, 0x4e, 0x46, 0x43, 0x46, 0x45, 0x45, 0x4e, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41, 0x41, 0x00 }; uint8_t smbbuf2[] = { /* session service - negotiate protocol */ 0x00, 0x00, 0x00, 0x85, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x20, 0x33, 0x2e, 0x31, 0x61, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4e, 0x54, 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00 }; uint32_t smblen1 = sizeof(smbbuf1); uint32_t smblen2 = sizeof(smbbuf2); TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } SMBState *smb_state = f.alstate; if (smb_state == NULL) { printf("no smb state: "); goto end; } if (smb_state->smb.command != 0) { printf("we shouldn't have any smb state as yet\n"); goto end; } if (smb_state->nbss.length != 68 || smb_state->nbss.type != NBSS_SESSION_REQUEST) { printf("something wrong with nbss parsing\n"); goto end; } if (smb_state->bytesprocessed != 0) { printf("smb parser bytesprocessed should be 0, but it is not\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } if (smb_state->smb.command != SMB_COM_NEGOTIATE) { printf("we should expect SMB command 0x%02x , got 0x%02x : ", SMB_COM_NEGOTIATE, smb_state->smb.command); goto end; } if (smb_state->nbss.length != 133 || smb_state->nbss.type != NBSS_SESSION_MESSAGE) { printf("something wrong with nbss parsing\n"); goto end; } if (smb_state->bytesprocessed != 0) { printf("smb parser bytesprocessed should be 0, but it is not\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** * \test Test to temporarily to show the direction demaraction issue in the * smb parser. */ int SMBParserTest10(void) { int result = 0; Flow f; uint8_t smbbuf1[] = { /* partial request */ 0x00, 0x00, 0x00, 0x85, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x20, 0x33, 0x2e, 0x31, 0x61, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, }; //0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4e, 0x54, //0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, //0x00 uint8_t smbbuf2[] = { /* response */ 0x00, 0x00, 0x00, 0x55, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, 0x32, 0x00, 0x01, 0x00, 0x04, 0x41, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xf3, 0x00, 0x80, 0x20, 0x03, 0x1a, 0x2d, 0x77, 0x98, 0xc5, 0x01, 0xa4, 0x01, 0x00, 0x10, 0x00, 0xb7, 0xeb, 0x0b, 0x05, 0x21, 0x22, 0x50, 0x42, 0x8c, 0x38, 0x2a, 0x7f, 0xc5, 0x6a, 0x7c, 0x0c }; uint32_t smblen1 = sizeof(smbbuf1); uint32_t smblen2 = sizeof(smbbuf2); TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); goto end; } SMBState *smb_state = f.alstate; if (smb_state == NULL) { printf("no smb state: "); goto end; } if (smb_state->bytesprocessed == 0) { printf("request - smb parser bytesprocessed should not be 0.\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SMB, STREAM_TOCLIENT, smbbuf2, smblen2); if (r == 0) { printf("smb parser didn't return fail\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } #endif void SMBParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SMBParserTest01", SMBParserTest01, 1); UtRegisterTest("SMBParserTest02", SMBParserTest02, 1); UtRegisterTest("SMBParserTest03", SMBParserTest03, 1); UtRegisterTest("SMBParserTest04", SMBParserTest04, 1); UtRegisterTest("SMBParserTest05", SMBParserTest05, 1); UtRegisterTest("SMBParserTest06", SMBParserTest06, 1); UtRegisterTest("SMBParserTest07", SMBParserTest07, 1); UtRegisterTest("SMBParserTest08", SMBParserTest08, 1); UtRegisterTest("SMBParserTest09", SMBParserTest09, 1); UtRegisterTest("SMBParserTest10", SMBParserTest10, 1); #endif } suricata-1.4.7/src/util-decode-der.c0000644000000000000000000005242312253546156014145 00000000000000/* * Copyright (C) 2011-2012 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * \author Pierre Chifflier * */ /* * An ASN.1 Parser for DER-encoded structures. * This parser is not written to be complete or fast, but is rather * focused on stability and security. * It does not support all ASN.1 structure, only a meaningful subset * to decode x509v3 certificates (See RFC 3280). * * References (like 8.19.4) are relative to the ISO/IEC 8825-1:2003 document * */ #include "suricata-common.h" #include "util-decode-der.h" #define MAX_OID_LENGTH 256 static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); static Asn1Generic * Asn1GenericNew(void) { Asn1Generic *obj; obj = SCMalloc(sizeof(Asn1Generic)); if (obj != NULL) memset(obj, 0, sizeof(Asn1Generic)); return obj; } static void Asn1SequenceAppend(Asn1Generic *seq, Asn1Generic *node) { Asn1Generic *it, *new_container; if (seq->data == NULL) { seq->data = node; return; } new_container = Asn1GenericNew(); if (new_container == NULL) return; new_container->data = node; for (it=seq; it->next != NULL; it=it->next) ; it->next = new_container; } static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t max_size, uint8_t depth, int seq_index, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t numbytes, el_max_size; Asn1ElementType el; uint8_t c; uint32_t i; Asn1Generic *child; uint8_t el_type; el.cls = (d_ptr[0] & 0xc0) >> 6; el.pc = (d_ptr[0] & 0x20) >> 5; el.tag = (d_ptr[0] & 0x1f); el_type = el.tag; if (el.tag == 0x1f) return NULL; switch (el.cls) { case ASN1_CLASS_CONTEXTSPEC: /* get element type from definition * see http://www.ietf.org/rfc/rfc3280.txt) */ if (depth == 2 && el.tag == 0) { el_type = ASN1_SEQUENCE; /* TBSCertificate */ break; } if (depth == 2 && el.tag == 1) { el_type = ASN1_BITSTRING; /* issuerUniqueID */ break; } if (depth == 2 && el.tag == 2) { el_type = ASN1_BITSTRING; /* subjectUniqueID */ break; } if (depth == 2 && el.tag == 3) { el_type = ASN1_SEQUENCE; /* extensions */ break; } /* unknown context specific value - do not decode */ break; }; el_max_size = max_size - (d_ptr-buffer); switch (el_type) { case ASN1_INTEGER: child = DecodeAsn1DerInteger(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_BOOLEAN: child = DecodeAsn1DerBoolean(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_NULL: child = DecodeAsn1DerNull(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_BITSTRING: child = DecodeAsn1DerBitstring(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_OID: child = DecodeAsn1DerOid(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_IA5STRING: child = DecodeAsn1DerIA5String(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_OCTETSTRING: child = DecodeAsn1DerOctetString(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_UTF8STRING: child = DecodeAsn1DerUTF8String(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_PRINTSTRING: child = DecodeAsn1DerPrintableString(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_SEQUENCE: child = DecodeAsn1DerSequence(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_SET: child = DecodeAsn1DerSet(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_T61STRING: child = DecodeAsn1DerT61String(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_UTCTIME: child = DecodeAsn1DerUTCTime(d_ptr, el_max_size, depth+1, errcode); break; default: /* unknown ASN.1 type */ child = NULL; child = Asn1GenericNew(); if (child == NULL) break; child->type = el.tag; /* total sequence length */ const unsigned char * save_d_ptr = d_ptr; d_ptr++; c = d_ptr[0]; if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ child->length = c; d_ptr++; } else { /* long form 8.1.3.5 */ numbytes = c & 0x7f; if (numbytes > el_max_size) { SCFree(child); if (errcode) *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; return NULL; } child->length = 0; d_ptr++; for (i=0; ilength = child->length<<8 | d_ptr[0]; d_ptr++; } } /* fix the length for unknown objects, else * sequence parsing will fail */ child->length += (d_ptr - save_d_ptr); break; }; if (child == NULL) return NULL; child->header = el; return child; } static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint8_t numbytes; uint32_t value; uint32_t i; Asn1Generic *a; numbytes = d_ptr[1]; if (numbytes > size) { if (errcode) *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; return NULL; } d_ptr += 2; value = 0; /* Here we need to ensure that numbytes is less than 4 so integer affectation is possible. We set the value to 0xffffffff which is by convention the unknown value. In this case, the hexadecimal value must be used. */ if (numbytes > 4) { value = 0xffffffff; } else { for (i=0; itype = ASN1_INTEGER; a->length = (d_ptr - buffer) + numbytes; a->value = value; a->str = SCMalloc(2*numbytes + 1); if (a->str == NULL) { SCFree(a); return NULL; } for (i=0; istr + 2*i, 2*(numbytes-i)+1, "%02X", d_ptr[i]); } a->str[2*numbytes]='\0'; return a; } static int DecodeAsn1BuildValue(const unsigned char **d_ptr, uint32_t *val, uint8_t numbytes, uint32_t *errcode) { int i; uint32_t value = 0; if (numbytes > 4) { if (errcode) *errcode = ERR_DER_INVALID_SIZE; /* too big won't fit: set it to 0xffffffff by convention */ value = 0xffffffff; *val = value; return -1; } else { for (i=0; itype = ASN1_BOOLEAN; a->length = (d_ptr - buffer); a->value = value; return a; } static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint8_t numbytes; uint32_t value; Asn1Generic *a; numbytes = d_ptr[1]; d_ptr += 2; if (DecodeAsn1BuildValue(&d_ptr, &value, numbytes, errcode) == -1) { return NULL; } a = Asn1GenericNew(); if (a == NULL) return NULL; a->type = ASN1_NULL; a->length = (d_ptr - buffer); a->value = 0; return a; } static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length; uint8_t numbytes, c; Asn1Generic *a; d_ptr++; /* size */ c = d_ptr[0]; if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ length = c; d_ptr++; } else { /* long form 8.1.3.5 */ numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } if (length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; a->type = ASN1_BITSTRING; a->strlen = length; a->str = SCMalloc(length); if (a->str == NULL) { SCFree(a); return NULL; } memcpy(a->str, (const char*)d_ptr, length); d_ptr += length; a->length = (d_ptr - buffer); return a; } static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t oid_length, oid_value; uint8_t numbytes, c; Asn1Generic *a; uint32_t i; d_ptr++; /* size */ c = d_ptr[0]; if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ oid_length = c; d_ptr++; } else { /* long form 8.1.3.5 */ numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &oid_length, numbytes, errcode) == -1) { return NULL; } } if (oid_length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; a->type = ASN1_OID; a->str = SCMalloc(MAX_OID_LENGTH); if (a->str == NULL) { SCFree(a); return NULL; } /* first element = X*40 + Y (See 8.19.4) */ snprintf(a->str, MAX_OID_LENGTH, "%d.%d", (d_ptr[0]/40), (d_ptr[0]%40)); d_ptr++; /* sub-identifiers are multi valued, coded and 7 bits, first bit of the 8bits is used to indicate, if a new value is starting */ for (i=1; istr); c = d_ptr[0]; oid_value = 0; while ( istr + s, MAX_OID_LENGTH - s, ".%d", oid_value); } a->length = (d_ptr - buffer); return a; } static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; Asn1Generic *a; unsigned char c; d_ptr++; /* total sequence length */ c = d_ptr[0]; if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ length = c; d_ptr++; } else { /* long form 8.1.3.5 */ numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } if (length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; a->type = ASN1_IA5STRING; a->strlen = length; a->str = SCMalloc(length+1); if (a->str == NULL) { SCFree(a); return NULL; } strlcpy(a->str, (const char*)d_ptr, length+1); d_ptr += length; a->length = (d_ptr - buffer); return a; } static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; Asn1Generic *a; unsigned char c; d_ptr++; /* total sequence length */ c = d_ptr[0]; if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ length = c; d_ptr++; } else { /* long form 8.1.3.5 */ numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } if (length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; a->type = ASN1_OCTETSTRING; a->strlen = length; /* Add one to the octet string for the 0. This will then * allow us to use the string in printf */ a->str = SCMalloc(length + 1); if (a->str == NULL) { SCFree(a); return NULL; } memcpy(a->str, (const char*)d_ptr, length); a->str[length] = 0; d_ptr += length; a->length = (d_ptr - buffer); return a; } static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { Asn1Generic *a = DecodeAsn1DerOctetString(buffer, max_size, depth, errcode); if (a != NULL) a->type = ASN1_UTF8STRING; return a; } static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; Asn1Generic *a; unsigned char c; d_ptr++; /* total sequence length */ c = d_ptr[0]; if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ length = c; d_ptr++; } else { /* long form 8.1.3.5 */ numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } if (length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; a->type = ASN1_PRINTSTRING; a->strlen = length; a->str = SCMalloc(length+1); if (a->str == NULL) { SCFree(a); return NULL; } strlcpy(a->str, (const char*)d_ptr, length+1); a->str[length] = '\0'; d_ptr += length; a->length = (d_ptr - buffer); return a; } static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, parsed_bytes, numbytes, el_max_size; uint8_t c; uint32_t seq_index; Asn1Generic *node; Asn1Generic *child; d_ptr++; node = Asn1GenericNew(); if (node == NULL) return NULL; node->type = ASN1_SEQUENCE; /* total sequence length */ c = d_ptr[0]; if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ d_length = c; d_ptr++; } else { /* long form 8.1.3.5 */ numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { SCFree(node); return NULL; } } node->length = d_length + (d_ptr - buffer); if (node->length > max_size) { SCFree(node); return NULL; } parsed_bytes = 0; seq_index = 0; /* decode child elements */ while (parsed_bytes < d_length) { el_max_size = max_size - (d_ptr-buffer); child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode); if (child == NULL) { break; } Asn1SequenceAppend(node, child); parsed_bytes += child->length; d_ptr += child->length; seq_index++; } return (Asn1Generic *)node; } static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, numbytes, el_max_size; uint8_t c; uint32_t seq_index; Asn1Generic *node; Asn1Generic *child; d_ptr++; node = Asn1GenericNew(); if (node == NULL) return NULL; node->type = ASN1_SET; node->data = NULL; /* total sequence length */ c = d_ptr[0]; if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ d_length = c; d_ptr++; } else { /* long form 8.1.3.5 */ numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { SCFree(node); return NULL; } } node->length = d_length + (d_ptr - buffer); if (node->length > max_size) { if (errcode) *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; SCFree(node); return NULL; } seq_index = 0; el_max_size = max_size - (d_ptr-buffer); child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode); node->data = child; return (Asn1Generic *)node; } static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { Asn1Generic *a; a = DecodeAsn1DerIA5String(buffer, max_size, depth, errcode); if (a != NULL) a->type = ASN1_T61STRING; return a; } static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) { Asn1Generic *a; a = DecodeAsn1DerIA5String(buffer, max_size, depth, errcode); if (a != NULL) a->type = ASN1_UTCTIME; return a; } Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, numbytes; Asn1Generic *cert; uint8_t c; /* Check that buffer is an ASN.1 structure (basic checks) */ if (d_ptr[0] != 0x30 && d_ptr[1] != 0x82) /* Sequence */ return NULL; c = d_ptr[1]; if ((c & (1<<7))>>7 != 1) return NULL; numbytes = c & 0x7f; d_ptr += 2; if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { return NULL; } if (d_length+(d_ptr-buffer) != size) return NULL; if (errcode) *errcode = 0; cert = DecodeAsn1DerGeneric(buffer, size, 0 /* depth */, 0, errcode); return cert; } void DerFree(Asn1Generic *a) { Asn1Generic *it, *n; if (a == NULL) return; it = a; while (it) { n = it->next; if (it->data) { DerFree(it->data); } if (it->str) SCFree(it->str); memset(it, 0xff, sizeof(Asn1Generic)); SCFree(it); it = n; } } suricata-1.4.7/src/decode-ethernet.h0000644000000000000000000000316212253546156014237 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DECODE_ETHERNET_H__ #define __DECODE_ETHERNET_H__ #define ETHERNET_HEADER_LEN 14 /* 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_ { uint8_t eth_dst[6]; uint8_t eth_src[6]; uint16_t eth_type; } EthernetHdr; #endif /* __DECODE_ETHERNET_H__ */ suricata-1.4.7/src/runmode-af-packet.c0000644000000000000000000004154412253546156014503 00000000000000/* Copyright (C) 2011,2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup afppacket * * @{ */ /** * \file * * \author Eric Leblond * * AF_PACKET socket runmode * */ #include "suricata-common.h" #include "config.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-af-packet.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" #include "util-device.h" #include "util-runmodes.h" #include "source-af-packet.h" extern int max_pending_packets; static const char *default_mode_auto = NULL; static const char *default_mode_autofp = NULL; const char *RunModeAFPGetDefaultMode(void) { return default_mode_autofp; } void RunModeIdsAFPRegister(void) { default_mode_auto = "autofp"; RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "auto", "Multi threaded af-packet mode", RunModeIdsAFPAuto); RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single", "Single threaded af-packet mode", RunModeIdsAFPSingle); RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "workers", "Workers af-packet mode, each thread does all" " tasks from acquisition to logging", RunModeIdsAFPWorkers); default_mode_autofp = "autofp"; RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "autofp", "Multi socket AF_PACKET mode. Packets from " "each flow are assigned to a single detect " "thread.", RunModeIdsAFPAutoFp); return; } void AFPDerefConfig(void *conf) { AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf; /* Pcap config is used only once but cost of this low. */ if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { SCFree(pfp); } } /** * \brief extract information from config file * * The returned structure will be freed by the thread init function. * This is thus necessary to or copy the structure before giving it * to thread or to reparse the file for each thread (and thus have * new structure. * * \return a AFPIfaceConfig corresponding to the interface name */ void *ParseAFPConfig(const char *iface) { char *threadsstr = NULL; ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *af_packet_node; AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpclusterid; char *tmpctype; char *copymodestr; intmax_t value; int boolval; char *bpf_filter = NULL; char *out_iface = NULL; if (unlikely(aconf == NULL)) { return NULL; } if (iface == NULL) { SCFree(aconf); return NULL; } strlcpy(aconf->iface, iface, sizeof(aconf->iface)); aconf->threads = 1; SC_ATOMIC_INIT(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, 1); aconf->buffer_size = 0; aconf->cluster_id = 1; aconf->cluster_type = PACKET_FANOUT_HASH; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; aconf->DerefFunc = AFPDerefConfig; aconf->flags = 0; aconf->bpf_filter = NULL; aconf->out_iface = NULL; if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; SCLogInfo("Going to use command-line provided bpf filter '%s'", aconf->bpf_filter); } } /* Find initial node */ af_packet_node = ConfGetNode("af-packet"); if (af_packet_node == NULL) { SCLogInfo("Unable to find af-packet config using default value"); return aconf; } if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", iface); if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find af-packet config for " "interface \"%s\" or \"default\", using default value", iface); return aconf; } /* If there is no setting for current interface use default one as main iface */ if (if_root == NULL) { if_root = if_default; if_default = NULL; } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { aconf->threads = 1; } else { if (threadsstr != NULL) { aconf->threads = (uint8_t)atoi(threadsstr); } } if (aconf->threads == 0) { aconf->threads = 1; } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { aconf->out_iface = out_iface; } } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval); if (boolval) { SCLogInfo("Enabling mmaped capture on iface %s", aconf->iface); aconf->flags |= AFP_RING_MODE; } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-emergency-flush", (int *)&boolval); if (boolval) { SCLogInfo("Enabling ring emergency flush on iface %s", aconf->iface); aconf->flags |= AFP_EMERGENCY_MODE; } aconf->copy_mode = AFP_COPY_MODE_NONE; if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { if (aconf->out_iface == NULL) { SCLogInfo("Copy mode activated but no destination" " iface. Disabling feature"); } else if (!(aconf->flags & AFP_RING_MODE)) { SCLogInfo("Copy mode activated but use-mmap " "set to no. Disabling feature"); } else if (strlen(copymodestr) <= 0) { aconf->out_iface = NULL; } else if (strcmp(copymodestr, "ips") == 0) { SCLogInfo("AF_PACKET IPS mode activated %s->%s", iface, aconf->out_iface); aconf->copy_mode = AFP_COPY_MODE_IPS; } else if (strcmp(copymodestr, "tap") == 0) { SCLogInfo("AF_PACKET TAP mode activated %s->%s", iface, aconf->out_iface); aconf->copy_mode = AFP_COPY_MODE_TAP; } else { SCLogInfo("Invalid mode (not in tap, ips)"); } } SC_ATOMIC_RESET(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { aconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id); } if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type from config"); } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_LB; } else if (strcmp(tmpctype, "cluster_flow") == 0) { /* In hash mode, we also ask for defragmentation needed to * compute the hash */ uint16_t defrag = 0; SCLogInfo("Using flow cluster mode for AF_PACKET (iface %s)", aconf->iface); ConfGetChildValueBoolWithDefault(if_root, if_default, "defrag", (int *)&defrag); if (defrag) { SCLogInfo("Using defrag kernel functionality for AF_PACKET (iface %s)", aconf->iface); defrag = PACKET_FANOUT_FLAG_DEFRAG; } aconf->cluster_type = PACKET_FANOUT_HASH | defrag; } else if (strcmp(tmpctype, "cluster_cpu") == 0) { SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_CPU; } else { SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); SCFree(aconf); return NULL; } /*load af_packet bpf filter*/ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) != 1) { if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter); } } } if ((ConfGetChildValueIntWithDefault(if_root, if_default, "buffer-size", &value)) == 1) { aconf->buffer_size = value; } else { aconf->buffer_size = 0; } if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) { aconf->ring_size = value; if (value * aconf->threads < max_pending_packets) { aconf->ring_size = max_pending_packets / aconf->threads + 1; SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. " "Resetting to decent value %d.", aconf->ring_size); /* We want at least that max_pending_packets packets can be handled by the * interface. This is generous if we have multiple interfaces listening. */ } } else { /* We want that max_pending_packets packets can be handled by suricata * for this interface. To take burst into account we multiply the obtained * size by 2. */ aconf->ring_size = max_pending_packets * 2 / aconf->threads; } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); if (boolval) { SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface); aconf->promisc = 0; } if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (strcmp(tmpctype, "yes") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (strcmp(tmpctype, "no") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "kernel") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); } } return aconf; } int AFPConfigGeThreadsCount(void *conf) { AFPIfaceConfig *afp = (AFPIfaceConfig *)conf; return afp->threads; } /** * \brief RunModeIdsAFPAuto set up the following thread packet handlers: * - Receive thread (from live iface) * - Decode thread * - Stream thread * - Detect: If we have only 1 cpu, it will setup one Detect thread * If we have more than one, it will setup num_cpus - 1 * starting from the second cpu available. * - Respond/Reject thread * - Outputs thread * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * * \param de_ctx Pointer to the Detection Engine. * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) { SCEnter(); #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; RunModeInitialize(); TimeModeSetLive(); (void)ConfGet("af-packet.live-interface", &live_dev); if (AFPPeersListInit() != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); exit(EXIT_FAILURE); } ret = RunModeSetLiveCaptureAuto(de_ctx, ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "RecvAFP", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); exit(EXIT_FAILURE); } /* In IPS mode each threads must have a peer */ if (AFPPeersListCheck() != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsAFPAuto initialised"); #endif SCReturnInt(0); } int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); /* We include only if AF_PACKET is enabled */ #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; RunModeInitialize(); TimeModeSetLive(); (void)ConfGet("af-packet.live-interface", &live_dev); SCLogDebug("live_dev %s", live_dev); if (AFPPeersListInit() != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); exit(EXIT_FAILURE); } ret = RunModeSetLiveCaptureAutoFp(de_ctx, ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "RxAFP", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); exit(EXIT_FAILURE); } /* In IPS mode each threads must have a peer */ if (AFPPeersListCheck() != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsAFPAutoFp initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); } /** * \brief Single thread version of the AF_PACKET processing. */ int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) { #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; #endif SCEnter(); #ifdef HAVE_AF_PACKET RunModeInitialize(); TimeModeSetLive(); (void)ConfGet("af-packet.live-interface", &live_dev); if (AFPPeersListInit() != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); exit(EXIT_FAILURE); } ret = RunModeSetLiveCaptureSingle(de_ctx, ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "AFPacket", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); exit(EXIT_FAILURE); } /* In IPS mode each threads must have a peer */ if (AFPPeersListCheck() != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsAFPSingle initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); } /** * \brief Workers version of the AF_PACKET processing. * * Start N threads with each thread doing all the work. * */ int RunModeIdsAFPWorkers(DetectEngineCtx *de_ctx) { #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; #endif SCEnter(); #ifdef HAVE_AF_PACKET RunModeInitialize(); TimeModeSetLive(); (void)ConfGet("af-packet.live-interface", &live_dev); if (AFPPeersListInit() != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); exit(EXIT_FAILURE); } ret = RunModeSetLiveCaptureWorkers(de_ctx, ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", "DecodeAFP", "AFPacket", live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); exit(EXIT_FAILURE); } /* In IPS mode each threads must have a peer */ if (AFPPeersListCheck() != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); exit(EXIT_FAILURE); } SCLogInfo("RunModeIdsAFPWorkers initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); } /** * @} */ suricata-1.4.7/src/detect-http-hrh.c0000644000000000000000000022302712253546156014203 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Anoop Saldanha * * Implements support for the http_raw_host keyword. */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "app-layer.h" #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-hrh.h" int DetectHttpHRHSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpHRHRegisterTests(void); void DetectHttpHRHFree(void *); /** * \brief Registers the keyword handlers for the "http_raw_host" keyword. */ void DetectHttpHRHRegister(void) { sigmatch_table[DETECT_AL_HTTP_RAW_HOST].name = "http_raw_host"; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].desc = "content modifier to match only on the HTTP host header or the raw hostname from the HTTP uri"; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Match = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Setup = DetectHttpHRHSetup; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Free = DetectHttpHRHFree; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].RegisterTests = DetectHttpHRHRegisterTests; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_PAYLOAD ; return; } /** * \brief The setup function for the http_raw_host keyword for a signature. * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to the signature for the current Signature being * parsed from the rules. * \param m Pointer to the head of the SigMatch for the current rule * being parsed. * \param arg Pointer to the string holding the keyword value. * * \retval 0 On success * \retval -1 On failure */ int DetectHttpHRHSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_raw_host not supplied with args"); goto error; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if we still can't find any previous content keywords, it's an invalid * rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_raw_host\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_raw_host\" keyword"); goto error; } cd = (DetectContentData *)sm->ctx; /* http_raw_host should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_raw_host rule can not " "be used with the rawbytes rule keyword"); goto error; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if (s->flags & SIG_FLAG_TOCLIENT) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_raw_host can not be used " "with flow:to_client or flow:from_server. "); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_raw_host seen with a " "distance or within without a previous http_raw_host " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HRHHDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hrhhdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HRHHDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } /** * \brief The function to free the http_raw_host data. * * \param ptr Pointer to the http_raw_host. */ void DetectHttpHRHFree(void *ptr) { DetectContentData *hrhhd = (DetectContentData *)ptr; if (hrhhd == NULL) return; if (hrhhd->content != NULL) SCFree(hrhhd->content); BoyerMooreCtxDeInit(hrhhd->bm_ctx); SCFree(hrhhd); return; } /************************************Unittests*********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Test that a signature containting a http_raw_host is correctly parsed * and the keyword is registered. */ static int DetectHttpHRHTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_host\"; " "content:\"one\"; http_raw_host; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a signature containing an valid http_raw_host entry is * parsed. */ static int DetectHttpHRHTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_host\"; " "content:\"one\"; http_raw_host; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing no content but a * http_raw_host is invalidated. */ static int DetectHttpHRHTest03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_host\"; " "http_raw_host; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_raw_host is invalidated. */ static int DetectHttpHRHTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_host\"; " "content:\"one\"; rawbytes; http_raw_host; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a http_raw_host with nocase is parsed. */ static int DetectHttpHRHTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_host\"; " "content:\"one\"; http_raw_host; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectHttpHRHTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy message body\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"message\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectHttpHRHTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy message"; uint8_t http2_buf[] = "body1\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"message\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched on p1 but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match on p2 but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectHttpHRHTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "host: This is dummy mess"; uint8_t http2_buf[] = "age body\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"message\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_raw_host content matches against a http request * which holds the content, against a cross boundary present pattern. */ static int DetectHttpHRHTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"body1This\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_raw_host content matches against a http request * against a case insensitive pattern. */ static int DetectHttpHRHTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy bodY1"; uint8_t http2_buf[] = "This is dummy message body2\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy bodY1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"bodY1This\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the negated http_raw_host content matches against a * http request which doesn't hold the content. */ static int DetectHttpHRHTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy message body\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:!\"message\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Negative test that the negated http_raw_host content matches against a * http request which holds hold the content. */ static int DetectHttpHRHTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy body\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:!\"message\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectHttpHRHTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test multiple http transactions and body chunks of request handling */ static int DetectHttpHRHTest14(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "Cookie: dummy1\r\n"; uint8_t httpbuf3[] = "Host: Body one!!\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf5[] = "Cookie: dummy2\r\n"; uint8_t httpbuf6[] = "Host: Body two\r\n\r\n"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; http_cookie; content:\"Body one\"; http_raw_host; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"dummy2\"; http_cookie; content:\"Body two\"; http_raw_host; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) || PacketAlertCheck(p, 2)) { printf("sig 1 alerted (4): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) || !(PacketAlertCheck(p, 2))) { printf("signature 2 didn't match or sig 1 matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } int DetectHttpHRHTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"one\"; http_raw_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (cd->id == hrhhd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (cd->id == hrhhd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_raw_host; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (cd->id != 0 || hrhhd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (cd->id != 1 || hrhhd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; " "content:\"one\"; content:\"one\"; http_raw_host; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (cd->id != 1 || hrhhd1->id != 0 || hrhhd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; " "content:\"one\"; content:\"one\"; http_raw_host; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; if (cd->id != 2 || hrhhd1->id != 0 || hrhhd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; http_raw_host; " "content:\"three\"; distance:10; http_raw_host; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "two", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hrhhd2->content, "three", hrhhd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd1) || !DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hrhhd1) || DETECT_CONTENT_IS_SINGLE(hrhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; pcre:/two/; " "content:\"three\"; distance:10; http_raw_host; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hrhhd2->content, "three", hrhhd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hrhhd1) || DETECT_CONTENT_IS_SINGLE(hrhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; pcre:/two/; " "content:\"three\"; distance:10; within:15; http_raw_host; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(hrhhd2->content, "three", hrhhd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hrhhd1) || DETECT_CONTENT_IS_SINGLE(hrhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; pcre:/two/; " "content:\"three\"; distance:10; http_raw_host; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hrhhd2->content, "three", hrhhd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hrhhd1) || DETECT_CONTENT_IS_SINGLE(hrhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_raw_host; pcre:/two/; " "content:\"three\"; distance:10; http_raw_host; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(hrhhd2->content, "three", hrhhd1->content_len) != 0) { printf ("failed: http_raw_host incorrect flags"); goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hrhhd1) || DETECT_CONTENT_IS_SINGLE(hrhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_raw_host; pcre:/two/; " "content:\"three\"; distance:10; http_raw_host; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; pcre:/two/; " "content:\"three\"; http_raw_host; depth:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_NOCASE) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DEPTH) || memcmp(hrhhd2->content, "three", hrhhd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || !DETECT_CONTENT_IS_SINGLE(hrhhd1) || DETECT_CONTENT_IS_SINGLE(hrhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; " "content:\"two\"; distance:0; http_raw_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hrhhd2->content, "two", hrhhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; " "content:\"two\"; within:5; http_raw_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hrhhd2->content, "two", hrhhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; http_raw_host; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/Zi; " "content:\"two\"; within:5; http_raw_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_RAW_HOST | DETECT_PCRE_CASELESS) || hrhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hrhhd2->content, "two", hrhhd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; " "pcre:/one/ZRi; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_PCRE || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_CONTENT) { goto end; } DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_RAW_HOST | DETECT_PCRE_CASELESS) || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "two", hrhhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHRHTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/Zi; " "content:\"two\"; distance:5; http_raw_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_RAW_HOST | DETECT_PCRE_CASELESS) || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hrhhd2->content, "two", hrhhd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_raw_host content matches against a http request * against a case insensitive pattern. */ static int DetectHttpHRHTest37(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy bodY1"; uint8_t http2_buf[] = "This is dummy message body2\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy bodY1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"body1this\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } #endif /* UNITTESTS */ void DetectHttpHRHRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectHttpHRHTest01", DetectHttpHRHTest01, 1); UtRegisterTest("DetectHttpHRHTest02", DetectHttpHRHTest02, 1); UtRegisterTest("DetectHttpHRHTest03", DetectHttpHRHTest03, 1); UtRegisterTest("DetectHttpHRHTest04", DetectHttpHRHTest04, 1); UtRegisterTest("DetectHttpHRHTest05", DetectHttpHRHTest05, 1); UtRegisterTest("DetectHttpHRHTest06", DetectHttpHRHTest06, 1); UtRegisterTest("DetectHttpHRHTest07", DetectHttpHRHTest07, 1); UtRegisterTest("DetectHttpHRHTest08", DetectHttpHRHTest08, 1); UtRegisterTest("DetectHttpHRHTest09", DetectHttpHRHTest09, 1); UtRegisterTest("DetectHttpHRHTest10", DetectHttpHRHTest10, 1); UtRegisterTest("DetectHttpHRHTest11", DetectHttpHRHTest11, 1); UtRegisterTest("DetectHttpHRHTest12", DetectHttpHRHTest12, 1); UtRegisterTest("DetectHttpHRHTest13", DetectHttpHRHTest13, 1); UtRegisterTest("DetectHttpHRHTest14", DetectHttpHRHTest14, 1); UtRegisterTest("DetectHttpHRHTest16", DetectHttpHRHTest16, 1); UtRegisterTest("DetectHttpHRHTest17", DetectHttpHRHTest17, 1); UtRegisterTest("DetectHttpHRHTest18", DetectHttpHRHTest18, 1); UtRegisterTest("DetectHttpHRHTest19", DetectHttpHRHTest19, 1); UtRegisterTest("DetectHttpHRHTest20", DetectHttpHRHTest20, 1); UtRegisterTest("DetectHttpHRHTest21", DetectHttpHRHTest21, 1); UtRegisterTest("DetectHttpHRHTest22", DetectHttpHRHTest22, 1); UtRegisterTest("DetectHttpHRHTest23", DetectHttpHRHTest23, 1); UtRegisterTest("DetectHttpHRHTest24", DetectHttpHRHTest24, 1); UtRegisterTest("DetectHttpHRHTest25", DetectHttpHRHTest25, 1); UtRegisterTest("DetectHttpHRHTest26", DetectHttpHRHTest26, 1); UtRegisterTest("DetectHttpHRHTest27", DetectHttpHRHTest27, 1); UtRegisterTest("DetectHttpHRHTest28", DetectHttpHRHTest28, 1); UtRegisterTest("DetectHttpHRHTest29", DetectHttpHRHTest29, 1); UtRegisterTest("DetectHttpHRHTest30", DetectHttpHRHTest30, 1); UtRegisterTest("DetectHttpHRHTest31", DetectHttpHRHTest31, 1); UtRegisterTest("DetectHttpHRHTest32", DetectHttpHRHTest32, 1); UtRegisterTest("DetectHttpHRHTest33", DetectHttpHRHTest33, 1); UtRegisterTest("DetectHttpHRHTest34", DetectHttpHRHTest34, 1); UtRegisterTest("DetectHttpHRHTest35", DetectHttpHRHTest35, 1); UtRegisterTest("DetectHttpHRHTest36", DetectHttpHRHTest36, 1); UtRegisterTest("DetectHttpHRHTest37", DetectHttpHRHTest37, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/util-path.c0000644000000000000000000000302312253546156013076 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "util-debug.h" /** * \brief Check if a path is absolute * * \param path string with the path * * \retval 1 absolute * \retval 0 not absolute */ int PathIsAbsolute(const char *path) { if (strlen(path) > 1 && path[0] == '/') { return 1; } #if (defined OS_WIN32 || defined __CYGWIN__) if (strlen(path) > 2) { if (isalpha((unsigned char)path[0]) && path[1] == ':') { return 1; } } #endif return 0; } /** * \brief Check if a path is relative * * \param path string with the path * * \retval 1 relative * \retval 0 not relative */ int PathIsRelative(const char *path) { return PathIsAbsolute(path) ? 0 : 1; } suricata-1.4.7/src/Makefile.in0000644000000000000000000023226012253546174013077 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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@ bin_PROGRAMS = suricata$(EXEEXT) @BUILD_LIBHTP_TRUE@am__append_1 = -I$(top_srcdir)/libhtp @BUILD_CUDA_TRUE@am__append_2 = cuda-ptxdump.h subdir = src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp \ $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am__suricata_SOURCES_DIST = alert-debuglog.c alert-debuglog.h \ alert-fastlog.c alert-fastlog.h alert-pcapinfo.c \ alert-pcapinfo.h alert-prelude.c alert-prelude.h \ alert-syslog.c alert-syslog.h alert-unified2-alert.c \ alert-unified2-alert.h app-layer.c app-layer.h \ app-layer-dcerpc.c app-layer-dcerpc.h app-layer-dcerpc-udp.c \ app-layer-dcerpc-udp.h app-layer-detect-proto.c \ app-layer-detect-proto.h app-layer-ftp.c app-layer-ftp.h \ app-layer-htp-body.c app-layer-htp-body.h app-layer-htp.c \ app-layer-htp.h app-layer-htp-file.c app-layer-htp-file.h \ app-layer-parser.c app-layer-parser.h app-layer-protos.c \ app-layer-protos.h app-layer-smb2.c app-layer-smb2.h \ app-layer-smb.c app-layer-smb.h app-layer-smtp.c \ app-layer-smtp.h app-layer-ssh.c app-layer-ssh.h \ app-layer-ssl.c app-layer-ssl.h app-layer-tls-handshake.c \ app-layer-tls-handshake.h conf.c conf.h conf-yaml-loader.c \ conf-yaml-loader.h counters.c counters.h cuda-packet-batcher.c \ cuda-packet-batcher.h data-queue.c data-queue.h decode.c \ decode.h decode-ethernet.c decode-ethernet.h decode-events.c \ decode-events.h decode-gre.c decode-gre.h decode-icmpv4.c \ decode-icmpv4.h decode-icmpv6.c decode-icmpv6.h decode-ipv4.c \ decode-ipv4.h decode-ipv6.c decode-ipv6.h decode-ppp.c \ decode-ppp.h decode-pppoe.c decode-pppoe.h decode-raw.c \ decode-raw.h decode-sctp.c decode-sctp.h decode-sll.c \ decode-sll.h decode-tcp.c decode-tcp.h decode-teredo.c \ decode-teredo.h decode-udp.c decode-udp.h decode-vlan.c \ decode-vlan.h defrag.c defrag.h defrag-hash.c defrag-hash.h \ defrag-queue.c defrag-queue.h defrag-timeout.c \ defrag-timeout.h detect-ack.c detect-ack.h \ detect-app-layer-event.c detect-app-layer-event.h \ detect-asn1.c detect-asn1.h detect-byte-extract.c \ detect-byte-extract.h detect-bytejump.c detect-bytejump.h \ detect-bytetest.c detect-bytetest.h detect.c detect.h \ detect-classtype.c detect-classtype.h detect-content.c \ detect-content.h detect-csum.c detect-csum.h \ detect-dce-iface.c detect-dce-iface.h detect-dce-opnum.c \ detect-dce-opnum.h detect-dce-stub-data.c \ detect-dce-stub-data.h detect-depth.c detect-depth.h \ detect-detection-filter.c detect-detection-filter.h \ detect-distance.c detect-distance.h detect-dsize.c \ detect-dsize.h detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ detect-engine-address-ipv6.c detect-engine-address-ipv6.h \ detect-engine-alert.c detect-engine-alert.h \ detect-engine-analyzer.c detect-engine-analyzer.h \ detect-engine.c detect-engine.h \ detect-engine-content-inspection.c \ detect-engine-content-inspection.h detect-engine-dcepayload.c \ detect-engine-dcepayload.h detect-engine-event.c \ detect-engine-event.h detect-engine-file.c \ detect-engine-file.h detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h detect-engine-hhd.c \ detect-engine-hhd.h detect-engine-hhhd.c detect-engine-hhhd.h \ detect-engine-hmd.c detect-engine-hmd.h detect-engine-hrhd.c \ detect-engine-hrhd.h detect-engine-hrhhd.c \ detect-engine-hrhhd.h detect-engine-hrud.c \ detect-engine-hrud.h detect-engine-hsbd.c detect-engine-hsbd.h \ detect-engine-hscd.c detect-engine-hscd.h detect-engine-hsmd.c \ detect-engine-hsmd.h detect-engine-hua.c detect-engine-hua.h \ detect-engine-iponly.c detect-engine-iponly.h \ detect-engine-mpm.c detect-engine-mpm.h \ detect-engine-payload.c detect-engine-payload.h \ detect-engine-port.c detect-engine-port.h \ detect-engine-proto.c detect-engine-proto.h \ detect-engine-siggroup.c detect-engine-siggroup.h \ detect-engine-sigorder.c detect-engine-sigorder.h \ detect-engine-state.c detect-engine-state.h \ detect-engine-tag.c detect-engine-tag.h \ detect-engine-threshold.c detect-engine-threshold.h \ detect-engine-uri.c detect-engine-uri.h detect-fast-pattern.c \ detect-fast-pattern.h detect-file-data.c detect-file-data.h \ detect-fileext.c detect-fileext.h detect-filemagic.c \ detect-filemagic.h detect-filemd5.c detect-filemd5.h \ detect-filename.c detect-filename.h detect-filesize.c \ detect-filesize.h detect-filestore.c detect-filestore.h \ detect-flags.c detect-flags.h detect-flowbits.c \ detect-flowbits.h detect-flow.c detect-flow.h detect-flowint.c \ detect-flowint.h detect-flowvar.c detect-flowvar.h \ detect-fragbits.c detect-fragbits.h detect-fragoffset.c \ detect-fragoffset.h detect-ftpbounce.c detect-ftpbounce.h \ detect-geoip.c detect-geoip.h detect-gid.c detect-gid.h \ detect-http-client-body.c detect-http-client-body.h \ detect-http-cookie.c detect-http-cookie.h detect-http-header.c \ detect-http-header.h detect-http-hh.c detect-http-hh.h \ detect-http-hrh.c detect-http-hrh.h detect-http-method.c \ detect-http-method.h detect-http-raw-header.c \ detect-http-raw-header.h detect-http-raw-uri.c \ detect-http-raw-uri.h detect-http-server-body.c \ detect-http-server-body.h detect-http-stat-code.c \ detect-http-stat-code.h detect-http-stat-msg.c \ detect-http-stat-msg.h detect-http-ua.c detect-http-ua.h \ detect-http-uri.c detect-http-uri.h detect-icmp-id.c \ detect-icmp-id.h detect-icmp-seq.c detect-icmp-seq.h \ detect-icode.c detect-icode.h detect-id.c detect-id.h \ detect-ipopts.c detect-ipopts.h detect-ipproto.c \ detect-ipproto.h detect-iprep.c detect-iprep.h \ detect-isdataat.c detect-isdataat.h detect-itype.c \ detect-itype.h detect-l3proto.c detect-l3proto.h \ detect-luajit.c detect-luajit.h detect-mark.c detect-mark.h \ detect-metadata.c detect-metadata.h detect-msg.c detect-msg.h \ detect-noalert.c detect-noalert.h detect-nocase.c \ detect-nocase.h detect-offset.c detect-offset.h detect-parse.c \ detect-parse.h detect-pcre.c detect-pcre.h detect-pkt-data.c \ detect-pkt-data.h detect-pktvar.c detect-pktvar.h \ detect-priority.c detect-priority.h detect-rawbytes.c \ detect-rawbytes.h detect-reference.c detect-reference.h \ detect-replace.c detect-replace.h detect-rev.c detect-rev.h \ detect-rpc.c detect-rpc.h detect-sameip.c detect-sameip.h \ detect-seq.c detect-seq.h detect-sid.c detect-sid.h \ detect-ssh-proto-version.c detect-ssh-proto-version.h \ detect-ssh-software-version.c detect-ssh-software-version.h \ detect-ssl-state.c detect-ssl-state.h detect-ssl-version.c \ detect-ssl-version.h detect-stream_size.c detect-stream_size.h \ detect-tag.c detect-tag.h detect-threshold.c \ detect-threshold.h detect-tls.c detect-tls.h \ detect-tls-version.c detect-tls-version.h detect-tos.c \ detect-tos.h detect-ttl.c detect-ttl.h detect-uricontent.c \ detect-uricontent.h detect-urilen.c detect-urilen.h \ detect-window.c detect-window.h detect-within.c \ detect-within.h flow-alert-sid.c flow-alert-sid.h flow-bit.c \ flow-bit.h flow.c flow.h flow-hash.c flow-hash.h \ flow-manager.c flow-manager.h flow-queue.c flow-queue.h \ flow-timeout.c flow-timeout.h flow-util.c flow-util.h \ flow-var.c flow-var.h host.c host.h host-queue.c host-queue.h \ host-timeout.c host-timeout.h log-droplog.c log-droplog.h \ log-file.c log-file.h log-filestore.c log-filestore.h \ log-httplog.c log-httplog.h log-pcap.c log-pcap.h log-tlslog.c \ log-tlslog.h output.c output.h packet-queue.c packet-queue.h \ pkt-var.c pkt-var.h reputation.c reputation.h respond-reject.c \ respond-reject.h respond-reject-libnet11.h \ respond-reject-libnet11.c runmode-af-packet.c \ runmode-af-packet.h runmode-erf-dag.c runmode-erf-dag.h \ runmode-erf-file.c runmode-erf-file.h runmode-ipfw.c \ runmode-ipfw.h runmode-napatech.c runmode-napatech.h \ runmode-nfq.c runmode-nfq.h runmode-pcap.c runmode-pcap.h \ runmode-pcap-file.c runmode-pcap-file.h runmode-pfring.c \ runmode-pfring.h runmode-unix-socket.c runmode-unix-socket.h \ runmodes.c runmodes.h source-af-packet.c source-af-packet.h \ source-erf-dag.c source-erf-dag.h source-erf-file.c \ source-erf-file.h source-ipfw.c source-ipfw.h \ source-napatech.c source-napatech.h source-nfq.c source-nfq.h \ source-pcap.c source-pcap.h source-pcap-file.c \ source-pcap-file.h source-pfring.c source-pfring.h stream.c \ stream.h stream-tcp.c stream-tcp.h stream-tcp-private.h \ stream-tcp-inline.c stream-tcp-inline.h \ stream-tcp-reassemble.c stream-tcp-reassemble.h \ stream-tcp-sack.c stream-tcp-sack.h stream-tcp-util.c \ stream-tcp-util.h suricata.c suricata.h threads.c threads.h \ tm-modules.c tm-modules.h tmqh-flow.c tmqh-flow.h tmqh-nfq.c \ tmqh-nfq.h tmqh-packetpool.c tmqh-packetpool.h \ tmqh-ringbuffer.c tmqh-ringbuffer.h tmqh-simple.c \ tmqh-simple.h tm-queuehandlers.c tm-queuehandlers.h \ tm-queues.c tm-queues.h tm-threads.c tm-threads.h \ tm-threads-common.h unix-manager.c unix-manager.h \ util-action.c util-action.h util-atomic.c util-atomic.h \ util-bloomfilter-counting.c util-bloomfilter-counting.h \ util-bloomfilter.c util-bloomfilter.h util-buffer.c \ util-buffer.h util-byte.c util-byte.h util-checksum.c \ util-checksum.h util-cidr.c util-cidr.h \ util-classification-config.c util-classification-config.h \ util-coredump-config.c util-coredump-config.h util-cpu.c \ util-cpu.h util-crypt.c util-crypt.h util-cuda.c util-cuda.h \ util-cuda-handlers.c util-cuda-handlers.h util-daemon.c \ util-daemon.h util-debug.c util-debug.h util-debug-filters.c \ util-debug-filters.h util-decode-asn1.c util-decode-asn1.h \ util-decode-der.c util-decode-der.h util-decode-der-get.c \ util-decode-der-get.h util-device.c util-device.h util-enum.c \ util-enum.h util-error.c util-error.h util-file.c util-file.h \ util-fix_checksum.c util-fix_checksum.h util-fmemopen.c \ util-fmemopen.h util-hash.c util-hash.h util-hashlist.c \ util-hashlist.h util-hash-lookup3.c util-hash-lookup3.h \ util-host-os-info.c util-host-os-info.h util-ioctl.h \ util-ioctl.c util-logopenfile.h util-logopenfile.c \ util-magic.c util-magic.h util-memcmp.c util-memcmp.h \ util-mem.h util-misc.c util-misc.h util-mpm-ac-bs.c \ util-mpm-ac-bs.h util-mpm-ac.c util-mpm-ac.h \ util-mpm-ac-gfbs.c util-mpm-ac-gfbs.h util-mpm-b2gc.c \ util-mpm-b2gc.h util-mpm-b2g-cuda.c util-mpm-b2g-cuda.h \ util-mpm-b2g.c util-mpm-b2g.h util-mpm-b2gm.c util-mpm-b2gm.h \ util-mpm-b3g.c util-mpm-b3g.h util-mpm.c util-mpm.h \ util-mpm-wumanber.c util-mpm-wumanber.h util-optimize.h \ util-path.c util-path.h util-pidfile.c util-pidfile.h \ util-pool.c util-pool.h util-print.c util-print.h util-privs.c \ util-privs.h util-profiling.c util-profiling.h \ util-profiling-locks.c util-profiling-locks.h \ util-profiling-rules.c util-proto-name.c util-proto-name.h \ util-radix-tree.c util-radix-tree.h util-random.c \ util-random.h util-reference-config.c util-reference-config.h \ util-ringbuffer.c util-ringbuffer.h util-rohash.c \ util-rohash.h util-rule-vars.c util-rule-vars.h \ util-runmodes.c util-runmodes.h util-signal.c util-signal.h \ util-spm-bm.c util-spm-bm.h util-spm-bs2bm.c util-spm-bs2bm.h \ util-spm-bs.c util-spm-bs.h util-spm.c util-spm.h util-clock.h \ util-strlcatu.c util-strlcpyu.c util-syslog.c util-syslog.h \ util-threshold-config.c util-threshold-config.h util-time.c \ util-time.h util-unittest.c util-unittest.h \ util-unittest-helper.c util-unittest-helper.h util-validate.h \ util-affinity.h util-affinity.c util-var.c util-var.h \ util-var-name.c util-var-name.h util-vector.h win32-misc.c \ win32-misc.h win32-service.c win32-service.h win32-syslog.h \ cuda-ptxdump.h am__objects_1 = am_suricata_OBJECTS = alert-debuglog.$(OBJEXT) alert-fastlog.$(OBJEXT) \ alert-pcapinfo.$(OBJEXT) alert-prelude.$(OBJEXT) \ alert-syslog.$(OBJEXT) alert-unified2-alert.$(OBJEXT) \ app-layer.$(OBJEXT) app-layer-dcerpc.$(OBJEXT) \ app-layer-dcerpc-udp.$(OBJEXT) \ app-layer-detect-proto.$(OBJEXT) app-layer-ftp.$(OBJEXT) \ app-layer-htp-body.$(OBJEXT) app-layer-htp.$(OBJEXT) \ app-layer-htp-file.$(OBJEXT) app-layer-parser.$(OBJEXT) \ app-layer-protos.$(OBJEXT) app-layer-smb2.$(OBJEXT) \ app-layer-smb.$(OBJEXT) app-layer-smtp.$(OBJEXT) \ app-layer-ssh.$(OBJEXT) app-layer-ssl.$(OBJEXT) \ app-layer-tls-handshake.$(OBJEXT) conf.$(OBJEXT) \ conf-yaml-loader.$(OBJEXT) counters.$(OBJEXT) \ cuda-packet-batcher.$(OBJEXT) data-queue.$(OBJEXT) \ decode.$(OBJEXT) decode-ethernet.$(OBJEXT) \ decode-events.$(OBJEXT) decode-gre.$(OBJEXT) \ decode-icmpv4.$(OBJEXT) decode-icmpv6.$(OBJEXT) \ decode-ipv4.$(OBJEXT) decode-ipv6.$(OBJEXT) \ decode-ppp.$(OBJEXT) decode-pppoe.$(OBJEXT) \ decode-raw.$(OBJEXT) decode-sctp.$(OBJEXT) \ decode-sll.$(OBJEXT) decode-tcp.$(OBJEXT) \ decode-teredo.$(OBJEXT) decode-udp.$(OBJEXT) \ decode-vlan.$(OBJEXT) defrag.$(OBJEXT) defrag-hash.$(OBJEXT) \ defrag-queue.$(OBJEXT) defrag-timeout.$(OBJEXT) \ detect-ack.$(OBJEXT) detect-app-layer-event.$(OBJEXT) \ detect-asn1.$(OBJEXT) detect-byte-extract.$(OBJEXT) \ detect-bytejump.$(OBJEXT) detect-bytetest.$(OBJEXT) \ detect.$(OBJEXT) detect-classtype.$(OBJEXT) \ detect-content.$(OBJEXT) detect-csum.$(OBJEXT) \ detect-dce-iface.$(OBJEXT) detect-dce-opnum.$(OBJEXT) \ detect-dce-stub-data.$(OBJEXT) detect-depth.$(OBJEXT) \ detect-detection-filter.$(OBJEXT) detect-distance.$(OBJEXT) \ detect-dsize.$(OBJEXT) detect-engine-address.$(OBJEXT) \ detect-engine-address-ipv4.$(OBJEXT) \ detect-engine-address-ipv6.$(OBJEXT) \ detect-engine-alert.$(OBJEXT) detect-engine-analyzer.$(OBJEXT) \ detect-engine.$(OBJEXT) \ detect-engine-content-inspection.$(OBJEXT) \ detect-engine-dcepayload.$(OBJEXT) \ detect-engine-event.$(OBJEXT) detect-engine-file.$(OBJEXT) \ detect-engine-hcbd.$(OBJEXT) detect-engine-hcd.$(OBJEXT) \ detect-engine-hhd.$(OBJEXT) detect-engine-hhhd.$(OBJEXT) \ detect-engine-hmd.$(OBJEXT) detect-engine-hrhd.$(OBJEXT) \ detect-engine-hrhhd.$(OBJEXT) detect-engine-hrud.$(OBJEXT) \ detect-engine-hsbd.$(OBJEXT) detect-engine-hscd.$(OBJEXT) \ detect-engine-hsmd.$(OBJEXT) detect-engine-hua.$(OBJEXT) \ detect-engine-iponly.$(OBJEXT) detect-engine-mpm.$(OBJEXT) \ detect-engine-payload.$(OBJEXT) detect-engine-port.$(OBJEXT) \ detect-engine-proto.$(OBJEXT) detect-engine-siggroup.$(OBJEXT) \ detect-engine-sigorder.$(OBJEXT) detect-engine-state.$(OBJEXT) \ detect-engine-tag.$(OBJEXT) detect-engine-threshold.$(OBJEXT) \ detect-engine-uri.$(OBJEXT) detect-fast-pattern.$(OBJEXT) \ detect-file-data.$(OBJEXT) detect-fileext.$(OBJEXT) \ detect-filemagic.$(OBJEXT) detect-filemd5.$(OBJEXT) \ detect-filename.$(OBJEXT) detect-filesize.$(OBJEXT) \ detect-filestore.$(OBJEXT) detect-flags.$(OBJEXT) \ detect-flowbits.$(OBJEXT) detect-flow.$(OBJEXT) \ detect-flowint.$(OBJEXT) detect-flowvar.$(OBJEXT) \ detect-fragbits.$(OBJEXT) detect-fragoffset.$(OBJEXT) \ detect-ftpbounce.$(OBJEXT) detect-geoip.$(OBJEXT) \ detect-gid.$(OBJEXT) detect-http-client-body.$(OBJEXT) \ detect-http-cookie.$(OBJEXT) detect-http-header.$(OBJEXT) \ detect-http-hh.$(OBJEXT) detect-http-hrh.$(OBJEXT) \ detect-http-method.$(OBJEXT) detect-http-raw-header.$(OBJEXT) \ detect-http-raw-uri.$(OBJEXT) \ detect-http-server-body.$(OBJEXT) \ detect-http-stat-code.$(OBJEXT) detect-http-stat-msg.$(OBJEXT) \ detect-http-ua.$(OBJEXT) detect-http-uri.$(OBJEXT) \ detect-icmp-id.$(OBJEXT) detect-icmp-seq.$(OBJEXT) \ detect-icode.$(OBJEXT) detect-id.$(OBJEXT) \ detect-ipopts.$(OBJEXT) detect-ipproto.$(OBJEXT) \ detect-iprep.$(OBJEXT) detect-isdataat.$(OBJEXT) \ detect-itype.$(OBJEXT) detect-l3proto.$(OBJEXT) \ detect-luajit.$(OBJEXT) detect-mark.$(OBJEXT) \ detect-metadata.$(OBJEXT) detect-msg.$(OBJEXT) \ detect-noalert.$(OBJEXT) detect-nocase.$(OBJEXT) \ detect-offset.$(OBJEXT) detect-parse.$(OBJEXT) \ detect-pcre.$(OBJEXT) detect-pkt-data.$(OBJEXT) \ detect-pktvar.$(OBJEXT) detect-priority.$(OBJEXT) \ detect-rawbytes.$(OBJEXT) detect-reference.$(OBJEXT) \ detect-replace.$(OBJEXT) detect-rev.$(OBJEXT) \ detect-rpc.$(OBJEXT) detect-sameip.$(OBJEXT) \ detect-seq.$(OBJEXT) detect-sid.$(OBJEXT) \ detect-ssh-proto-version.$(OBJEXT) \ detect-ssh-software-version.$(OBJEXT) \ detect-ssl-state.$(OBJEXT) detect-ssl-version.$(OBJEXT) \ detect-stream_size.$(OBJEXT) detect-tag.$(OBJEXT) \ detect-threshold.$(OBJEXT) detect-tls.$(OBJEXT) \ detect-tls-version.$(OBJEXT) detect-tos.$(OBJEXT) \ detect-ttl.$(OBJEXT) detect-uricontent.$(OBJEXT) \ detect-urilen.$(OBJEXT) detect-window.$(OBJEXT) \ detect-within.$(OBJEXT) flow-alert-sid.$(OBJEXT) \ flow-bit.$(OBJEXT) flow.$(OBJEXT) flow-hash.$(OBJEXT) \ flow-manager.$(OBJEXT) flow-queue.$(OBJEXT) \ flow-timeout.$(OBJEXT) flow-util.$(OBJEXT) flow-var.$(OBJEXT) \ host.$(OBJEXT) host-queue.$(OBJEXT) host-timeout.$(OBJEXT) \ log-droplog.$(OBJEXT) log-file.$(OBJEXT) \ log-filestore.$(OBJEXT) log-httplog.$(OBJEXT) \ log-pcap.$(OBJEXT) log-tlslog.$(OBJEXT) output.$(OBJEXT) \ packet-queue.$(OBJEXT) pkt-var.$(OBJEXT) reputation.$(OBJEXT) \ respond-reject.$(OBJEXT) respond-reject-libnet11.$(OBJEXT) \ runmode-af-packet.$(OBJEXT) runmode-erf-dag.$(OBJEXT) \ runmode-erf-file.$(OBJEXT) runmode-ipfw.$(OBJEXT) \ runmode-napatech.$(OBJEXT) runmode-nfq.$(OBJEXT) \ runmode-pcap.$(OBJEXT) runmode-pcap-file.$(OBJEXT) \ runmode-pfring.$(OBJEXT) runmode-unix-socket.$(OBJEXT) \ runmodes.$(OBJEXT) source-af-packet.$(OBJEXT) \ source-erf-dag.$(OBJEXT) source-erf-file.$(OBJEXT) \ source-ipfw.$(OBJEXT) source-napatech.$(OBJEXT) \ source-nfq.$(OBJEXT) source-pcap.$(OBJEXT) \ source-pcap-file.$(OBJEXT) source-pfring.$(OBJEXT) \ stream.$(OBJEXT) stream-tcp.$(OBJEXT) \ stream-tcp-inline.$(OBJEXT) stream-tcp-reassemble.$(OBJEXT) \ stream-tcp-sack.$(OBJEXT) stream-tcp-util.$(OBJEXT) \ suricata.$(OBJEXT) threads.$(OBJEXT) tm-modules.$(OBJEXT) \ tmqh-flow.$(OBJEXT) tmqh-nfq.$(OBJEXT) \ tmqh-packetpool.$(OBJEXT) tmqh-ringbuffer.$(OBJEXT) \ tmqh-simple.$(OBJEXT) tm-queuehandlers.$(OBJEXT) \ tm-queues.$(OBJEXT) tm-threads.$(OBJEXT) \ unix-manager.$(OBJEXT) util-action.$(OBJEXT) \ util-atomic.$(OBJEXT) util-bloomfilter-counting.$(OBJEXT) \ util-bloomfilter.$(OBJEXT) util-buffer.$(OBJEXT) \ util-byte.$(OBJEXT) util-checksum.$(OBJEXT) \ util-cidr.$(OBJEXT) util-classification-config.$(OBJEXT) \ util-coredump-config.$(OBJEXT) util-cpu.$(OBJEXT) \ util-crypt.$(OBJEXT) util-cuda.$(OBJEXT) \ util-cuda-handlers.$(OBJEXT) util-daemon.$(OBJEXT) \ util-debug.$(OBJEXT) util-debug-filters.$(OBJEXT) \ util-decode-asn1.$(OBJEXT) util-decode-der.$(OBJEXT) \ util-decode-der-get.$(OBJEXT) util-device.$(OBJEXT) \ util-enum.$(OBJEXT) util-error.$(OBJEXT) util-file.$(OBJEXT) \ util-fix_checksum.$(OBJEXT) util-fmemopen.$(OBJEXT) \ util-hash.$(OBJEXT) util-hashlist.$(OBJEXT) \ util-hash-lookup3.$(OBJEXT) util-host-os-info.$(OBJEXT) \ util-ioctl.$(OBJEXT) util-logopenfile.$(OBJEXT) \ util-magic.$(OBJEXT) util-memcmp.$(OBJEXT) util-misc.$(OBJEXT) \ util-mpm-ac-bs.$(OBJEXT) util-mpm-ac.$(OBJEXT) \ util-mpm-ac-gfbs.$(OBJEXT) util-mpm-b2gc.$(OBJEXT) \ util-mpm-b2g-cuda.$(OBJEXT) util-mpm-b2g.$(OBJEXT) \ util-mpm-b2gm.$(OBJEXT) util-mpm-b3g.$(OBJEXT) \ util-mpm.$(OBJEXT) util-mpm-wumanber.$(OBJEXT) \ util-path.$(OBJEXT) util-pidfile.$(OBJEXT) util-pool.$(OBJEXT) \ util-print.$(OBJEXT) util-privs.$(OBJEXT) \ util-profiling.$(OBJEXT) util-profiling-locks.$(OBJEXT) \ util-profiling-rules.$(OBJEXT) util-proto-name.$(OBJEXT) \ util-radix-tree.$(OBJEXT) util-random.$(OBJEXT) \ util-reference-config.$(OBJEXT) util-ringbuffer.$(OBJEXT) \ util-rohash.$(OBJEXT) util-rule-vars.$(OBJEXT) \ util-runmodes.$(OBJEXT) util-signal.$(OBJEXT) \ util-spm-bm.$(OBJEXT) util-spm-bs2bm.$(OBJEXT) \ util-spm-bs.$(OBJEXT) util-spm.$(OBJEXT) \ util-strlcatu.$(OBJEXT) util-strlcpyu.$(OBJEXT) \ util-syslog.$(OBJEXT) util-threshold-config.$(OBJEXT) \ util-time.$(OBJEXT) util-unittest.$(OBJEXT) \ util-unittest-helper.$(OBJEXT) util-affinity.$(OBJEXT) \ util-var.$(OBJEXT) util-var-name.$(OBJEXT) \ win32-misc.$(OBJEXT) win32-service.$(OBJEXT) $(am__objects_1) suricata_OBJECTS = $(am_suricata_OBJECTS) @BUILD_LIBHTP_TRUE@suricata_DEPENDENCIES = \ @BUILD_LIBHTP_TRUE@ $(top_builddir)/libhtp/htp/libhtp.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = suricata_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(suricata_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(suricata_SOURCES) DIST_SOURCES = $(am__suricata_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_HEADERS = action-globals.h \ app-layer-nbss.h app-layer-dcerpc-common.h \ debug.h \ flow-private.h queue.h source-nfq-prototypes.h \ suricata-common.h threadvars.h util-binsearch.h \ util-validate.h suricata_SOURCES = alert-debuglog.c alert-debuglog.h alert-fastlog.c \ alert-fastlog.h alert-pcapinfo.c alert-pcapinfo.h \ alert-prelude.c alert-prelude.h alert-syslog.c alert-syslog.h \ alert-unified2-alert.c alert-unified2-alert.h app-layer.c \ app-layer.h app-layer-dcerpc.c app-layer-dcerpc.h \ app-layer-dcerpc-udp.c app-layer-dcerpc-udp.h \ app-layer-detect-proto.c app-layer-detect-proto.h \ app-layer-ftp.c app-layer-ftp.h app-layer-htp-body.c \ app-layer-htp-body.h app-layer-htp.c app-layer-htp.h \ app-layer-htp-file.c app-layer-htp-file.h app-layer-parser.c \ app-layer-parser.h app-layer-protos.c app-layer-protos.h \ app-layer-smb2.c app-layer-smb2.h app-layer-smb.c \ app-layer-smb.h app-layer-smtp.c app-layer-smtp.h \ app-layer-ssh.c app-layer-ssh.h app-layer-ssl.c \ app-layer-ssl.h app-layer-tls-handshake.c \ app-layer-tls-handshake.h conf.c conf.h conf-yaml-loader.c \ conf-yaml-loader.h counters.c counters.h cuda-packet-batcher.c \ cuda-packet-batcher.h data-queue.c data-queue.h decode.c \ decode.h decode-ethernet.c decode-ethernet.h decode-events.c \ decode-events.h decode-gre.c decode-gre.h decode-icmpv4.c \ decode-icmpv4.h decode-icmpv6.c decode-icmpv6.h decode-ipv4.c \ decode-ipv4.h decode-ipv6.c decode-ipv6.h decode-ppp.c \ decode-ppp.h decode-pppoe.c decode-pppoe.h decode-raw.c \ decode-raw.h decode-sctp.c decode-sctp.h decode-sll.c \ decode-sll.h decode-tcp.c decode-tcp.h decode-teredo.c \ decode-teredo.h decode-udp.c decode-udp.h decode-vlan.c \ decode-vlan.h defrag.c defrag.h defrag-hash.c defrag-hash.h \ defrag-queue.c defrag-queue.h defrag-timeout.c \ defrag-timeout.h detect-ack.c detect-ack.h \ detect-app-layer-event.c detect-app-layer-event.h \ detect-asn1.c detect-asn1.h detect-byte-extract.c \ detect-byte-extract.h detect-bytejump.c detect-bytejump.h \ detect-bytetest.c detect-bytetest.h detect.c detect.h \ detect-classtype.c detect-classtype.h detect-content.c \ detect-content.h detect-csum.c detect-csum.h \ detect-dce-iface.c detect-dce-iface.h detect-dce-opnum.c \ detect-dce-opnum.h detect-dce-stub-data.c \ detect-dce-stub-data.h detect-depth.c detect-depth.h \ detect-detection-filter.c detect-detection-filter.h \ detect-distance.c detect-distance.h detect-dsize.c \ detect-dsize.h detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ detect-engine-address-ipv6.c detect-engine-address-ipv6.h \ detect-engine-alert.c detect-engine-alert.h \ detect-engine-analyzer.c detect-engine-analyzer.h \ detect-engine.c detect-engine.h \ detect-engine-content-inspection.c \ detect-engine-content-inspection.h detect-engine-dcepayload.c \ detect-engine-dcepayload.h detect-engine-event.c \ detect-engine-event.h detect-engine-file.c \ detect-engine-file.h detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h detect-engine-hhd.c \ detect-engine-hhd.h detect-engine-hhhd.c detect-engine-hhhd.h \ detect-engine-hmd.c detect-engine-hmd.h detect-engine-hrhd.c \ detect-engine-hrhd.h detect-engine-hrhhd.c \ detect-engine-hrhhd.h detect-engine-hrud.c \ detect-engine-hrud.h detect-engine-hsbd.c detect-engine-hsbd.h \ detect-engine-hscd.c detect-engine-hscd.h detect-engine-hsmd.c \ detect-engine-hsmd.h detect-engine-hua.c detect-engine-hua.h \ detect-engine-iponly.c detect-engine-iponly.h \ detect-engine-mpm.c detect-engine-mpm.h \ detect-engine-payload.c detect-engine-payload.h \ detect-engine-port.c detect-engine-port.h \ detect-engine-proto.c detect-engine-proto.h \ detect-engine-siggroup.c detect-engine-siggroup.h \ detect-engine-sigorder.c detect-engine-sigorder.h \ detect-engine-state.c detect-engine-state.h \ detect-engine-tag.c detect-engine-tag.h \ detect-engine-threshold.c detect-engine-threshold.h \ detect-engine-uri.c detect-engine-uri.h detect-fast-pattern.c \ detect-fast-pattern.h detect-file-data.c detect-file-data.h \ detect-fileext.c detect-fileext.h detect-filemagic.c \ detect-filemagic.h detect-filemd5.c detect-filemd5.h \ detect-filename.c detect-filename.h detect-filesize.c \ detect-filesize.h detect-filestore.c detect-filestore.h \ detect-flags.c detect-flags.h detect-flowbits.c \ detect-flowbits.h detect-flow.c detect-flow.h detect-flowint.c \ detect-flowint.h detect-flowvar.c detect-flowvar.h \ detect-fragbits.c detect-fragbits.h detect-fragoffset.c \ detect-fragoffset.h detect-ftpbounce.c detect-ftpbounce.h \ detect-geoip.c detect-geoip.h detect-gid.c detect-gid.h \ detect-http-client-body.c detect-http-client-body.h \ detect-http-cookie.c detect-http-cookie.h detect-http-header.c \ detect-http-header.h detect-http-hh.c detect-http-hh.h \ detect-http-hrh.c detect-http-hrh.h detect-http-method.c \ detect-http-method.h detect-http-raw-header.c \ detect-http-raw-header.h detect-http-raw-uri.c \ detect-http-raw-uri.h detect-http-server-body.c \ detect-http-server-body.h detect-http-stat-code.c \ detect-http-stat-code.h detect-http-stat-msg.c \ detect-http-stat-msg.h detect-http-ua.c detect-http-ua.h \ detect-http-uri.c detect-http-uri.h detect-icmp-id.c \ detect-icmp-id.h detect-icmp-seq.c detect-icmp-seq.h \ detect-icode.c detect-icode.h detect-id.c detect-id.h \ detect-ipopts.c detect-ipopts.h detect-ipproto.c \ detect-ipproto.h detect-iprep.c detect-iprep.h \ detect-isdataat.c detect-isdataat.h detect-itype.c \ detect-itype.h detect-l3proto.c detect-l3proto.h \ detect-luajit.c detect-luajit.h detect-mark.c detect-mark.h \ detect-metadata.c detect-metadata.h detect-msg.c detect-msg.h \ detect-noalert.c detect-noalert.h detect-nocase.c \ detect-nocase.h detect-offset.c detect-offset.h detect-parse.c \ detect-parse.h detect-pcre.c detect-pcre.h detect-pkt-data.c \ detect-pkt-data.h detect-pktvar.c detect-pktvar.h \ detect-priority.c detect-priority.h detect-rawbytes.c \ detect-rawbytes.h detect-reference.c detect-reference.h \ detect-replace.c detect-replace.h detect-rev.c detect-rev.h \ detect-rpc.c detect-rpc.h detect-sameip.c detect-sameip.h \ detect-seq.c detect-seq.h detect-sid.c detect-sid.h \ detect-ssh-proto-version.c detect-ssh-proto-version.h \ detect-ssh-software-version.c detect-ssh-software-version.h \ detect-ssl-state.c detect-ssl-state.h detect-ssl-version.c \ detect-ssl-version.h detect-stream_size.c detect-stream_size.h \ detect-tag.c detect-tag.h detect-threshold.c \ detect-threshold.h detect-tls.c detect-tls.h \ detect-tls-version.c detect-tls-version.h detect-tos.c \ detect-tos.h detect-ttl.c detect-ttl.h detect-uricontent.c \ detect-uricontent.h detect-urilen.c detect-urilen.h \ detect-window.c detect-window.h detect-within.c \ detect-within.h flow-alert-sid.c flow-alert-sid.h flow-bit.c \ flow-bit.h flow.c flow.h flow-hash.c flow-hash.h \ flow-manager.c flow-manager.h flow-queue.c flow-queue.h \ flow-timeout.c flow-timeout.h flow-util.c flow-util.h \ flow-var.c flow-var.h host.c host.h host-queue.c host-queue.h \ host-timeout.c host-timeout.h log-droplog.c log-droplog.h \ log-file.c log-file.h log-filestore.c log-filestore.h \ log-httplog.c log-httplog.h log-pcap.c log-pcap.h log-tlslog.c \ log-tlslog.h output.c output.h packet-queue.c packet-queue.h \ pkt-var.c pkt-var.h reputation.c reputation.h respond-reject.c \ respond-reject.h respond-reject-libnet11.h \ respond-reject-libnet11.c runmode-af-packet.c \ runmode-af-packet.h runmode-erf-dag.c runmode-erf-dag.h \ runmode-erf-file.c runmode-erf-file.h runmode-ipfw.c \ runmode-ipfw.h runmode-napatech.c runmode-napatech.h \ runmode-nfq.c runmode-nfq.h runmode-pcap.c runmode-pcap.h \ runmode-pcap-file.c runmode-pcap-file.h runmode-pfring.c \ runmode-pfring.h runmode-unix-socket.c runmode-unix-socket.h \ runmodes.c runmodes.h source-af-packet.c source-af-packet.h \ source-erf-dag.c source-erf-dag.h source-erf-file.c \ source-erf-file.h source-ipfw.c source-ipfw.h \ source-napatech.c source-napatech.h source-nfq.c source-nfq.h \ source-pcap.c source-pcap.h source-pcap-file.c \ source-pcap-file.h source-pfring.c source-pfring.h stream.c \ stream.h stream-tcp.c stream-tcp.h stream-tcp-private.h \ stream-tcp-inline.c stream-tcp-inline.h \ stream-tcp-reassemble.c stream-tcp-reassemble.h \ stream-tcp-sack.c stream-tcp-sack.h stream-tcp-util.c \ stream-tcp-util.h suricata.c suricata.h threads.c threads.h \ tm-modules.c tm-modules.h tmqh-flow.c tmqh-flow.h tmqh-nfq.c \ tmqh-nfq.h tmqh-packetpool.c tmqh-packetpool.h \ tmqh-ringbuffer.c tmqh-ringbuffer.h tmqh-simple.c \ tmqh-simple.h tm-queuehandlers.c tm-queuehandlers.h \ tm-queues.c tm-queues.h tm-threads.c tm-threads.h \ tm-threads-common.h unix-manager.c unix-manager.h \ util-action.c util-action.h util-atomic.c util-atomic.h \ util-bloomfilter-counting.c util-bloomfilter-counting.h \ util-bloomfilter.c util-bloomfilter.h util-buffer.c \ util-buffer.h util-byte.c util-byte.h util-checksum.c \ util-checksum.h util-cidr.c util-cidr.h \ util-classification-config.c util-classification-config.h \ util-coredump-config.c util-coredump-config.h util-cpu.c \ util-cpu.h util-crypt.c util-crypt.h util-cuda.c util-cuda.h \ util-cuda-handlers.c util-cuda-handlers.h util-daemon.c \ util-daemon.h util-debug.c util-debug.h util-debug-filters.c \ util-debug-filters.h util-decode-asn1.c util-decode-asn1.h \ util-decode-der.c util-decode-der.h util-decode-der-get.c \ util-decode-der-get.h util-device.c util-device.h util-enum.c \ util-enum.h util-error.c util-error.h util-file.c util-file.h \ util-fix_checksum.c util-fix_checksum.h util-fmemopen.c \ util-fmemopen.h util-hash.c util-hash.h util-hashlist.c \ util-hashlist.h util-hash-lookup3.c util-hash-lookup3.h \ util-host-os-info.c util-host-os-info.h util-ioctl.h \ util-ioctl.c util-logopenfile.h util-logopenfile.c \ util-magic.c util-magic.h util-memcmp.c util-memcmp.h \ util-mem.h util-misc.c util-misc.h util-mpm-ac-bs.c \ util-mpm-ac-bs.h util-mpm-ac.c util-mpm-ac.h \ util-mpm-ac-gfbs.c util-mpm-ac-gfbs.h util-mpm-b2gc.c \ util-mpm-b2gc.h util-mpm-b2g-cuda.c util-mpm-b2g-cuda.h \ util-mpm-b2g.c util-mpm-b2g.h util-mpm-b2gm.c util-mpm-b2gm.h \ util-mpm-b3g.c util-mpm-b3g.h util-mpm.c util-mpm.h \ util-mpm-wumanber.c util-mpm-wumanber.h util-optimize.h \ util-path.c util-path.h util-pidfile.c util-pidfile.h \ util-pool.c util-pool.h util-print.c util-print.h util-privs.c \ util-privs.h util-profiling.c util-profiling.h \ util-profiling-locks.c util-profiling-locks.h \ util-profiling-rules.c util-proto-name.c util-proto-name.h \ util-radix-tree.c util-radix-tree.h util-random.c \ util-random.h util-reference-config.c util-reference-config.h \ util-ringbuffer.c util-ringbuffer.h util-rohash.c \ util-rohash.h util-rule-vars.c util-rule-vars.h \ util-runmodes.c util-runmodes.h util-signal.c util-signal.h \ util-spm-bm.c util-spm-bm.h util-spm-bs2bm.c util-spm-bs2bm.h \ util-spm-bs.c util-spm-bs.h util-spm.c util-spm.h util-clock.h \ util-strlcatu.c util-strlcpyu.c util-syslog.c util-syslog.h \ util-threshold-config.c util-threshold-config.h util-time.c \ util-time.h util-unittest.c util-unittest.h \ util-unittest-helper.c util-unittest-helper.h util-validate.h \ util-affinity.h util-affinity.c util-var.c util-var.h \ util-var-name.c util-var-name.h util-vector.h win32-misc.c \ win32-misc.h win32-service.c win32-service.h win32-syslog.h \ $(am__append_2) EXTRA_DIST = util-mpm-b2g-cuda-kernel.cu ptxdump.py # set the include path found by configure INCLUDES = $(all_includes) $(am__append_1) # the library search path. suricata_LDFLAGS = $(all_libraries) @BUILD_LIBHTP_TRUE@suricata_LDADD = $(top_builddir)/libhtp/htp/libhtp.la # Rules to build CUDA ptx modules @BUILD_CUDA_TRUE@BUILT_SOURCES = cuda-ptxdump.h @BUILD_CUDA_TRUE@suricata_CUDA_KERNELS = \ @BUILD_CUDA_TRUE@util-mpm-b2g-cuda-kernel.cu @BUILD_CUDA_TRUE@NVCCFLAGS = -O2 @BUILD_CUDA_TRUE@SUFFIXES = \ @BUILD_CUDA_TRUE@.ptx_sm_10 \ @BUILD_CUDA_TRUE@.ptx_sm_11 \ @BUILD_CUDA_TRUE@.ptx_sm_12 \ @BUILD_CUDA_TRUE@.ptx_sm_13 \ @BUILD_CUDA_TRUE@.ptx_sm_20 \ @BUILD_CUDA_TRUE@.ptx_sm_21 @BUILD_CUDA_TRUE@PTXS = $(suricata_CUDA_KERNELS:.cu=.ptx_sm_10) \ @BUILD_CUDA_TRUE@ $(suricata_CUDA_KERNELS:.cu=.ptx_sm_11) \ @BUILD_CUDA_TRUE@ $(suricata_CUDA_KERNELS:.cu=.ptx_sm_12) \ @BUILD_CUDA_TRUE@ $(suricata_CUDA_KERNELS:.cu=.ptx_sm_13) \ @BUILD_CUDA_TRUE@ $(suricata_CUDA_KERNELS:.cu=.ptx_sm_20) \ @BUILD_CUDA_TRUE@ $(suricata_CUDA_KERNELS:.cu=.ptx_sm_21) @BUILD_CUDA_TRUE@CLEANFILES = $(PTXS) cuda-ptxdump.h #suricata_CFLAGS = -Wall -fno-strict-aliasing AM_CFLAGS = -DLOCAL_STATE_DIR=\"$(localstatedir)\" all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .ptx_sm_10 .ptx_sm_11 .ptx_sm_12 .ptx_sm_13 .ptx_sm_20 .ptx_sm_21 .c .cu .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list suricata$(EXEEXT): $(suricata_OBJECTS) $(suricata_DEPENDENCIES) $(EXTRA_suricata_DEPENDENCIES) @rm -f suricata$(EXEEXT) $(AM_V_CCLD)$(suricata_LINK) $(suricata_OBJECTS) $(suricata_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-debuglog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-fastlog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-pcapinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-prelude.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-syslog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-unified2-alert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-dcerpc-udp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-dcerpc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-detect-proto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-ftp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-htp-body.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-htp-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-htp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-parser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-protos.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-smb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-smb2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-smtp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-ssh.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-ssl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-tls-handshake.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf-yaml-loader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/counters.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuda-packet-batcher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-ethernet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-events.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-gre.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-icmpv4.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-icmpv6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-ipv4.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-ipv6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-ppp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-pppoe.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-raw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-sctp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-sll.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-tcp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-teredo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-udp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-vlan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defrag-hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defrag-queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defrag-timeout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defrag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ack.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-app-layer-event.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-asn1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-byte-extract.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-bytejump.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-bytetest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-classtype.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-content.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-csum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-dce-iface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-dce-opnum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-dce-stub-data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-depth.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-detection-filter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-distance.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-dsize.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-address-ipv4.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-address-ipv6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-address.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-alert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-analyzer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-content-inspection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-dcepayload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-event.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hcbd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hcd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hhd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hhhd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hrhd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hrhhd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hrud.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hsbd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hscd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hsmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-hua.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-iponly.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-mpm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-port.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-proto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-siggroup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-sigorder.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-state.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-tag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-threshold.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine-uri.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-engine.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-fast-pattern.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-file-data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-fileext.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-filemagic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-filemd5.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-filename.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-filesize.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-filestore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-flags.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-flow.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-flowbits.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-flowint.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-flowvar.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-fragbits.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-fragoffset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ftpbounce.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-geoip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-gid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-client-body.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-cookie.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-header.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-hh.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-hrh.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-method.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-raw-header.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-raw-uri.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-server-body.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-stat-code.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-stat-msg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-ua.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-http-uri.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-icmp-id.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-icmp-seq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-icode.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-id.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ipopts.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ipproto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-iprep.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-isdataat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-itype.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-l3proto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-luajit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-mark.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-metadata.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-msg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-noalert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-nocase.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-offset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-parse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-pcre.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-pkt-data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-pktvar.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-priority.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-rawbytes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-reference.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-replace.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-rev.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-rpc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-sameip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-seq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-sid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ssh-proto-version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ssh-software-version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ssl-state.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ssl-version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-stream_size.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-tag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-threshold.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-tls-version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-tls.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-tos.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ttl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-uricontent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-urilen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-window.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-within.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-alert-sid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-bit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-timeout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-var.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/host-queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/host-timeout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/host.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log-droplog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log-filestore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log-httplog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log-pcap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log-tlslog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet-queue.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkt-var.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reputation.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/respond-reject-libnet11.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/respond-reject.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-af-packet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-erf-dag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-erf-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-ipfw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-napatech.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-nfq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-pcap-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-pcap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-pfring.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmode-unix-socket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runmodes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-af-packet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-erf-dag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-erf-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-ipfw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-napatech.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-nfq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-pcap-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-pcap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source-pfring.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream-tcp-inline.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream-tcp-reassemble.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream-tcp-sack.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream-tcp-util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream-tcp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/suricata.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/threads.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tm-modules.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tm-queuehandlers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tm-queues.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tm-threads.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tmqh-flow.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tmqh-nfq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tmqh-packetpool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tmqh-ringbuffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tmqh-simple.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unix-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-action.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-affinity.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-atomic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-bloomfilter-counting.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-bloomfilter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-byte.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-checksum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-cidr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-classification-config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-coredump-config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-cpu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-crypt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-cuda-handlers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-cuda.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-daemon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-debug-filters.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-decode-asn1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-decode-der-get.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-decode-der.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-enum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-error.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-file.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-fix_checksum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-fmemopen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-hash-lookup3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-hashlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-host-os-info.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-ioctl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-logopenfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-magic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-memcmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-misc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-ac-bs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-ac-gfbs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-ac.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-b2g-cuda.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-b2g.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-b2gc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-b2gm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-b3g.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm-wumanber.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-mpm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-path.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-pidfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-pool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-print.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-privs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-profiling-locks.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-profiling-rules.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-profiling.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-proto-name.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-radix-tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-random.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-reference-config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-ringbuffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-rohash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-rule-vars.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-runmodes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-signal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-spm-bm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-spm-bs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-spm-bs2bm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-spm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-strlcatu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-strlcpyu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-syslog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-threshold-config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-unittest-helper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-var-name.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util-var.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32-misc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32-service.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(PROGRAMS) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-local distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-local distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS 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 \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS @BUILD_CUDA_TRUE@.cu.ptx_sm_10: @BUILD_CUDA_TRUE@ $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_10 -ptx $< @BUILD_CUDA_TRUE@.cu.ptx_sm_11: @BUILD_CUDA_TRUE@ $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_11 -ptx $< @BUILD_CUDA_TRUE@.cu.ptx_sm_12: @BUILD_CUDA_TRUE@ $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_12 -ptx $< @BUILD_CUDA_TRUE@.cu.ptx_sm_13: @BUILD_CUDA_TRUE@ $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_13 -ptx $< @BUILD_CUDA_TRUE@.cu.ptx_sm_20: @BUILD_CUDA_TRUE@ $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_20 -ptx $< @BUILD_CUDA_TRUE@.cu.ptx_sm_21: @BUILD_CUDA_TRUE@ $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_21 -ptx $< @BUILD_CUDA_TRUE@cuda-ptxdump.h: $(PTXS) @BUILD_CUDA_TRUE@ $(PYTHON) ptxdump.py cuda-ptxdump $(PTXS) @BUILD_UNITTESTS_TRUE@check-am: @BUILD_UNITTESTS_TRUE@ $(top_builddir)/src/suricata -u distclean-local: -rm -rf $(top_builddir)/src/build-info.h # 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: suricata-1.4.7/src/detect-bytejump.h0000644000000000000000000001050312253546156014302 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus */ #ifndef __DETECT_BYTEJUMP_H__ #define __DETECT_BYTEJUMP_H__ /** Bytejump Base */ #define DETECT_BYTEJUMP_BASE_UNSET 0 /**< Unset type value string (automatic)*/ #define DETECT_BYTEJUMP_BASE_OCT 8 /**< "oct" type value string */ #define DETECT_BYTEJUMP_BASE_DEC 10 /**< "dec" type value string */ #define DETECT_BYTEJUMP_BASE_HEX 16 /**< "hex" type value string */ /** Bytejump Flags */ #define DETECT_BYTEJUMP_BEGIN 0x01 /**< "from_beginning" jump */ #define DETECT_BYTEJUMP_LITTLE 0x02 /**< "little" endian value */ #define DETECT_BYTEJUMP_BIG 0x04 /**< "big" endian value */ #define DETECT_BYTEJUMP_STRING 0x08 /**< "string" value */ #define DETECT_BYTEJUMP_RELATIVE 0x10 /**< "relative" offset */ #define DETECT_BYTEJUMP_ALIGN 0x20 /**< "align" offset */ #define DETECT_BYTEJUMP_DCE 0x40 /**< "dce" enabled */ #define DETECT_BYTEJUMP_OFFSET_BE 0x80 /**< "byte extract" enabled */ typedef struct DetectBytejumpData_ { uint8_t nbytes; /**< Number of bytes to compare */ uint8_t base; /**< String value base (oct|dec|hex) */ uint8_t flags; /**< Flags (big|little|relative|string) */ uint32_t multiplier; /**< Multiplier for nbytes (multiplier n)*/ int32_t offset; /**< Offset in payload to extract value */ int32_t post_offset; /**< Offset to adjust post-jump */ } DetectBytejumpData; /* prototypes */ /** * Registration function for byte_jump. * * \todo add support for no_stream and stream_only */ void DetectBytejumpRegister (void); /** * This function is used to add the parsed byte_jump data * into the current signature. * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param optstr pointer to the user provided options * * \retval 0 on Success * \retval -1 on Failure */ int DetectBytejumpSetup(DetectEngineCtx *, Signature *, char *); /** * \brief this function will free memory associated with DetectBytejumpData * * \param data pointer to DetectBytejumpData */ void DetectBytejumpFree(void *ptr); /** * This function is used to parse byte_jump options passed via * * byte_jump: bytes, offset [,flags [, ...]] * * flags: "big", "little", "relative", "string", "oct", "dec", "hex" * "align", "from beginning", "multiplier N", "post_offset N" * * \param optstr Pointer to the user provided byte_jump options * \param offset Used to pass the offset back, if byte_jump uses a byte_extract * var. * * \retval data pointer to DetectBytejumpData on success * \retval NULL on failure */ DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); /** * This function is used to match byte_jump * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectBytejumpData * * \retval -1 error * \retval 0 no match * \retval 1 match * * \todo The return seems backwards. We should return a non-zero error code. * One of the error codes is "no match". As-is if someone accidentally * does: if (DetectBytejumpMatch(...)) { match }, then they catch an * error as a match. */ int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m); int DetectBytejumpDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, uint8_t *, uint32_t, uint8_t, int32_t); #endif /* __DETECT_BYTEJUMP_H__ */ suricata-1.4.7/src/detect-mark.h0000644000000000000000000000271212253546156013400 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond * * Based on detect-mark.h by Breno Silva * * Implements the nfq_set_mark keyword */ #ifndef __DETECT_MARK_H__ #define __DETECT_MARK_H__ #include "decode.h" #include "detect.h" /** * \struct DetectMarkData_ * DetectMarkData_ is used to store nfq_set_mark: input value */ /** * \typedef DetectMarkData * A typedef for DetectMarkData_ */ typedef struct DetectMarkData_ { uint32_t mark; /**< Rule mark */ uint32_t mask; /**< Rule mask */ } DetectMarkData; /** * Registration function for nfq_set_mark: keyword */ void DetectMarkRegister (void); /** * This function registers unit tests for Mark */ void MarkRegisterTests(void); #endif /*__DETECT_MARK_H__ */ suricata-1.4.7/src/source-napatech.h0000644000000000000000000000223312253546156014257 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author nPulse Technologies, LLC * \author Matt Keeler */ #ifndef __SOURCE_NAPATECH_H__ #define __SOURCE_NAPATECH_H__ void TmModuleNapatechStreamRegister (void); TmEcode NapatechStreamThreadDeinit(ThreadVars *tv, void *data); void TmModuleNapatechDecodeRegister (void); struct NapatechStreamDevConf { int stream_id; intmax_t hba; }; #ifdef HAVE_NAPATECH #include #endif #endif /* __SOURCE_NAPATECH_H__ */ suricata-1.4.7/src/detect-engine-mpm.c0000644000000000000000000036334712253546156014513 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * * Multi pattern matcher */ #include "suricata.h" #include "suricata-common.h" #include "app-layer-protos.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-siggroup.h" #include "detect-engine-mpm.h" #include "detect-engine-iponly.h" #include "detect-parse.h" #include "util-mpm.h" #include "conf.h" #include "detect-fast-pattern.h" #include "flow.h" #include "flow-var.h" #include "detect-flow.h" #include "detect-content.h" #include "detect-uricontent.h" #include "stream.h" #include "util-cuda-handlers.h" #include "util-mpm-b2g-cuda.h" #include "util-enum.h" #include "util-debug.h" #include "util-print.h" #include "util-memcmp.h" /** \todo make it possible to use multiple pattern matcher algorithms next to eachother. */ #ifdef __SC_CUDA_SUPPORT__ #define PM MPM_B2G_CUDA #else #define PM MPM_AC #endif #define POPULATE_MPM_AVOID_PACKET_MPM_PATTERNS 0x01 #define POPULATE_MPM_AVOID_STREAM_MPM_PATTERNS 0x02 #define POPULATE_MPM_AVOID_URI_MPM_PATTERNS 0x04 /** * \brief check if a signature has patterns that are to be inspected * against a packets payload (as opposed to the stream payload) * * \param s signature * * \retval 1 true * \retval 0 false */ int SignatureHasPacketContent(Signature *s) { SCEnter(); if (s == NULL) { SCReturnInt(0); } if (!(s->proto.proto[6 / 8] & 1 << (6 % 8))) { SCReturnInt(1); } if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { SCLogDebug("no mpm"); SCReturnInt(0); } if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { SCReturnInt(0); } SCReturnInt(1); } /** * \brief check if a signature has patterns that are to be inspected * against the stream payload (as opposed to the individual packets * payload(s)) * * \param s signature * * \retval 1 true * \retval 0 false */ int SignatureHasStreamContent(Signature *s) { SCEnter(); if (s == NULL) { SCReturnInt(0); } if (!(s->proto.proto[6 / 8] & 1 << (6 % 8))) { SCReturnInt(0); } if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { SCLogDebug("no mpm"); SCReturnInt(0); } if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { SCReturnInt(0); } SCReturnInt(1); } /** * \brief Function to return the multi pattern matcher algorithm to be * used by the engine, based on the mpm-algo setting in yaml * Use the default mpm non is found in yaml. * * \retval mpm algo value */ uint16_t PatternMatchDefaultMatcher(void) { char *mpm_algo; uint16_t mpm_algo_val = PM; /* Get the mpm algo defined in config file by the user */ if ((ConfGet("mpm-algo", &mpm_algo)) == 1) { uint16_t u; if (mpm_algo != NULL) { for (u = 0; u < MPM_TABLE_SIZE; u++) { if (mpm_table[u].name == NULL) continue; if (strcmp(mpm_table[u].name, mpm_algo) == 0) { return u; } } } SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid mpm algo supplied " "in the yaml conf file: \"%s\"", mpm_algo); exit(EXIT_FAILURE); } return mpm_algo_val; } uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, Packet *p) { SCEnter(); uint32_t ret = 0; if (p->flowflags & FLOW_PKT_TOSERVER) { if (det_ctx->sgh->mpm_stream_ctx_ts == NULL) SCReturnInt(0); ret = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); } else { if (det_ctx->sgh->mpm_stream_ctx_tc == NULL) SCReturnInt(0); ret = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); } SCReturnInt(ret); } /** \brief Pattern match -- searches for only one pattern per signature. * * \param det_ctx detection engine thread ctx * \param p packet to inspect * * \retval ret number of matches */ uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) { SCEnter(); uint32_t ret; MpmCtx *mpm_ctx = NULL; if (p->proto == IPPROTO_TCP) { if (p->flowflags & FLOW_PKT_TOSERVER) { mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_ts; } else { mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_tc; } } else if (p->proto == IPPROTO_UDP) { if (p->flowflags & FLOW_PKT_TOSERVER) { mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_ts; } else { mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_tc; } } else { mpm_ctx = det_ctx->sgh->mpm_proto_other_ctx; } if (mpm_ctx == NULL) SCReturnInt(0); #ifndef __SC_CUDA_SUPPORT__ ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); #else /* if the user has enabled cuda support, but is not using the cuda mpm * algo, then we shouldn't take the path of the dispatcher. Call the mpm * directly */ if (mpm_ctx->mpm_type != MPM_B2G_CUDA) { ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); SCReturnInt(ret); } if (p->cuda_mpm_enabled) { ret = B2gCudaResultsPostProcessing(p, mpm_ctx, &det_ctx->mtc, &det_ctx->pmq); } else { ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); } #endif SCReturnInt(ret); } /** \brief Uri Pattern match -- searches for one pattern per signature. * * \param det_ctx detection engine thread ctx * \param p packet to inspect * * \retval ret number of matches */ uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *uri, uint16_t uri_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_uri_ctx_ts == NULL) SCReturnUInt(0U); ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_uri_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); } else { if (det_ctx->sgh->mpm_uri_ctx_tc == NULL) SCReturnUInt(0U); ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_uri_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); } //PrintRawDataFp(stdout, uri, uri_len); SCReturnUInt(ret); } /** \brief Http client body pattern match -- searches for one pattern per * signature. * * \param det_ctx Detection engine thread ctx. * \param body The request body to inspect. * \param body_len Body length. * * \retval ret Number of matches. */ uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *body, uint32_t body_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hcbd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, body, body_len); } else { if (det_ctx->sgh->mpm_hcbd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hcbd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, body, body_len); } SCReturnUInt(ret); } /** \brief Http server body pattern match -- searches for one pattern per * signature. * * \param det_ctx Detection engine thread ctx. * \param body The request body to inspect. * \param body_len Body length. * * \retval ret Number of matches. */ uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *body, uint32_t body_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hsbd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hsbd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, body, body_len); } else { if (det_ctx->sgh->mpm_hsbd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, body, body_len); } SCReturnUInt(ret); } /** * \brief Http header match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param headers Headers to inspect. * \param headers_len Headers length. * * \retval ret Number of matches. */ uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *headers, uint32_t headers_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hhd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hhd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, headers, headers_len); } else { if (det_ctx->sgh->mpm_hhd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hhd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, headers, headers_len); } SCReturnUInt(ret); } /** * \brief Http raw header match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param headers Raw headers to inspect. * \param headers_len Raw headers length. * * \retval ret Number of matches. */ uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *raw_headers, uint32_t raw_headers_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hrhd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hrhd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, raw_headers, raw_headers_len); } else { if (det_ctx->sgh->mpm_hrhd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hrhd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, raw_headers, raw_headers_len); } SCReturnUInt(ret); } /** * \brief Http method match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param method Method to inspect. * \param method_len Method length. * * \retval ret Number of matches. */ uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *raw_method, uint32_t raw_method_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hmd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, raw_method, raw_method_len); } else { if (det_ctx->sgh->mpm_hmd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hmd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, raw_method, raw_method_len); } SCReturnUInt(ret); } /** * \brief Http cookie match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param cookie Cookie to inspect. * \param cookie_len Cookie length. * * \retval ret Number of matches. */ uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *cookie, uint32_t cookie_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hcd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hcd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, cookie, cookie_len); } else { if (det_ctx->sgh->mpm_hcd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hcd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, cookie, cookie_len); } SCReturnUInt(ret); } /** * \brief Http raw uri match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param uri Raw uri to inspect. * \param uri_len Raw uri length. * * \retval ret Number of matches. */ uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *uri, uint32_t uri_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hrud_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); } else { if (det_ctx->sgh->mpm_hrud_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hrud_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); } SCReturnUInt(ret); } /** * \brief Http stat msg match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param stat_msg Stat msg to inspect. * \param stat_msg_len Stat msg length. * * \retval ret Number of matches. */ uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *stat_msg, uint32_t stat_msg_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hsmd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hsmd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, stat_msg, stat_msg_len); } else { if (det_ctx->sgh->mpm_hsmd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, stat_msg, stat_msg_len); } SCReturnUInt(ret); } /** * \brief Http stat code match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param stat_code Stat code to inspect. * \param stat_code_len Stat code length. * * \retval ret Number of matches. */ uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *stat_code, uint32_t stat_code_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hscd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hscd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, stat_code, stat_code_len); } else { if (det_ctx->sgh->mpm_hscd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, stat_code, stat_code_len); } SCReturnUInt(ret); } /** * \brief Http user agent match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param cookie User-Agent to inspect. * \param cookie_len User-Agent buffer length. * * \retval ret Number of matches. */ uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *ua, uint32_t ua_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_huad_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, ua, ua_len); } else { if (det_ctx->sgh->mpm_huad_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_huad_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, ua, ua_len); } SCReturnUInt(ret); } /** * \brief Http host header match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param hh Host header to inspect. * \param hh_len Host header buffer length. * \param flags Flags * * \retval ret Number of matches. */ uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *hh, uint32_t hh_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hhhd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, hh, hh_len); } else { if (det_ctx->sgh->mpm_hhhd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hhhd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, hh, hh_len); } SCReturnUInt(ret); } /** * \brief Http raw host header match -- searches for one pattern per signature. * * \param det_ctx Detection engine thread ctx. * \param hrh Raw hostname to inspect. * \param hrh_len Raw hostname buffer length. * \param flags Flags * * \retval ret Number of matches. */ uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *hrh, uint32_t hrh_len, uint8_t flags) { SCEnter(); uint32_t ret; if (flags & STREAM_TOSERVER) { if (det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, &det_ctx->pmq, hrh, hrh_len); } else { if (det_ctx->sgh->mpm_hrhhd_ctx_tc == NULL) SCReturnUInt(0); ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_hrhhd_ctx_tc, &det_ctx->mtcu, &det_ctx->pmq, hrh, hrh_len); } SCReturnUInt(ret); } /** \brief Pattern match -- searches for only one pattern per signature. * * \param det_ctx detection engine thread ctx * \param p packet * \param smsg stream msg (reassembled stream data) * \param flags stream flags * * \retval ret number of matches */ uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, StreamMsg *smsg, uint8_t flags) { SCEnter(); uint32_t ret = 0; uint8_t cnt = 0; //PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); uint32_t r; if (flags & STREAM_TOSERVER) { for ( ; smsg != NULL; smsg = smsg->next) { r = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtcs, &det_ctx->smsg_pmq[cnt], smsg->data.data, smsg->data.data_len); if (r > 0) { ret += r; SCLogDebug("smsg match stored in det_ctx->smsg_pmq[%u]", cnt); /* merge results with overall pmq */ PmqMerge(&det_ctx->smsg_pmq[cnt], &det_ctx->pmq); } cnt++; } } else { for ( ; smsg != NULL; smsg = smsg->next) { r = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtcs, &det_ctx->smsg_pmq[cnt], smsg->data.data, smsg->data.data_len); if (r > 0) { ret += r; SCLogDebug("smsg match stored in det_ctx->smsg_pmq[%u]", cnt); /* merge results with overall pmq */ PmqMerge(&det_ctx->smsg_pmq[cnt], &det_ctx->pmq); } cnt++; } } SCReturnInt(ret); } /** \brief cleans up the mpm instance after a match */ void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) { PmqReset(&det_ctx->pmq); if (det_ctx->sgh == NULL) return; /* content */ if (det_ctx->sgh->mpm_proto_tcp_ctx_ts != NULL && mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_ts->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_ts->mpm_type].Cleanup(&det_ctx->mtc); } if (det_ctx->sgh->mpm_proto_tcp_ctx_tc != NULL && mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_tc->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_tc->mpm_type].Cleanup(&det_ctx->mtc); } if (det_ctx->sgh->mpm_proto_udp_ctx_ts != NULL && mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_ts->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_ts->mpm_type].Cleanup(&det_ctx->mtc); } if (det_ctx->sgh->mpm_proto_udp_ctx_tc != NULL && mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_tc->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_tc->mpm_type].Cleanup(&det_ctx->mtc); } if (det_ctx->sgh->mpm_proto_other_ctx != NULL && mpm_table[det_ctx->sgh->mpm_proto_other_ctx->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_proto_other_ctx->mpm_type].Cleanup(&det_ctx->mtc); } /* uricontent */ if (det_ctx->sgh->mpm_uri_ctx_ts != NULL && mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type].Cleanup(&det_ctx->mtcu); } if (det_ctx->sgh->mpm_uri_ctx_tc != NULL && mpm_table[det_ctx->sgh->mpm_uri_ctx_tc->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_uri_ctx_tc->mpm_type].Cleanup(&det_ctx->mtcu); } /* stream content */ if (det_ctx->sgh->mpm_stream_ctx_ts != NULL && mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type].Cleanup(&det_ctx->mtcs); } if (det_ctx->sgh->mpm_stream_ctx_tc != NULL && mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type].Cleanup != NULL) { mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type].Cleanup(&det_ctx->mtcs); } return; } void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg) { uint8_t cnt = 0; while (smsg != NULL) { PmqReset(&det_ctx->smsg_pmq[cnt]); smsg = smsg->next; cnt++; } } void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher) { SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher); mpm_table[mpm_matcher].DestroyCtx(mpm_ctx); } void PatternMatchPrepare(MpmCtx *mpm_ctx, uint16_t mpm_matcher) { SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher); MpmInitCtx(mpm_ctx, mpm_matcher, -1); } void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) { SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16" defunct", mpm_thread_ctx, mpm_matcher); //mpm_table[mpm_matcher].PrintThreadCtx(mpm_thread_ctx); } void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) { SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher); mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx); } void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher, uint32_t max_id) { SCLogDebug("mpm_thread_ctx %p, type %"PRIu16", max_id %"PRIu32"", mpm_thread_ctx, mpm_matcher, max_id); MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher, max_id); } /* free the pattern matcher part of a SigGroupHead */ void PatternMatchDestroyGroup(SigGroupHead *sh) { /* content */ if (!(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) { SCLogDebug("destroying mpm_ctx %p (sh %p)", sh->mpm_proto_tcp_ctx_ts, sh); if (sh->mpm_proto_tcp_ctx_ts != NULL && !sh->mpm_proto_tcp_ctx_ts->global) { mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. DestroyCtx(sh->mpm_proto_tcp_ctx_ts); SCFree(sh->mpm_proto_tcp_ctx_ts); } /* ready for reuse */ sh->mpm_proto_tcp_ctx_ts = NULL; SCLogDebug("destroying mpm_ctx %p (sh %p)", sh->mpm_proto_tcp_ctx_tc, sh); if (sh->mpm_proto_tcp_ctx_tc != NULL && !sh->mpm_proto_tcp_ctx_tc->global) { mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. DestroyCtx(sh->mpm_proto_tcp_ctx_tc); SCFree(sh->mpm_proto_tcp_ctx_tc); } /* ready for reuse */ sh->mpm_proto_tcp_ctx_tc = NULL; SCLogDebug("destroying mpm_ctx %p (sh %p)", sh->mpm_proto_udp_ctx_ts, sh); if (sh->mpm_proto_udp_ctx_ts != NULL && !sh->mpm_proto_udp_ctx_ts->global) { mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. DestroyCtx(sh->mpm_proto_udp_ctx_ts); SCFree(sh->mpm_proto_udp_ctx_ts); } /* ready for reuse */ sh->mpm_proto_udp_ctx_ts = NULL; SCLogDebug("destroying mpm_ctx %p (sh %p)", sh->mpm_proto_udp_ctx_tc, sh); if (sh->mpm_proto_udp_ctx_tc != NULL && !sh->mpm_proto_udp_ctx_tc->global) { mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. DestroyCtx(sh->mpm_proto_udp_ctx_tc); SCFree(sh->mpm_proto_udp_ctx_tc); } /* ready for reuse */ sh->mpm_proto_udp_ctx_tc = NULL; SCLogDebug("destroying mpm_ctx %p (sh %p)", sh->mpm_proto_other_ctx, sh); if (sh->mpm_proto_other_ctx != NULL && !sh->mpm_proto_other_ctx->global) { mpm_table[sh->mpm_proto_other_ctx->mpm_type]. DestroyCtx(sh->mpm_proto_other_ctx); SCFree(sh->mpm_proto_other_ctx); } /* ready for reuse */ sh->mpm_proto_other_ctx = NULL; } /* uricontent */ if ((sh->mpm_uri_ctx_ts != NULL || sh->mpm_uri_ctx_tc != NULL) && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) { if (sh->mpm_uri_ctx_ts != NULL) { SCLogDebug("destroying mpm_uri_ctx %p (sh %p)", sh->mpm_uri_ctx_ts, sh); if (!sh->mpm_uri_ctx_ts->global) { mpm_table[sh->mpm_uri_ctx_ts->mpm_type].DestroyCtx(sh->mpm_uri_ctx_ts); SCFree(sh->mpm_uri_ctx_ts); } /* ready for reuse */ sh->mpm_uri_ctx_ts = NULL; } if (sh->mpm_uri_ctx_tc != NULL) { SCLogDebug("destroying mpm_uri_ctx %p (sh %p)", sh->mpm_uri_ctx_tc, sh); if (!sh->mpm_uri_ctx_tc->global) { mpm_table[sh->mpm_uri_ctx_tc->mpm_type].DestroyCtx(sh->mpm_uri_ctx_tc); SCFree(sh->mpm_uri_ctx_tc); } /* ready for reuse */ sh->mpm_uri_ctx_tc = NULL; } } /* stream content */ if ((sh->mpm_stream_ctx_ts != NULL || sh->mpm_stream_ctx_tc != NULL) && !(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) { if (sh->mpm_stream_ctx_ts != NULL) { SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_ts, sh); if (!sh->mpm_stream_ctx_ts->global) { mpm_table[sh->mpm_stream_ctx_ts->mpm_type].DestroyCtx(sh->mpm_stream_ctx_ts); SCFree(sh->mpm_stream_ctx_ts); } /* ready for reuse */ sh->mpm_stream_ctx_ts = NULL; } if (sh->mpm_stream_ctx_tc != NULL) { SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_tc, sh); if (!sh->mpm_stream_ctx_tc->global) { mpm_table[sh->mpm_stream_ctx_tc->mpm_type].DestroyCtx(sh->mpm_stream_ctx_tc); SCFree(sh->mpm_stream_ctx_tc); } /* ready for reuse */ sh->mpm_stream_ctx_tc = NULL; } } if (sh->mpm_hcbd_ctx_ts != NULL || sh->mpm_hcbd_ctx_tc != NULL) { if (sh->mpm_hcbd_ctx_ts != NULL) { if (!sh->mpm_hcbd_ctx_ts->global) { mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hcbd_ctx_ts); SCFree(sh->mpm_hcbd_ctx_ts); } sh->mpm_hcbd_ctx_ts = NULL; } if (sh->mpm_hcbd_ctx_tc != NULL) { if (!sh->mpm_hcbd_ctx_tc->global) { mpm_table[sh->mpm_hcbd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hcbd_ctx_tc); SCFree(sh->mpm_hcbd_ctx_tc); } sh->mpm_hcbd_ctx_tc = NULL; } } if (sh->mpm_hsbd_ctx_ts != NULL || sh->mpm_hsbd_ctx_tc != NULL) { if (sh->mpm_hsbd_ctx_ts != NULL) { if (!sh->mpm_hsbd_ctx_ts->global) { mpm_table[sh->mpm_hsbd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hsbd_ctx_ts); SCFree(sh->mpm_hsbd_ctx_ts); } sh->mpm_hsbd_ctx_ts = NULL; } if (sh->mpm_hsbd_ctx_tc != NULL) { if (!sh->mpm_hsbd_ctx_tc->global) { mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hsbd_ctx_tc); SCFree(sh->mpm_hsbd_ctx_tc); } sh->mpm_hsbd_ctx_tc = NULL; } } if (sh->mpm_hhd_ctx_ts != NULL || sh->mpm_hhd_ctx_tc != NULL) { if (sh->mpm_hhd_ctx_ts != NULL) { if (!sh->mpm_hhd_ctx_ts->global) { mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hhd_ctx_ts); SCFree(sh->mpm_hhd_ctx_ts); } sh->mpm_hhd_ctx_ts = NULL; } if (sh->mpm_hhd_ctx_tc != NULL) { if (!sh->mpm_hhd_ctx_tc->global) { mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hhd_ctx_tc); SCFree(sh->mpm_hhd_ctx_tc); } sh->mpm_hhd_ctx_tc = NULL; } } if (sh->mpm_hrhd_ctx_ts != NULL || sh->mpm_hrhd_ctx_tc != NULL) { if (sh->mpm_hrhd_ctx_ts != NULL) { if (!sh->mpm_hrhd_ctx_ts->global) { mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hrhd_ctx_ts); SCFree(sh->mpm_hrhd_ctx_ts); } sh->mpm_hrhd_ctx_ts = NULL; } if (sh->mpm_hrhd_ctx_tc != NULL) { if (!sh->mpm_hrhd_ctx_tc->global) { mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hrhd_ctx_tc); SCFree(sh->mpm_hrhd_ctx_tc); } sh->mpm_hrhd_ctx_tc = NULL; } } if (sh->mpm_hmd_ctx_ts != NULL || sh->mpm_hmd_ctx_tc != NULL) { if (sh->mpm_hmd_ctx_ts != NULL) { if (!sh->mpm_hmd_ctx_ts->global) { mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hmd_ctx_ts); SCFree(sh->mpm_hmd_ctx_ts); } sh->mpm_hmd_ctx_ts = NULL; } if (sh->mpm_hmd_ctx_tc != NULL) { if (!sh->mpm_hmd_ctx_tc->global) { mpm_table[sh->mpm_hmd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hmd_ctx_tc); SCFree(sh->mpm_hmd_ctx_tc); } sh->mpm_hmd_ctx_tc = NULL; } } if (sh->mpm_hcd_ctx_ts != NULL || sh->mpm_hcd_ctx_tc != NULL) { if (sh->mpm_hcd_ctx_ts != NULL) { if (!sh->mpm_hcd_ctx_ts->global) { mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hcd_ctx_ts); SCFree(sh->mpm_hcd_ctx_ts); } sh->mpm_hcd_ctx_ts = NULL; } if (sh->mpm_hcd_ctx_tc != NULL) { if (!sh->mpm_hcd_ctx_tc->global) { mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hcd_ctx_tc); SCFree(sh->mpm_hcd_ctx_tc); } sh->mpm_hcd_ctx_tc = NULL; } } if (sh->mpm_hrud_ctx_ts != NULL || sh->mpm_hrud_ctx_tc != NULL) { if (sh->mpm_hrud_ctx_ts != NULL) { if (!sh->mpm_hrud_ctx_ts->global) { mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hrud_ctx_ts); SCFree(sh->mpm_hrud_ctx_ts); } sh->mpm_hrud_ctx_ts = NULL; } if (sh->mpm_hrud_ctx_tc != NULL) { if (!sh->mpm_hrud_ctx_tc->global) { mpm_table[sh->mpm_hrud_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hrud_ctx_tc); SCFree(sh->mpm_hrud_ctx_tc); } sh->mpm_hrud_ctx_tc = NULL; } } if (sh->mpm_hsmd_ctx_ts != NULL || sh->mpm_hsmd_ctx_tc != NULL) { if (sh->mpm_hsmd_ctx_ts != NULL) { if (!sh->mpm_hsmd_ctx_ts->global) { mpm_table[sh->mpm_hsmd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hsmd_ctx_ts); SCFree(sh->mpm_hsmd_ctx_ts); } sh->mpm_hsmd_ctx_ts = NULL; } if (sh->mpm_hsmd_ctx_tc != NULL) { if (!sh->mpm_hsmd_ctx_tc->global) { mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hsmd_ctx_tc); SCFree(sh->mpm_hsmd_ctx_tc); } sh->mpm_hsmd_ctx_tc = NULL; } } if (sh->mpm_hscd_ctx_ts != NULL || sh->mpm_hscd_ctx_tc != NULL) { if (sh->mpm_hscd_ctx_ts != NULL) { if (!sh->mpm_hscd_ctx_ts->global) { mpm_table[sh->mpm_hscd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hscd_ctx_ts); SCFree(sh->mpm_hscd_ctx_ts); } sh->mpm_hscd_ctx_ts = NULL; } if (sh->mpm_hscd_ctx_tc != NULL) { if (!sh->mpm_hscd_ctx_tc->global) { mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hscd_ctx_tc); SCFree(sh->mpm_hscd_ctx_tc); } sh->mpm_hscd_ctx_tc = NULL; } } if (sh->mpm_huad_ctx_ts != NULL || sh->mpm_huad_ctx_tc != NULL) { if (sh->mpm_huad_ctx_ts != NULL) { if (!sh->mpm_huad_ctx_ts->global) { mpm_table[sh->mpm_huad_ctx_ts->mpm_type].DestroyCtx(sh->mpm_huad_ctx_ts); SCFree(sh->mpm_huad_ctx_ts); } sh->mpm_huad_ctx_ts = NULL; } if (sh->mpm_huad_ctx_tc != NULL) { if (!sh->mpm_huad_ctx_tc->global) { mpm_table[sh->mpm_huad_ctx_tc->mpm_type].DestroyCtx(sh->mpm_huad_ctx_tc); SCFree(sh->mpm_huad_ctx_tc); } sh->mpm_huad_ctx_tc = NULL; } } return; } /** \brief Hash for looking up contents that are most used, * always used, etc. */ typedef struct ContentHash_ { DetectContentData *ptr; uint16_t cnt; uint8_t use; /* use no matter what */ } ContentHash; typedef struct UricontentHash_ { DetectContentData *ptr; uint16_t cnt; uint8_t use; /* use no matter what */ } UricontentHash; uint32_t ContentHashFunc(HashTable *ht, void *data, uint16_t datalen) { ContentHash *ch = (ContentHash *)data; DetectContentData *co = ch->ptr; uint32_t hash = 0; int i; for (i = 0; i < co->content_len; i++) { hash += co->content[i]; } hash = hash % ht->array_size; SCLogDebug("hash %" PRIu32 "", hash); return hash; } uint32_t UricontentHashFunc(HashTable *ht, void *data, uint16_t datalen) { UricontentHash *ch = (UricontentHash *)data; DetectContentData *ud = ch->ptr; uint32_t hash = 0; int i; for (i = 0; i < ud->content_len; i++) { hash += ud->content[i]; } hash = hash % ht->array_size; SCLogDebug("hash %" PRIu32 "", hash); return hash; } char ContentHashCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { ContentHash *ch1 = (ContentHash *)data1; ContentHash *ch2 = (ContentHash *)data2; DetectContentData *co1 = ch1->ptr; DetectContentData *co2 = ch2->ptr; if (co1->content_len == co2->content_len && ((co1->flags & DETECT_CONTENT_NOCASE) == (co2->flags & DETECT_CONTENT_NOCASE)) && SCMemcmp(co1->content, co2->content, co1->content_len) == 0) return 1; return 0; } char UricontentHashCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { UricontentHash *ch1 = (UricontentHash *)data1; UricontentHash *ch2 = (UricontentHash *)data2; DetectContentData *ud1 = ch1->ptr; DetectContentData *ud2 = ch2->ptr; if (ud1->content_len == ud2->content_len && ((ud1->flags & DETECT_CONTENT_NOCASE) == (ud2->flags & DETECT_CONTENT_NOCASE)) && SCMemcmp(ud1->content, ud2->content, ud1->content_len) == 0) return 1; return 0; } ContentHash *ContentHashAlloc(DetectContentData *ptr) { ContentHash *ch = SCMalloc(sizeof(ContentHash)); if (unlikely(ch == NULL)) return NULL; ch->ptr = ptr; ch->cnt = 1; ch->use = 0; return ch; } UricontentHash *UricontentHashAlloc(DetectContentData *ptr) { UricontentHash *ch = SCMalloc(sizeof(UricontentHash)); if (unlikely(ch == NULL)) return NULL; ch->ptr = ptr; ch->cnt = 1; ch->use = 0; return ch; } void ContentHashFree(void *ch) { SCFree(ch); } void UricontentHashFree(void *ch) { SCFree(ch); } /** \brief Predict a strength value for patterns * * Patterns with high character diversity score higher. * Alpha chars score not so high * Other printable + a few common codes a little higher * Everything else highest. * Longer patterns score better than short patters. * * \param pat pattern * \param patlen length of the patternn * * \retval s pattern score */ uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) { uint8_t a[256]; memset(&a, 0 ,sizeof(a)); uint32_t s = 0; uint16_t u = 0; for (u = 0; u < patlen; u++) { if (a[pat[u]] == 0) { if (isalpha(pat[u])) s += 3; else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF) s += 4; else s += 6; a[pat[u]] = 1; } else { s++; } } return s; } static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, DetectContentData *cd, Signature *s, uint8_t flags, int chop) { if (cd->flags & DETECT_CONTENT_NOCASE) { if (chop) { mpm_table[mpm_ctx->mpm_type]. AddPatternNocase(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } else { mpm_table[mpm_ctx->mpm_type]. AddPatternNocase(mpm_ctx, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } } else { if (chop) { mpm_table[mpm_ctx->mpm_type]. AddPattern(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } else { mpm_table[mpm_ctx->mpm_type]. AddPattern(mpm_ctx, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } } return; } static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, SigGroupHead *sgh, Signature *s, SigMatch *mpm_sm) { s->mpm_sm = mpm_sm; if (mpm_sm == NULL) { SCLogDebug("%"PRIu32" no mpm pattern selected", s->id); return; } int sm_list = SigMatchListSMBelongsTo(s, mpm_sm); if (sm_list == -1) BUG_ON(SigMatchListSMBelongsTo(s, mpm_sm) == -1); uint8_t flags = 0; DetectContentData *cd = NULL; switch (sm_list) { case DETECT_SM_LIST_PMATCH: { cd = (DetectContentData *)mpm_sm->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { if (DETECT_CONTENT_IS_SINGLE(cd) && !(cd->flags & DETECT_CONTENT_NEGATED) && !(cd->flags & DETECT_CONTENT_REPLACE) && cd->content_len == cd->fp_chop_len) { cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; } /* add the content to the "packet" mpm */ if (SignatureHasPacketContent(s)) { if (s->proto.proto[6 / 8] & 1 << (6 % 8)) { if (s->flags & SIG_FLAG_TOSERVER) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_ts, cd, s, flags, 1); } if (s->flags & SIG_FLAG_TOCLIENT) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_tc, cd, s, flags, 1); } } if (s->proto.proto[17 / 8] & 1 << (17 % 8)) { if (s->flags & SIG_FLAG_TOSERVER) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_ts, cd, s, flags, 1); } if (s->flags & SIG_FLAG_TOCLIENT) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_tc, cd, s, flags, 1); } } int i; for (i = 0; i < 256; i++) { if (i == 6 || i == 17) continue; if (s->proto.proto[i / 8] & (1 << (i % 8))) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_other_ctx, cd, s, flags, 1); break; } } /* tell matcher we are inspecting packet */ s->flags |= SIG_FLAG_MPM_PACKET; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); if (cd->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); s->flags |= SIG_FLAG_MPM_PACKET_NEG; } } if (SignatureHasStreamContent(s)) { if (cd->flags & DETECT_CONTENT_NOCASE) { if (s->flags & SIG_FLAG_TOSERVER) { mpm_table[sgh->mpm_stream_ctx_ts->mpm_type]. AddPatternNocase(sgh->mpm_stream_ctx_ts, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } if (s->flags & SIG_FLAG_TOCLIENT) { mpm_table[sgh->mpm_stream_ctx_tc->mpm_type]. AddPatternNocase(sgh->mpm_stream_ctx_tc, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } } else { if (s->flags & SIG_FLAG_TOSERVER) { mpm_table[sgh->mpm_stream_ctx_ts->mpm_type]. AddPattern(sgh->mpm_stream_ctx_ts, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } if (s->flags & SIG_FLAG_TOCLIENT) { mpm_table[sgh->mpm_stream_ctx_tc->mpm_type]. AddPattern(sgh->mpm_stream_ctx_tc, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } } /* tell matcher we are inspecting stream */ s->flags |= SIG_FLAG_MPM_STREAM; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); if (cd->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); s->flags |= SIG_FLAG_MPM_STREAM_NEG; } } } else { if (DETECT_CONTENT_IS_SINGLE(cd) && !(cd->flags & DETECT_CONTENT_NEGATED) && !(cd->flags & DETECT_CONTENT_REPLACE)) { cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; } if (SignatureHasPacketContent(s)) { /* add the content to the "packet" mpm */ if (s->proto.proto[6 / 8] & 1 << (6 % 8)) { if (s->flags & SIG_FLAG_TOSERVER) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_ts, cd, s, flags, 0); } if (s->flags & SIG_FLAG_TOCLIENT) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_tc, cd, s, flags, 0); } } if (s->proto.proto[17 / 8] & 1 << (17 % 8)) { if (s->flags & SIG_FLAG_TOSERVER) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_ts, cd, s, flags, 0); } if (s->flags & SIG_FLAG_TOCLIENT) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_tc, cd, s, flags, 0); } } int i; for (i = 0; i < 256; i++) { if (i == 6 || i == 17) continue; if (s->proto.proto[i / 8] & (1 << (i % 8))) { PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_other_ctx, cd, s, flags, 0); break; } } /* tell matcher we are inspecting packet */ s->flags |= SIG_FLAG_MPM_PACKET; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); if (cd->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); s->flags |= SIG_FLAG_MPM_PACKET_NEG; } } if (SignatureHasStreamContent(s)) { /* add the content to the "packet" mpm */ if (cd->flags & DETECT_CONTENT_NOCASE) { if (s->flags & SIG_FLAG_TOSERVER) { mpm_table[sgh->mpm_stream_ctx_ts->mpm_type]. AddPatternNocase(sgh->mpm_stream_ctx_ts, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } if (s->flags & SIG_FLAG_TOCLIENT) { mpm_table[sgh->mpm_stream_ctx_tc->mpm_type]. AddPatternNocase(sgh->mpm_stream_ctx_tc, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } } else { if (s->flags & SIG_FLAG_TOSERVER) { mpm_table[sgh->mpm_stream_ctx_ts->mpm_type]. AddPattern(sgh->mpm_stream_ctx_ts, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } if (s->flags & SIG_FLAG_TOCLIENT) { mpm_table[sgh->mpm_stream_ctx_tc->mpm_type]. AddPattern(sgh->mpm_stream_ctx_tc, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } } /* tell matcher we are inspecting stream */ s->flags |= SIG_FLAG_MPM_STREAM; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); if (cd->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); s->flags |= SIG_FLAG_MPM_STREAM_NEG; } } } if (SignatureHasPacketContent(s)) { sgh->flags |= SIG_GROUP_HEAD_MPM_PACKET; } if (SignatureHasStreamContent(s)) { sgh->flags |= SIG_GROUP_HEAD_MPM_STREAM; } break; } /* case DETECT_CONTENT */ case DETECT_SM_LIST_UMATCH: case DETECT_SM_LIST_HRUDMATCH: case DETECT_SM_LIST_HCBDMATCH: case DETECT_SM_LIST_HSBDMATCH: case DETECT_SM_LIST_HHDMATCH: case DETECT_SM_LIST_HRHDMATCH: case DETECT_SM_LIST_HMDMATCH: case DETECT_SM_LIST_HCDMATCH: case DETECT_SM_LIST_HSMDMATCH: case DETECT_SM_LIST_HSCDMATCH: case DETECT_SM_LIST_HUADMATCH: case DETECT_SM_LIST_HHHDMATCH: case DETECT_SM_LIST_HRHHDMATCH: { MpmCtx *mpm_ctx_ts = NULL; MpmCtx *mpm_ctx_tc = NULL; uint32_t sgh_flags = 0; uint32_t sig_flags = 0; cd = (DetectContentData *)mpm_sm->ctx; if (sm_list == DETECT_SM_LIST_UMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_uri_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_uri_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_URI; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HCBDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hcbd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hcbd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HCBD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HSBDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hsbd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hsbd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HSBD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HHDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hhd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hhd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HHD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HRHDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hrhd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hrhd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HRHD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HMDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hmd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hmd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HMD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HCDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hcd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hcd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HCD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HRUDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hrud_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hrud_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HRUD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HSMDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hsmd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hsmd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HSMD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HSCDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hscd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hscd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HSCD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HUADMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_huad_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_huad_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HUAD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HHHDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hhhd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hhhd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HHHD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } else if (sm_list == DETECT_SM_LIST_HRHHDMATCH) { if (s->flags & SIG_FLAG_TOSERVER) mpm_ctx_ts = sgh->mpm_hrhhd_ctx_ts; if (s->flags & SIG_FLAG_TOCLIENT) mpm_ctx_tc = sgh->mpm_hrhhd_ctx_tc; sgh_flags = SIG_GROUP_HEAD_MPM_HRHHD; sig_flags |= SIG_FLAG_MPM_HTTP; if (cd->flags & DETECT_CONTENT_NEGATED) sig_flags |= SIG_FLAG_MPM_HTTP_NEG; } if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { if (DETECT_CONTENT_IS_SINGLE(cd) && !(cd->flags & DETECT_CONTENT_NEGATED) && !(cd->flags & DETECT_CONTENT_REPLACE) && cd->content_len == cd->fp_chop_len) { cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; } /* add the content to the mpm */ if (cd->flags & DETECT_CONTENT_NOCASE) { if (mpm_ctx_ts != NULL) { mpm_table[mpm_ctx_ts->mpm_type]. AddPatternNocase(mpm_ctx_ts, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } if (mpm_ctx_tc != NULL) { mpm_table[mpm_ctx_tc->mpm_type]. AddPatternNocase(mpm_ctx_tc, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } } else { if (mpm_ctx_ts != NULL) { mpm_table[mpm_ctx_ts->mpm_type]. AddPattern(mpm_ctx_ts, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } if (mpm_ctx_tc != NULL) { mpm_table[mpm_ctx_tc->mpm_type]. AddPattern(mpm_ctx_tc, cd->content + cd->fp_chop_offset, cd->fp_chop_len, 0, 0, cd->id, s->num, flags); } } } else { if (DETECT_CONTENT_IS_SINGLE(cd) && !(cd->flags & DETECT_CONTENT_NEGATED) && !(cd->flags & DETECT_CONTENT_REPLACE)) { cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; } /* add the content to the "uri" mpm */ if (cd->flags & DETECT_CONTENT_NOCASE) { if (mpm_ctx_ts != NULL) { mpm_table[mpm_ctx_ts->mpm_type]. AddPatternNocase(mpm_ctx_ts, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } if (mpm_ctx_tc != NULL) { mpm_table[mpm_ctx_tc->mpm_type]. AddPatternNocase(mpm_ctx_tc, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } } else { if (mpm_ctx_ts != NULL) { mpm_table[mpm_ctx_ts->mpm_type]. AddPattern(mpm_ctx_ts, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } if (mpm_ctx_tc != NULL) { mpm_table[mpm_ctx_tc->mpm_type]. AddPattern(mpm_ctx_tc, cd->content, cd->content_len, 0, 0, cd->id, s->num, flags); } } } /* tell matcher we are inspecting uri */ s->flags |= sig_flags; s->mpm_pattern_id_div_8 = cd->id / 8; s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); sgh->flags |= sgh_flags; break; } } /* switch (mpm_sm->type) */ SCLogDebug("%"PRIu32" adding cd->id %"PRIu32" to the mpm phase " "(s->num %"PRIu32")", s->id, ((DetectContentData *)mpm_sm->ctx)->id, s->num); return; } SigMatch *RetrieveFPForSig(Signature *s) { SigMatch *mpm_sm = NULL; uint8_t has_non_negated_non_stream_pattern = 0; if (s->mpm_sm != NULL) return s->mpm_sm; for (int list_id = 0 ; list_id < DETECT_SM_LIST_MAX; list_id++) { /* we have no keywords that support fp in this Signature sm list */ if (!FastPatternSupportEnabledForSigMatchList(list_id)) continue; for (SigMatch *sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { /* this keyword isn't registered for fp support */ if (sm->type != DETECT_CONTENT) continue; DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN) return sm; if (!(cd->flags & DETECT_CONTENT_NEGATED) && (list_id != DETECT_SM_LIST_PMATCH) && (list_id != DETECT_SM_LIST_HMDMATCH) && (list_id != DETECT_SM_LIST_HSMDMATCH) && (list_id != DETECT_SM_LIST_HSCDMATCH)) { has_non_negated_non_stream_pattern = 1; } } } int max_len = 0; int max_len_negated = 0; int max_len_non_negated = 0; for (int list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { if (!FastPatternSupportEnabledForSigMatchList(list_id)) continue; if (has_non_negated_non_stream_pattern && ((list_id == DETECT_SM_LIST_PMATCH) || (list_id == DETECT_SM_LIST_HMDMATCH) || (list_id == DETECT_SM_LIST_HSMDMATCH) || (list_id == DETECT_SM_LIST_HSCDMATCH))) { continue; } for (SigMatch *sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_NEGATED) { if (max_len_negated < cd->content_len) max_len_negated = cd->content_len; } else { if (max_len_non_negated < cd->content_len) max_len_non_negated = cd->content_len; } } } int skip_negated_content = 0; if (max_len_non_negated == 0) { max_len = max_len_negated; skip_negated_content = 0; } else { max_len = max_len_non_negated; skip_negated_content = 1; } for (int list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { if (!FastPatternSupportEnabledForSigMatchList(list_id)) continue; if (has_non_negated_non_stream_pattern && ((list_id == DETECT_SM_LIST_PMATCH) || (list_id == DETECT_SM_LIST_HMDMATCH) || (list_id == DETECT_SM_LIST_HSMDMATCH) || (list_id == DETECT_SM_LIST_HSCDMATCH))) { continue; } for (SigMatch *sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; DetectContentData *cd = (DetectContentData *)sm->ctx; if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content) continue; if (cd->content_len < max_len) continue; if (mpm_sm == NULL) { mpm_sm = sm; } else { DetectContentData *data1 = (DetectContentData *)sm->ctx; DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx; uint32_t ls = PatternStrength(data1->content, data1->content_len); uint32_t ss = PatternStrength(data2->content, data2->content_len); if (ls > ss) { mpm_sm = sm; } else if (ls == ss) { /* if 2 patterns are of equal strength, we pick the longest */ if (data1->content_len > data2->content_len) mpm_sm = sm; } else { SCLogDebug("sticking with mpm_sm"); } } /* else - if (mpm == NULL) */ } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */ } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */ return mpm_sm; } /** * \internal * \brief Setup the mpm content. * * \param de_ctx Pointer to the detect engine context. * \param sgh Pointer to the signature group head against which we are * adding patterns to the mpm ctx. * * \retval 0 Always. */ static int PatternMatchPreparePopulateMpm(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { for (uint32_t sig = 0; sig < sgh->sig_cnt; sig++) { Signature *s = sgh->match_array[sig]; if (s == NULL) continue; PopulateMpmAddPatternToMpm(de_ctx, sgh, s, RetrieveFPForSig(s)); } /* for (sig = 0; sig < sgh->sig_cnt; sig++) */ return 0; } /** \brief Prepare the pattern matcher ctx in a sig group head. * * \todo determine if a content match can set the 'single' flag * \todo do error checking * \todo rewrite the COPY stuff */ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) { Signature *s = NULL; uint32_t has_co_packet = 0; /**< our sgh has packet payload inspecting content */ uint32_t has_co_stream = 0; /**< our sgh has stream inspecting content */ uint32_t has_co_uri = 0; /**< our sgh has uri inspecting content */ /* used to indicate if sgh has atleast one sig with http_client_body */ uint32_t has_co_hcbd = 0; /* used to indicate if sgh has atleast one sig with http_server_body */ uint32_t has_co_hsbd = 0; /* used to indicate if sgh has atleast one sig with http_header */ uint32_t has_co_hhd = 0; /* used to indicate if sgh has atleast one sig with http_raw_header */ uint32_t has_co_hrhd = 0; /* used to indicate if sgh has atleast one sig with http_method */ uint32_t has_co_hmd = 0; /* used to indicate if sgh has atleast one sig with http_cookie */ uint32_t has_co_hcd = 0; /* used to indicate if sgh has atleast one sig with http_raw_uri */ uint32_t has_co_hrud = 0; /* used to indicate if sgh has atleast one sig with http_stat_msg */ uint32_t has_co_hsmd = 0; /* used to indicate if sgh has atleast one sig with http_stat_code */ uint32_t has_co_hscd = 0; /* used to indicate if sgh has atleast one sig with http_user_agent */ uint32_t has_co_huad = 0; /* used to indicate if sgh has atleast one sig with http_host */ uint32_t has_co_hhhd = 0; /* used to indicate if sgh has atleast one sig with http_raw_host */ uint32_t has_co_hrhhd = 0; //uint32_t cnt = 0; uint32_t sig = 0; /* see if this head has content and/or uricontent */ for (sig = 0; sig < sh->sig_cnt; sig++) { s = sh->match_array[sig]; if (s == NULL) continue; if (SignatureHasPacketContent(s) == 1) { has_co_packet = 1; } if (SignatureHasStreamContent(s) == 1) { has_co_stream = 1; } if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { has_co_uri = 1; } if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { has_co_hcbd = 1; } if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { has_co_hsbd = 1; } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { has_co_hhd = 1; } if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { has_co_hrhd = 1; } if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { has_co_hmd = 1; } if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { has_co_hcd = 1; } if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { has_co_hrud = 1; } if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { has_co_hsmd = 1; } if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { has_co_hscd = 1; } if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { has_co_huad = 1; } if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { has_co_hhhd = 1; } if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { has_co_hrhhd = 1; } } /* intialize contexes */ if (has_co_packet) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); } else { sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_proto_tcp_ctx_ts == NULL || sh->mpm_proto_tcp_ctx_tc == NULL) { SCLogDebug("sh->mpm_proto_tcp_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_proto_tcp_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_proto_tcp_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_proto_tcp_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_proto_tcp_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_proto_udp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); sh->mpm_proto_udp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); } else { sh->mpm_proto_udp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_proto_udp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_proto_udp_ctx_ts == NULL || sh->mpm_proto_udp_ctx_tc == NULL) { SCLogDebug("sh->mpm_proto_udp_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_proto_udp_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_proto_udp_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_proto_udp_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_proto_udp_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_proto_other_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); } else { sh->mpm_proto_other_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); } if (sh->mpm_proto_other_ctx == NULL) { SCLogDebug("sh->mpm_proto_other_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_proto_other_ctx, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_proto_other_ctx, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } /* if (has_co_packet) */ if (has_co_stream) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_stream_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); sh->mpm_stream_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); } else { sh->mpm_stream_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_stream_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_stream_ctx_tc == NULL || sh->mpm_stream_ctx_tc == NULL) { SCLogDebug("sh->mpm_stream_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_stream_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_stream_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_stream_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_stream_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_uri) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_uri_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); sh->mpm_uri_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 1); } else { sh->mpm_uri_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_uri_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_uri_ctx_ts == NULL || sh->mpm_uri_ctx_tc == NULL) { SCLogDebug("sh->mpm_uri_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_uri_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_uri_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_uri_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_uri_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hcbd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hcbd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 0); sh->mpm_hcbd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 1); } else { sh->mpm_hcbd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hcbd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hcbd_ctx_ts == NULL || sh->mpm_hcbd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hcbd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hcbd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hcbd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hcbd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hcbd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hsbd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hsbd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsbd, 0); sh->mpm_hsbd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsbd, 1); } else { sh->mpm_hsbd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hsbd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hsbd_ctx_ts == NULL || sh->mpm_hsbd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hsbd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hsbd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hsbd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hsbd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hsbd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hhd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); sh->mpm_hhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 1); } else { sh->mpm_hhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hhd_ctx_ts == NULL || sh->mpm_hhd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hhd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hhd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hhd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hhd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hhd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hrhd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hrhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 0); sh->mpm_hrhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 1); } else { sh->mpm_hrhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hrhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hrhd_ctx_ts == NULL || sh->mpm_hrhd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hrhd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hrhd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hrhd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hrhd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hrhd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hmd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hmd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 0); sh->mpm_hmd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 1); } else { sh->mpm_hmd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hmd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hmd_ctx_ts == NULL || sh->mpm_hmd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hmd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hmd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hmd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hmd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hmd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hcd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hcd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 0); sh->mpm_hcd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 1); } else { sh->mpm_hcd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hcd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hcd_ctx_ts == NULL || sh->mpm_hcd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hcd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hcd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hcd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hcd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hcd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hrud) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hrud_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 0); sh->mpm_hrud_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 1); } else { sh->mpm_hrud_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hrud_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hrud_ctx_ts == NULL || sh->mpm_hrud_ctx_tc == NULL) { SCLogDebug("sh->mpm_hrud_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hrud_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hrud_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hrud_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hrud_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hsmd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hsmd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 0); sh->mpm_hsmd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 1); } else { sh->mpm_hsmd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hsmd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hsmd_ctx_ts == NULL || sh->mpm_hsmd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hsmd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hsmd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hsmd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hsmd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hsmd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hscd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hscd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 0); sh->mpm_hscd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 1); } else { sh->mpm_hscd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hscd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hscd_ctx_ts == NULL || sh->mpm_hscd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hscd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hscd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hscd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hscd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hscd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_huad) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_huad_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 0); sh->mpm_huad_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 1); } else { sh->mpm_huad_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_huad_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_huad_ctx_ts == NULL || sh->mpm_huad_ctx_tc == NULL) { SCLogDebug("sh->mpm_huad_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_huad_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_huad_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_huad_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_huad_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hhhd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 0); sh->mpm_hhhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 1); } else { sh->mpm_hhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hhhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hhhd_ctx_ts == NULL || sh->mpm_hhhd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hhhd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hhhd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hhhd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hhhd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hhhd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_hrhhd) { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { sh->mpm_hrhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 0); sh->mpm_hrhhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 1); } else { sh->mpm_hrhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); sh->mpm_hrhhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); } if (sh->mpm_hrhhd_ctx_ts == NULL || sh->mpm_hrhhd_ctx_tc == NULL) { SCLogDebug("sh->mpm_hrhhd_ctx == NULL. This should never happen"); exit(EXIT_FAILURE); } #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(sh->mpm_hrhhd_ctx_ts, de_ctx->mpm_matcher, -1); MpmInitCtx(sh->mpm_hrhhd_ctx_tc, de_ctx->mpm_matcher, -1); #else MpmInitCtx(sh->mpm_hrhhd_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); MpmInitCtx(sh->mpm_hrhhd_ctx_tc, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle); #endif } if (has_co_packet || has_co_stream || has_co_uri || has_co_hcbd || has_co_hsbd || has_co_hhd || has_co_hrhd || has_co_hmd || has_co_hcd || has_co_hsmd || has_co_hscd || has_co_hrud || has_co_huad || has_co_hhhd || has_co_hrhhd) { PatternMatchPreparePopulateMpm(de_ctx, sh); //if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (sh->mpm_proto_tcp_ctx_ts != NULL) { if (sh->mpm_proto_tcp_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); sh->mpm_proto_tcp_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type].Prepare != NULL) { mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. Prepare(sh->mpm_proto_tcp_ctx_ts); } } } } if (sh->mpm_proto_tcp_ctx_tc != NULL) { if (sh->mpm_proto_tcp_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); sh->mpm_proto_tcp_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type].Prepare != NULL) { mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. Prepare(sh->mpm_proto_tcp_ctx_tc); } } } } if (sh->mpm_proto_udp_ctx_ts != NULL) { if (sh->mpm_proto_udp_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_ts); sh->mpm_proto_udp_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type].Prepare != NULL) { mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. Prepare(sh->mpm_proto_udp_ctx_ts); } } } } if (sh->mpm_proto_udp_ctx_tc != NULL) { if (sh->mpm_proto_udp_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_tc); sh->mpm_proto_udp_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type].Prepare != NULL) { mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. Prepare(sh->mpm_proto_udp_ctx_tc); } } } } if (sh->mpm_proto_other_ctx != NULL) { if (sh->mpm_proto_other_ctx->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); sh->mpm_proto_other_ctx = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_proto_other_ctx->mpm_type].Prepare != NULL) { mpm_table[sh->mpm_proto_other_ctx->mpm_type]. Prepare(sh->mpm_proto_other_ctx); } } } } if (sh->mpm_stream_ctx_ts != NULL) { if (sh->mpm_stream_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_ts); sh->mpm_stream_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare(sh->mpm_stream_ctx_ts); } } } if (sh->mpm_stream_ctx_tc != NULL) { if (sh->mpm_stream_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_tc); sh->mpm_stream_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare(sh->mpm_stream_ctx_tc); } } } if (sh->mpm_uri_ctx_ts != NULL) { if (sh->mpm_uri_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); sh->mpm_uri_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare(sh->mpm_uri_ctx_ts); } } } if (sh->mpm_uri_ctx_tc != NULL) { if (sh->mpm_uri_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_tc); sh->mpm_uri_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_uri_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_uri_ctx_tc->mpm_type].Prepare(sh->mpm_uri_ctx_tc); } } } if (sh->mpm_hcbd_ctx_ts != NULL) { if (sh->mpm_hcbd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); sh->mpm_hcbd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare(sh->mpm_hcbd_ctx_ts); } } } if (sh->mpm_hcbd_ctx_tc != NULL) { if (sh->mpm_hcbd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_tc); sh->mpm_hcbd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hcbd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hcbd_ctx_tc->mpm_type].Prepare(sh->mpm_hcbd_ctx_tc); } } } if (sh->mpm_hsbd_ctx_ts != NULL) { if (sh->mpm_hsbd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsbd_ctx_ts); sh->mpm_hsbd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hsbd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hsbd_ctx_ts->mpm_type].Prepare(sh->mpm_hsbd_ctx_ts); } } } if (sh->mpm_hsbd_ctx_tc != NULL) { if (sh->mpm_hsbd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsbd_ctx_tc); sh->mpm_hsbd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare(sh->mpm_hsbd_ctx_tc); } } } if (sh->mpm_hhd_ctx_ts != NULL) { if (sh->mpm_hhd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); sh->mpm_hhd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhd_ctx_ts); } } } if (sh->mpm_hhd_ctx_tc != NULL) { if (sh->mpm_hhd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); sh->mpm_hhd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare(sh->mpm_hhd_ctx_tc); } } } if (sh->mpm_hrhd_ctx_ts != NULL) { if (sh->mpm_hrhd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_ts); sh->mpm_hrhd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhd_ctx_ts); } } } if (sh->mpm_hrhd_ctx_tc != NULL) { if (sh->mpm_hrhd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); sh->mpm_hrhd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare(sh->mpm_hrhd_ctx_tc); } } } if (sh->mpm_hmd_ctx_ts != NULL) { if (sh->mpm_hmd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_ts); sh->mpm_hmd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare(sh->mpm_hmd_ctx_ts); } } } if (sh->mpm_hmd_ctx_tc != NULL) { if (sh->mpm_hmd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_tc); sh->mpm_hmd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hmd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hmd_ctx_tc->mpm_type].Prepare(sh->mpm_hmd_ctx_tc); } } } if (sh->mpm_hcd_ctx_ts != NULL) { if (sh->mpm_hcd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_ts); sh->mpm_hcd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare(sh->mpm_hcd_ctx_ts); } } } if (sh->mpm_hcd_ctx_tc != NULL) { if (sh->mpm_hcd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_tc); sh->mpm_hcd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare(sh->mpm_hcd_ctx_tc); } } } if (sh->mpm_hrud_ctx_ts != NULL) { if (sh->mpm_hrud_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_ts); sh->mpm_hrud_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare(sh->mpm_hrud_ctx_ts); } } } if (sh->mpm_hrud_ctx_tc != NULL) { if (sh->mpm_hrud_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_tc); sh->mpm_hrud_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hrud_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hrud_ctx_tc->mpm_type].Prepare(sh->mpm_hrud_ctx_tc); } } } if (sh->mpm_hsmd_ctx_ts != NULL) { if (sh->mpm_hsmd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_ts); sh->mpm_hsmd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hsmd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hsmd_ctx_ts->mpm_type].Prepare(sh->mpm_hsmd_ctx_ts); } } } if (sh->mpm_hsmd_ctx_tc != NULL) { if (sh->mpm_hsmd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_tc); sh->mpm_hsmd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare(sh->mpm_hsmd_ctx_tc); } } } if (sh->mpm_hscd_ctx_ts != NULL) { if (sh->mpm_hscd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_ts); sh->mpm_hscd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hscd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hscd_ctx_ts->mpm_type].Prepare(sh->mpm_hscd_ctx_ts); } } } if (sh->mpm_hscd_ctx_tc != NULL) { if (sh->mpm_hscd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_tc); sh->mpm_hscd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare(sh->mpm_hscd_ctx_tc); } } } if (sh->mpm_huad_ctx_ts != NULL) { if (sh->mpm_huad_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_ts); sh->mpm_huad_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare(sh->mpm_huad_ctx_ts); } } } if (sh->mpm_huad_ctx_tc != NULL) { if (sh->mpm_huad_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_tc); sh->mpm_huad_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_huad_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_huad_ctx_tc->mpm_type].Prepare(sh->mpm_huad_ctx_tc); } } } if (sh->mpm_hhhd_ctx_ts != NULL) { if (sh->mpm_hhhd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_ts); sh->mpm_hhhd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhhd_ctx_ts); } } } if (sh->mpm_hhhd_ctx_tc != NULL) { if (sh->mpm_hhhd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_tc); sh->mpm_hhhd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hhhd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hhhd_ctx_tc->mpm_type].Prepare(sh->mpm_hhhd_ctx_tc); } } } if (sh->mpm_hrhhd_ctx_ts != NULL) { if (sh->mpm_hrhhd_ctx_ts->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts); sh->mpm_hrhhd_ctx_ts = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhhd_ctx_ts); } } } if (sh->mpm_hrhhd_ctx_tc != NULL) { if (sh->mpm_hrhhd_ctx_tc->pattern_cnt == 0) { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_tc); sh->mpm_hrhhd_ctx_tc = NULL; } else { if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { if (mpm_table[sh->mpm_hrhhd_ctx_tc->mpm_type].Prepare != NULL) mpm_table[sh->mpm_hrhhd_ctx_tc->mpm_type].Prepare(sh->mpm_hrhhd_ctx_tc); } } } //} /* if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) */ } else { MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); sh->mpm_proto_other_ctx = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); sh->mpm_proto_tcp_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_ts); sh->mpm_proto_udp_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_ts); sh->mpm_stream_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); sh->mpm_uri_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); sh->mpm_hcbd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); sh->mpm_hhd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_ts); sh->mpm_hrhd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_ts); sh->mpm_hmd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_ts); sh->mpm_hcd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_ts); sh->mpm_hrud_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_ts); sh->mpm_hsmd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_ts); sh->mpm_hscd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_ts); sh->mpm_huad_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_ts); sh->mpm_hhhd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts); sh->mpm_hrhhd_ctx_ts = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); sh->mpm_proto_tcp_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_tc); sh->mpm_proto_udp_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_tc); sh->mpm_stream_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_tc); sh->mpm_uri_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_tc); sh->mpm_hcbd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); sh->mpm_hhd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); sh->mpm_hrhd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_tc); sh->mpm_hmd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_tc); sh->mpm_hcd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_tc); sh->mpm_hrud_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_tc); sh->mpm_hsmd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_tc); sh->mpm_hscd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_tc); sh->mpm_huad_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_tc); sh->mpm_hhhd_ctx_tc = NULL; MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_tc); sh->mpm_hrhhd_ctx_tc = NULL; } return 0; } /** \brief Pattern ID Hash for sharing pattern id's * * A per detection engine hash to make sure each pattern has a unique * global id but patterns that are the same share id's. */ typedef struct MpmPatternIdTableElmt_ { uint8_t *pattern; /**< ptr to the pattern */ uint16_t pattern_len; /**< pattern len */ PatIntId id; /**< pattern id */ uint16_t dup_count; /**< duplicate count */ uint8_t sm_list; /**< SigMatch list */ } MpmPatternIdTableElmt; /** \brief Hash compare func for MpmPatternId api * \retval 1 patterns are the same * \retval 0 patterns are not the same **/ static char MpmPatternIdCompare(void *p1, uint16_t len1, void *p2, uint16_t len2) { SCEnter(); BUG_ON(len1 < sizeof(MpmPatternIdTableElmt)); BUG_ON(len2 < sizeof(MpmPatternIdTableElmt)); MpmPatternIdTableElmt *e1 = (MpmPatternIdTableElmt *)p1; MpmPatternIdTableElmt *e2 = (MpmPatternIdTableElmt *)p2; if (e1->pattern_len != e2->pattern_len || e1->sm_list != e2->sm_list) { SCReturnInt(0); } if (SCMemcmp(e1->pattern, e2->pattern, e1->pattern_len) != 0) { SCReturnInt(0); } SCReturnInt(1); } /** \brief Hash func for MpmPatternId api * \retval hash hash value */ static uint32_t MpmPatternIdHashFunc(HashTable *ht, void *p, uint16_t len) { SCEnter(); BUG_ON(len < sizeof(MpmPatternIdTableElmt)); MpmPatternIdTableElmt *e = (MpmPatternIdTableElmt *)p; uint32_t hash = e->pattern_len; uint16_t u = 0; for (u = 0; u < e->pattern_len; u++) { hash += e->pattern[u]; } SCReturnUInt(hash % ht->array_size); } /** \brief free a MpmPatternIdTableElmt */ static void MpmPatternIdTableElmtFree(void *e) { SCEnter(); MpmPatternIdTableElmt *c = (MpmPatternIdTableElmt *)e; SCFree(c->pattern); SCFree(c); SCReturn; } /** \brief alloc initialize the MpmPatternIdHash */ MpmPatternIdStore *MpmPatternIdTableInitHash(void) { SCEnter(); MpmPatternIdStore *ht = SCMalloc(sizeof(MpmPatternIdStore)); BUG_ON(ht == NULL); memset(ht, 0x00, sizeof(MpmPatternIdStore)); ht->hash = HashTableInit(65536, MpmPatternIdHashFunc, MpmPatternIdCompare, MpmPatternIdTableElmtFree); BUG_ON(ht->hash == NULL); SCReturnPtr(ht, "MpmPatternIdStore"); } void MpmPatternIdTableFreeHash(MpmPatternIdStore *ht) { SCEnter(); if (ht == NULL) { SCReturn; } if (ht->hash != NULL) { HashTableFree(ht->hash); } SCFree(ht); SCReturn; } uint32_t MpmPatternIdStoreGetMaxId(MpmPatternIdStore *ht) { if (ht == NULL) { return 0; } return ht->max_id; } /** * \brief Get the pattern id for a content pattern * * \param ht mpm pattern id hash table store * \param co content pattern data * * \retval id pattern id * \initonly */ uint32_t DetectContentGetId(MpmPatternIdStore *ht, DetectContentData *co) { SCEnter(); BUG_ON(ht == NULL || ht->hash == NULL); MpmPatternIdTableElmt *e = NULL; MpmPatternIdTableElmt *r = NULL; uint32_t id = 0; e = SCMalloc(sizeof(MpmPatternIdTableElmt)); BUG_ON(e == NULL); memset(e, 0, sizeof(MpmPatternIdTableElmt)); e->pattern = SCMalloc(co->content_len); BUG_ON(e->pattern == NULL); memcpy(e->pattern, co->content, co->content_len); e->pattern_len = co->content_len; e->id = 0; r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt)); if (r == NULL) { e->id = ht->max_id; ht->max_id++; id = e->id; int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt)); BUG_ON(ret != 0); e = NULL; ht->unique_patterns++; } else { id = r->id; ht->shared_patterns++; } if (e != NULL) MpmPatternIdTableElmtFree(e); SCReturnUInt(id); } /** * \brief Get the pattern id for a uricontent pattern * * \param ht mpm pattern id hash table store * \param co content pattern data * * \retval id pattern id */ uint32_t DetectUricontentGetId(MpmPatternIdStore *ht, DetectContentData *co) { SCEnter(); BUG_ON(ht == NULL || ht->hash == NULL); MpmPatternIdTableElmt *e = NULL; MpmPatternIdTableElmt *r = NULL; uint32_t id = 0; e = SCMalloc(sizeof(MpmPatternIdTableElmt)); BUG_ON(e == NULL); e->pattern = SCMalloc(co->content_len); BUG_ON(e->pattern == NULL); memcpy(e->pattern, co->content, co->content_len); e->pattern_len = co->content_len; e->sm_list = DETECT_SM_LIST_UMATCH; e->dup_count = 1; e->id = 0; r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt)); if (r == NULL) { e->id = ht->max_id; ht->max_id++; id = e->id; int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt)); BUG_ON(ret != 0); e = NULL; ht->unique_patterns++; } else { id = r->id; r->dup_count++; ht->shared_patterns++; } if (e != NULL) MpmPatternIdTableElmtFree(e); SCReturnUInt(id); } /** * \brief Get the pattern id for a for any content related keyword. * * Supported keywords are content, http_client_body, * http_method, http_uri, http_header, http_cookie. * * Please note that you can't use it to get a pattern id for * uricontent. To retrieve a uricontent pattern id please * use DetectUricontentGetId(). * * \param ht Mpm pattern id hash table store. * \param ctx The keyword context. * \param type The SigMatch context. * * \retval id Pattern id. */ uint32_t DetectPatternGetId(MpmPatternIdStore *ht, void *ctx, uint8_t sm_list) { SCEnter(); MpmPatternIdTableElmt *e = NULL; MpmPatternIdTableElmt *r = NULL; PatIntId id = 0; e = SCMalloc(sizeof(MpmPatternIdTableElmt)); if (unlikely(e == NULL)) { exit(EXIT_FAILURE); } DetectContentData *cd = ctx; e->pattern = SCMalloc(cd->content_len); if (e->pattern == NULL) { exit(EXIT_FAILURE); } memcpy(e->pattern, cd->content, cd->content_len); e->pattern_len = cd->content_len; e->dup_count = 1; e->sm_list = sm_list; e->id = 0; r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt)); if (r == NULL) { /* we don't have a duplicate with this pattern + id type. If the id is * for content, then it is the first entry for such a * pattern + id combination. Let us create an entry for it */ if (sm_list == DETECT_SM_LIST_PMATCH) { e->id = ht->max_id; ht->max_id++; id = e->id; int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt)); BUG_ON(ret != 0); e = NULL; /* the id type is not content or uricontent. It would be one of * those http_ modifiers against content then */ } else { /* we know that this is one of those http_ modifiers against content. * So we would have seen a content before coming across this http_ * modifier. Let's retrieve this content entry that has already * been registered. */ e->sm_list = DETECT_SM_LIST_PMATCH; MpmPatternIdTableElmt *tmp_r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt)); if (tmp_r == NULL) { SCLogError(SC_ERR_FATAL, "How can this happen? We have to have " "a content of type DETECT_CONTENT already registered " "at this point. Impossible"); exit(EXIT_FAILURE); } /* we have retrieved the content, and the content registered was the * first entry made(dup_count is 1) for that content. Let us just * reset the sm_type to the http_ keyword's sm_type */ if (tmp_r->dup_count == 1) { tmp_r->sm_list = sm_list; id = tmp_r->id; /* interestingly we have more than one entry for this content. * Out of these tmp_r->dup_count entries, one would be for the content * entry made for this http_ modifier. Erase this entry and make * a separate entry for the http_ modifier(of course with a new id) */ } else { tmp_r->dup_count--; /* reset the sm_type, since we changed it to DETECT_CONTENT prev */ e->sm_list = sm_list; e->id = ht->max_id; ht->max_id++; id = e->id; int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt)); BUG_ON(ret != 0); e = NULL; } } /* we do seem to have an entry for this already */ } else { /* oh cool! It is a duplicate for content, uricontent types. Update the * dup_count and get out */ if (sm_list == DETECT_SM_LIST_PMATCH) { r->dup_count++; id = r->id; goto end; } /* uh oh! a duplicate for a http_ modifier type. Let's increase the * dup_count for the entry */ r->dup_count++; id = r->id; /* let's get the content entry associated with the http keyword we are * currently operating on */ e->sm_list = DETECT_SM_LIST_PMATCH; MpmPatternIdTableElmt *tmp_r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt)); if (tmp_r == NULL) { SCLogError(SC_ERR_FATAL, "How can this happen? We have to have " "a content of type DETECT_CONTENT already registered " "at this point. Impossible"); exit(EXIT_FAILURE); } /* so there are more than one content keyword entries for this pattern. * Reduce the dup_count */ if (tmp_r->dup_count > 1) { tmp_r->dup_count--; /* We have just one entry. Remove this hash table entry */ } else { HashTableRemove(ht->hash, tmp_r, sizeof(MpmPatternIdTableElmt)); ht->max_id--; } } end: if (e != NULL) MpmPatternIdTableElmtFree(e); SCReturnUInt(id); } suricata-1.4.7/src/detect-engine-hmd.c0000644000000000000000000013275012253546156014462 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP method match * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-hmd.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { htp_tx_t *tx = NULL; uint32_t cnt = 0; int idx; /* we need to lock because the buffers are not actually true buffers * but are ones that point to a buffer given by libhtp */ FLOWLOCK_RDLOCK(f); if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->request_method == NULL) continue; cnt += HttpMethodPatternSearch(det_ctx, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), flags); } end: FLOWLOCK_UNLOCK(f); return cnt; } /** * \brief Do the http_method content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpMethod(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL || tx->request_method == NULL) return 0; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HMDMATCH], f, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest01(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"GET\"; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest02(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; depth:4; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest03(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"ECT\"; depth:4; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest04(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"ECT\"; depth:4; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest05(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"CON\"; depth:4; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"ECT\"; offset:3; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest07(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"CO\"; offset:3; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest08(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"ECT\"; offset:3; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest09(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CON\"; offset:3; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest10(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_method; " "content:\"EC\"; within:4; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_method; " "content:!\"EC\"; within:3; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_method; " "content:\"EC\"; within:3; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_method; " "content:!\"EC\"; within:4; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest14(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_method; " "content:\"EC\"; distance:2; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest15(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_method; " "content:!\"EC\"; distance:3; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest16(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_method; " "content:\"EC\"; distance:3; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_method content matches against a http request * which holds the content. */ static int DetectEngineHttpMethodTest17(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_method; " "content:!\"EC\"; distance:2; http_method; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpMethodRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpMethodTest01", DetectEngineHttpMethodTest01, 1); UtRegisterTest("DetectEngineHttpMethodTest02", DetectEngineHttpMethodTest02, 1); UtRegisterTest("DetectEngineHttpMethodTest03", DetectEngineHttpMethodTest03, 1); UtRegisterTest("DetectEngineHttpMethodTest04", DetectEngineHttpMethodTest04, 1); UtRegisterTest("DetectEngineHttpMethodTest05", DetectEngineHttpMethodTest05, 1); UtRegisterTest("DetectEngineHttpMethodTest06", DetectEngineHttpMethodTest06, 1); UtRegisterTest("DetectEngineHttpMethodTest07", DetectEngineHttpMethodTest07, 1); UtRegisterTest("DetectEngineHttpMethodTest08", DetectEngineHttpMethodTest08, 1); UtRegisterTest("DetectEngineHttpMethodTest09", DetectEngineHttpMethodTest09, 1); UtRegisterTest("DetectEngineHttpMethodTest10", DetectEngineHttpMethodTest10, 1); UtRegisterTest("DetectEngineHttpMethodTest11", DetectEngineHttpMethodTest11, 1); UtRegisterTest("DetectEngineHttpMethodTest12", DetectEngineHttpMethodTest12, 1); UtRegisterTest("DetectEngineHttpMethodTest13", DetectEngineHttpMethodTest13, 1); UtRegisterTest("DetectEngineHttpMethodTest14", DetectEngineHttpMethodTest14, 1); UtRegisterTest("DetectEngineHttpMethodTest15", DetectEngineHttpMethodTest15, 1); UtRegisterTest("DetectEngineHttpMethodTest16", DetectEngineHttpMethodTest16, 1); UtRegisterTest("DetectEngineHttpMethodTest17", DetectEngineHttpMethodTest17, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/suricata.c0000644000000000000000000021743212253546156013015 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #include "suricata-common.h" #include "config.h" #if HAVE_GETOPT_H #include #endif #if HAVE_SIGNAL_H #include #endif #ifdef HAVE_NSS #include #include #endif #include "suricata.h" #include "decode.h" #include "detect.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "util-atomic.h" #include "util-spm.h" #include "util-hash.h" #include "util-hashlist.h" #include "util-bloomfilter.h" #include "util-bloomfilter-counting.h" #include "util-pool.h" #include "util-byte.h" #include "util-cpu.h" #include "util-action.h" #include "util-pidfile.h" #include "util-ioctl.h" #include "util-device.h" #include "util-misc.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-address.h" #include "detect-engine-proto.h" #include "detect-engine-port.h" #include "detect-engine-mpm.h" #include "detect-engine-sigorder.h" #include "detect-engine-payload.h" #include "detect-engine-dcepayload.h" #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-hua.h" #include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" #include "detect-engine-state.h" #include "detect-engine-tag.h" #include "detect-fast-pattern.h" #include "tm-queuehandlers.h" #include "tm-queues.h" #include "tm-threads.h" #include "tmqh-flow.h" #include "conf.h" #include "conf-yaml-loader.h" #include "alert-fastlog.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "alert-prelude.h" #include "alert-syslog.h" #include "alert-pcapinfo.h" #include "log-droplog.h" #include "log-httplog.h" #include "log-tlslog.h" #include "log-pcap.h" #include "log-file.h" #include "log-filestore.h" #include "stream-tcp.h" #include "source-nfq.h" #include "source-nfq-prototypes.h" #include "source-ipfw.h" #include "source-pcap.h" #include "source-pcap-file.h" #include "source-pfring.h" #include "source-erf-file.h" #include "source-erf-dag.h" #include "source-napatech.h" #include "source-af-packet.h" #include "respond-reject.h" #include "flow.h" #include "flow-timeout.h" #include "flow-manager.h" #include "flow-var.h" #include "flow-bit.h" #include "flow-alert-sid.h" #include "pkt-var.h" #include "host.h" #include "unix-manager.h" #include "app-layer-detect-proto.h" #include "app-layer-parser.h" #include "app-layer-smb.h" #include "app-layer-dcerpc.h" #include "app-layer-dcerpc-udp.h" #include "app-layer-htp.h" #include "app-layer-ftp.h" #include "app-layer-ssl.h" #include "app-layer-ssh.h" #include "app-layer-smtp.h" #include "util-radix-tree.h" #include "util-host-os-info.h" #include "util-cidr.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-time.h" #include "util-rule-vars.h" #include "util-classification-config.h" #include "util-threshold-config.h" #include "util-reference-config.h" #include "util-profiling.h" #include "util-magic.h" #include "util-signal.h" #include "util-coredump-config.h" #include "defrag.h" #include "runmodes.h" #include "util-cuda.h" #include "util-decode-asn1.h" #include "util-debug.h" #include "util-error.h" #include "detect-engine-siggroup.h" #include "util-daemon.h" #include "reputation.h" /* holds the cuda b2g module */ #include "util-mpm-b2g-cuda.h" #include "util-cuda-handlers.h" #include "cuda-packet-batcher.h" #include "output.h" #include "util-privs.h" #include "tmqh-packetpool.h" #include "util-ringbuffer.h" #include "util-mem.h" #include "util-memcmp.h" #include "util-proto-name.h" #include "util-spm-bm.h" /* * we put this here, because we only use it here in main. */ volatile sig_atomic_t sigint_count = 0; volatile sig_atomic_t sighup_count = 0; volatile sig_atomic_t sigterm_count = 0; /* * Flag to indicate if the engine is at the initialization * or already processing packets. 2 stages: SURICATA_INIT, * SURICATA_RUNTIME and SURICATA_FINALIZE */ SC_ATOMIC_DECLARE(unsigned int, engine_stage); /* Max packets processed simultaniously. */ #define DEFAULT_MAX_PENDING_PACKETS 1024 int rule_reload = 0; /** suricata engine control flags */ uint8_t suricata_ctl_flags = 0; /** Run mode selected */ int run_mode = RUNMODE_UNKNOWN; /** engine_analysis. disabled(0) by default, unless enabled by the user by * running the engine with --engine-analysis */ int engine_analysis = 0; /** Engine mode: inline (ENGINE_MODE_IPS) or just * detection mode (ENGINE_MODE_IDS by default) */ uint8_t engine_mode = ENGINE_MODE_IDS; /** Maximum packets to simultaneously process. */ intmax_t max_pending_packets; /** set caps or not */ int sc_set_caps; char *conf_filename = NULL; int RunmodeIsUnittests(void) { if (run_mode == RUNMODE_UNITTEST) return 1; return 0; } int RunmodeGetCurrent(void) { return run_mode; } static void SignalHandlerSigint(/*@unused@*/ int sig) { sigint_count = 1; suricata_ctl_flags |= SURICATA_STOP; } static void SignalHandlerSigterm(/*@unused@*/ int sig) { sigterm_count = 1; suricata_ctl_flags |= SURICATA_KILL; } void SignalHandlerSigusr2Disabled(int sig) { SCLogInfo("Live rule reload not enabled in config."); return; } void SignalHandlerSigusr2SigFileStartup(int sig) { SCLogInfo("Live rule reload not possible if -s or -S option used at runtime."); return; } void SignalHandlerSigusr2Idle(int sig) { if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) { SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode"); return; } SCLogInfo("Ruleset load in progress. New ruleset load " "allowed after current is done"); return; } void SignalHandlerSigusr2(int sig) { if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) { SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode"); return; } if (suricata_ctl_flags != 0) { SCLogInfo("Live rule swap no longer possible. Engine in shutdown mode."); return; } UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle); DetectEngineSpawnLiveRuleSwapMgmtThread(); return; } #if 0 static void SignalHandlerSighup(/*@unused@*/ int sig) { sighup_count = 1; suricata_ctl_flags |= SURICATA_SIGHUP; } #endif #ifdef DBG_MEM_ALLOC #ifndef _GLOBAL_MEM_ #define _GLOBAL_MEM_ /* This counter doesn't complain realloc's(), it's gives * an aproximation for the startup */ size_t global_mem = 0; #ifdef DBG_MEM_ALLOC_SKIP_STARTUP uint8_t print_mem_flag = 0; #else uint8_t print_mem_flag = 1; #endif #endif #endif void GlobalInits() { memset(trans_q, 0, sizeof(trans_q)); memset(data_queues, 0, sizeof(data_queues)); /* Initialize the trans_q mutex */ int blah; int r = 0; for(blah=0;blah<256;blah++) { r |= SCMutexInit(&trans_q[blah].mutex_q, NULL); r |= SCCondInit(&trans_q[blah].cond_q, NULL); r |= SCMutexInit(&data_queues[blah].mutex_q, NULL); r |= SCCondInit(&data_queues[blah].cond_q, NULL); } if (r != 0) { SCLogInfo("Trans_Q Mutex not initialized correctly"); exit(EXIT_FAILURE); } } /* XXX hack: make sure threads can stop the engine by calling this function. Purpose: pcap file mode needs to be able to tell the engine the file eof is reached. */ void EngineStop(void) { suricata_ctl_flags |= SURICATA_STOP; } void EngineKill(void) { suricata_ctl_flags |= SURICATA_KILL; } /** * \brief Used to indicate that the current task is done. * * This is mainly used by pcap-file to tell it has finished * to treat a pcap files when running in unix-socket mode. */ void EngineDone(void) { suricata_ctl_flags |= SURICATA_DONE; } static void SetBpfString(int optind, char *argv[]) { char *bpf_filter = NULL; uint32_t bpf_len = 0; int tmpindex = 0; /* attempt to parse remaining args as bpf filter */ tmpindex = optind; while(argv[tmpindex] != NULL) { bpf_len+=strlen(argv[tmpindex]) + 1; tmpindex++; } if (bpf_len == 0) return; if (IS_ENGINE_MODE_IPS(engine_mode)) { SCLogError(SC_ERR_NOT_SUPPORTED, "BPF filter not available in IPS mode." " Use firewall filtering if possible."); exit(EXIT_FAILURE); } bpf_filter = SCMalloc(bpf_len); if (unlikely(bpf_filter == NULL)) return; memset(bpf_filter, 0x00, bpf_len); tmpindex = optind; while(argv[tmpindex] != NULL) { strlcat(bpf_filter, argv[tmpindex],bpf_len); if(argv[tmpindex + 1] != NULL) { strlcat(bpf_filter," ", bpf_len); } tmpindex++; } if(strlen(bpf_filter) > 0) { if (ConfSet("bpf-filter", bpf_filter, 0) != 1) { SCLogError(SC_ERR_FATAL, "Failed to set bpf filter."); exit(EXIT_FAILURE); } } SCFree(bpf_filter); } static void SetBpfStringFromFile(char *filename) { char *bpf_filter = NULL; char *bpf_comment_tmp = NULL; char *bpf_comment_start = NULL; uint32_t bpf_len = 0; #ifdef OS_WIN32 struct _stat st; #else struct stat st; #endif /* OS_WIN32 */ FILE *fp = NULL; size_t nm = 0; #ifdef OS_WIN32 if(_stat(filename, &st) != 0) { #else if(stat(filename, &st) != 0) { #endif /* OS_WIN32 */ SCLogError(SC_ERR_FOPEN, "Failed to stat file %s", filename); exit(EXIT_FAILURE); } bpf_len = st.st_size + 1; fp = fopen(filename,"r"); if (fp == NULL) { SCLogError(SC_ERR_FOPEN, "Failed to open file %s", filename); exit(EXIT_FAILURE); } bpf_filter = SCMalloc(bpf_len * sizeof(char)); if (unlikely(bpf_filter == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate buffer for bpf filter in file %s", filename); exit(EXIT_FAILURE); } memset(bpf_filter, 0x00, bpf_len); nm = fread(bpf_filter, bpf_len - 1, 1, fp); if((ferror(fp) != 0)||( nm != 1)) { *bpf_filter='\0'; } fclose(fp); if(strlen(bpf_filter) > 0) { /*replace comments with space*/ bpf_comment_start = bpf_filter; while((bpf_comment_tmp = strchr(bpf_comment_start, '#')) != NULL) { while((*bpf_comment_tmp !='\0') && (*bpf_comment_tmp != '\r') && (*bpf_comment_tmp != '\n')) { *bpf_comment_tmp++ = ' '; } bpf_comment_start = bpf_comment_tmp; } /*remove remaining '\r' and '\n' */ while((bpf_comment_tmp = strchr(bpf_filter, '\r')) != NULL) { *bpf_comment_tmp = ' '; } while((bpf_comment_tmp = strchr(bpf_filter, '\n')) != NULL) { *bpf_comment_tmp = ' '; } if(ConfSet("bpf-filter", bpf_filter, 0) != 1) { SCLogError(SC_ERR_FOPEN, "ERROR: Failed to set bpf filter!"); SCFree(bpf_filter); exit(EXIT_FAILURE); } } SCFree(bpf_filter); } void usage(const char *progname) { #ifdef REVISION printf("%s %s (rev %s)\n", PROG_NAME, PROG_VER, xstr(REVISION)); #else printf("%s %s\n", PROG_NAME, PROG_VER); #endif printf("USAGE: %s [OPTIONS] [BPF FILTER]\n\n", progname); printf("\t-c : path to configuration file\n"); printf("\t-T : test configuration file (use with -c)\n"); printf("\t-i : run in pcap live mode\n"); printf("\t-F : bpf filter file\n"); printf("\t-r : run in pcap file/offline mode\n"); #ifdef NFQ printf("\t-q : run in inline nfqueue mode\n"); #endif /* NFQ */ #ifdef IPFW printf("\t-d : run in inline ipfw divert mode\n"); #endif /* IPFW */ printf("\t-s : path to signature file loaded in addition to suricata.yaml settings (optional)\n"); printf("\t-S : path to signature file loaded exclusively (optional)\n"); printf("\t-l : default log directory\n"); #ifndef OS_WIN32 printf("\t-D : run as daemon\n"); #else printf("\t--service-install : install as service\n"); printf("\t--service-remove : remove service\n"); printf("\t--service-change-params : change service startup parameters\n"); #endif /* OS_WIN32 */ printf("\t-V : display Suricata version\n"); #ifdef UNITTESTS printf("\t-u : run the unittests and exit\n"); printf("\t-U, --unittest-filter=REGEX : filter unittests with a regex\n"); printf("\t--list-unittests : list unit tests\n"); printf("\t--fatal-unittests : enable fatal failure on unittest error\n"); #endif /* UNITTESTS */ printf("\t--list-app-layer-protos : list supported app layer protocols\n"); printf("\t--list-keywords[=all|csv|] : list keywords implemented by the engine\n"); #ifdef __SC_CUDA_SUPPORT__ printf("\t--list-cuda-cards : list cuda supported cards\n"); #endif printf("\t--list-runmodes : list supported runmodes\n"); printf("\t--runmode : specific runmode modification the engine should run. The argument\n" "\t supplied should be the id for the runmode obtained by running\n" "\t --list-runmodes\n"); printf("\t--engine-analysis : print reports on analysis of different sections in the engine and exit.\n" "\t Please have a look at the conf parameter engine-analysis on what reports\n" "\t can be printed\n"); printf("\t--pidfile : write pid to this file (only for daemon mode)\n"); printf("\t--init-errors-fatal : enable fatal failure on signature init error\n"); printf("\t--dump-config : show the running configuration\n"); printf("\t--build-info : display build information\n"); printf("\t--pcap[=] : run in pcap mode, no value select interfaces from suricata.yaml\n"); #ifdef HAVE_PCAP_SET_BUFF printf("\t--pcap-buffer-size : size of the pcap buffer value from 0 - %i\n",INT_MAX); #endif /* HAVE_SET_PCAP_BUFF */ #ifdef HAVE_AF_PACKET printf("\t--af-packet[=] : run in af-packet mode, no value select interfaces from suricata.yaml\n"); #endif #ifdef HAVE_PFRING printf("\t--pfring[=] : run in pfring mode, use interfaces from suricata.yaml\n"); printf("\t--pfring-int : run in pfring mode, use interface \n"); printf("\t--pfring-cluster-id : pfring cluster id \n"); printf("\t--pfring-cluster-type : pfring cluster type for PF_RING 4.1.2 and later cluster_round_robin|cluster_flow\n"); #endif /* HAVE_PFRING */ #ifdef HAVE_LIBCAP_NG printf("\t--user : run suricata as this user after init\n"); printf("\t--group : run suricata as this group after init\n"); #endif /* HAVE_LIBCAP_NG */ printf("\t--erf-in : process an ERF file\n"); #ifdef HAVE_DAG printf("\t--dag : process ERF records from DAG interface X, stream Y\n"); #endif #ifdef HAVE_NAPATECH printf("\t--napatech : run Napatech Streams using the API\n"); #endif #ifdef BUILD_UNIX_SOCKET printf("\t--unix-socket[=] : use unix socket to control suricata work\n"); #endif printf("\n"); printf("\nTo run the engine with default configuration on " "interface eth0 with signature file \"signatures.rules\", run the " "command as:\n\n%s -c suricata.yaml -s signatures.rules -i eth0 \n\n", progname); } void SCPrintBuildInfo(void) { char *bits = "-bits"; char *endian = "-endian"; char features[2048] = ""; #ifdef REVISION printf("This is %s version %s (rev %s)\n", PROG_NAME, PROG_VER, xstr(REVISION)); #elif defined RELEASE printf("This is %s version %s RELEASE\n", PROG_NAME, PROG_VER); #else printf("This is %s version %s\n", PROG_NAME, PROG_VER); #endif #ifdef DEBUG strlcat(features, "DEBUG ", sizeof(features)); #endif #ifdef DEBUG_VALIDATION strlcat(features, "DEBUG_VALIDATION ", sizeof(features)); #endif #ifdef UNITTESTS strlcat(features, "UNITTESTS ", sizeof(features)); #endif #ifdef NFQ strlcat(features, "NFQ ", sizeof(features)); #endif #ifdef IPFW strlcat(features, "IPFW ", sizeof(features)); #endif #ifdef HAVE_PCAP_SET_BUFF strlcat(features, "PCAP_SET_BUFF ", sizeof(features)); #endif #if LIBPCAP_VERSION_MAJOR == 1 strlcat(features, "LIBPCAP_VERSION_MAJOR=1 ", sizeof(features)); #elif LIBPCAP_VERSION_MAJOR == 0 strlcat(features, "LIBPCAP_VERSION_MAJOR=0 ", sizeof(features)); #endif #ifdef __SC_CUDA_SUPPORT__ strlcat(features, "CUDA ", sizeof(features)); #endif #ifdef HAVE_PFRING strlcat(features, "PF_RING ", sizeof(features)); #endif #ifdef HAVE_AF_PACKET strlcat(features, "AF_PACKET ", sizeof(features)); #endif #ifdef HAVE_PACKET_FANOUT strlcat(features, "HAVE_PACKET_FANOUT ", sizeof(features)); #endif #ifdef HAVE_DAG strlcat(features, "DAG ", sizeof(features)); #endif #ifdef HAVE_LIBCAP_NG strlcat(features, "LIBCAP_NG ", sizeof(features)); #endif #ifdef HAVE_LIBNET11 strlcat(features, "LIBNET1.1 ", sizeof(features)); #endif #ifdef HAVE_HTP_URI_NORMALIZE_HOOK strlcat(features, "HAVE_HTP_URI_NORMALIZE_HOOK ", sizeof(features)); #endif #ifdef HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW strlcat(features, "HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW ", sizeof(features)); #endif #ifdef PCRE_HAVE_JIT strlcat(features, "PCRE_JIT ", sizeof(features)); #endif #ifdef HAVE_NSS strlcat(features, "HAVE_NSS ", sizeof(features)); #endif #ifdef HAVE_LUAJIT strlcat(features, "HAVE_LUAJIT ", sizeof(features)); #endif #ifdef HAVE_LIBJANSSON strlcat(features, "HAVE_LIBJANSSON ", sizeof(features)); #endif #ifdef PROFILING strlcat(features, "PROFILING ", sizeof(features)); #endif #ifdef PROFILE_LOCKING strlcat(features, "PROFILE_LOCKING ", sizeof(features)); #endif if (strlen(features) == 0) { strlcat(features, "none", sizeof(features)); } printf("Features: %s\n", features); #if __WORDSIZE == 64 bits = "64-bits"; #elif __WORDSIZE == 32 bits = "32-bits"; #endif #if __BYTE_ORDER == __BIG_ENDIAN endian = "Big-endian"; #elif __BYTE_ORDER == __LITTLE_ENDIAN endian = "Little-endian"; #endif printf("%s, %s architecture\n", bits, endian); #ifdef __GNUC__ printf("GCC version %s, C version %"PRIiMAX"\n", __VERSION__, (intmax_t)__STDC_VERSION__); #else printf("C version %"PRIiMAX"\n", (intmax_t)__STDC_VERSION__); #endif #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 printf(" __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1\n"); #endif #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 printf(" __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2\n"); #endif #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 printf(" __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4\n"); #endif #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 printf(" __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8\n"); #endif #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 printf(" __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16\n"); #endif #if __SSP__ == 1 printf("compiled with -fstack-protector\n"); #endif #if __SSP_ALL__ == 2 printf("compiled with -fstack-protector-all\n"); #endif #ifdef _FORTIFY_SOURCE printf("compiled with _FORTIFY_SOURCE=%d\n", _FORTIFY_SOURCE); #endif printf("compiled with libhtp %s, linked against %s\n", HTP_BASE_VERSION_TEXT, htp_get_version()); #include "build-info.h" } int main(int argc, char **argv) { int opt; char pcap_dev[128]; char *sig_file = NULL; int sig_file_exclusive = FALSE; int conf_test = 0; char *pid_filename = NULL; #ifdef UNITTESTS char *regex_arg = NULL; #endif int dump_config = 0; int list_app_layer_protocols = 0; int list_unittests = 0; int list_cuda_cards = 0; int list_runmodes = 0; int list_keywords = 0; const char *keyword_info = NULL; const char *runmode_custom_mode = NULL; int daemon = 0; #ifndef OS_WIN32 char *user_name = NULL; char *group_name = NULL; uint8_t do_setuid = FALSE; uint8_t do_setgid = FALSE; uint32_t userid = 0; uint32_t groupid = 0; #endif /* OS_WIN32 */ int build_info = 0; int delayed_detect = 0; char *log_dir; #ifdef OS_WIN32 struct _stat buf; #else struct stat buf; #endif /* OS_WIN32 */ sc_set_caps = FALSE; SC_ATOMIC_INIT(engine_stage); /* initialize the logging subsys */ SCLogInitLogModule(NULL); if (SCSetThreadName("Suricata-Main") < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); } RunModeRegisterRunModes(); /* By default use IDS mode, but if nfq or ipfw * are specified, IPS mode will overwrite this */ SET_ENGINE_MODE_IDS(engine_mode); memset(pcap_dev, 0, sizeof(pcap_dev)); #ifdef OS_WIN32 /* service initialization */ if (SCRunningAsService()) { char path[MAX_PATH]; char *p = NULL; strlcpy(path, argv[0], MAX_PATH); if ((p = strrchr(path, '\\'))) { *p = '\0'; } if (!SetCurrentDirectory(path)) { SCLogError(SC_ERR_FATAL, "Can't set current directory to: %s", path); return -1; } SCLogInfo("Current directory is set to: %s", path); daemon = 1; SCServiceInit(argc, argv); } /* Windows socket subsystem initialization */ WSADATA wsaData; if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) { SCLogError(SC_ERR_FATAL, "Can't initialize Windows sockets: %d", WSAGetLastError()); exit(EXIT_FAILURE); } #endif /* OS_WIN32 */ /* Initialize the configuration module. */ ConfInit(); struct option long_opts[] = { {"dump-config", 0, &dump_config, 1}, {"pfring", optional_argument, 0, 0}, {"pfring-int", required_argument, 0, 0}, {"pfring-cluster-id", required_argument, 0, 0}, {"pfring-cluster-type", required_argument, 0, 0}, {"af-packet", optional_argument, 0, 0}, {"pcap", optional_argument, 0, 0}, #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, #endif {"pcap-buffer-size", required_argument, 0, 0}, {"unittest-filter", required_argument, 0, 'U'}, {"list-app-layer-protos", 0, &list_app_layer_protocols, 1}, {"list-unittests", 0, &list_unittests, 1}, {"list-cuda-cards", 0, &list_cuda_cards, 1}, {"list-runmodes", 0, &list_runmodes, 1}, {"list-keywords", optional_argument, &list_keywords, 1}, {"runmode", required_argument, NULL, 0}, {"engine-analysis", 0, &engine_analysis, 1}, #ifdef OS_WIN32 {"service-install", 0, 0, 0}, {"service-remove", 0, 0, 0}, {"service-change-params", 0, 0, 0}, #endif /* OS_WIN32 */ {"pidfile", required_argument, 0, 0}, {"init-errors-fatal", 0, 0, 0}, {"fatal-unittests", 0, 0, 0}, {"user", required_argument, 0, 0}, {"group", required_argument, 0, 0}, {"erf-in", required_argument, 0, 0}, {"dag", required_argument, 0, 0}, {"napatech", 0, 0, 0}, {"build-info", 0, &build_info, 1}, {NULL, 0, NULL, 0} }; /* getopt_long stores the option index here. */ int option_index = 0; char short_opts[] = "c:TDhi:l:q:d:r:us:S:U:VF:"; while ((opt = getopt_long(argc, argv, short_opts, long_opts, &option_index)) != -1) { switch (opt) { case 0: if (strcmp((long_opts[option_index]).name , "pfring") == 0 || strcmp((long_opts[option_index]).name , "pfring-int") == 0) { #ifdef HAVE_PFRING run_mode = RUNMODE_PFRING; if (optarg != NULL) { memset(pcap_dev, 0, sizeof(pcap_dev)); strlcpy(pcap_dev, optarg, ((strlen(optarg) < sizeof(pcap_dev)) ? (strlen(optarg) + 1) : sizeof(pcap_dev))); LiveRegisterDevice(optarg); } #else SCLogError(SC_ERR_NO_PF_RING,"PF_RING not enabled. Make sure " "to pass --enable-pfring to configure when building."); exit(EXIT_FAILURE); #endif /* HAVE_PFRING */ } else if(strcmp((long_opts[option_index]).name , "pfring-cluster-id") == 0){ #ifdef HAVE_PFRING if (ConfSet("pfring.cluster-id", optarg, 0) != 1) { fprintf(stderr, "ERROR: Failed to set pfring.cluster-id.\n"); exit(EXIT_FAILURE); } #else SCLogError(SC_ERR_NO_PF_RING,"PF_RING not enabled. Make sure " "to pass --enable-pfring to configure when building."); exit(EXIT_FAILURE); #endif /* HAVE_PFRING */ } else if(strcmp((long_opts[option_index]).name , "pfring-cluster-type") == 0){ #ifdef HAVE_PFRING if (ConfSet("pfring.cluster-type", optarg, 0) != 1) { fprintf(stderr, "ERROR: Failed to set pfring.cluster-type.\n"); exit(EXIT_FAILURE); } #else SCLogError(SC_ERR_NO_PF_RING,"PF_RING not enabled. Make sure " "to pass --enable-pfring to configure when building."); exit(EXIT_FAILURE); #endif /* HAVE_PFRING */ } else if (strcmp((long_opts[option_index]).name , "af-packet") == 0){ #ifdef HAVE_AF_PACKET if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_AFP_DEV; if (optarg) { LiveRegisterDevice(optarg); memset(pcap_dev, 0, sizeof(pcap_dev)); strlcpy(pcap_dev, optarg, ((strlen(optarg) < sizeof(pcap_dev)) ? (strlen(optarg) + 1) : sizeof(pcap_dev))); } } else if (run_mode == RUNMODE_AFP_DEV) { SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " "multiple devices to get packets is experimental."); if (optarg) { LiveRegisterDevice(optarg); } else { SCLogInfo("Multiple af-packet option without interface on each is useless"); break; } } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " "has been specified"); usage(argv[0]); exit(EXIT_FAILURE); } #else SCLogError(SC_ERR_NO_AF_PACKET,"AF_PACKET not enabled. On Linux " "host, make sure to pass --enable-af-packet to " "configure when building."); exit(EXIT_FAILURE); #endif } else if (strcmp((long_opts[option_index]).name , "pcap") == 0) { if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_PCAP_DEV; if (optarg) { LiveRegisterDevice(optarg); memset(pcap_dev, 0, sizeof(pcap_dev)); strlcpy(pcap_dev, optarg, ((strlen(optarg) < sizeof(pcap_dev)) ? (strlen(optarg) + 1) : sizeof(pcap_dev))); } } else if (run_mode == RUNMODE_PCAP_DEV) { #ifdef OS_WIN32 SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " "support is not (yet) supported on Windows."); exit(EXIT_FAILURE); #else SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " "multiple pcap devices to get packets is experimental."); LiveRegisterDevice(optarg); #endif } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " "has been specified"); usage(argv[0]); exit(EXIT_FAILURE); } } else if(strcmp((long_opts[option_index]).name, "init-errors-fatal") == 0) { if (ConfSet("engine.init-failure-fatal", "1", 0) != 1) { fprintf(stderr, "ERROR: Failed to set engine init-failure-fatal.\n"); exit(EXIT_FAILURE); } #ifdef BUILD_UNIX_SOCKET } else if (strcmp((long_opts[option_index]).name , "unix-socket") == 0) { if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_UNIX_SOCKET; if (optarg) { if (ConfSet("unix-command.filename", optarg, 0) != 1) { fprintf(stderr, "ERROR: Failed to set unix-command.filename.\n"); exit(EXIT_FAILURE); } } } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " "has been specified"); usage(argv[0]); exit(EXIT_FAILURE); } #endif } else if(strcmp((long_opts[option_index]).name, "list-app-layer-protocols") == 0) { /* listing all supported app layer protocols */ } else if(strcmp((long_opts[option_index]).name, "list-unittests") == 0) { #ifdef UNITTESTS /* Set run_mode to unit tests. */ run_mode = RUNMODE_UNITTEST; #else fprintf(stderr, "ERROR: Unit tests not enabled. Make sure to pass --enable-unittests to configure when building.\n"); exit(EXIT_FAILURE); #endif /* UNITTESTS */ } else if(strcmp((long_opts[option_index]).name, "list-cuda-cards") == 0) { #ifndef __SC_CUDA_SUPPORT__ fprintf(stderr, "ERROR: Cuda not enabled. Make sure to pass " "--enable-cuda to configure when building.\n"); exit(EXIT_FAILURE); #endif /* UNITTESTS */ } else if (strcmp((long_opts[option_index]).name, "list-runmodes") == 0) { RunModeListRunmodes(); exit(EXIT_SUCCESS); } else if (strcmp((long_opts[option_index]).name, "list-keywords") == 0) { if (optarg) { if (strcmp("short",optarg)) { keyword_info = optarg; } } } else if (strcmp((long_opts[option_index]).name, "runmode") == 0) { runmode_custom_mode = optarg; } else if(strcmp((long_opts[option_index]).name, "engine-analysis") == 0) { // do nothing for now } #ifdef OS_WIN32 else if(strcmp((long_opts[option_index]).name, "service-install") == 0) { if (SCServiceInstall(argc, argv)) { exit(EXIT_FAILURE); } SCLogInfo("Suricata service has been successfuly installed."); exit(EXIT_SUCCESS); } else if(strcmp((long_opts[option_index]).name, "service-remove") == 0) { if (SCServiceRemove(argc, argv)) { exit(EXIT_FAILURE); } SCLogInfo("Suricata service has been successfuly removed."); exit(EXIT_SUCCESS); } else if(strcmp((long_opts[option_index]).name, "service-change-params") == 0) { if (SCServiceChangeParams(argc, argv)) { exit(EXIT_FAILURE); } SCLogInfo("Suricata service startup parameters has been successfuly changed."); exit(EXIT_SUCCESS); } #endif /* OS_WIN32 */ else if(strcmp((long_opts[option_index]).name, "pidfile") == 0) { pid_filename = optarg; } else if(strcmp((long_opts[option_index]).name, "fatal-unittests") == 0) { #ifdef UNITTESTS if (ConfSet("unittests.failure-fatal", "1", 0) != 1) { fprintf(stderr, "ERROR: Failed to set unittests failure-fatal.\n"); exit(EXIT_FAILURE); } #else fprintf(stderr, "ERROR: Unit tests not enabled. Make sure to pass --enable-unittests to configure when building.\n"); exit(EXIT_FAILURE); #endif /* UNITTESTS */ } else if(strcmp((long_opts[option_index]).name, "user") == 0) { #ifndef HAVE_LIBCAP_NG SCLogError(SC_ERR_LIBCAP_NG_REQUIRED, "libcap-ng is required to" " drop privileges, but it was not compiled into Suricata."); exit(EXIT_FAILURE); #else user_name = optarg; do_setuid = TRUE; #endif /* HAVE_LIBCAP_NG */ } else if(strcmp((long_opts[option_index]).name, "group") == 0) { #ifndef HAVE_LIBCAP_NG SCLogError(SC_ERR_LIBCAP_NG_REQUIRED, "libcap-ng is required to" " drop privileges, but it was not compiled into Suricata."); exit(EXIT_FAILURE); #else group_name = optarg; do_setgid = TRUE; #endif /* HAVE_LIBCAP_NG */ } else if (strcmp((long_opts[option_index]).name, "erf-in") == 0) { run_mode = RUNMODE_ERF_FILE; if (ConfSet("erf-file.file", optarg, 0) != 1) { fprintf(stderr, "ERROR: Failed to set erf-file.file\n"); exit(EXIT_FAILURE); } } else if (strcmp((long_opts[option_index]).name, "dag") == 0) { #ifdef HAVE_DAG if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_DAG; } else if (run_mode != RUNMODE_DAG) { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode has been specified"); usage(argv[0]); exit(EXIT_FAILURE); } LiveRegisterDevice(optarg); #else SCLogError(SC_ERR_DAG_REQUIRED, "libdag and a DAG card are required" " to receieve packets using --dag."); exit(EXIT_FAILURE); #endif /* HAVE_DAG */ } else if (strcmp((long_opts[option_index]).name, "napatech") == 0) { #ifdef HAVE_NAPATECH run_mode = RUNMODE_NAPATECH; #else SCLogError(SC_ERR_NAPATECH_REQUIRED, "libntapi and a Napatech adapter are required" " to capture packets using --napatech."); exit(EXIT_FAILURE); #endif /* HAVE_NAPATECH */ } else if(strcmp((long_opts[option_index]).name, "pcap-buffer-size") == 0) { #ifdef HAVE_PCAP_SET_BUFF if (ConfSet("pcap.buffer-size", optarg, 0) != 1) { fprintf(stderr, "ERROR: Failed to set pcap-buffer-size.\n"); exit(EXIT_FAILURE); } #else SCLogError(SC_ERR_NO_PCAP_SET_BUFFER_SIZE, "The version of libpcap you have" " doesn't support setting buffer size."); #endif /* HAVE_PCAP_SET_BUFF */ } else if(strcmp((long_opts[option_index]).name, "build-info") == 0) { SCPrintBuildInfo(); exit(EXIT_SUCCESS); } break; case 'c': conf_filename = optarg; break; case 'T': SCLogInfo("Running suricata under test mode"); conf_test = 1; if (ConfSet("engine.init-failure-fatal", "1", 0) != 1) { fprintf(stderr, "ERROR: Failed to set engine init-failure-fatal.\n"); exit(EXIT_FAILURE); } break; #ifndef OS_WIN32 case 'D': daemon = 1; break; #endif /* OS_WIN32 */ case 'h': usage(argv[0]); exit(EXIT_SUCCESS); break; case 'i': memset(pcap_dev, 0, sizeof(pcap_dev)); /* some windows shells require escaping of the \ in \Device. Otherwise * the backslashes are stripped. We put them back here. */ if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { snprintf(pcap_dev, sizeof(pcap_dev), "\\Device\\NPF%s", optarg+9); } else { strlcpy(pcap_dev, optarg, ((strlen(optarg) < sizeof(pcap_dev)) ? (strlen(optarg)+1) : (sizeof(pcap_dev)))); PcapTranslateIPToDevice(pcap_dev, sizeof(pcap_dev)); } if (strcmp(pcap_dev, optarg) != 0) { SCLogInfo("translated %s to pcap device %s", optarg, pcap_dev); } else if (strlen(pcap_dev) > 0 && isdigit((unsigned char)pcap_dev[0])) { SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", optarg); exit(EXIT_FAILURE); } if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_PCAP_DEV; LiveRegisterDevice(pcap_dev); } else if (run_mode == RUNMODE_PCAP_DEV) { #ifdef OS_WIN32 SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " "support is not (yet) supported on Windows."); exit(EXIT_FAILURE); #else SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " "multiple pcap devices to get packets is experimental."); LiveRegisterDevice(pcap_dev); #endif } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " "has been specified"); usage(argv[0]); exit(EXIT_FAILURE); } break; case 'l': if (ConfSet("default-log-dir", optarg, 0) != 1) { fprintf(stderr, "ERROR: Failed to set log directory.\n"); exit(EXIT_FAILURE); } if (stat(optarg, &buf) != 0) { SCLogError(SC_ERR_LOGDIR_CMDLINE, "The logging directory \"%s\"" " supplied at the commandline (-l %s) doesn't " "exist. Shutting down the engine.", optarg, optarg); exit(EXIT_FAILURE); } break; case 'q': #ifdef NFQ if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_NFQ; SET_ENGINE_MODE_IPS(engine_mode); if (NFQRegisterQueue(optarg) == -1) exit(EXIT_FAILURE); } else if (run_mode == RUNMODE_NFQ) { if (NFQRegisterQueue(optarg) == -1) exit(EXIT_FAILURE); } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " "has been specified"); usage(argv[0]); exit(EXIT_FAILURE); } #else SCLogError(SC_ERR_NFQ_NOSUPPORT,"NFQUEUE not enabled. Make sure to pass --enable-nfqueue to configure when building."); exit(EXIT_FAILURE); #endif /* NFQ */ break; case 'd': #ifdef IPFW if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_IPFW; SET_ENGINE_MODE_IPS(engine_mode); if (IPFWRegisterQueue(optarg) == -1) exit(EXIT_FAILURE); } else if (run_mode == RUNMODE_IPFW) { if (IPFWRegisterQueue(optarg) == -1) exit(EXIT_FAILURE); } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " "has been specified"); usage(argv[0]); exit(EXIT_SUCCESS); } #else SCLogError(SC_ERR_IPFW_NOSUPPORT,"IPFW not enabled. Make sure to pass --enable-ipfw to configure when building."); exit(EXIT_FAILURE); #endif /* IPFW */ break; case 'r': if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_PCAP_FILE; } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " "has been specified"); usage(argv[0]); exit(EXIT_SUCCESS); } if (ConfSet("pcap-file.file", optarg, 0) != 1) { fprintf(stderr, "ERROR: Failed to set pcap-file.file\n"); exit(EXIT_FAILURE); } break; case 's': if (sig_file != NULL) { SCLogError(SC_ERR_CMD_LINE, "can't have multiple -s options or mix -s and -S."); exit(EXIT_FAILURE); } sig_file = optarg; break; case 'S': if (sig_file != NULL) { SCLogError(SC_ERR_CMD_LINE, "can't have multiple -S options or mix -s and -S."); exit(EXIT_FAILURE); } sig_file = optarg; sig_file_exclusive = TRUE; break; case 'u': #ifdef UNITTESTS if (run_mode == RUNMODE_UNKNOWN) { run_mode = RUNMODE_UNITTEST; } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode has" " been specified"); usage(argv[0]); exit(EXIT_SUCCESS); } #else fprintf(stderr, "ERROR: Unit tests not enabled. Make sure to pass --enable-unittests to configure when building.\n"); exit(EXIT_FAILURE); #endif /* UNITTESTS */ break; case 'U': #ifdef UNITTESTS regex_arg = optarg; if(strlen(regex_arg) == 0) regex_arg = NULL; #endif break; case 'V': #ifdef REVISION printf("This is %s version %s (rev %s)\n", PROG_NAME, PROG_VER, xstr(REVISION)); #elif defined RELEASE printf("This is %s version %s RELEASE\n", PROG_NAME, PROG_VER); #else printf("This is %s version %s\n", PROG_NAME, PROG_VER); #endif exit(EXIT_SUCCESS); case 'F': SetBpfStringFromFile(optarg); break; default: usage(argv[0]); exit(EXIT_FAILURE); } } if (!list_keywords && !list_app_layer_protocols) { #ifdef REVISION SCLogInfo("This is %s version %s (rev %s)", PROG_NAME, PROG_VER, xstr(REVISION)); #elif defined RELEASE SCLogInfo("This is %s version %s RELEASE", PROG_NAME, PROG_VER); #else SCLogInfo("This is %s version %s", PROG_NAME, PROG_VER); #endif } #ifndef HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW SCLogWarning(SC_WARN_OUTDATED_LIBHTP, "libhtp < 0.2.7 detected. Keyword " "http_raw_header will not be able to inspect response headers."); #endif SetBpfString(optind, argv); if (!list_keywords && !list_app_layer_protocols) UtilCpuPrintSummary(); #ifdef __SC_CUDA_SUPPORT__ /* Init the CUDA environment */ SCCudaInitCudaEnvironment(); if (list_cuda_cards) { SCCudaListCards(); exit(EXIT_SUCCESS); } #endif if (!CheckValidDaemonModes(daemon, run_mode)) { exit(EXIT_FAILURE); } /* Initializations for global vars, queues, etc (memsets, mutex init..) */ GlobalInits(); TimeInit(); SupportFastPatternForSigMatchTypes(); /* load the pattern matchers */ MpmTableSetup(); if (run_mode != RUNMODE_UNITTEST && !list_keywords && !list_app_layer_protocols) { if (conf_filename == NULL) conf_filename = DEFAULT_CONF_FILE; } /** \todo we need an api for these */ /* Load yaml configuration file if provided. */ if (conf_filename != NULL) { #ifdef UNITTESTS if (run_mode == RUNMODE_UNITTEST) { SCLogError(SC_ERR_CMD_LINE, "should not use a configuration file with unittests"); exit(EXIT_FAILURE); } #endif if (ConfYamlLoadFile(conf_filename) != 0) { /* Error already displayed. */ exit(EXIT_FAILURE); } ConfNode *file; ConfNode *includes = ConfGetNode("include"); if (includes != NULL) { TAILQ_FOREACH(file, &includes->head, next) { char *ifile = ConfLoadCompleteIncludePath(file->val); SCLogInfo("Including: %s", ifile); if (ConfYamlLoadFile(ifile) != 0) { /* Error already displayed. */ exit(EXIT_FAILURE); } } } ConfNode *denode = NULL; ConfNode *decnf = ConfGetNode("detect-engine"); if (decnf != NULL) { TAILQ_FOREACH(denode, &decnf->head, next) { if (strcmp(denode->val, "rule-reload") == 0) { (void)ConfGetChildValueBool(denode, "rule-reload", &rule_reload); SCLogInfo("Live rule reloads %s", rule_reload ? "enabled" : "disabled"); } } } } AppLayerDetectProtoThreadInit(); if (list_app_layer_protocols) { AppLayerListSupportedProtocols(); exit(EXIT_SUCCESS); } AppLayerParsersInitPostProcess(); if (dump_config) { ConfDump(); exit(EXIT_SUCCESS); } /* Check for the existance of the default logging directory which we pick * from suricata.yaml. If not found, shut the engine down */ if (ConfGet("default-log-dir", &log_dir) != 1) { #ifdef OS_WIN32 log_dir = _getcwd(NULL, 0); if (log_dir == NULL) { log_dir = DEFAULT_LOG_DIR; } #else log_dir = DEFAULT_LOG_DIR; #endif /* OS_WIN32 */ } if (!list_keywords && !list_app_layer_protocols) { #ifdef OS_WIN32 if (_stat(log_dir, &buf) != 0) { #else if (stat(log_dir, &buf) != 0) { #endif /* OS_WIN32 */ SCLogError(SC_ERR_LOGDIR_CONFIG, "The logging directory \"%s\" " "supplied by %s (default-log-dir) doesn't exist. " "Shutting down the engine", log_dir, conf_filename); exit(EXIT_FAILURE); } } /* Pull the max pending packets from the config, if not found fall * back on a sane default. */ if (ConfGetInt("max-pending-packets", &max_pending_packets) != 1) max_pending_packets = DEFAULT_MAX_PENDING_PACKETS; if (max_pending_packets >= 65535) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Maximum max-pending-packets setting is 65534. " "Please check %s for errors", conf_filename); exit(EXIT_FAILURE); } SCLogDebug("Max pending packets set to %"PRIiMAX, max_pending_packets); /* Pull the default packet size from the config, if not found fall * back on a sane default. */ char *temp_default_packet_size; if ((ConfGet("default-packet-size", &temp_default_packet_size)) != 1) { switch (run_mode) { case RUNMODE_PCAP_DEV: case RUNMODE_AFP_DEV: case RUNMODE_PFRING: /* FIXME this don't work effficiently in multiinterface */ /* find payload for interface and use it */ default_packet_size = GetIfaceMaxPayloadSize(pcap_dev); if (default_packet_size) break; default: default_packet_size = DEFAULT_PACKET_SIZE; } } else { if (ParseSizeStringU32(temp_default_packet_size, &default_packet_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing max-pending-packets " "from conf file - %s. Killing engine", temp_default_packet_size); exit(EXIT_FAILURE); } } SCLogDebug("Default packet size set to %"PRIu32, default_packet_size); #ifdef NFQ if (run_mode == RUNMODE_NFQ) NFQInitConfig(FALSE); #endif /* Since our config is now loaded we can finish configurating the * logging module. */ SCLogLoadConfig(daemon); #ifdef __SC_CUDA_SUPPORT__ /* load the cuda configuration */ SCCudaHlGetYamlConf(); #endif /* __SC_CUDA_SUPPORT__ */ /* Load the Host-OS lookup. */ SCHInfoLoadFromConfig(); if (!list_keywords && !list_app_layer_protocols && (run_mode != RUNMODE_UNIX_SOCKET)) { DefragInit(); } if (run_mode == RUNMODE_UNKNOWN) { if (!engine_analysis && !list_keywords && !conf_test) { usage(argv[0]); exit(EXIT_FAILURE); } } if (engine_analysis) { SCLogInfo("== Carrying out Engine Analysis =="); char *temp = NULL; if (ConfGet("engine-analysis", &temp) == 0) { SCLogInfo("no engine-analysis parameter(s) defined in conf file. " "Please define/enable them in the conf to use this " "feature."); exit(EXIT_FAILURE); } } /* create table for O(1) lowercase conversion lookup. It was removed, but * we still need it for cuda. So resintalling it back into the codebase */ uint8_t c = 0; memset(g_u8_lowercasetable, 0x00, sizeof(g_u8_lowercasetable)); for ( ; c < 255; c++) { if (c >= 'A' && c <= 'Z') g_u8_lowercasetable[c] = (c + ('a' - 'A')); else g_u8_lowercasetable[c] = c; } /* hardcoded initialization code */ SigTableSetup(); /* load the rule keywords */ if (list_keywords) { SigTableList(keyword_info); exit(EXIT_FAILURE); } TmqhSetup(); CIDRInit(); SigParsePrepare(); //PatternMatchPrepare(mpm_ctx, MPM_B2G); if (run_mode != RUNMODE_UNIX_SOCKET) { SCPerfInitCounterApi(); } #ifdef PROFILING SCProfilingRulesGlobalInit(); SCProfilingInit(); #endif /* PROFILING */ SCReputationInitCtx(); SCProtoNameInit(); TagInitCtx(); if (DetectAddressTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "basic address vars test failed. Please check %s for errors", conf_filename); exit(EXIT_FAILURE); } if (DetectPortTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "basic port vars test failed. Please check %s for errors", conf_filename); exit(EXIT_FAILURE); } /* nfq */ TmModuleReceiveNFQRegister(); TmModuleVerdictNFQRegister(); TmModuleDecodeNFQRegister(); /* ipfw */ TmModuleReceiveIPFWRegister(); TmModuleVerdictIPFWRegister(); TmModuleDecodeIPFWRegister(); /* pcap live */ TmModuleReceivePcapRegister(); TmModuleDecodePcapRegister(); /* pcap file */ TmModuleReceivePcapFileRegister(); TmModuleDecodePcapFileRegister(); /* af-packet */ TmModuleReceiveAFPRegister(); TmModuleDecodeAFPRegister(); /* pfring */ TmModuleReceivePfringRegister(); TmModuleDecodePfringRegister(); /* dag file */ TmModuleReceiveErfFileRegister(); TmModuleDecodeErfFileRegister(); /* dag live */ TmModuleReceiveErfDagRegister(); TmModuleDecodeErfDagRegister(); /* napatech */ TmModuleNapatechStreamRegister(); TmModuleNapatechDecodeRegister(); /* stream engine */ TmModuleStreamTcpRegister(); /* detection */ TmModuleDetectRegister(); /* respond-reject */ TmModuleRespondRejectRegister(); /* fast log */ TmModuleAlertFastLogRegister(); TmModuleAlertFastLogIPv4Register(); TmModuleAlertFastLogIPv6Register(); /* debug log */ TmModuleAlertDebugLogRegister(); /* prelue log */ TmModuleAlertPreludeRegister(); /* syslog log */ TmModuleAlertSyslogRegister(); TmModuleAlertSyslogIPv4Register(); TmModuleAlertSyslogIPv6Register(); /* unified2 log */ TmModuleUnified2AlertRegister(); /* pcap info log */ TmModuleAlertPcapInfoRegister(); /* drop log */ TmModuleLogDropLogRegister(); /* http log */ TmModuleLogHttpLogRegister(); TmModuleLogHttpLogIPv4Register(); TmModuleLogHttpLogIPv6Register(); TmModuleLogTlsLogRegister(); TmModuleLogTlsLogIPv4Register(); TmModuleLogTlsLogIPv6Register(); /* pcap log */ TmModulePcapLogRegister(); /* file log */ TmModuleLogFileLogRegister(); TmModuleLogFilestoreRegister(); /* cuda */ #ifdef __SC_CUDA_SUPPORT__ TmModuleCudaMpmB2gRegister(); TmModuleCudaPacketBatcherRegister(); #endif TmModuleDebugList(); AppLayerHtpNeedFileInspection(); DetectEngineRegisterAppInspectionEngines(); if (rule_reload) { if (sig_file == NULL) UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle); else UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); } else { UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Disabled); } #ifdef UNITTESTS if (run_mode == RUNMODE_UNITTEST) { #ifdef DBG_MEM_ALLOC SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); #endif /* test and initialize the unittesting subsystem */ if(regex_arg == NULL){ regex_arg = ".*"; UtRunSelftest(regex_arg); /* inits and cleans up again */ } AppLayerHtpEnableRequestBodyCallback(); AppLayerHtpNeedFileInspection(); UtInitialize(); UTHRegisterTests(); SCReputationRegisterTests(); TmModuleRegisterTests(); SigTableRegisterTests(); HashTableRegisterTests(); HashListTableRegisterTests(); BloomFilterRegisterTests(); BloomFilterCountingRegisterTests(); PoolRegisterTests(); ByteRegisterTests(); MpmRegisterTests(); FlowBitRegisterTests(); FlowAlertSidRegisterTests(); SCPerfRegisterTests(); DecodePPPRegisterTests(); DecodeVLANRegisterTests(); HTPParserRegisterTests(); SSLParserRegisterTests(); SSHParserRegisterTests(); SMBParserRegisterTests(); DCERPCParserRegisterTests(); DCERPCUDPParserRegisterTests(); FTPParserRegisterTests(); DecodeRawRegisterTests(); DecodePPPOERegisterTests(); DecodeICMPV4RegisterTests(); DecodeICMPV6RegisterTests(); DecodeIPV4RegisterTests(); DecodeIPV6RegisterTests(); DecodeTCPRegisterTests(); DecodeUDPV4RegisterTests(); DecodeGRERegisterTests(); DecodeAsn1RegisterTests(); AlpDetectRegisterTests(); ConfRegisterTests(); ConfYamlRegisterTests(); TmqhFlowRegisterTests(); FlowRegisterTests(); SCSigRegisterSignatureOrderingTests(); SCRadixRegisterTests(); DefragRegisterTests(); SigGroupHeadRegisterTests(); SCHInfoRegisterTests(); SCRuleVarsRegisterTests(); AppLayerParserRegisterTests(); ThreadMacrosRegisterTests(); UtilSpmSearchRegistertests(); UtilActionRegisterTests(); SCClassConfRegisterTests(); SCThresholdConfRegisterTests(); SCRConfRegisterTests(); #ifdef __SC_CUDA_SUPPORT__ SCCudaRegisterTests(); #endif PayloadRegisterTests(); DcePayloadRegisterTests(); UriRegisterTests(); #ifdef PROFILING SCProfilingRegisterTests(); #endif DeStateRegisterTests(); DetectRingBufferRegisterTests(); MemcmpRegisterTests(); DetectEngineHttpClientBodyRegisterTests(); DetectEngineHttpServerBodyRegisterTests(); DetectEngineHttpHeaderRegisterTests(); DetectEngineHttpRawHeaderRegisterTests(); DetectEngineHttpMethodRegisterTests(); DetectEngineHttpCookieRegisterTests(); DetectEngineHttpRawUriRegisterTests(); DetectEngineHttpStatMsgRegisterTests(); DetectEngineHttpStatCodeRegisterTests(); DetectEngineHttpUARegisterTests(); DetectEngineHttpHHRegisterTests(); DetectEngineHttpHRHRegisterTests(); DetectEngineRegisterTests(); SCLogRegisterTests(); SMTPParserRegisterTests(); MagicRegisterTests(); UtilMiscRegisterTests(); DetectAddressTests(); DetectProtoTests(); DetectPortTests(); SCAtomicRegisterTests(); if (list_unittests) { UtListTests(regex_arg); } else { uint32_t failed = UtRunTests(regex_arg); UtCleanup(); #ifdef __SC_CUDA_SUPPORT__ /* need this in case any of the cuda dispatcher threads are still * running, kill them, so that we can free the cuda contexts. We * need to free those cuda contexts so that next when we call * deregister functions, we will need to attach to those contexts * the contexts and its associated data */ TmThreadKillThreads(); SCCudaHlDeRegisterAllRegisteredModules(); #endif if (failed) { exit(EXIT_FAILURE); } } #ifdef DBG_MEM_ALLOC SCLogInfo("Total memory used (without SCFree()): %"PRIdMAX, (intmax_t)global_mem); #endif exit(EXIT_SUCCESS); } #endif /* UNITTESTS */ TmModuleRunInit(); if (daemon == 1) { if (pid_filename == NULL) { if (ConfGet("pid-file", &pid_filename) == 1) { SCLogInfo("Use pid file %s from config file.", pid_filename); } else { pid_filename = DEFAULT_PID_FILENAME; } } if (SCPidfileTestRunning(pid_filename) != 0) { pid_filename = NULL; exit(EXIT_FAILURE); } Daemonize(); if (SCPidfileCreate(pid_filename) != 0) { pid_filename = NULL; #if 1 SCLogError(SC_ERR_PIDFILE_DAEMON, "Unable to create PID file, concurrent run of" " Suricata can occur."); SCLogError(SC_ERR_PIDFILE_DAEMON, "PID file creation WILL be mandatory for daemon mode" " in future version"); #else exit(EXIT_FAILURE); #endif } } else { if (pid_filename != NULL) { SCLogError(SC_ERR_PIDFILE_DAEMON, "The pidfile file option applies " "only to the daemon modes"); pid_filename = NULL; exit(EXIT_FAILURE); } } #ifdef HAVE_NSS /* init NSS for md5 */ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); NSS_NoDB_Init(NULL); #endif /* registering signals we use */ UtilSignalHandlerSetup(SIGINT, SignalHandlerSigint); UtilSignalHandlerSetup(SIGTERM, SignalHandlerSigterm); UtilSignalHandlerSetup(SIGPIPE, SIG_IGN); UtilSignalHandlerSetup(SIGSYS, SIG_IGN); #ifndef OS_WIN32 /* SIGHUP is not implemnetd on WIN32 */ //UtilSignalHandlerSetup(SIGHUP, SignalHandlerSighup); /* Try to get user/group to run suricata as if command line as not decide of that */ if (do_setuid == FALSE && do_setgid == FALSE) { char *id; if (ConfGet("run-as.user", &id) == 1) { do_setuid = TRUE; user_name = id; } if (ConfGet("run-as.group", &id) == 1) { do_setgid = TRUE; group_name = id; } } /* Get the suricata user ID to given user ID */ if (do_setuid == TRUE) { if (SCGetUserID(user_name, group_name, &userid, &groupid) != 0) { SCLogError(SC_ERR_UID_FAILED, "failed in getting user ID"); exit(EXIT_FAILURE); } sc_set_caps = TRUE; /* Get the suricata group ID to given group ID */ } else if (do_setgid == TRUE) { if (SCGetGroupID(group_name, &groupid) != 0) { SCLogError(SC_ERR_GID_FAILED, "failed in getting group ID"); exit(EXIT_FAILURE); } sc_set_caps = TRUE; } #endif /* OS_WIN32 */ PacketPoolInit(max_pending_packets); HostInitConfig(HOST_VERBOSE); if (run_mode != RUNMODE_UNIX_SOCKET) { FlowInitConfig(FLOW_VERBOSE); } DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " "context failed."); exit(EXIT_FAILURE); } SCClassConfLoadClassficationConfigFile(de_ctx); SCRConfLoadReferenceConfigFile(de_ctx); if (ActionInitConfig() < 0) { exit(EXIT_FAILURE); } if (MagicInit() != 0) exit(EXIT_FAILURE); /* In offline mode delayed init of detect is a bad idea */ if ((run_mode == RUNMODE_PCAP_FILE) || (run_mode == RUNMODE_ERF_FILE) || engine_analysis) { delayed_detect = 0; } else { ConfNode *denode = NULL; ConfNode *decnf = ConfGetNode("detect-engine"); if (decnf != NULL) { TAILQ_FOREACH(denode, &decnf->head, next) { if (strcmp(denode->val, "delayed-detect") == 0) { (void)ConfGetChildValueBool(denode, "delayed-detect", &delayed_detect); } } } } de_ctx->delayed_detect = delayed_detect; SCLogInfo("Delayed detect %s", delayed_detect ? "enabled" : "disabled"); if (delayed_detect) { SCLogInfo("Packets will start being processed before signatures are active."); } if (!delayed_detect) { if (SigLoadSignatures(de_ctx, sig_file, sig_file_exclusive) < 0) { if (sig_file == NULL) { SCLogError(SC_ERR_OPENING_FILE, "Signature file has not been provided"); } else { SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); } if (de_ctx->failure_fatal) exit(EXIT_FAILURE); } if (engine_analysis) { exit(EXIT_SUCCESS); } SCThresholdConfInitContext(de_ctx,NULL); } /* registering singal handlers we use. We register usr2 here, so that one * can't call it during the first sig load phase */ if (sig_file == NULL && rule_reload == 1) UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); #ifdef __SC_CUDA_SUPPORT__ SCCudaPBSetUpQueuesAndBuffers(); #endif /* __SC_CUDA_SUPPORT__ */ SCAsn1LoadConfig(); CoredumpLoadConfig(); struct timeval start_time; memset(&start_time, 0, sizeof(start_time)); gettimeofday(&start_time, NULL); SCDropMainThreadCaps(userid, groupid); if (run_mode != RUNMODE_UNIX_SOCKET) { RunModeInitializeOutputs(); } /* run the selected runmode */ if (run_mode == RUNMODE_PCAP_DEV) { if (strlen(pcap_dev) == 0) { int ret = LiveBuildDeviceList("pcap"); if (ret == 0) { fprintf(stderr, "ERROR: No interface found in config for pcap\n"); exit(EXIT_FAILURE); } } #ifdef HAVE_PFRING } else if (run_mode == RUNMODE_PFRING) { /* FIXME add backward compat support */ /* iface has been set on command line */ if (strlen(pcap_dev)) { if (ConfSet("pfring.live-interface", pcap_dev, 0) != 1) { fprintf(stderr, "ERROR: Failed to set pfring.live-interface\n"); exit(EXIT_FAILURE); } } else { /* not an error condition if we have a 1.0 config */ LiveBuildDeviceList("pfring"); } #endif /* HAVE_PFRING */ } else if (run_mode == RUNMODE_AFP_DEV) { /* iface has been set on command line */ if (strlen(pcap_dev)) { if (ConfSet("af-packet.live-interface", pcap_dev, 0) != 1) { fprintf(stderr, "ERROR: Failed to set af-packet.live-interface\n"); exit(EXIT_FAILURE); } } else { int ret = LiveBuildDeviceList("af-packet"); if (ret == 0) { fprintf(stderr, "ERROR: No interface found in config for af-packet\n"); exit(EXIT_FAILURE); } } } if(conf_test == 1){ SCLogInfo("Configuration provided was successfully loaded. Exiting."); exit(EXIT_SUCCESS); } RunModeDispatch(run_mode, runmode_custom_mode, de_ctx); #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_B2G_CUDA) { /* start the dispatcher thread for this module */ if (B2gCudaStartDispatcherThreadRC("SC_RULES_CONTENT_B2G_CUDA") == -1) exit(EXIT_FAILURE); } #endif /* In Unix socket runmode, Flow manager is started on demand */ if (run_mode != RUNMODE_UNIX_SOCKET) { /* Spawn the unix socket manager thread */ int unix_socket = 0; if (ConfGetBool("unix-command.enabled", &unix_socket) != 1) unix_socket = 0; if (unix_socket == 1) { UnixManagerThreadSpawn(de_ctx, 0); #ifdef BUILD_UNIX_SOCKET UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0); #endif } /* Spawn the flow manager thread */ FlowManagerThreadSpawn(); StreamTcpInitConfig(STREAM_VERBOSE); } /* Spawn the L7 App Detect thread */ //AppLayerDetectProtoThreadSpawn(); /* Spawn the perf counter threads. Let these be the last one spawned */ if (run_mode != RUNMODE_UNIX_SOCKET) { SCPerfSpawnThreads(); } /* Check if the alloted queues have at least 1 reader and writer */ TmValidateQueueState(); /* Wait till all the threads have been initialized */ if (TmThreadWaitOnThreadInit() == TM_ECODE_FAILED) { SCLogError(SC_ERR_INITIALIZATION, "Engine initialization failed, " "aborting..."); exit(EXIT_FAILURE); } (void) SC_ATOMIC_CAS(&engine_stage, SURICATA_INIT, SURICATA_RUNTIME); /* Un-pause all the paused threads */ TmThreadContinueThreads(); if (delayed_detect) { if (SigLoadSignatures(de_ctx, sig_file, sig_file_exclusive) < 0) { if (sig_file == NULL) { SCLogError(SC_ERR_OPENING_FILE, "Signature file has not been provided"); } else { SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); } if (de_ctx->failure_fatal) exit(EXIT_FAILURE); } SCThresholdConfInitContext(de_ctx,NULL); TmThreadActivateDummySlot(); SCLogInfo("Signature(s) loaded, Detect thread(s) activated."); } #ifdef DBG_MEM_ALLOC SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); #ifdef DBG_MEM_ALLOC_SKIP_STARTUP print_mem_flag = 1; #endif #endif int engine_retval = EXIT_SUCCESS; while(1) { if (suricata_ctl_flags & (SURICATA_KILL | SURICATA_STOP)) { SCLogInfo("Signal Received. Stopping engine."); break; } TmThreadCheckThreadState(); usleep(10* 1000); } /* Update the engine stage/status flag */ (void) SC_ATOMIC_CAS(&engine_stage, SURICATA_RUNTIME, SURICATA_DEINIT); #ifdef __SC_CUDA_SUPPORT__ SCCudaPBKillBatchingPackets(); #endif UnixSocketKillSocketThread(); if (run_mode != RUNMODE_UNIX_SOCKET) { /* First we need to kill the flow manager thread */ FlowKillFlowManagerThread(); } /* Disable packet acquire thread first */ TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM); if (run_mode != RUNMODE_UNIX_SOCKET) { FlowForceReassembly(); } struct timeval end_time; memset(&end_time, 0, sizeof(end_time)); gettimeofday(&end_time, NULL); uint64_t milliseconds = ((end_time.tv_sec - start_time.tv_sec) * 1000) + (((1000000 + end_time.tv_usec - start_time.tv_usec) / 1000) - 1000); SCLogInfo("time elapsed %.3fs", (float)milliseconds/(float)1000); if (rule_reload == 1) { /* Disable detect threads first. This is required by live rule swap */ TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM | TM_FLAG_STREAM_TM | TM_FLAG_DETECT_TM); /* wait if live rule swap is in progress */ if (UtilSignalIsHandler(SIGUSR2, SignalHandlerSigusr2Idle)) { SCLogInfo("Live rule swap in progress. Waiting for it to end " "before we shut the engine/threads down"); while (UtilSignalIsHandler(SIGUSR2, SignalHandlerSigusr2Idle)) { /* sleep for 0.5 seconds */ usleep(500000); } SCLogInfo("Received notification that live rule swap is done. " "Continuing with engine/threads shutdown"); } } DetectEngineCtx *global_de_ctx = DetectEngineGetGlobalDeCtx(); if (run_mode != RUNMODE_UNIX_SOCKET) { BUG_ON(global_de_ctx == NULL); } TmThreadKillThreads(); if (run_mode != RUNMODE_UNIX_SOCKET) { SCPerfReleaseResources(); FlowShutdown(); StreamTcpFreeConfig(STREAM_VERBOSE); } HostShutdown(); HTPFreeConfig(); HTPAtExitPrintStats(); #ifdef DBG_MEM_ALLOC SCLogInfo("Total memory used (without SCFree()): %"PRIdMAX, (intmax_t)global_mem); #ifdef DBG_MEM_ALLOC_SKIP_STARTUP print_mem_flag = 0; #endif #endif SCPidfileRemove(pid_filename); /** \todo review whats needed here */ #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_B2G_CUDA) { /* all threadvars related to cuda should be free by now, which means * the cuda contexts would be floating */ if (SCCudaHlPushCudaContextFromModule("SC_RULES_CONTENT_B2G_CUDA") == -1) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Call to " "SCCudaHlPushCudaContextForModule() failed during the " "shutdown phase just before the call to SigGroupCleanup()"); } } #endif #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_B2G_CUDA) { /* pop the cuda context we just pushed before the call to SigGroupCleanup() */ if (SCCudaCtxPopCurrent(NULL) == -1) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Call to SCCudaCtxPopCurrent() " "during the shutdown phase just before the call to " "SigGroupCleanup()"); return 0; } } #endif AppLayerHtpPrintStats(); if (global_de_ctx) { DetectEngineCtxFree(global_de_ctx); } AlpProtoDestroy(); TagDestroyCtx(); RunModeShutDown(); OutputDeregisterAll(); TimeDeinit(); SCProtoNameDeInit(); if (run_mode != RUNMODE_UNIX_SOCKET) { DefragDestroy(); } PacketPoolDestroy(); MagicDeinit(); TmqhCleanup(); TmModuleRunDeInit(); #ifdef HAVE_AF_PACKET AFPPeersListClean(); #endif #ifdef PROFILING if (profiling_rules_enabled) SCProfilingDump(); SCProfilingDestroy(); #endif #ifdef __SC_CUDA_SUPPORT__ /* all cuda contexts attached to any threads should be free by now. * if any host_thread is still attached to any cuda_context, they need * to pop them by the time we reach here, if they aren't using those * cuda contexts in any way */ SCCudaHlDeRegisterAllRegisteredModules(); #endif #ifdef OS_WIN32 if (daemon) { return 0; } #endif /* OS_WIN32 */ SC_ATOMIC_DESTROY(engine_stage); exit(engine_retval); } suricata-1.4.7/src/detect-fragoffset.h0000644000000000000000000000207512253546156014576 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DETECT_FRAGOFFSET_H__ #define __DETECT_FRAGOFFSET_H__ #define FRAG_LESS 1 #define FRAG_MORE 2 typedef struct DetectFragOffsetData_ { uint16_t frag_off; uint8_t mode; } DetectFragOffsetData; /* prototypes */ void DetectFragOffsetRegister(void); #endif /* __DETECT_FRAGOFFSET__ */ suricata-1.4.7/src/app-layer-dcerpc.h0000644000000000000000000000232612253546156014331 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Kirby Kuehl */ #ifndef __APP_LAYER_DCERPC_H__ #define __APP_LAYER_DCERPC_H__ #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-dcerpc-common.h" #include "flow.h" #include "queue.h" #include "util-byte.h" typedef struct DCERPCState_ { DCERPC dcerpc; uint8_t data_needed_for_dir; } DCERPCState; void RegisterDCERPCParsers(void); void DCERPCParserTests(void); void DCERPCParserRegisterTests(void); #endif /* __APP_LAYER_DCERPC_H__ */ suricata-1.4.7/src/util-decode-asn1.h0000644000000000000000000001714012253546156014237 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * Implements ASN1 decoding (needed for the asn1 keyword) */ #ifndef __DECODE_ASN1_H__ #define __DECODE_ASN1_H__ #include #include #include #include #include #include #include #include #define ASN1_MAX_FRAMES 128 /* For future enconding type implementations */ enum { ASN1_BER_ENC, ASN1_ENC_UNKNOWN }; /* Class of tag */ #define ASN1_BER_CLASS_UNIV 0 #define ASN1_BER_CLASS_APP 1 #define ASN1_BER_CLASS_CTX_SPECIFIC 2 #define ASN1_BER_CLASS_PRIV 3 /* For low tag numbers */ #define ASN1_BER_GET_CLASS_TAG(id_octet) \ ((id_octet >> 6) & 0x03) /* (8.1.2.2a) */ #define ASN1_BER_IS_CONSTRUCTED(id_octet) \ ((id_octet >> 5) & 0x01) /* (8.1.2.5) Constructed Tag */ #define ASN1_BER_IS_PRIMITIVE(id_octet) \ (((id_octet >> 5) & 0x01)?0:1) /* (8.1.2.5) Primitive Tag */ #define ASN1_BER_IS_LOW_TAG(id_octet) \ ASN1_BER_IS_PRIMITIVE(id_octet) /* (8.1.2.5) Is Low Tag Number */ #define ASN1_BER_GET_LOW_TAG_NUM(id_octet) \ (id_octet & 0x1F) /* (8.1.2.2c) Get LowTag Number */ /* For high tag numbers */ #define ASN1_BER_IS_HIGH_TAG(id_octet) \ ((ASN1_BER_GET_LOW_TAG_NUM(id_octet) == 0x1F) && \ ASN1_BER_IS_CONSTRUCTED(id_octet)) /* (8.1.2.4) High Tag Number */ #define ASN1_BER_IS_HIGH_TAG_END(id_octet) \ ( !((id_octet >> 7) & 0x01)) /* (8.1.2.4) Is End of Tag Num */ #define ASN1_BER_GET_HIGH_TAG_NUM(id_octet) \ (id_octet & 0x7F) /* (8.1.2.4) Part of High Tag Number */ #define ASN1_BER_IS_SHORT_LEN(id_octet) \ ( !((id_octet >> 7) & 0x01)) /* (8.1.3.3) Is short form */ #define ASN1_BER_GET_SHORT_LEN(id_octet) \ (id_octet & 0x7F) /* (8.1.3.3) length value */ #define ASN1_BER_GET_LONG_LEN_OCTETS(id_octet) \ (id_octet & 0x7F) /* (8.1.3.5) the number of bytes */ #define ASN1_BER_GET_LONG_LEN(id_octet) \ (id_octet) /* (8.1.3.5) the byte itself*/ #define ASN1_BER_LONG_LEN_HAS_NEXT(id_octet) \ ( !((id_octet >> 7) & 0x01)) /* (8.1.3.5) Has next octets lenght */ #define ASN1_BER_IS_INDEFINITE_LEN(id_octet) \ (id_octet == 0x80) /* (8.1.3.6) Need end-of-ccontent */ #define ASN1_BER_IS_EOC(tmp_iter) (*tmp_iter == 0 && *(tmp_iter + 1) == 0) /* Return the current node/frame that we are filling */ #define ASN1CTX_CUR_NODE(ac) (ac->asn1_stack[ac->cur_frame]) #define ASN1CTX_GET_NODE(ac, node) (ac->asn1_stack[node]) /* BER Universal tags */ #define ASN1_UNITAG_EOC 0 /* EOC */ #define ASN1_UNITAG_BOOLEAN 1 #define ASN1_UNITAG_INTEGER 2 #define ASN1_UNITAG_BIT_STRING 3 #define ASN1_UNITAG_OCTET_STRING 4 #define ASN1_UNITAG_NULL 5 #define ASN1_UNITAG_OID 6 #define ASN1_UNITAG_OBJECT_DESCRIPTOR 7 #define ASN1_UNITAG_EXTERNAL 8 #define ASN1_UNITAG_REAL 9 #define ASN1_UNITAG_ENUMERATED 10 #define ASN1_UNITAG_EMBEDDED_PDV 11 #define ASN1_UNITAG_UTF8_STRING 12 #define ASN1_UNITAG_RELATIVE_OID 13 #define ASN1_UNITAG_SEQUENCE 16 #define ASN1_UNITAG_SET 17 #define ASN1_UNITAG_NUMERIC_STRING 18 #define ASN1_UNITAG_PRINTABLE_STRING 19 #define ASN1_UNITAG_TELETEX_STRING 20 #define ASN1_UNITAG_VIDEOTEX_STRING 21 #define ASN1_UNITAG_IA5_STRING 22 #define ASN1_UNITAG_UTCTIME 23 #define ASN1_UNITAG_GENERALIZED_TIME 24 #define ASN1_UNITAG_GRAPHIC_STRING 25 #define ASN1_UNITAG_VISIBLE_STRING 26 #define ASN1_UNITAG_GENERAL_STRING 27 #define ASN1_UNITAG_UNIVERSAL_STRING 28 #define ASN1_UNITAG_CHARACTER_STRING 29 #define ASN1_UNITAG_BMP_STRING 30 /* Length form */ #define ASN1_BER_LEN_SHORT 0 #define ASN1_BER_LEN_LONG 1 #define ASN1_BER_LEN_INDEFINITE 2 /* Error events/flags */ #define ASN1_BER_EVENT_ID_TOO_LONG 0x01 #define ASN1_BER_EVENT_INVALID_ID 0x02 /* (8.1.2.4.2c) First subsequent id val (from bit 7 to 0) Shall not be 0 */ #define ASN1_BER_EVENT_INVALID_LEN 0x04 /* (8.1.3.2a) we expect a simple form, or (8.1.3.5c) we got 0xFF, or not enough data */ #define ASN1_BER_EVENT_LEN_TOO_LONG 0x08 #define ASN1_BER_EVENT_EOC_NOT_FOUND 0x10 /* EOC not found */ /* Helper flags */ #define ASN1_NODE_IS_EOC 1 #define ASN1_TAG_TYPE_PRIMITIVE 0 #define ASN1_TAG_TYPE_CONSTRUCTED 1 typedef struct Asn1Len_ { uint8_t form; uint32_t len; uint8_t *ptr; } Asn1Len; typedef struct Asn1Id_ { uint8_t *ptr; uint8_t class_tag; uint8_t tag_type; uint32_t tag_num; } Asn1Id; typedef struct Asn1Data_ { uint8_t *ptr; uint32_t len; uint8_t type; } Asn1Data; typedef struct Asn1Node_ { uint8_t *raw_str; uint8_t data_len; Asn1Len len; Asn1Id id; Asn1Data data; uint8_t flags; } Asn1Node; typedef struct Asn1Ctx_ { uint8_t *data; uint8_t *end; uint16_t len; uint8_t *iter; uint16_t cur_frame; Asn1Node *asn1_stack2[ASN1_MAX_FRAMES]; Asn1Node **asn1_stack; uint8_t parser_status; uint8_t ctx_flags; } Asn1Ctx; /* Return codes of the decoder */ #define ASN1_PARSER_OK 0x01 /* Everything ok */ #define ASN1_PARSER_ERR 0x02 /* Internal error, fatal error, we can't continue decoding */ /* Status of the parser */ #define ASN1_STATUS_OK 0x00 /* On the road */ #define ASN1_STATUS_INVALID 0x01 /* We found something weird/invalid by the specification, but we can try to continue parsing */ #define ASN1_STATUS_OOB 0x02 /* We don't have enough data or ran out of bounds */ #define ASN1_STATUS_DONE 0x04 /* We have finished cleanly */ void SCPrintByteBin(uint8_t); Asn1Ctx *SCAsn1CtxNew(void); void SCAsn1CtxInit(Asn1Ctx *, uint8_t *, uint16_t); void SCAsn1CtxDestroy(Asn1Ctx *); uint8_t SCAsn1Decode(Asn1Ctx *, uint16_t); uint8_t SCAsn1DecodeIdentifier(Asn1Ctx *); uint8_t SCAsn1DecodeLength(Asn1Ctx *); uint8_t SCAsn1DecodeContent(Asn1Ctx *); uint8_t SCAsn1CheckBounds(Asn1Ctx *); void DecodeAsn1RegisterTests(void); void SCAsn1LoadConfig(); #endif /* __DECODE_ASN1_H__ */ suricata-1.4.7/src/detect-classtype.c0000644000000000000000000002373012253546156014453 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implements classtype keyword. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-classtype.h" #include "flow-var.h" #include "util-classification-config.h" #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" #define DETECT_CLASSTYPE_REGEX "^\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*$" static pcre *regex = NULL; static pcre_extra *regex_study = NULL; static int DetectClasstypeSetup(DetectEngineCtx *, Signature *, char *); void DetectClasstypeRegisterTests(void); /** * \brief Registers the handler functions for the "Classtype" keyword. */ void DetectClasstypeRegister(void) { const char *eb = NULL; int eo; int opts = 0; SCLogDebug("Registering the Classtype keyword handler"); sigmatch_table[DETECT_CLASSTYPE].name = "classtype"; sigmatch_table[DETECT_CLASSTYPE].desc = "information about the classification of rules and alerts"; sigmatch_table[DETECT_CLASSTYPE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Classtype"; sigmatch_table[DETECT_CLASSTYPE].Match = NULL; sigmatch_table[DETECT_CLASSTYPE].Setup = DetectClasstypeSetup; sigmatch_table[DETECT_CLASSTYPE].Free = NULL; sigmatch_table[DETECT_CLASSTYPE].RegisterTests = DetectClasstypeRegisterTests; regex = pcre_compile(DETECT_CLASSTYPE_REGEX, opts, &eb, &eo, NULL); if (regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", DETECT_CLASSTYPE_REGEX, eo, eb); goto end; } regex_study = pcre_study(regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto end; } end: return; } /** * \brief Parses the raw string supplied with the "Classtype" keyword. * * \param Pointer to the string to be parsed. * * \retval ct_name Pointer to the parsed string on Success; NULL on failure. */ static inline const char *DetectClasstypeParseRawString(char *rawstr) { const char *ct_name = NULL; #define MAX_SUBSTRINGS 30 int ret = 0; int ov[MAX_SUBSTRINGS]; /* get rid of the double quotes if present */ if (rawstr[0] == '\"' && rawstr[strlen(rawstr) - 1] == '\"') { if ( (rawstr = SCStrdup(rawstr + 1)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); goto end; } rawstr[strlen(rawstr) - 1] = '\0'; } ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30); if (ret < 0) { SCLogError(SC_ERR_PCRE_MATCH, "Invalid Classtype in Signature"); goto end; } ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto end; } end: return ct_name; } /** * \brief The setup function that would be called when the Signature parsing * module encounters the "Classtype" keyword. * * \param de_ctx Pointer to the Detection Engine Context. * \param s Pointer the current Signature instance that is being parsed. * \param rawstr Pointer to the argument supplied to the classtype keyword. * * \retval 0 On success * \retval -1 On failure */ static int DetectClasstypeSetup(DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { const char *parsed_ct_name = NULL; SCClassConfClasstype *ct = NULL; if ( (parsed_ct_name = DetectClasstypeParseRawString(rawstr)) == NULL) { SCLogError(SC_ERR_PCRE_PARSE, "Error parsing classtype argument supplied with the " "classtype keyword"); goto error; } ct = SCClassConfGetClasstype(parsed_ct_name, de_ctx); if (ct == NULL) { SCLogError(SC_ERR_UNKNOWN_VALUE, "Unknown Classtype: \"%s\". Invalidating the Signature", parsed_ct_name); goto error; } /* if we have retrieved the classtype, assign the message to be displayed * for this Signature by fast.log, if a Packet matches this Signature */ s->class = ct->classtype_id; s->class_msg = ct->classtype_desc; /* if a priority keyword has appeared before the classtype, s->prio would * hold a value which is != -1, in which case we don't overwrite the value. * Otherwise, overwrite the value */ if (s->prio == -1) s->prio = ct->priority; pcre_free_substring(parsed_ct_name); return 0; error: if (parsed_ct_name != NULL) pcre_free_substring(parsed_ct_name); return -1; } /*------------------------------Unittests-------------------------------------*/ #ifdef UNITTESTS /** * \test Check that supplying an invalid classtype in the rule, results in the * rule being invalidated. */ int DetectClasstypeTest01() { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; " "Classtype:not_available; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; DetectEngineCtxFree(de_ctx); end: return result; } /** * \test Check that both valid and invalid classtypes in a rule are handled * properly, with rules containing invalid classtypes being rejected * and the ones containing valid classtypes parsed and returned. */ int DetectClasstypeTest02() { int result = 0; Signature *last = NULL; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:bad-unknown; sid:1;)"); if (sig == NULL) { printf("first sig failed to parse: "); result = 0; goto end; } de_ctx->sig_list = last = sig; result = (sig != NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:not-there; sid:1;)"); last->next = sig; result &= (sig == NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:Bad-UnkNown; sid:1;)"); if (sig == NULL) { printf("second sig failed to parse: "); result = 0; goto end; } last->next = sig; last = sig; result &= (sig != NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:nothing-wrong; sid:1;)"); if (sig == NULL) { result = 0; goto end; } last->next = sig; last = sig; result &= (sig != NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:attempted_dos; sid:1;)"); last->next = sig; result &= (sig == NULL); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); end: return result; } /** * \test Check that the signatures are assigned priority based on classtype they * are given. */ int DetectClasstypeTest03() { int result = 0; Signature *last = NULL; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:bad-unknown; priority:1; sid:1;)"); if (sig == NULL) { result = 0; goto end; } de_ctx->sig_list = last = sig; result = (sig != NULL); result &= (sig->prio == 1); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:unKnoWn; " "priority:3; sid:1;)"); if (sig == NULL) { result = 0; goto end; } last->next = sig; last = sig; result &= (sig != NULL); result &= (sig->prio == 3); sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; " "Classtype:nothing-wrong; priority:1; sid:1;)"); if (sig == NULL) { result = 0; goto end; } last->next = sig; last = sig; result &= (sig != NULL); result &= (sig->prio == 1); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); end: return result; } #endif /* UNITTESTS */ /** * \brief This function registers unit tests for Classification Config API. */ void DetectClasstypeRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectClasstypeTest01", DetectClasstypeTest01, 1); UtRegisterTest("DetectClasstypeTest02", DetectClasstypeTest02, 1); UtRegisterTest("DetectClasstypeTest03", DetectClasstypeTest03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-engine-hsmd.c0000644000000000000000000015315612253546156014650 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-hsmd.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" /** * \brief Run the mpm against http stat msg. * * \retval cnt Number of matches reported by the mpm algo. */ int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { SCEnter(); uint32_t cnt = 0; if (htp_state == NULL) { SCLogDebug("no HTTP state"); SCReturnInt(0); } /* locking the flow, we will inspect the htp state */ FLOWLOCK_RDLOCK(f); if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } int idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } htp_tx_t *tx = NULL; int size = (int)list_size(htp_state->connp->conn->transactions); for ( ; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->response_message == NULL) continue; cnt += HttpStatMsgPatternSearch(det_ctx, (uint8_t *)bstr_ptr(tx->response_message), bstr_len(tx->response_message), flags); } end: FLOWLOCK_UNLOCK(f); SCReturnInt(cnt); } /** * \brief Do the http_stat_msg content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL || tx->response_message == NULL) return 0; det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HSMDMATCH], f, (uint8_t *)bstr_ptr(tx->response_message), bstr_len(tx->response_message), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSMD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS static int DetectEngineHttpStatMsgTest01(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 message\r\n" "Content-Type: text/html\r\n" "Content-Length: 7\r\n" "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"message\"; http_stat_msg; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest02(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 xxxxABC\r\n" "Content-Type: text/html\r\n" "Content-Length: 7\r\n" "\r\n" "xxxxABC"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"ABC\"; http_stat_msg; offset:4; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpStatMsgTest03(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; int result = 0; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 1234567"; uint32_t http_len2 = sizeof(http_buf2) - 1; uint8_t http_buf3[] = "8901234ABC\r\n" "Content-Type: text/html\r\n" "Content-Length: 17\r\n" "\r\n" "12345678901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"ABC\"; http_stat_msg; offset:14; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest04(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:!\"abc\"; http_stat_msg; offset:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest05(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"abc\"; http_stat_msg; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest06(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:!\"def\"; http_stat_msg; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:!\"def\"; http_stat_msg; offset:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:!\"abc\"; http_stat_msg; depth:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"abc\"; http_stat_msg; depth:3; " "content:\"def\"; http_stat_msg; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"abc\"; http_stat_msg; depth:3; " "content:!\"xyz\"; http_stat_msg; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest11(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"abc\"; http_stat_msg; depth:3; " "content:\"xyz\"; http_stat_msg; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 did match but should not have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest12(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"ab\"; http_stat_msg; depth:2; " "content:\"ef\"; http_stat_msg; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest13(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "content:\"ab\"; http_stat_msg; depth:3; " "content:!\"yz\"; http_stat_msg; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest14(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "pcre:/ab/Y; " "content:\"ef\"; http_stat_msg; distance:2; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpStatMsgTest15(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http stat msg test\"; " "pcre:/abc/Y; " "content:!\"xyz\"; http_stat_msg; distance:0; within:3; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 did not match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpStatMsgRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpStatMsgTest01", DetectEngineHttpStatMsgTest01, 1); UtRegisterTest("DetectEngineHttpStatMsgTest02", DetectEngineHttpStatMsgTest02, 1); UtRegisterTest("DetectEngineHttpStatMsgTest03", DetectEngineHttpStatMsgTest03, 1); UtRegisterTest("DetectEngineHttpStatMsgTest04", DetectEngineHttpStatMsgTest04, 1); UtRegisterTest("DetectEngineHttpStatMsgTest05", DetectEngineHttpStatMsgTest05, 1); UtRegisterTest("DetectEngineHttpStatMsgTest06", DetectEngineHttpStatMsgTest06, 1); UtRegisterTest("DetectEngineHttpStatMsgTest07", DetectEngineHttpStatMsgTest07, 1); UtRegisterTest("DetectEngineHttpStatMsgTest08", DetectEngineHttpStatMsgTest08, 1); UtRegisterTest("DetectEngineHttpStatMsgTest09", DetectEngineHttpStatMsgTest09, 1); UtRegisterTest("DetectEngineHttpStatMsgTest10", DetectEngineHttpStatMsgTest10, 1); UtRegisterTest("DetectEngineHttpStatMsgTest11", DetectEngineHttpStatMsgTest11, 1); UtRegisterTest("DetectEngineHttpStatMsgTest12", DetectEngineHttpStatMsgTest12, 1); UtRegisterTest("DetectEngineHttpStatMsgTest13", DetectEngineHttpStatMsgTest13, 1); UtRegisterTest("DetectEngineHttpStatMsgTest14", DetectEngineHttpStatMsgTest14, 1); UtRegisterTest("DetectEngineHttpStatMsgTest15", DetectEngineHttpStatMsgTest15, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-sid.h0000644000000000000000000000162312253546156013225 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_SID_H__ #define __DETECT_SID_H__ /* prototypes */ void DetectSidRegister (void); #endif /* __DETECT_SID_H__ */ suricata-1.4.7/src/util-ioctl.c0000644000000000000000000000577412253546156013273 00000000000000/* Copyright (C) 2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #include "suricata-common.h" #include "conf.h" #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_NET_IF_H #include #endif /** * \brief output a majorant of hardware header length * * \param Name of a network interface */ int GetIfaceMaxHWHeaderLength(char *pcap_dev) { if ((!strcmp("eth", pcap_dev)) || (!strcmp("br", pcap_dev)) || (!strcmp("bond", pcap_dev)) || (!strcmp("wlan", pcap_dev)) || (!strcmp("tun", pcap_dev)) || (!strcmp("tap", pcap_dev)) || (!strcmp("lo", pcap_dev)) ) return ETHERNET_HEADER_LEN; if ( (!strcmp("ppp", pcap_dev)) ) return SLL_HEADER_LEN; /* SLL_HEADER_LEN is the biggest one */ return SLL_HEADER_LEN; } /** * \brief output the link MTU * * \param Name of link * \retval -1 in case of error, 0 if MTU can not be found */ int GetIfaceMTU(char *pcap_dev) { #ifdef SIOCGIFMTU struct ifreq ifr; int fd; (void)strlcpy(ifr.ifr_name, pcap_dev, sizeof(ifr.ifr_name)); fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { return -1; } if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { SCLogInfo("Failure when trying to get MTU via ioctl: %d", errno); close(fd); return -1; } close(fd); SCLogInfo("Found an MTU of %d for '%s'", ifr.ifr_mtu, pcap_dev); return ifr.ifr_mtu; #else /* ioctl is not defined, let's pretend returning 0 is ok */ return 0; #endif } /** * \brief output max payload size for a link * * This does a best effort to find the maximum packet size * for the link. In case of uncertainty, it will output a * majorant to be sure avoid the cost of dynamic allocation. * * \param Name of a network interface * \retval 0 in case of error */ int GetIfaceMaxPayloadSize(char *pcap_dev) { int ll_header = GetIfaceMaxHWHeaderLength(pcap_dev); int mtu = GetIfaceMTU(pcap_dev); switch (mtu) { case 0: case -1: return 0; } if (ll_header == -1) { /* be conservative, choose a big one */ ll_header = 16; } return ll_header + mtu; } suricata-1.4.7/src/detect-filemagic.c0000644000000000000000000003327612253546156014372 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-spm-bm.h" #include "util-magic.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "stream-tcp.h" #include "detect-filemagic.h" #include "conf.h" #include "util-magic.h" static int DetectFilemagicMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFilemagicSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilemagicRegisterTests(void); static void DetectFilemagicFree(void *); /** * \brief Registration function for keyword: filemagic */ void DetectFilemagicRegister(void) { sigmatch_table[DETECT_FILEMAGIC].name = "filemagic"; sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; sigmatch_table[DETECT_FILEMAGIC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemagic"; sigmatch_table[DETECT_FILEMAGIC].FileMatch = DetectFilemagicMatch; sigmatch_table[DETECT_FILEMAGIC].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetup; sigmatch_table[DETECT_FILEMAGIC].Free = DetectFilemagicFree; sigmatch_table[DETECT_FILEMAGIC].RegisterTests = DetectFilemagicRegisterTests; SCLogDebug("registering filemagic rule option"); return; } #define FILEMAGIC_MIN_SIZE 512 /** * \brief run the magic check * * \param file the file * * \retval -1 error * \retval 0 ok */ int FilemagicGlobalLookup(File *file) { if (file == NULL || file->chunks_head == NULL) { SCReturnInt(-1); } /* initial chunk already matching our requirement */ if (file->chunks_head->len >= FILEMAGIC_MIN_SIZE) { file->magic = MagicGlobalLookup(file->chunks_head->data, FILEMAGIC_MIN_SIZE); } else { uint8_t *buf = SCMalloc(FILEMAGIC_MIN_SIZE); uint32_t size = 0; if (likely(buf != NULL)) { FileData *ffd = file->chunks_head; for ( ; ffd != NULL; ffd = ffd->next) { uint32_t copy_len = ffd->len; if (size + ffd->len > FILEMAGIC_MIN_SIZE) copy_len = FILEMAGIC_MIN_SIZE - size; memcpy(buf + size, ffd->data, copy_len); size += copy_len; if (size >= FILEMAGIC_MIN_SIZE) { file->magic = MagicGlobalLookup(buf, size); break; } /* file is done but smaller than FILEMAGIC_MIN_SIZE */ if (ffd->next == NULL && file->state >= FILE_STATE_CLOSED) { file->magic = MagicGlobalLookup(buf, size); break; } } SCFree(buf); } } SCReturnInt(0); } /** * \brief run the magic check * * \param file the file * * \retval -1 error * \retval 0 ok */ int FilemagicThreadLookup(magic_t *ctx, File *file) { if (ctx == NULL || file == NULL || file->chunks_head == NULL) { SCReturnInt(-1); } /* initial chunk already matching our requirement */ if (file->chunks_head->len >= FILEMAGIC_MIN_SIZE) { file->magic = MagicThreadLookup(ctx, file->chunks_head->data, FILEMAGIC_MIN_SIZE); } else { uint8_t *buf = SCMalloc(FILEMAGIC_MIN_SIZE); uint32_t size = 0; if (likely(buf != NULL)) { FileData *ffd = file->chunks_head; for ( ; ffd != NULL; ffd = ffd->next) { uint32_t copy_len = ffd->len; if (size + ffd->len > FILEMAGIC_MIN_SIZE) copy_len = FILEMAGIC_MIN_SIZE - size; memcpy(buf + size, ffd->data, copy_len); size += copy_len; if (size >= FILEMAGIC_MIN_SIZE) { file->magic = MagicThreadLookup(ctx, buf, size); break; } /* file is done but smaller than FILEMAGIC_MIN_SIZE */ if (ffd->next == NULL && file->state >= FILE_STATE_CLOSED) { file->magic = MagicThreadLookup(ctx, buf, size); break; } } SCFree(buf); } } SCReturnInt(0); } /** * \brief match the specified filemagic * * \param t thread local vars * \param det_ctx pattern matcher thread local data * \param f *LOCKED* flow * \param flags direction flags * \param file file being inspected * \param s signature being inspected * \param m sigmatch that we will cast into DetectFilemagicData * * \retval 0 no match * \retval 1 match */ static int DetectFilemagicMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; DetectFilemagicData *filemagic = (DetectFilemagicData *)m->ctx; if (file->txid < det_ctx->tx_id) SCReturnInt(0); if (file->txid > det_ctx->tx_id) SCReturnInt(0); DetectFilemagicThreadData *tfilemagic = (DetectFilemagicThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, filemagic->thread_ctx_id); if (tfilemagic == NULL) { SCReturnInt(0); } if (file->magic == NULL) { FilemagicThreadLookup(&tfilemagic->ctx, file); } if (file->magic != NULL) { SCLogDebug("magic %s", file->magic); /* we include the \0 in the inspection, so patterns can match on the * end of the string. */ if (BoyerMooreNocase(filemagic->name, filemagic->len, (uint8_t *)file->magic, strlen(file->magic) + 1, filemagic->bm_ctx->bmGs, filemagic->bm_ctx->bmBc) != NULL) { #ifdef DEBUG if (SCLogDebugEnabled()) { char *name = SCMalloc(filemagic->len + 1); if (name != NULL) { memcpy(name, filemagic->name, filemagic->len); name[filemagic->len] = '\0'; SCLogDebug("will look for filemagic %s", name); } } #endif if (!(filemagic->flags & DETECT_CONTENT_NEGATED)) { ret = 1; } } else if (filemagic->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("negated match"); ret = 1; } } SCReturnInt(ret); } /** * \brief Parse the filemagic keyword * * \param idstr Pointer to the user provided option * * \retval filemagic pointer to DetectFilemagicData on success * \retval NULL on failure */ static DetectFilemagicData *DetectFilemagicParse (char *str) { DetectFilemagicData *filemagic = NULL; /* We have a correct filemagic option */ filemagic = SCMalloc(sizeof(DetectFilemagicData)); if (unlikely(filemagic == NULL)) goto error; memset(filemagic, 0x00, sizeof(DetectFilemagicData)); if (DetectParseContentString (str, &filemagic->name, &filemagic->len, &filemagic->flags) == -1) { goto error; } filemagic->bm_ctx = BoyerMooreCtxInit(filemagic->name, filemagic->len); if (filemagic->bm_ctx == NULL) { goto error; } SCLogDebug("flags %02X", filemagic->flags); if (filemagic->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("negated filemagic"); } BoyerMooreCtxToNocase(filemagic->bm_ctx, filemagic->name, filemagic->len); #ifdef DEBUG if (SCLogDebugEnabled()) { char *name = SCMalloc(filemagic->len + 1); if (name != NULL) { memcpy(name, filemagic->name, filemagic->len); name[filemagic->len] = '\0'; SCLogDebug("will look for filemagic %s", name); } } #endif return filemagic; error: if (filemagic != NULL) DetectFilemagicFree(filemagic); return NULL; } static void *DetectFilemagicThreadInit(void *data) { char *filename = NULL; FILE *fd = NULL; DetectFilemagicData *filemagic = (DetectFilemagicData *)data; BUG_ON(filemagic == NULL); DetectFilemagicThreadData *t = SCMalloc(sizeof(DetectFilemagicThreadData)); if (unlikely(t == NULL)) { SCLogError(SC_ERR_LUAJIT_ERROR, "couldn't alloc ctx memory"); return NULL; } memset(t, 0x00, sizeof(DetectFilemagicThreadData)); t->ctx = magic_open(0); if (t->ctx == NULL) { SCLogError(SC_ERR_MAGIC_OPEN, "magic_open failed: %s", magic_error(t->ctx)); goto error; } (void)ConfGet("magic-file", &filename); if (filename != NULL) { SCLogInfo("using magic-file %s", filename); if ( (fd = fopen(filename, "r")) == NULL) { SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } fclose(fd); } if (magic_load(t->ctx, filename) != 0) { SCLogError(SC_ERR_MAGIC_LOAD, "magic_load failed: %s", magic_error(t->ctx)); goto error; } SCLogInfo("returning %p", t); return (void *)t; error: if (t->ctx) magic_close(t->ctx); SCFree(t); return NULL; } static void DetectFilemagicThreadFree(void *ctx) { if (ctx != NULL) { DetectFilemagicThreadData *t = (DetectFilemagicThreadData *)ctx; if (t->ctx) magic_close(t->ctx); SCFree(t); } } /** * \brief this function is used to parse filemagic options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param str pointer to the user provided "filemagic" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectFilemagicData *filemagic = NULL; SigMatch *sm = NULL; filemagic = DetectFilemagicParse(str); if (filemagic == NULL) goto error; filemagic->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "filemagic", DetectFilemagicThreadInit, (void *)filemagic, DetectFilemagicThreadFree, 1); if (filemagic->thread_ctx_id == -1) 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_FILEMAGIC; sm->ctx = (void *)filemagic; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } AppLayerHtpNeedFileInspection(); /** \todo remove this once we support more than http */ s->alproto = ALPROTO_HTTP; s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MAGIC); return 0; error: if (filemagic != NULL) DetectFilemagicFree(filemagic); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectFilemagicData * * \param filemagic pointer to DetectFilemagicData */ static void DetectFilemagicFree(void *ptr) { if (ptr != NULL) { DetectFilemagicData *filemagic = (DetectFilemagicData *)ptr; if (filemagic->bm_ctx != NULL) { BoyerMooreCtxDeInit(filemagic->bm_ctx); } if (filemagic->name != NULL) SCFree(filemagic->name); SCFree(filemagic); } } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectFilemagicTestParse01 */ int DetectFilemagicTestParse01 (void) { DetectFilemagicData *dnd = DetectFilemagicParse("secret.pdf"); if (dnd != NULL) { DetectFilemagicFree(dnd); return 1; } return 0; } /** * \test DetectFilemagicTestParse02 */ int DetectFilemagicTestParse02 (void) { int result = 0; DetectFilemagicData *dnd = DetectFilemagicParse("\"backup.tar.gz\""); if (dnd != NULL) { if (dnd->len == 13 && memcmp(dnd->name, "backup.tar.gz", 13) == 0) { result = 1; } DetectFilemagicFree(dnd); return result; } return 0; } /** * \test DetectFilemagicTestParse03 */ int DetectFilemagicTestParse03 (void) { int result = 0; DetectFilemagicData *dnd = DetectFilemagicParse("cmd.exe"); if (dnd != NULL) { if (dnd->len == 7 && memcmp(dnd->name, "cmd.exe", 7) == 0) { result = 1; } DetectFilemagicFree(dnd); return result; } return 0; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectFilemagic */ void DetectFilemagicRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectFilemagicTestParse01", DetectFilemagicTestParse01, 1); UtRegisterTest("DetectFilemagicTestParse02", DetectFilemagicTestParse02, 1); UtRegisterTest("DetectFilemagicTestParse03", DetectFilemagicTestParse03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-tag.c0000644000000000000000000007045012253546156013220 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file detect-tag.c * * \author Pablo Rincon * \author Victor Julien * * Implements the tag keyword * */ #include "suricata-common.h" #include "detect.h" #include "detect-parse.h" #include "detect-tag.h" #include "detect-engine-tag.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "app-layer-parser.h" #include "debug.h" #include "decode.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "stream-tcp-private.h" #include "util-time.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "threads.h" SC_ATOMIC_EXTERN(unsigned int, num_tags); /* format: tag: , , , [direction]; */ #define PARSE_REGEX "^\\s*(host|session)\\s*(,\\s*(\\d+)\\s*,\\s*(packets|bytes|seconds)\\s*(,\\s*(src|dst))?\\s*)?$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectTagMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectTagSetup (DetectEngineCtx *, Signature *, char *); void DetectTagRegisterTests(void); void DetectTagDataFree(void *); /** * \brief Registration function for keyword tag */ void DetectTagRegister (void) { sigmatch_table[DETECT_TAG].name = "tag"; sigmatch_table[DETECT_TAG].Match = DetectTagMatch; sigmatch_table[DETECT_TAG].Setup = DetectTagSetup; sigmatch_table[DETECT_TAG].Free = DetectTagDataFree; sigmatch_table[DETECT_TAG].RegisterTests = DetectTagRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /** * \brief This function is used to setup a tag for session/host * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectTagData * * \retval 0 no match * \retval 1 match */ int DetectTagMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectTagData *td = (DetectTagData *) m->ctx; DetectTagDataEntry tde; memset(&tde, 0, sizeof(DetectTagDataEntry)); switch (td->type) { case DETECT_TAG_TYPE_HOST: #ifdef DEBUG BUG_ON(!(td->direction == DETECT_TAG_DIR_SRC || td->direction == DETECT_TAG_DIR_DST)); #endif tde.sid = s->id; tde.gid = s->gid; tde.last_ts = tde.first_ts = p->ts.tv_sec; tde.metric = td->metric; tde.count = td->count; if (td->direction == DETECT_TAG_DIR_SRC) tde.flags |= TAG_ENTRY_FLAG_DIR_SRC; else if (td->direction == DETECT_TAG_DIR_DST) tde.flags |= TAG_ENTRY_FLAG_DIR_DST; SCLogDebug("Tagging Host with sid %"PRIu32":%"PRIu32"", s->id, s->gid); TagHashAddTag(&tde, p); break; case DETECT_TAG_TYPE_SESSION: if (p->flow != NULL) { /* If it already exists it will be updated */ tde.sid = s->id; tde.gid = s->gid; tde.last_ts = tde.first_ts = p->ts.tv_sec; tde.metric = td->metric; tde.count = td->count; TagFlowAdd(p, &tde); } else { SCLogDebug("No flow to append the session tag"); } break; #ifdef DEBUG default: SCLogDebug("unknown type of a tag keyword (not session nor host)"); BUG_ON(1); break; #endif } return 1; } /** * \brief This function is used to parse tag options passed to tag keyword * * \param tagstr Pointer to the user provided tag options * * \retval td pointer to DetectTagData on success * \retval NULL on failure */ DetectTagData *DetectTagParse (char *tagstr) { DetectTagData td; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr = NULL; ret = pcre_exec(parse_regex, parse_regex_study, tagstr, strlen(tagstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 ", string %s", ret, tagstr); goto error; } res = pcre_get_substring((char *)tagstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0 || str_ptr == NULL) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* Type */ if (strcasecmp("session", str_ptr) == 0) { td.type = DETECT_TAG_TYPE_SESSION; } else if (strcasecmp("host", str_ptr) == 0) { td.type = DETECT_TAG_TYPE_HOST; } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid argument type. Must be session or host (%s)", tagstr); goto error; } pcre_free_substring(str_ptr); str_ptr = NULL; /* default tag is 256 packets from session or dst host */ td.count = DETECT_TAG_MAX_PKTS; td.metric = DETECT_TAG_METRIC_PACKET; td.direction = DETECT_TAG_DIR_DST; if (ret > 4) { res = pcre_get_substring((char *)tagstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0 || str_ptr == NULL) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* count */ if (ByteExtractStringUint32(&td.count, 10, strlen(str_ptr), str_ptr) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Invalid argument for count. Must be a value in the range of 0 to %"PRIu32" (%s)", UINT32_MAX, tagstr); goto error; } pcre_free_substring(str_ptr); str_ptr = NULL; res = pcre_get_substring((char *)tagstr, ov, MAX_SUBSTRINGS, 4, &str_ptr); if (res < 0 || str_ptr == NULL) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* metric */ if (strcasecmp("packets", str_ptr) == 0) { td.metric = DETECT_TAG_METRIC_PACKET; if (DETECT_TAG_MAX_PKTS > 0 && td.count > DETECT_TAG_MAX_PKTS) td.count = DETECT_TAG_MAX_PKTS; /* TODO: load DETECT_TAG_MAX_PKTS from config */ } else if (strcasecmp("seconds", str_ptr) == 0) { td.metric = DETECT_TAG_METRIC_SECONDS; } else if (strcasecmp("bytes", str_ptr) == 0) { td.metric = DETECT_TAG_METRIC_BYTES; } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid argument metric. Must be one of \"seconds\", \"packets\" or \"bytes\" (%s)", tagstr); goto error; } pcre_free_substring(str_ptr); str_ptr = NULL; /* if specified, overwrite it */ if (ret == 7) { res = pcre_get_substring((char *)tagstr, ov, MAX_SUBSTRINGS, 6, &str_ptr); if (res < 0 || str_ptr == NULL) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* metric */ if (strcasecmp("src", str_ptr) == 0) { td.direction = DETECT_TAG_DIR_SRC; } else if (strcasecmp("dst", str_ptr) == 0) { td.direction = DETECT_TAG_DIR_DST; } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid argument direction. Must be one of \"src\" or \"dst\" (only valid for tag host type, not sessions) (%s)", tagstr); goto error; } if (td.type != DETECT_TAG_TYPE_HOST) { SCLogWarning(SC_ERR_INVALID_VALUE, "Argument direction doesn't make sense for type \"session\" (%s [%"PRIu8"])", tagstr, td.type); } pcre_free_substring(str_ptr); str_ptr = NULL; } } DetectTagData *real_td = SCMalloc(sizeof(DetectTagData)); if (unlikely(real_td == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); goto error; } memcpy(real_td, &td, sizeof(DetectTagData)); return real_td; error: if (str_ptr != NULL) pcre_free_substring(str_ptr); return NULL; } /** * \brief this function is used to add the parsed tag data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param tagstr pointer to the user provided tag options * * \retval 0 on Success * \retval -1 on Failure */ int DetectTagSetup (DetectEngineCtx *de_ctx, Signature *s, char *tagstr) { DetectTagData *td = NULL; SigMatch *sm = NULL; td = DetectTagParse(tagstr); if (td == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_TAG; sm->ctx = (void *)td; /* Append it to the list of tags */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TMATCH); return 0; error: if (td != NULL) DetectTagDataFree(td); if (sm != NULL) SCFree(sm); return -1; } /** \internal * \brief this function will free memory associated with * DetectTagDataEntry * * \param td pointer to DetectTagDataEntry */ static void DetectTagDataEntryFree(void *ptr) { if (ptr != NULL) { DetectTagDataEntry *dte = (DetectTagDataEntry *)ptr; SCFree(dte); } } /** * \brief this function will free all the entries of a list * DetectTagDataEntry * * \param td pointer to DetectTagDataEntryList */ void DetectTagDataListFree(void *ptr) { if (ptr != NULL) { DetectTagDataEntry *entry = ptr; while (entry != NULL) { DetectTagDataEntry *next_entry = entry->next; DetectTagDataEntryFree(entry); (void) SC_ATOMIC_SUB(num_tags, 1); entry = next_entry; } } } /** * \brief this function will free memory associated with DetectTagData * * \param td pointer to DetectTagData */ void DetectTagDataFree(void *ptr) { DetectTagData *td = (DetectTagData *)ptr; SCFree(td); } #ifdef UNITTESTS /** * \test DetectTagTestParse01 is a test to make sure that we return "something" * when given valid tag opt */ int DetectTagTestParse01 (void) { int result = 0; DetectTagData *td = NULL; td = DetectTagParse("session, 123, packets"); if (td != NULL && td->type == DETECT_TAG_TYPE_SESSION && td->count == 123 && td->metric == DETECT_TAG_METRIC_PACKET) { DetectTagDataFree(td); result = 1; } return result; } /** * \test DetectTagTestParse02 is a test to check that we parse tag correctly */ int DetectTagTestParse02 (void) { int result = 0; DetectTagData *td = NULL; td = DetectTagParse("host, 200, bytes, src"); if (td != NULL && td->type == DETECT_TAG_TYPE_HOST && td->count == 200 && td->metric == DETECT_TAG_METRIC_BYTES && td->direction == DETECT_TAG_DIR_SRC) { result = 1; DetectTagDataFree(td); } return result; } /** * \test DetectTagTestParse03 is a test for setting the stateless tag opt */ int DetectTagTestParse03 (void) { int result = 0; DetectTagData *td = NULL; td = DetectTagParse("host, 200, bytes, dst"); if (td != NULL && td->type == DETECT_TAG_TYPE_HOST && td->count == 200 && td->metric == DETECT_TAG_METRIC_BYTES && td->direction == DETECT_TAG_DIR_DST) { result = 1; DetectTagDataFree(td); } return result; } /** * \test DetectTagTestParse04 is a test for default opts */ int DetectTagTestParse04 (void) { int result = 0; DetectTagData *td = NULL; td = DetectTagParse("session"); if (td != NULL && td->type == DETECT_TAG_TYPE_SESSION && td->count == DETECT_TAG_MAX_PKTS && td->metric == DETECT_TAG_METRIC_PACKET) { result = 1; DetectTagDataFree(td); } return result; } /** * \test DetectTagTestParse05 is a test for default opts */ int DetectTagTestParse05 (void) { int result = 0; DetectTagData *td = NULL; td = DetectTagParse("host"); if (td != NULL && td->type == DETECT_TAG_TYPE_HOST && td->count == DETECT_TAG_MAX_PKTS && td->metric == DETECT_TAG_METRIC_PACKET && td->direction == DETECT_TAG_DIR_DST) { result = 1; DetectTagDataFree(td); } return result; } /** * \test DetectTagTestPacket01 is a test to check tagged hosts */ int DetectTagTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; uint16_t buf_len = strlen((char *)buf); uint16_t buf_len2 = strlen((char *)buf2); Packet *p[7]; p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.9", 41424, 80); p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.11", 41424, 80); p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.11", 41424, 80); char *sigs[5]; sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host, 3, packets, src; sid:4;)"; sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host, 4, packets, dst; sid:5;)"; sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:6;)"; sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:2;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ uint32_t sid[5] = {1,2,3,4,5}; int32_t results[7][5] = { {0, 0, 0, 1, 1}, {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }; result = UTHGenericTest(p, 7, sigs, sid, (uint32_t *) results, 5); UTHFreePackets(p, 7); TagRestartCtx(); return result; } /** * \test DetectTagTestPacket02 is a test to check tagged hosts */ int DetectTagTestPacket02 (void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; uint16_t buf_len = strlen((char *)buf); uint16_t buf_len2 = strlen((char *)buf2); DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; Packet *p[7]; p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.9", 41424, 80); p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.11", 41424, 80); p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.11", 41424, 80); char *sigs[5]; sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host, 3, seconds, src; sid:4;)"; sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host, 4, seconds, dst; sid:5;)"; sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:6;)"; sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:2;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ uint32_t sid[5] = {1,2,3,4,5}; int numsigs = 5; if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0) goto cleanup; //de_ctx->flags |= DE_QUIET; int32_t results[7][5] = { {0, 0, 0, 1, 1}, {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }; int num_packets = 7; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int i = 0; for (; i < num_packets; i++) { SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); if (UTHCheckPacketMatchResults(p[i], sid, (uint32_t *)&results[i][0], numsigs) == 0) goto cleanup; if (i == 3) TimeSetIncrementTime(10); } result = 1; cleanup: UTHFreePackets(p, 7); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: TagRestartCtx(); return result; } /** * \test DetectTagTestPacket03 is a test to check tagged hosts */ int DetectTagTestPacket03 (void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; uint16_t buf_len = strlen((char *)buf); uint16_t buf_len2 = strlen((char *)buf2); DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; Packet *p[7]; p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.9", 41424, 80); p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.11", 41424, 80); p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.11", 41424, 80); char *sigs[5]; sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host, 150, bytes, src; sid:4;)"; sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host, 150, bytes, dst; sid:5;)"; sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:6;)"; sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:2;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ uint32_t sid[5] = {1,2,3,4,5}; int numsigs = 5; if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0) goto cleanup; //de_ctx->flags |= DE_QUIET; int32_t results[7][5] = { {0, 0, 0, 1, 1}, {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }; int num_packets = 7; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); uint32_t sum = 0; int i = 0; for (; i < num_packets; i++) { SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); sum += GET_PKT_LEN(p[i]); //printf("Sum %"PRIu32"\n", sum); if (UTHCheckPacketMatchResults(p[i], sid, (uint32_t *)&results[i][0], numsigs) == 0) goto cleanup; } result = 1; cleanup: UTHFreePackets(p, 7); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: TagRestartCtx(); return result; } /** * \test DetectTagTestPacket04 is a test to check tagged hosts */ int DetectTagTestPacket04 (void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; uint16_t buf_len = strlen((char *)buf); uint16_t buf_len2 = strlen((char *)buf2); Flow f; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; if (inet_pton(AF_INET, "192.168.1.5", f.src.addr_data32) != 1) goto end; if (inet_pton(AF_INET, "192.168.1.1", f.dst.addr_data32) != 1) goto end; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; Packet *p[7]; p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 80, 41424); char *sigs[5]; sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:session, 5, packets; sid:4;)"; sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:5;)"; sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:6;)"; sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:2;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ uint32_t sid[5] = {1,2,3,4,5}; int numsigs = 5; if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0) goto cleanup; //de_ctx->flags |= DE_QUIET; int32_t results[7][5] = { {0, 0, 0, 1, 0}, {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }; int num_packets = 7; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); uint32_t sum = 0; int i = 0; for (; i < num_packets; i++) { p[i]->flow = &f; p[i]->flow->protoctx = &ssn; SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); sum += GET_PKT_LEN(p[i]); //printf("Sum %"PRIu32"\n", sum); if (UTHCheckPacketMatchResults(p[i], sid, (uint32_t *)&results[i][0], numsigs) == 0) goto cleanup; } result = 1; cleanup: UTHFreePackets(p, 7); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } FLOW_DESTROY(&f); end: TagRestartCtx(); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectTag */ void DetectTagRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectTagTestParse01", DetectTagTestParse01, 1); UtRegisterTest("DetectTagTestParse02", DetectTagTestParse02, 1); UtRegisterTest("DetectTagTestParse03", DetectTagTestParse03, 1); UtRegisterTest("DetectTagTestParse04", DetectTagTestParse04, 1); UtRegisterTest("DetectTagTestParse05", DetectTagTestParse05, 1); #if 0 As we have changed the way of handling tags, now we do not get an alert of a tagged packet, but the unified plugins write the tags. Now we reach the flag of p->flags & PACKET_HAS_TAG, but we do not know which signature triggered the tag, so this unittests needs to be updated, at least to check the packets one by one for the TAG flag UtRegisterTest("DetectTagTestPacket01", DetectTagTestPacket01, 1); UtRegisterTest("DetectTagTestPacket02", DetectTagTestPacket02, 1); UtRegisterTest("DetectTagTestPacket03", DetectTagTestPacket03, 1); UtRegisterTest("DetectTagTestPacket04", DetectTagTestPacket04, 1); #endif #endif /* UNITTESTS */ } suricata-1.4.7/src/util-threshold-config.h0000644000000000000000000000214212253546156015407 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva Pinto */ #ifndef __UTIL_THRESHOLD_CONFIG_H__ #define __UTIL_THRESHOLD_CONFIG_H__ void SCThresholdConfDeInitContext(DetectEngineCtx *, FILE *); void SCThresholdConfParseFile(DetectEngineCtx *, FILE *); int SCThresholdConfInitContext(DetectEngineCtx *, FILE *); void SCThresholdConfRegisterTests(); #endif /* __UTIL_THRESHOLD_CONFIG_H__ */ suricata-1.4.7/src/tm-modules.c0000644000000000000000000001455212253546156013266 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Thread Module functions */ #include "suricata-common.h" #include "packet-queue.h" #include "tm-threads.h" #include "util-debug.h" #include "threads.h" void TmModuleDebugList(void) { TmModule *t; uint16_t i; for (i = 0; i < TMM_SIZE; i++) { t = &tmm_modules[i]; if (t->name == NULL) continue; SCLogDebug("%s:%p", t->name, t->Func); } } /** \brief get a tm module ptr by name * \param name name string * \retval ptr to the module or NULL */ TmModule *TmModuleGetByName(char *name) { TmModule *t; uint16_t i; for (i = 0; i < TMM_SIZE; i++) { t = &tmm_modules[i]; if (t->name == NULL) continue; if (strcmp(t->name, name) == 0) return t; } return NULL; } /** * \brief Returns a TM Module by its id. * * \param id Id of the TM Module to return. * * \retval Pointer of the module to be returned if available; * NULL if unavailable. */ TmModule *TmModuleGetById(int id) { if (id < 0 || id >= TMM_SIZE) { SCLogError(SC_ERR_TM_MODULES_ERROR, "Threading module with the id " "\"%d\" doesn't exist", id); return NULL; } return &tmm_modules[id]; } /** * \brief Given a TM Module, returns its id. * * \param tm Pointer to the TM Module. * * \retval id of the TM Module if available; -1 if unavailable. */ int TmModuleGetIDForTM(TmModule *tm) { TmModule *t; int i; for (i = 0; i < TMM_SIZE; i++) { t = &tmm_modules[i]; if (strcmp(t->name, tm->name) == 0) return i; } return -1; } /** \brief LogFileNewCtx() Get a new LogFileCtx * \retval LogFileCtx * pointer if succesful, NULL if error * */ LogFileCtx *LogFileNewCtx() { LogFileCtx* lf_ctx; lf_ctx=(LogFileCtx*)SCMalloc(sizeof(LogFileCtx)); if(lf_ctx == NULL) return NULL; memset(lf_ctx, 0, sizeof(LogFileCtx)); SCMutexInit(&lf_ctx->fp_mutex,NULL); return lf_ctx; } /** \brief LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory) * \param motcx pointer to the OutputCtx * \retval int 1 if succesful, 0 if error * */ int LogFileFreeCtx(LogFileCtx *lf_ctx) { if (lf_ctx == NULL) { SCReturnInt(0); } if (lf_ctx->fp != NULL) { SCMutexLock(&lf_ctx->fp_mutex); fflush(lf_ctx->fp); fclose(lf_ctx->fp); SCMutexUnlock(&lf_ctx->fp_mutex); } SCMutexDestroy(&lf_ctx->fp_mutex); if (lf_ctx->prefix != NULL) SCFree(lf_ctx->prefix); if(lf_ctx->filename != NULL) SCFree(lf_ctx->filename); SCFree(lf_ctx); SCReturnInt(1); } void TmModuleRunInit(void) { TmModule *t; uint16_t i; for (i = 0; i < TMM_SIZE; i++) { t = &tmm_modules[i]; if (t->name == NULL) continue; if (t->Init == NULL) continue; t->Init(); } } void TmModuleRunDeInit(void) { TmModule *t; uint16_t i; for (i = 0; i < TMM_SIZE; i++) { t = &tmm_modules[i]; if (t->name == NULL) continue; if (t->DeInit == NULL) continue; t->DeInit(); } } /** \brief register all unittests for the tm modules */ void TmModuleRegisterTests(void) { #ifdef UNITTESTS TmModule *t; uint16_t i; for (i = 0; i < TMM_SIZE; i++) { t = &tmm_modules[i]; if (t->name == NULL) continue; if (t->RegisterTests == NULL) { SCLogDebug("threading module %s has no unittest " "registration function.", t->name); } else { t->RegisterTests(); } } #endif /* UNITTESTS */ } #define CASE_CODE(E) case E: return #E /** * \brief Maps the TmmId, to its string equivalent * * \param id tmm id * * \retval string equivalent for the tmm id */ const char * TmModuleTmmIdToString(TmmId id) { switch (id) { CASE_CODE (TMM_DECODENFQ); CASE_CODE (TMM_VERDICTNFQ); CASE_CODE (TMM_RECEIVENFQ); CASE_CODE (TMM_RECEIVEPCAP); CASE_CODE (TMM_RECEIVEPCAPFILE); CASE_CODE (TMM_DECODEPCAP); CASE_CODE (TMM_DECODEPCAPFILE); CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); CASE_CODE (TMM_DETECT); CASE_CODE (TMM_ALERTFASTLOG); CASE_CODE (TMM_ALERTFASTLOG4); CASE_CODE (TMM_ALERTFASTLOG6); CASE_CODE (TMM_ALERTUNIFIED2ALERT); CASE_CODE (TMM_ALERTPRELUDE); CASE_CODE (TMM_ALERTDEBUGLOG); CASE_CODE (TMM_ALERTSYSLOG); CASE_CODE (TMM_LOGDROPLOG); CASE_CODE (TMM_ALERTSYSLOG4); CASE_CODE (TMM_ALERTSYSLOG6); CASE_CODE (TMM_RESPONDREJECT); CASE_CODE (TMM_LOGHTTPLOG); CASE_CODE (TMM_LOGHTTPLOG4); CASE_CODE (TMM_LOGHTTPLOG6); CASE_CODE (TMM_LOGTLSLOG); CASE_CODE (TMM_LOGTLSLOG4); CASE_CODE (TMM_LOGTLSLOG6); CASE_CODE (TMM_PCAPLOG); CASE_CODE (TMM_FILELOG); CASE_CODE (TMM_FILESTORE); CASE_CODE (TMM_STREAMTCP); CASE_CODE (TMM_DECODEIPFW); CASE_CODE (TMM_VERDICTIPFW); CASE_CODE (TMM_RECEIVEIPFW); #ifdef __SC_CUDA_SUPPORT__ CASE_CODE (TMM_CUDA_MPM_B2G); CASE_CODE (TMM_CUDA_PACKET_BATCHER); #endif CASE_CODE (TMM_RECEIVEERFFILE); CASE_CODE (TMM_DECODEERFFILE); CASE_CODE (TMM_RECEIVEERFDAG); CASE_CODE (TMM_DECODEERFDAG); CASE_CODE (TMM_RECEIVENAPATECH); CASE_CODE (TMM_DECODENAPATECH); CASE_CODE (TMM_RECEIVEAFP); CASE_CODE (TMM_ALERTPCAPINFO); CASE_CODE (TMM_DECODEAFP); default: return "UNKNOWN"; } } suricata-1.4.7/src/util-random.c0000644000000000000000000000246312253546156013431 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * * Utility function for seeding rand */ #include "suricata-common.h" #include "detect.h" #include "threads.h" #include "util-debug.h" /** * \brief create a seed number to pass to rand() , rand_r(), and similars * \retval seed for rand() */ unsigned int RandomTimePreseed(void) { /* preseed rand() */ time_t now = time ( 0 ); unsigned char *p = (unsigned char *)&now; unsigned seed = 0; size_t ind; for ( ind = 0; ind < sizeof now; ind++ ) seed = seed * ( UCHAR_MAX + 2U ) + p[ind]; return seed; } suricata-1.4.7/src/util-coredump-config.h0000644000000000000000000000165612253546156015242 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eileen Donlon */ #ifndef __COREDUMP_CONFIG_H__ #define __COREDUMP_CONFIG_H__ #include "suricata-common.h" int32_t CoredumpLoadConfig (void); #endif /* __COREDUMP_CONFIG_H__ */ suricata-1.4.7/src/app-layer-tls-handshake.h0000644000000000000000000000333412253546156015617 00000000000000/* * Copyright (C) 2011-2012 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * \author Pierre Chifflier * */ #ifndef __APP_LAYER_TLS_HANDSHAKE_H__ #define __APP_LAYER_TLS_HANDSHAKE_H__ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uint32_t input_len); #endif /* __APP_LAYER_TLS_HANDSHAKE_H__ */ suricata-1.4.7/src/decode-ppp.c0000644000000000000000000002021312253546156013207 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Breno Silva Pinto * * Decode PPP */ #include "suricata-common.h" #include "decode.h" #include "decode-ppp.h" #include "decode-events.h" #include "flow.h" #include "util-unittest.h" #include "util-debug.h" void DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_ppp, tv->sc_perf_pca); if(len < PPP_HEADER_LEN) { ENGINE_SET_EVENT(p,PPP_PKT_TOO_SMALL); return; } p->ppph = (PPPHdr *)pkt; if(p->ppph == NULL) return; SCLogDebug("p %p pkt %p PPP protocol %04x Len: %" PRId32 "", p, pkt, ntohs(p->ppph->protocol), len); switch (ntohs(p->ppph->protocol)) { case PPP_VJ_COMP: case PPP_IPX: case PPP_OSI: case PPP_NS: case PPP_DECNET: case PPP_APPLE: case PPP_BRPDU: case PPP_STII: case PPP_VINES: case PPP_HELLO: case PPP_LUXCOM: case PPP_SNS: case PPP_MPLS_UCAST: case PPP_MPLS_MCAST: case PPP_IPCP: case PPP_OSICP: case PPP_NSCP: case PPP_DECNETCP: case PPP_APPLECP: case PPP_IPXCP: case PPP_STIICP: case PPP_VINESCP: case PPP_IPV6CP: case PPP_MPLSCP: case PPP_LCP: case PPP_PAP: case PPP_LQM: case PPP_CHAP: ENGINE_SET_EVENT(p,PPP_UNSUP_PROTO); break; case PPP_VJ_UCOMP: if(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p,PPPVJU_PKT_TOO_SMALL); return; } if(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + PPP_HEADER_LEN)) == 4) { DecodeIPV4(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); } break; case PPP_IP: if(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p,PPPIPV4_PKT_TOO_SMALL); return; } DecodeIPV4(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); break; /* PPP IPv6 was not tested */ case PPP_IPV6: if(len < (PPP_HEADER_LEN + IPV6_HEADER_LEN)) { ENGINE_SET_EVENT(p,PPPIPV6_PKT_TOO_SMALL); return; } DecodeIPV6(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); break; default: SCLogDebug("unknown PPP protocol: %" PRIx32 "",ntohs(p->ppph->protocol)); ENGINE_SET_EVENT(p,PPP_WRONG_TYPE); return; } return; } /* TESTS BELOW */ #ifdef UNITTESTS /* DecodePPPtest01 * Decode malformed ip layer PPP packet * Expected test value: 1 */ static int DecodePPPtest01 (void) { uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp), NULL); /* Function my returns here with expected value */ if(ENGINE_ISSET_EVENT(p,PPPIPV4_PKT_TOO_SMALL)) { SCFree(p); return 1; } SCFree(p); return 0; } /* DecodePPPtest02 * Decode malformed ppp layer packet * Expected test value: 1 */ static int DecodePPPtest02 (void) { uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0xff, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00, 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp), NULL); /* Function must returns here */ if(ENGINE_ISSET_EVENT(p,PPP_WRONG_TYPE)) { SCFree(p); return 1; } SCFree(p); return 0; } /** DecodePPPtest03 * \brief Decode good PPP packet, additionally the IPv4 packet inside is * 4 bytes short. * \retval 0 Test failed * \retval 1 Test succeeded */ static int DecodePPPtest03 (void) { uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00, 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp), NULL); FlowShutdown(); if(p->ppph == NULL) { SCFree(p); return 0; } if(ENGINE_ISSET_EVENT(p,PPP_PKT_TOO_SMALL)) { SCFree(p); return 0; } if(ENGINE_ISSET_EVENT(p,PPPIPV4_PKT_TOO_SMALL)) { SCFree(p); return 0; } if(ENGINE_ISSET_EVENT(p,PPP_WRONG_TYPE)) { SCFree(p); return 0; } if (!(ENGINE_ISSET_EVENT(p,IPV4_TRUNC_PKT))) { SCFree(p); return 0; } /* Function must return here */ SCFree(p); return 1; } /* DecodePPPtest04 * Check if ppp header is null * Expected test value: 1 */ static int DecodePPPtest04 (void) { uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00, 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp), NULL); FlowShutdown(); if(p->ppph == NULL) { SCFree(p); return 0; } if (!(ENGINE_ISSET_EVENT(p,IPV4_TRUNC_PKT))) { SCFree(p); return 0; } /* Function must returns here */ SCFree(p); return 1; } #endif /* UNITTESTS */ void DecodePPPRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodePPPtest01", DecodePPPtest01, 1); UtRegisterTest("DecodePPPtest02", DecodePPPtest02, 1); UtRegisterTest("DecodePPPtest03", DecodePPPtest03, 1); UtRegisterTest("DecodePPPtest04", DecodePPPtest04, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/threadvars.h0000644000000000000000000000750012253546156013343 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __THREADVARS_H__ #define __THREADVARS_H__ #include "util-mpm.h" #include "util-affinity.h" #include "tm-queues.h" #include "counters.h" #include "threads.h" struct TmSlot_; /** Thread flags set and read by threads to control the threads */ #define THV_USE 1 /** thread is in use */ #define THV_INIT_DONE (1 << 1) /** thread initialization done */ #define THV_PAUSE (1 << 2) /** signal thread to pause itself */ #define THV_PAUSED (1 << 3) /** the thread is paused atm */ #define THV_KILL (1 << 4) /** thread has been asked to cleanup and exit */ #define THV_FAILED (1 << 5) /** thread has encountered an error and failed */ #define THV_CLOSED (1 << 6) /** thread done, should be joinable */ /* used to indicate the thread is going through de-init. Introduced as more * of a hack for solving stream-timeout-shutdown. Is set by the main thread. */ #define THV_DEINIT (1 << 7) #define THV_RUNNING_DONE (1 << 8) /** thread has completed running and is entering * the de-init phase */ /** Thread flags set and read by threads, to control the threads, when they * encounter certain conditions like failure */ #define THV_RESTART_THREAD 0x01 /** restart the thread */ #define THV_ENGINE_EXIT 0x02 /** shut the engine down gracefully */ /** Maximum no of times a thread can be restarted */ #define THV_MAX_RESTARTS 50 /** \brief Per thread variable structure */ typedef struct ThreadVars_ { pthread_t t; char *name; char *thread_group_name; SC_ATOMIC_DECLARE(unsigned short, flags); /** aof(action on failure) determines what should be done with the thread when it encounters certain conditions like failures */ uint8_t aof; /** the type of thread as defined in tm-threads.h (TVT_PPT, TVT_MGMT) */ uint8_t type; /** no of times the thread has been restarted on failure */ uint8_t restarted; /** queue's */ Tmq *inq; Tmq *outq; void *outctx; char *outqh_name; /** queue handlers */ struct Packet_ * (*tmqh_in)(struct ThreadVars_ *); void (*InShutdownHandler)(struct ThreadVars_ *); void (*tmqh_out)(struct ThreadVars_ *, struct Packet_ *); /** slot functions */ void *(*tm_func)(void *); struct TmSlot_ *tm_slots; uint8_t thread_setup_flags; uint16_t cpu_affinity; /** cpu or core number to set affinity to */ int thread_priority; /** priority (real time) for this thread. Look at threads.h */ /* the perf counter context and the perf counter array */ SCPerfContext sc_perf_pctx; SCPerfCounterArray *sc_perf_pca; SCMutex *m; SCCondT *cond; uint8_t cap_flags; /**< Flags to indicate the capabilities of all the TmModules resgitered under this thread */ struct ThreadVars_ *next; struct ThreadVars_ *prev; } ThreadVars; /** Thread setup flags: */ #define THREAD_SET_AFFINITY 0x01 /** CPU/Core affinity */ #define THREAD_SET_PRIORITY 0x02 /** Real time priority */ #define THREAD_SET_AFFTYPE 0x04 /** Priority and affinity */ #endif /* __THREADVARS_H__ */ suricata-1.4.7/src/detect-engine-hrud.c0000644000000000000000000027433712253546156014664 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP raw uri match */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-hrud.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" /** * \brief Run the mpm against raw http uris. * * \retval cnt Number of matches reported by the mpm algo. */ int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { SCEnter(); uint32_t cnt = 0; if (htp_state == NULL) { SCLogDebug("no HTTP state"); SCReturnInt(0); } /* locking the flow, we will inspect the htp state */ FLOWLOCK_RDLOCK(f); if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } int idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } htp_tx_t *tx = NULL; int size = (int)list_size(htp_state->connp->conn->transactions); for ( ; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->request_uri == NULL) continue; cnt += HttpRawUriPatternSearch(det_ctx, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri), flags); } end: FLOWLOCK_UNLOCK(f); SCReturnInt(cnt); } /** * \brief Do the http_raw_uri content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpRawUri(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL || tx->request_uri == NULL) return 0; det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; /* Inspect all the uricontents fetched on each * transaction at the app layer */ int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRUDMATCH], f, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRUD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS static int DetectEngineHttpRawUriTest01(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a/b/../c"; uint8_t http2_buf[] = "/./d.html HTTP/1.1\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"../c/./d\"; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest02(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 19\r\n" "\r\n" "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"/c/./d\"; http_raw_uri; offset:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest03(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a/b/../"; uint8_t http2_buf[] = "c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"/a/b\"; http_raw_uri; offset:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest04(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a/b/../"; uint8_t http2_buf[] = "c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:!\"/a/b\"; http_raw_uri; offset:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest05(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a/b/"; uint8_t http2_buf[] = "../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"a/b\"; http_raw_uri; depth:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest06(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a/b/"; uint8_t http2_buf[] = "../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:!\"/a/b\"; http_raw_uri; depth:25; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a/b/"; uint8_t http2_buf[] = "../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:!\"/c/./d\"; http_raw_uri; depth:12; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a/"; uint8_t http2_buf[] = "b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:!\"/c/./d\"; http_raw_uri; depth:18; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"/a\"; http_raw_uri; " "content:\"./c/.\"; http_raw_uri; within:9; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"/a\"; http_raw_uri; " "content:!\"boom\"; http_raw_uri; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest11(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"./a\"; http_raw_uri; " "content:\"boom\"; http_raw_uri; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest12(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"./a\"; http_raw_uri; " "content:!\"/b/..\"; http_raw_uri; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest13(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"./a\"; http_raw_uri; " "content:\"/c/.\"; http_raw_uri; distance:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest14(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"./a\"; http_raw_uri; " "content:!\"b/..\"; http_raw_uri; distance:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest15(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"./a\"; http_raw_uri; " "content:\"/c/\"; http_raw_uri; distance:7; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest16(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"./a\"; http_raw_uri; " "content:!\"/c/\"; http_raw_uri; distance:4; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest17(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http1_buf[] = "This_is_dummy_body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"body1\"; http_raw_uri; " "content:\"bambu\"; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); if (r != 1) { printf("expected 1 result, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpRawUriTest18(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http1_buf[] = "This_is_dummy_body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"body1\"; http_raw_uri; " "content:\"bambu\"; http_raw_uri; fast_pattern; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); if (r != 0) { printf("expected 0 result, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpRawUriTest19(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http1_buf[] = "This_is_dummy_body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"bambu\"; http_raw_uri; " "content:\"is\"; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); if (r != 0) { printf("expected 0 result, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpRawUriTest20(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http1_buf[] = "This_is_dummy_body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "content:\"bambu\"; http_raw_uri; " "content:\"is\"; http_raw_uri; fast_pattern; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); if (r != 2) { printf("expected 2 result, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpRawUriTest21(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "pcre:/\\.\\/a/I; " "content:!\"/c/\"; http_raw_uri; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest22(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "pcre:/\\.\\/a/I; " "content:!\"/c/\"; within:5; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest23(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "pcre:/\\.\\/a/I; " "content:!\"/c/\"; distance:3; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest24(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "pcre:/\\.\\/a/I; " "content:!\"/c/\"; distance:10; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest25(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "pcre:/\\.\\/a/I; " "content:\"/c/\"; within:10; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest26(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "pcre:/\\.\\/a/I; " "content:\"/c/\"; within:5; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest27(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "pcre:/\\.\\/a/I; " "content:\"/c/\"; distance:5; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpRawUriTest28(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /../a"; uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1" "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http raw uri test\"; " "pcre:/\\.\\/a/I; " "content:\"/c/\"; distance:10; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** * \test Test multiple relative contents with a negated content. */ static int DetectEngineHttpRawUriTest29(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /../a/b/../c/./d.html HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative raw uri contents\"; " "content:\"/c/\"; http_raw_uri; " "isdataat:4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test Test multiple relative contents with a negated content. */ static int DetectEngineHttpRawUriTest30(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /../a/b/../c/./d.html HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; HtpState *http_state = NULL; Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(http_buf, http_buf_len, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test multiple relative raw uri contents\"; " "uricontent:\"/c/\"; isdataat:!10,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should have: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } #endif /* UNITTESTS */ void DetectEngineHttpRawUriRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpRawUriTest01", DetectEngineHttpRawUriTest01, 1); UtRegisterTest("DetectEngineHttpRawUriTest02", DetectEngineHttpRawUriTest02, 1); UtRegisterTest("DetectEngineHttpRawUriTest03", DetectEngineHttpRawUriTest03, 1); UtRegisterTest("DetectEngineHttpRawUriTest04", DetectEngineHttpRawUriTest04, 1); UtRegisterTest("DetectEngineHttpRawUriTest05", DetectEngineHttpRawUriTest05, 1); UtRegisterTest("DetectEngineHttpRawUriTest06", DetectEngineHttpRawUriTest06, 1); UtRegisterTest("DetectEngineHttpRawUriTest07", DetectEngineHttpRawUriTest07, 1); UtRegisterTest("DetectEngineHttpRawUriTest08", DetectEngineHttpRawUriTest08, 1); UtRegisterTest("DetectEngineHttpRawUriTest09", DetectEngineHttpRawUriTest09, 1); UtRegisterTest("DetectEngineHttpRawUriTest10", DetectEngineHttpRawUriTest10, 1); UtRegisterTest("DetectEngineHttpRawUriTest11", DetectEngineHttpRawUriTest11, 1); UtRegisterTest("DetectEngineHttpRawUriTest12", DetectEngineHttpRawUriTest12, 1); UtRegisterTest("DetectEngineHttpRawUriTest13", DetectEngineHttpRawUriTest13, 1); UtRegisterTest("DetectEngineHttpRawUriTest14", DetectEngineHttpRawUriTest14, 1); UtRegisterTest("DetectEngineHttpRawUriTest15", DetectEngineHttpRawUriTest15, 1); UtRegisterTest("DetectEngineHttpRawUriTest16", DetectEngineHttpRawUriTest16, 1); UtRegisterTest("DetectEngineHttpRawUriTest17", DetectEngineHttpRawUriTest17, 1); UtRegisterTest("DetectEngineHttpRawUriTest18", DetectEngineHttpRawUriTest18, 1); UtRegisterTest("DetectEngineHttpRawUriTest19", DetectEngineHttpRawUriTest19, 1); UtRegisterTest("DetectEngineHttpRawUriTest20", DetectEngineHttpRawUriTest20, 1); UtRegisterTest("DetectEngineHttpRawUriTest21", DetectEngineHttpRawUriTest21, 1); UtRegisterTest("DetectEngineHttpRawUriTest22", DetectEngineHttpRawUriTest22, 1); UtRegisterTest("DetectEngineHttpRawUriTest23", DetectEngineHttpRawUriTest23, 1); UtRegisterTest("DetectEngineHttpRawUriTest24", DetectEngineHttpRawUriTest24, 1); UtRegisterTest("DetectEngineHttpRawUriTest25", DetectEngineHttpRawUriTest25, 1); UtRegisterTest("DetectEngineHttpRawUriTest26", DetectEngineHttpRawUriTest26, 1); UtRegisterTest("DetectEngineHttpRawUriTest27", DetectEngineHttpRawUriTest27, 1); UtRegisterTest("DetectEngineHttpRawUriTest28", DetectEngineHttpRawUriTest28, 1); UtRegisterTest("DetectEngineHttpRawUriTest29", DetectEngineHttpRawUriTest29, 1); UtRegisterTest("DetectEngineHttpRawUriTest30", DetectEngineHttpRawUriTest30, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/util-decode-der.h0000644000000000000000000000641212253546156014147 00000000000000/* * Copyright (C) 2011-2012 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * \author Pierre Chifflier * */ #ifndef __UTIL_DECODE_DER_H__ #define __UTIL_DECODE_DER_H__ #define ASN1_CLASS_UNIVERSAL 0 #define ASN1_CLASS_APPLICATION 1 #define ASN1_CLASS_CONTEXTSPEC 2 #define ASN1_CLASS_PRIVATE 3 #define ASN1_UNKNOWN 0 #define ASN1_BOOLEAN 0x01 #define ASN1_INTEGER 0x02 #define ASN1_BITSTRING 0x03 #define ASN1_OCTETSTRING 0x04 #define ASN1_NULL 0x05 #define ASN1_OID 0x06 #define ASN1_UTF8STRING 0x0c #define ASN1_SEQUENCE 0x10 #define ASN1_SET 0x11 #define ASN1_PRINTSTRING 0x13 #define ASN1_T61STRING 0x14 #define ASN1_IA5STRING 0x16 #define ASN1_UTCTIME 0x17 typedef struct Asn1ElementType_ { uint8_t cls:2; uint8_t pc:1; uint8_t tag:5; } __attribute__((packed)) Asn1ElementType; /* Generic ASN.1 element * Presence and meaning of fields depends on the header and type values. */ typedef struct Asn1Generic_ { Asn1ElementType header; uint8_t type; uint32_t length; /* length of node, including header */ struct Asn1Generic_ *data; /* only if type is structured */ char *str; uint32_t strlen; uint64_t value; struct Asn1Generic_ *next; /* only if type is sequence */ } Asn1Generic; /* Generic error */ #define ERR_DER_GENERIC 0x01 /* Unknown ASN.1 element type */ #define ERR_DER_UNKNOWN_ELEMENT 0x02 /* One element requires to read more bytes than available */ #define ERR_DER_ELEMENT_SIZE_TOO_BIG 0x03 /* One element size is invalid (more than 4 bytes long) */ #define ERR_DER_INVALID_SIZE 0x04 /* Unsupported string type */ #define ERR_DER_UNSUPPORTED_STRING 0x05 /* Missing field or element */ #define ERR_DER_MISSING_ELEMENT 0x06 Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *errcode); void DerFree(Asn1Generic *a); #endif /* __UTIL_DECODE_DER_H__ */ suricata-1.4.7/src/util-cuda.h0000644000000000000000000001743612253546156013100 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_CUDA__H__ #define __UTIL_CUDA__H__ #ifdef __SC_CUDA_SUPPORT__ #include #define SC_CUDA_DEFAULT_DEVICE 0 #define SC_CUDA_DEVICE_NAME_MAX_LEN 128 typedef struct SCCudaDevice_ { /* device id */ CUdevice device; /* device name */ char name[SC_CUDA_DEVICE_NAME_MAX_LEN]; /* device compute capability */ int major_rev; int minor_rev; /* device properties */ CUdevprop prop; /* device total memory */ unsigned int bytes; /* device attributes. We could have used a fixed int array table to hold * the attributes, but it is better we specify it exclusively this way, * since the usage would be less error prone */ int attr_max_threads_per_block; int attr_max_block_dim_x; int attr_max_block_dim_y; int attr_max_block_dim_z; int attr_max_grid_dim_x; int attr_max_grid_dim_y; int attr_max_grid_dim_z; int attr_max_shared_memory_per_block; int attr_total_constant_memory; int attr_warp_size; int attr_max_pitch; int attr_max_registers_per_block; int attr_clock_rate; int attr_texture_alignment; int attr_gpu_overlap; int attr_multiprocessor_count; int attr_kernel_exec_timeout; int attr_integrated; int attr_can_map_host_memory; int attr_compute_mode; } SCCudaDevice; typedef struct SCCudaDevices_ { int count; SCCudaDevice **devices; } SCCudaDevices; int SCCudaArray3DCreate(CUarray *, const CUDA_ARRAY3D_DESCRIPTOR *); int SCCudaArray3DGetDescriptor(CUDA_ARRAY3D_DESCRIPTOR *, CUarray); int SCCudaArrayCreate(CUarray *, const CUDA_ARRAY_DESCRIPTOR *); int SCCudaArrayDestroy(CUarray); int SCCudaArrayGetDescriptor(CUDA_ARRAY_DESCRIPTOR *, CUarray); int SCCudaMemAlloc(CUdeviceptr *dptr, unsigned int); int SCCudaMemAllocHost(void **, unsigned int); int SCCudaMemAllocPitch(CUdeviceptr *, unsigned int *, unsigned int, unsigned int, unsigned int); int SCCudaMemcpy2D(const CUDA_MEMCPY2D *); int SCCudaMemcpy2DAsync(const CUDA_MEMCPY2D *, CUstream); int SCCudaMemcpy2DUnaligned(const CUDA_MEMCPY2D *); int SCCudaMemcpy3D(const CUDA_MEMCPY3D *); int SCCudaMemcpy3DAsync(const CUDA_MEMCPY3D *, CUstream); int SCCudaMemcpyAtoA(CUarray, unsigned int, CUarray, unsigned int, unsigned int); int SCCudaMemcpyAtoD(CUdeviceptr, CUarray, unsigned int, unsigned int); int SCCudaMemcpyAtoH(void *, CUarray, unsigned int, unsigned int); int SCCudaMemcpyAtoHAsync(void *, CUarray, unsigned int, unsigned int, CUstream); int SCCudaMemcpyDtoA(CUarray, unsigned int, CUdeviceptr, unsigned int); int SCCudaMemcpyDtoD(CUdeviceptr, CUdeviceptr, unsigned int byte_count); int SCCudaMemcpyDtoH(void *, CUdeviceptr, unsigned int); int SCCudaMemcpyDtoHAsync(void *, CUdeviceptr, unsigned int, CUstream); int SCCudaMemcpyHtoA(CUarray, unsigned int, const void *, unsigned int); int SCCudaMemcpyHtoAAsync(CUarray, unsigned int, const void *, unsigned int, CUstream); int SCCudaMemcpyHtoD(CUdeviceptr, const void *, unsigned int); int SCCudaMemcpyHtoDAsync(CUdeviceptr, const void *, unsigned int, CUstream); int SCCudaMemFree(CUdeviceptr); int SCCudaMemFreeHost(void *); int SCCudaMemGetAddressRange(CUdeviceptr *, unsigned int *, CUdeviceptr); int SCCudaMemGetInfo(unsigned int *, unsigned int *); int SCCudaMemHostAlloc(void **, size_t, unsigned int); int SCCudaMemHostGetDevicePointer(CUdeviceptr *, void *, unsigned int); int SCCudaMemHostGetFlags(unsigned int *, void *); int SCCudaMemsetD16(CUdeviceptr, unsigned short, unsigned int); int SCCudaMemsetD2D16(CUdeviceptr, unsigned int, unsigned short, unsigned int, unsigned int); int SCCudaMemsetD2D32(CUdeviceptr, unsigned int, unsigned int, unsigned int, unsigned int); int SCCudaMemsetD2D8(CUdeviceptr, unsigned int, unsigned char, unsigned int, unsigned int); int SCCudaMemsetD32(CUdeviceptr, unsigned int, unsigned int); int SCCudaMemsetD8(CUdeviceptr, unsigned char, unsigned int); int SCCudaTexRefCreate(CUtexref *); int SCCudaTexRefDestroy(CUtexref); int SCCudaTexRefGetAddress(CUdeviceptr *, CUtexref); int SCCudaTexRefGetAddressMode(CUaddress_mode *, CUtexref, int); int SCCudaTexRefGetArray(CUarray *, CUtexref); int SCCudaTexRefGetFilterMode(CUfilter_mode *, CUtexref); int SCCudaTexRefGetFlags(unsigned int *, CUtexref); int SCCudaTexRefGetFormat(CUarray_format *, int *, CUtexref); int SCCudaTexRefSetAddress(unsigned int *, CUtexref, CUdeviceptr, unsigned int); int SCCudaTexRefSetAddress2D(CUtexref, const CUDA_ARRAY_DESCRIPTOR *, CUdeviceptr, unsigned int); int SCCudaTexRefSetAddressMode(CUtexref, int, CUaddress_mode); int SCCudaTexRefSetArray(CUtexref, CUarray, unsigned int); int SCCudaTexRefSetFilterMode(CUtexref, CUfilter_mode); int SCCudaTexRefSetFlags(CUtexref, unsigned int); int SCCudaTexRefSetFormat(CUtexref, CUarray_format, int); int SCCudaFuncGetAttribute(int *, CUfunction_attribute, CUfunction); int SCCudaFuncSetBlockShape(CUfunction, int, int, int); int SCCudaFuncSetSharedSize(CUfunction, unsigned int); int SCCudaLaunch(CUfunction); int SCCudaLaunchGrid(CUfunction, int, int); int SCCudaLaunchGridAsync(CUfunction, int, int, CUstream); int SCCudaParamSetf(CUfunction, int, float); int SCCudaParamSeti(CUfunction, int, unsigned int); int SCCudaParamSetSize(CUfunction, unsigned int); int SCCudaParamSetTexRef(CUfunction, int, CUtexref); int SCCudaParamSetv(CUfunction, int, void *, unsigned int); int SCCudaEventCreate(CUevent *, unsigned int); int SCCudaEventDestroy(CUevent); int SCCudaEventElapsedTime(float *, CUevent, CUevent); int SCCudaEventQuery(CUevent); int SCCudaEventRecord(CUevent, CUstream); int SCCudaEventSynchronize(CUevent); int SCCudaStreamCreate(CUstream *, unsigned int); int SCCudaStreamDestroy(CUstream); int SCCudaStreamQuery(CUstream); int SCCudaStreamSynchronize(CUstream); int SCCudaModuleGetFunction(CUfunction *, CUmodule, const char *); int SCCudaModuleGetGlobal(CUdeviceptr *, unsigned int *, CUmodule, const char *); int SCCudaModuleGetTexRef(CUtexref *, CUmodule, const char *); int SCCudaModuleLoad(CUmodule *, const char *); int SCCudaModuleLoadData(CUmodule *, const char *); int SCCudaModuleLoadDataEx(CUmodule *, const char *, unsigned int, CUjit_option *, void **); int SCCudaModuleLoadFatBinary(CUmodule *, const void *); int SCCudaModuleUnload(CUmodule); int SCCudaCtxAttach(CUcontext *, unsigned int); int SCCudaCtxCreate(CUcontext *, unsigned int, CUdevice); int SCCudaCtxDestroy(CUcontext); int SCCudaCtxDetach(CUcontext); int SCCudaCtxGetDevice(CUdevice *); int SCCudaCtxPopCurrent(CUcontext *); int SCCudaCtxPushCurrent(CUcontext); int SCCudaCtxSynchronize(void); int SCCudaDriverGetVersion(int *); void SCCudaPrintDeviceList(SCCudaDevices *); void SCCudaPrintBasicDeviceInfo(SCCudaDevices *); SCCudaDevices *SCCudaGetDeviceList(void); int SCCudaInitCudaEnvironment(void); void SCCudaListCards(void); int SCCudaIsCudaDeviceIdValid(int); void SCCudaRegisterTests(void); #endif /* __SC_CUDA_SUPPORT__ */ #endif /* __UTIL_CUDA_H__ */ suricata-1.4.7/src/util-spm-bm.c0000644000000000000000000002360112253546156013341 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * Boyer Moore simple pattern matcher implementation * * Boyer Moore algorithm has a really good performance. It need to arrays * of context for each pattern that hold applicable shifts on the text * to seach in, based on characters not available in the pattern * and combinations of characters that start a sufix on the pattern. * If possible, we should store the context of patterns that we are going * to search for multiple times, so we don't spend time on rebuilding them. */ #include "suricata-common.h" #include "suricata.h" #include "util-spm-bm.h" #include "util-debug.h" #include "util-error.h" /** * \brief Given a BmCtx structure, recreate the pre/suffixes for * nocase * * \retval BmCtx pointer to the already created BmCtx (with BoyerMooreCtxInit()) * \param str pointer to the pattern string * \param size length of the string */ void BoyerMooreCtxToNocase(BmCtx *bm_ctx, uint8_t *needle, uint16_t needle_len) { /* Prepare bad chars with nocase chars */ PreBmBcNocase(needle, needle_len, bm_ctx->bmBc); /* Prepare good Suffixes with nocase chars */ PreBmGsNocase(needle, needle_len, bm_ctx->bmGs); } /** * \brief Setup a Booyer More context. * * \param str pointer to the pattern string * \param size length of the string * \retval BmCtx pointer to the newly created Context for the pattern * \initonly BoyerMoore contexts should be created at init */ BmCtx *BoyerMooreCtxInit(uint8_t *needle, uint16_t needle_len) { BmCtx *new = SCMalloc(sizeof(BmCtx)); if (unlikely(new == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in BoyerMooreCtxInit. Exiting..."); exit(EXIT_FAILURE); } /* Prepare bad chars */ PreBmBc(needle, needle_len, new->bmBc); new->bmGs = SCMalloc(sizeof(uint16_t) * (needle_len + 1)); if (new->bmGs == NULL) { exit(EXIT_FAILURE); } /* Prepare good Suffixes */ if (PreBmGs(needle, needle_len, new->bmGs) == -1) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in BooyerMooreCtxInit. Exiting..."); exit(EXIT_FAILURE); } return new; } /** * \brief Free the memory allocated to Booyer More context. * * \param bmCtx pointer to the Context for the pattern */ void BoyerMooreCtxDeInit(BmCtx *bmctx) { SCEnter(); if (bmctx == NULL) SCReturn; if (bmctx->bmGs != NULL) SCFree(bmctx->bmGs); SCFree(bmctx); SCReturn; } /** * \brief Array setup function for bad characters that split the pattern * Remember that the result array should be the length of ALPHABET_SIZE * * \param str pointer to the pattern string * \param size length of the string * \param result pointer to an empty array that will hold the badchars */ void PreBmBc(const uint8_t *x, uint16_t m, uint16_t *bmBc) { int32_t i; for (i = 0; i < 256; ++i) { bmBc[i] = m; } for (i = 0; i < m - 1; ++i) { bmBc[(unsigned char)x[i]] = m - i - 1; } } /** * \brief Array setup function for building prefixes (shift for valid prefixes) for boyermoore context * * \param x pointer to the pattern string * \param m length of the string * \param suff pointer to an empty array that will hold the prefixes (shifts) */ void BoyerMooreSuffixes(const uint8_t *x, uint16_t m, uint16_t *suff) { int32_t f = 0, g, i; suff[m - 1] = m; g = m - 1; for (i = m - 2; i >= 0; --i) { if (i > g && suff[i + m - 1 - f] < i - g) suff[i] = suff[i + m - 1 - f]; else { if (i < g) g = i; f = i; while (g >= 0 && x[g] == x[g + m - 1 - f]) --g; suff[i] = f - g; } } } /** * \brief Array setup function for building prefixes (shift for valid prefixes) for boyermoore context * * \param x pointer to the pattern string * \param m length of the string * \param bmGs pointer to an empty array that will hold the prefixes (shifts) * \retval 0 ok, -1 failed */ int PreBmGs(const uint8_t *x, uint16_t m, uint16_t *bmGs) { int32_t i, j; uint16_t *suff; suff = SCMalloc(sizeof(uint16_t) * (m + 1)); if (unlikely(suff == NULL)) return -1; BoyerMooreSuffixes(x, m, suff); for (i = 0; i < m; ++i) bmGs[i] = m; j = 0; for (i = m - 1; i >= -1; --i) if (i == -1 || suff[i] == i + 1) for (; j < m - 1 - i; ++j) if (bmGs[j] == m) bmGs[j] = m - 1 - i; for (i = 0; i <= m - 2; ++i) bmGs[m - 1 - suff[i]] = m - 1 - i; SCFree(suff); return 0; } /** * \brief Array setup function for bad characters that split the pattern * Remember that the result array should be the length of ALPHABET_SIZE * * \param str pointer to the pattern string * \param size length of the string * \param result pointer to an empty array that will hold the badchars */ void PreBmBcNocase(const uint8_t *x, uint16_t m, uint16_t *bmBc) { int32_t i; for (i = 0; i < 256; ++i) { bmBc[i] = m; } for (i = 0; i < m - 1; ++i) { bmBc[u8_tolower((unsigned char)x[i])] = m - 1 - i; } } void BoyerMooreSuffixesNocase(const uint8_t *x, uint16_t m, uint16_t *suff) { int32_t f = 0, g, i; suff[m - 1] = m; g = m - 1; for (i = m - 2; i >= 0; --i) { if (i > g && suff[i + m - 1 - f] < i - g) { suff[i] = suff[i + m - 1 - f]; } else { if (i < g) { g = i; } f = i; while (g >= 0 && u8_tolower(x[g]) == u8_tolower(x[g + m - 1 - f])) { --g; } suff[i] = f - g; } } } /** * \brief Array setup function for building prefixes (shift for valid prefixes) * for boyermoore context case less * * \param x pointer to the pattern string * \param m length of the string * \param bmGs pointer to an empty array that will hold the prefixes (shifts) */ void PreBmGsNocase(const uint8_t *x, uint16_t m, uint16_t *bmGs) { int32_t i, j; uint16_t* suff; suff = SCMalloc(sizeof(uint16_t) * (m + 1)); if (unlikely(suff == NULL)) return; BoyerMooreSuffixesNocase(x, m, suff); for (i = 0; i < m; ++i) { bmGs[i] = m; } j = 0; for (i = m - 1; i >= 0; --i) { if (i == -1 || suff[i] == i + 1) { for (; j < m - 1 - i; ++j) { if (bmGs[j] == m) { bmGs[j] = m - 1 - i; } } } } for (i = 0; i <= m - 2; ++i) { bmGs[m - 1 - suff[i]] = m - 1 - i; } SCFree(suff); } /** * \brief Boyer Moore search algorithm * Is better as the pattern length increases and for big buffers to search in. * The algorithm needs a context of two arrays already prepared * by prep_bad_chars() and prep_good_suffix() * * \param y pointer to the buffer to search in * \param n length limit of the buffer * \param x pointer to the pattern we ar searching for * \param m length limit of the needle * \param bmBc pointer to an array of BoyerMooreSuffixes prepared by prep_good_suffix() * \param bmGs pointer to an array of bachars prepared by prep_bad_chars() * * \retval ptr to start of the match; NULL if no match */ uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, uint16_t *bmGs, uint16_t *bmBc) { int i, j, m1, m2; #if 0 printf("\nBad:\n"); for (i=0;i= 0 && x[i] == y[i + j]; --i); if (i < 0) { return y + j; //j += bmGs[0]; } else { // printf("%c", y[i+j]); j += (m1 = bmGs[i]) > (m2 = bmBc[y[i + j]] - m + 1 + i)? m1: m2; // printf("%d, %d\n", m1, m2); } } return NULL; } /** * \brief Boyer Moore search algorithm * Is better as the pattern length increases and for big buffers to search in. * The algorithm needs a context of two arrays already prepared * by prep_bad_chars() and prep_good_suffix() * * \param y pointer to the buffer to search in * \param n length limit of the buffer * \param x pointer to the pattern we ar searching for * \param m length limit of the needle * \param bmBc pointer to an array of BoyerMooreSuffixes prepared by prep_good_suffix() * \param bmGs pointer to an array of bachars prepared by prep_bad_chars() * * \retval ptr to start of the match; NULL if no match */ uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, uint16_t *bmGs, uint16_t *bmBc) { int i, j, m1, m2; #if 0 printf("\nBad:\n"); for (i=0;i= 0 && u8_tolower(x[i]) == u8_tolower(y[i + j]); --i); if (i < 0) { return y + j; } else { j += (m1=bmGs[i]) > (m2=bmBc[u8_tolower(y[i + j])] - m + 1 + i)?m1:m2; } } return NULL; } suricata-1.4.7/src/util-mpm-b2gm.c0000644000000000000000000040570612253546156013576 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implementation of the SBNDMq pattern matching algorithm. * * Future work: * - parray contains 1 byte patterns while they are not used * - 1 byte search hashes on tolower(*buf) reducing hash value * */ //#define PRINTMATCH #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "util-bloomfilter.h" #include "util-mpm-b2gm.h" #include "util-print.h" #include "util-hashlist.h" #include "util-debug.h" #include "util-unittest.h" #include "util-optimize.h" #include "conf.h" #define INIT_HASH_SIZE 65536 #ifdef B2GM_COUNTERS #define COUNT(counter) \ (counter) #else #define COUNT(counter) #endif /* B2GM_COUNTERS */ static uint32_t b2gm_hash_size = 0; static uint32_t b2gm_bloom_size = 0; static uint8_t b2gm_hash_shift = 0; static void *b2g_func; #define B2GM_HASH16(a,b) (((a) << b2gm_hash_shift) | (b)) void B2gmInitCtx (MpmCtx *, int); void B2gmThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void B2gmDestroyCtx(MpmCtx *); void B2gmThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); int B2gmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B2gmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B2gmPreparePatterns(MpmCtx *mpm_ctx); uint32_t B2gmSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t B2gmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); #ifdef B2GM_SEARCH2 uint32_t B2gmSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); #endif uint32_t B2gmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t B2gmSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); void B2gmPrintInfo(MpmCtx *mpm_ctx); void B2gmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void B2gmRegisterTests(void); void MpmB2gmRegister (void) { mpm_table[MPM_B2GM].name = "b2gm"; mpm_table[MPM_B2GM].max_pattern_length = B2GM_WORD_SIZE; mpm_table[MPM_B2GM].InitCtx = B2gmInitCtx; mpm_table[MPM_B2GM].InitThreadCtx = B2gmThreadInitCtx; mpm_table[MPM_B2GM].DestroyCtx = B2gmDestroyCtx; mpm_table[MPM_B2GM].DestroyThreadCtx = B2gmThreadDestroyCtx; mpm_table[MPM_B2GM].AddPattern = B2gmAddPatternCS; mpm_table[MPM_B2GM].AddPatternNocase = B2gmAddPatternCI; mpm_table[MPM_B2GM].Prepare = B2gmPreparePatterns; mpm_table[MPM_B2GM].Search = B2gmSearchWrap; mpm_table[MPM_B2GM].Cleanup = NULL; mpm_table[MPM_B2GM].PrintCtx = B2gmPrintInfo; mpm_table[MPM_B2GM].PrintThreadCtx = B2gmPrintSearchStats; mpm_table[MPM_B2GM].RegisterUnittests = B2gmRegisterTests; } #ifdef PRINTMATCH static void prt (uint8_t *buf, uint16_t buflen) { uint16_t i; for (i = 0; i < buflen; i++) { if (isprint(buf[i])) printf("%c", buf[i]); else printf("\\x%02X", buf[i]); } //printf("\n"); } #endif void B2gmPrintInfo(MpmCtx *mpm_ctx) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; printf("MPM B2gm Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); printf(" Sizeofs:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" B2gmCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmCtx)); printf(" B2gmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmPattern)); printf(" B2gmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Hash size: %" PRIu32 "\n", ctx->hash_size); printf("\n"); } static inline B2gmPattern *B2gmAllocPattern(MpmCtx *mpm_ctx) { B2gmPattern *p = SCMalloc(sizeof(B2gmPattern)); if (unlikely(p == NULL)) return NULL; memset(p,0,sizeof(B2gmPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gmPattern); return p; } static inline B2gmPattern * B2gmAllocHashItem(MpmCtx *mpm_ctx) { B2gmPattern *hi = SCMalloc(sizeof(B2gmPattern)); if (unlikely(hi == NULL)) return NULL; memset(hi,0,sizeof(B2gmPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gmPattern); return hi; } static void B2gmHashFree(MpmCtx *mpm_ctx, B2gmPattern *hi) { if (hi == NULL) return; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gmPattern); B2gmPattern *t = hi->next; SCFree(hi); B2gmHashFree(mpm_ctx, t); } static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) { d[i] = u8_tolower(s[i]); } } /* * INIT HASH START */ static inline uint32_t B2gmInitHash(B2gmPattern *p) { uint32_t hash = p->len * p->pat[0]; if (p->len > 1) hash += p->pat[1]; return (hash % INIT_HASH_SIZE); } static inline uint32_t B2gmInitHashRaw(uint8_t *pat, uint16_t patlen) { uint32_t hash = patlen * pat[0]; if (patlen > 1) hash += pat[1]; return (hash % INIT_HASH_SIZE); } static inline int B2gmInitHashAdd(B2gmCtx *ctx, B2gmPattern *p) { uint32_t hash = B2gmInitHash(p); if (ctx->init_hash[hash] == NULL) { ctx->init_hash[hash] = p; return 0; } B2gmPattern *tt = NULL; B2gmPattern *t = ctx->init_hash[hash]; /* get the list tail */ do { tt = t; t = t->next; } while (t != NULL); tt->next = p; return 0; } static inline int B2gmCmpPattern(B2gmPattern *p, uint8_t *pat, uint16_t patlen, char flags); static inline B2gmPattern *B2gmInitHashLookup(B2gmCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) { uint32_t hash = B2gmInitHashRaw(pat,patlen); if (ctx->init_hash[hash] == NULL) { return NULL; } B2gmPattern *t = ctx->init_hash[hash]; for ( ; t != NULL; t = t->next) { if (B2gmCmpPattern(t,pat,patlen,flags) == 1) return t; } return NULL; } static inline int B2gmCmpPattern(B2gmPattern *p, uint8_t *pat, uint16_t patlen, char flags) { if (p->len != patlen) return 0; if (p->flags != flags) return 0; if (memcmp(p->pat, pat, patlen) != 0) return 0; return 1; } /* * INIT HASH END */ void B2gmFreePattern(MpmCtx *mpm_ctx, B2gmPattern *p) { if (p != NULL) { if (p->pat != NULL) { SCFree(p->pat); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gmPattern); } } /** \internal * \brief add a pattern to the mpm/b2g context * * \param pat ptr to the pattern * \param patlen length of the pattern * \param pid pattern id * \param sid signature id (internal id) * \param flags pattern MPM_PATTERN_* flags */ static int B2gmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); if (patlen == 0) return 0; /* get a memory piece */ B2gmPattern *p = B2gmInitHashLookup(ctx, pat, patlen, flags); if (p == NULL) { SCLogDebug("allocing new pattern"); B2gmPattern *p = B2gmAllocPattern(mpm_ctx); if (p == NULL) return -1; p->len = patlen; p->flags = flags; p->id = pid; /* setup the case insensitive part of the pattern */ p->pat = SCMalloc(patlen); if (p->pat == NULL) { B2gmFreePattern(mpm_ctx, p); return -1; } mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; /* setup the case sensitive part of the pattern */ if (p->flags & MPM_PATTERN_FLAG_NOCASE) { memcpy_tolower(p->pat, pat, patlen); } else { memcpy(p->pat, pat, patlen); } /* put in the pattern hash */ B2gmInitHashAdd(ctx, p); if (mpm_ctx->pattern_cnt == 65535) { printf("Max search words reached\n"); exit(1); } mpm_ctx->pattern_cnt++; if (patlen == 1) { ctx->pat_1_cnt++; } else { ctx->pat_x_cnt++; } if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } return 0; } int B2gmAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return B2gmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int B2gmAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return B2gmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } static uint32_t B2gmHashPatternSortHash1(HashListTable *ht, void *pattern, uint16_t len) { BUG_ON(len != sizeof(B2gmPattern)); BUG_ON(pattern == NULL); B2gmPattern *p = (B2gmPattern *)pattern; return (uint32_t)p->pat[0]; } static char B2gmHashPatternCompare(void *pattern1, uint16_t len1, void *pattern2, uint16_t len2) { BUG_ON(len1 != sizeof(B2gmPattern)); BUG_ON(len2 != sizeof(B2gmPattern)); B2gmPattern *p1 = (B2gmPattern *)pattern1; B2gmPattern *p2 = (B2gmPattern *)pattern2; if (p1->id != p2->id) { return 0; } return 1; } static inline uint32_t B2gmBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint16_t i; uint32_t hash = (uint32_t)u8_tolower(*d); for (i = 1; i < datalen; i++) { d++; hash += (u8_tolower(*d)) ^ i; } hash <<= (iter+1); hash %= hash_size; return hash; } static void B2gmPrepareHashAddPattern(MpmCtx *mpm_ctx, uint16_t idx, uint32_t i) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; if (ctx->lookup[idx].hash == NULL) { B2gmPattern *hi = B2gmAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->len = ctx->parray[i]->len; hi->flags |= ctx->parray[i]->flags; hi->id = ctx->parray[i]->id; hi->pat = ctx->parray[i]->pat; ctx->lookup[idx].pminlen = ctx->parray[i]->len; ctx->lookup[idx].hash = hi; } else { B2gmPattern *hi = B2gmAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->len = ctx->parray[i]->len; hi->flags |= ctx->parray[i]->flags; hi->id = ctx->parray[i]->id; hi->pat = ctx->parray[i]->pat; if (ctx->parray[i]->len < ctx->lookup[idx].pminlen) ctx->lookup[idx].pminlen = ctx->parray[i]->len; /* Append this HashItem to the list */ B2gmPattern *thi = ctx->lookup[idx].hash; while (thi->next) thi = thi->next; thi->next = hi; } return; error: return; } static void B2gmPrepareHash(MpmCtx *mpm_ctx) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; uint16_t i; uint16_t size1 = 1; HashListTable *b2gm_sort_hash1 = HashListTableInit(256, B2gmHashPatternSortHash1, B2gmHashPatternCompare, NULL); if (b2gm_sort_hash1 == NULL) { exit(EXIT_FAILURE); } for (i = 0; i < mpm_ctx->pattern_cnt; i++) { SCLogDebug("ctx->parray[i]->len %u", ctx->parray[i]->len); if(ctx->parray[i]->len == 1) { HashListTableAdd(b2gm_sort_hash1, (void *)ctx->parray[i], sizeof(B2gmPattern)); size1 += (sizeof(B2gmPattern1)); } else { if (ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE) { /* u, u */ uint16_t uuidx = B2GM_HASH16(toupper(ctx->parray[i]->pat[ctx->m - 2]), toupper(ctx->parray[i]->pat[ctx->m - 1])); B2gmPrepareHashAddPattern(mpm_ctx, uuidx, i); /* l, l */ uint16_t llidx = B2GM_HASH16(tolower(ctx->parray[i]->pat[ctx->m - 2]), tolower(ctx->parray[i]->pat[ctx->m - 1])); if (llidx != uuidx) { B2gmPrepareHashAddPattern(mpm_ctx, llidx, i); } /* u, l */ uint16_t ulidx = B2GM_HASH16(toupper(ctx->parray[i]->pat[ctx->m - 2]), tolower(ctx->parray[i]->pat[ctx->m - 1])); if (ulidx != llidx && ulidx != uuidx) { B2gmPrepareHashAddPattern(mpm_ctx, ulidx, i); } /* l, u */ uint16_t luidx = B2GM_HASH16(tolower(ctx->parray[i]->pat[ctx->m - 2]), toupper(ctx->parray[i]->pat[ctx->m - 1])); if (luidx != ulidx && luidx != llidx && luidx != uuidx) { B2gmPrepareHashAddPattern(mpm_ctx, luidx, i); } } else { uint16_t uuidx = B2GM_HASH16(ctx->parray[i]->pat[ctx->m - 2], ctx->parray[i]->pat[ctx->m - 1]); B2gmPrepareHashAddPattern(mpm_ctx, uuidx, i); } } } uint32_t h; for (h = 0; h < ctx->hash_size; h++) { B2gmPattern *hi = ctx->lookup[h].hash; if (hi == NULL) continue; ctx->lookup[h].bloom = BloomFilterInit(b2gm_bloom_size, 2, B2gmBloomHash); if (ctx->lookup[h].bloom == NULL) continue; mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->lookup[h].bloom); mpm_ctx->memory_size += BloomFilterMemorySize(ctx->lookup[h].bloom); if (ctx->lookup[h].pminlen > 8) ctx->lookup[h].pminlenb = 8; else ctx->lookup[h].pminlenb = (uint8_t)ctx->lookup[h].pminlen; B2gmPattern *thi = hi; do { SCLogDebug("adding \"%c%c\" to the bloom", thi->pat[0], thi->pat[1]); BloomFilterAdd(ctx->lookup[h].bloom, thi->pat, ctx->lookup[h].pminlenb); thi = thi->next; } while (thi != NULL); } /* build the 1 byte match array */ SCLogDebug("size1 %u", size1); ctx->patterns1 = SCMalloc(size1); BUG_ON(ctx->patterns1 == NULL); memset(ctx->patterns1, 0x00, size1); /* skip the first byte of the buffer */ uint16_t offset1 = 1; uint32_t a; for (a = 0; a < b2gm_sort_hash1->array_size; a++) { HashListTableBucket *buck = b2gm_sort_hash1->array[a]; if (buck != NULL) { while (buck != NULL) { if (buck->data != NULL) { B2gmPattern *p = (B2gmPattern *) (buck->data); BUG_ON(p == NULL); BUG_ON(p->len != 1); B2gmPattern1 *h = (B2gmPattern1 *)&ctx->patterns1[offset1]; h->id = p->id; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { h->flags |= B2GM_FLAG_NOCASE; h->pat = p->pat[0]; } else { h->pat = p->pat[0]; } offset1 += (sizeof(B2gmPattern1)); } buck = buck->bucknext; } } } /* build the hash containing idx' to the pattern array */ offset1 = 1; B2gmPattern1 *ph1 = NULL; uint8_t prevhash1 = 0; while (offset1 < size1) { B2gmPattern1 *h = (B2gmPattern1 *)&ctx->patterns1[offset1]; if (ctx->ha1[u8_tolower(h->pat)] == 0) ctx->ha1[u8_tolower(h->pat)] = offset1; /* check the prev pattern for setting the final flag */ if (ph1 != NULL) { if (u8_tolower(h->pat) != prevhash1) { SCLogDebug("setting final flag on %p", ph1); ph1->flags |= B2GM_FLAG_FINAL; } } prevhash1 = u8_tolower(h->pat); ph1 = h; offset1 += (sizeof(B2gmPattern1)); /* last item is "final" too */ if (offset1 == size1) { SCLogDebug("final pattern in the array"); h->flags |= B2GM_FLAG_FINAL; } SCLogDebug("offset %u, size %u", offset1, size1); } HashListTableFree(b2gm_sort_hash1); b2gm_sort_hash1 = NULL; return; } static void B2gmAddToMatchArray(MpmCtx *mpm_ctx, B2gmPattern *p, int j) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* u, u */ uint16_t uuidx = B2GM_HASH16(toupper(p->pat[j]), toupper(p->pat[j + 1])); ctx->B2GM[uuidx] = ctx->B2GM[uuidx] | (1 << (ctx->m - j)); /* l, l */ uint16_t llidx = B2GM_HASH16(u8_tolower(p->pat[j]), u8_tolower(p->pat[j + 1])); if (llidx != uuidx) { ctx->B2GM[llidx] = ctx->B2GM[llidx] | (1 << (ctx->m - j)); } /* u, l */ uint16_t ulidx = B2GM_HASH16(toupper(p->pat[j]), u8_tolower(p->pat[j + 1])); if (ulidx != llidx && ulidx != uuidx) { ctx->B2GM[ulidx] = ctx->B2GM[ulidx] | (1 << (ctx->m - j)); } /* l, u */ uint16_t luidx = B2GM_HASH16(u8_tolower(p->pat[j]), toupper(p->pat[j + 1])); if (luidx != ulidx && luidx != llidx && luidx != uuidx) { ctx->B2GM[luidx] = ctx->B2GM[luidx] | (1 << (ctx->m - j)); } SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); } } int B2gmBuildMatchArray(MpmCtx *mpm_ctx) { SCEnter(); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; ctx->B2GM = SCMalloc(sizeof(B2GM_TYPE) * ctx->hash_size); if (ctx->B2GM == NULL) return -1; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B2GM_TYPE) * ctx->hash_size); memset(ctx->B2GM,0, b2gm_hash_size * sizeof(B2GM_TYPE)); uint32_t j; uint32_t a; /* fill the match array */ for (j = 0; j <= (ctx->m - B2GM_Q); j++) { for (a = 0; a < ctx->pat_x_cnt; a++) { if (ctx->parray[a]->len < ctx->m) continue; uint16_t h; if (ctx->parray[a]->flags & MPM_PATTERN_FLAG_NOCASE) { B2gmAddToMatchArray(mpm_ctx, ctx->parray[a], j); } else { h = B2GM_HASH16(ctx->parray[a]->pat[j], ctx->parray[a]->pat[j+1]); ctx->B2GM[h] = ctx->B2GM[h] | (1 << (ctx->m - j)); SCLogDebug("h %"PRIu16", ctx->B2GM[h] %"PRIu32" (cs)", h, ctx->B2GM[h]); } } } //ctx->s0 = 1; SCReturnInt(0); } int B2gmPreparePatterns(MpmCtx *mpm_ctx) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; /* alloc the lookup array */ ctx->lookup = SCMalloc(b2gm_hash_size * sizeof(B2gmLookup)); if (ctx->lookup == NULL) goto error; memset(ctx->lookup, 0x00, b2gm_hash_size * sizeof(B2gmLookup)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (b2gm_hash_size * sizeof(B2gmLookup)); /* alloc the pattern array */ ctx->parray = (B2gmPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); if (ctx->parray == NULL) goto error; memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0; uint32_t p = 0; for (i = 0; i < INIT_HASH_SIZE; i++) { B2gmPattern *node = ctx->init_hash[i]; B2gmPattern *nnode = NULL; for ( ; node != NULL; ) { nnode = node->next; node->next = NULL; ctx->parray[p] = node; p++; node = nnode; } } /* we no longer need the hash, so free it's memory */ SCFree(ctx->init_hash); ctx->init_hash = NULL; /* set 'm' to the smallest pattern size */ ctx->m = mpm_ctx->minlen; /* make sure 'm' stays in bounds m can be max WORD_SIZE - 1 */ if (ctx->m >= B2GM_WORD_SIZE) { ctx->m = B2GM_WORD_SIZE - 1; } if (ctx->m < 2) ctx->m = 2; ctx->hash_size = b2gm_hash_size; B2gmPrepareHash(mpm_ctx); B2gmBuildMatchArray(mpm_ctx); SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); if (ctx->pat_1_cnt) { ctx->Search = B2gmSearch1; ctx->MBSearch = b2g_func; } return 0; error: return -1; } void B2gmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef B2GM_COUNTERS B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; printf("B2gm Thread Search stats (tctx %p)\n", tctx); printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); printf("Avg pminlen: %0.2f\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); printf("Test bug %"PRIu32"\n", tctx->stat_test_buf); printf("Test bug ok %"PRIu32"\n", tctx->stat_test_buf_ok); printf("Test bug fail %"PRIu32"\n\n", tctx->stat_test_buf_fail); #endif /* B2GM_COUNTERS */ } static inline int memcmp_lowercase(const uint8_t *s1, const uint8_t *s2, const uint16_t n) { size_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ for (i = n - 1; i; i--) { if (s1[i] != u8_tolower(*(s2+i))) return 1; } return 0; } /** * \brief Function to get the user defined values for b2g algorithm from the * config file 'suricata.yaml' */ static void B2gmGetConfig() { ConfNode *b2g_conf; const char *hash_val = NULL; const char *bloom_val = NULL; const char *algo = NULL; /* init defaults */ b2gm_hash_size = HASHSIZE_LOW; b2gm_hash_shift = B2GM_HASHSHIFT_LOW; b2gm_bloom_size = BLOOMSIZE_MEDIUM; b2g_func = B2GM_SEARCHFUNC; ConfNode *pm = ConfGetNode("pattern-matcher"); if (pm != NULL) { TAILQ_FOREACH(b2g_conf, &pm->head, next) { if (strcmp(b2g_conf->val, "b2gm") == 0) { algo = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "algo"); hash_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "hash_size"); bloom_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "bf_size"); if (algo != NULL) { if (strcmp(algo, "B2gmSearch") == 0) { b2g_func = B2gmSearch; } else if (strcmp(algo, "B2gmSearchBNDMq") == 0) { b2g_func = B2gmSearchBNDMq; } } if (hash_val != NULL) { b2gm_hash_size = MpmGetHashSize(hash_val); switch (b2gm_hash_size) { case HASHSIZE_LOWEST: b2gm_hash_shift = B2GM_HASHSHIFT_LOWEST; break; case HASHSIZE_LOW: b2gm_hash_shift = B2GM_HASHSHIFT_LOW; break; case HASHSIZE_MEDIUM: b2gm_hash_shift = B2GM_HASHSHIFT_MEDIUM; break; case HASHSIZE_HIGH: b2gm_hash_shift = B2GM_HASHSHIFT_HIGH; break; case HASHSIZE_HIGHER: b2gm_hash_shift = B2GM_HASHSHIFT_HIGHER; break; case HASHSIZE_MAX: b2gm_hash_shift = B2GM_HASHSHIFT_MAX; break; } } if (bloom_val != NULL) b2gm_bloom_size = MpmGetBloomSize(bloom_val); SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", b2gm_hash_size, b2gm_bloom_size); } } } } void B2gmInitCtx (MpmCtx *mpm_ctx, int module_handle) { SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); BUG_ON(mpm_ctx->ctx != NULL); mpm_ctx->ctx = SCMalloc(sizeof(B2gmCtx)); if (mpm_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_ctx->ctx, 0, sizeof(B2gmCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gmCtx); /* initialize the hash we use to speed up pattern insertions */ B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; ctx->init_hash = SCMalloc(sizeof(B2gmPattern *) * INIT_HASH_SIZE); if (ctx->init_hash == NULL) { exit(EXIT_FAILURE); } memset(ctx->init_hash, 0, sizeof(B2gmPattern *) * INIT_HASH_SIZE); /* Initialize the defaults value from the config file. The given check make sure that we query config file only once for config values */ if (b2gm_hash_size == 0) B2gmGetConfig(); ctx->ha1 = SCMalloc(256 * sizeof(uint16_t)); BUG_ON(ctx->ha1 == NULL); memset(ctx->ha1, 0x00, 256 * sizeof(uint16_t)); /* init defaults search functions */ ctx->Search = b2g_func; SCReturn; } void B2gmDestroyCtx(MpmCtx *mpm_ctx) { SCLogDebug("mpm_ctx %p", mpm_ctx); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->init_hash != NULL) { SCFree(ctx->init_hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B2gmPattern *)); } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { B2gmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gmPattern)); } if (ctx->B2GM != NULL) { SCFree(ctx->B2GM); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B2GM_TYPE) * ctx->hash_size); } if (ctx->lookup != NULL) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->lookup[h].bloom == NULL) continue; B2gmHashFree(mpm_ctx, ctx->lookup[h].hash); mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->lookup[h].bloom); mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->lookup[h].bloom); BloomFilterFree(ctx->lookup[h].bloom); } SCFree(ctx->lookup); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B2gmLookup) * ctx->hash_size); } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gmCtx); } void B2gmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); if (sizeof(B2gmThreadCtx) > 0) { /* size can be null when optimized */ mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gmThreadCtx)); if (mpm_thread_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_thread_ctx->ctx, 0, sizeof(B2gmThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(B2gmThreadCtx); } } void B2gmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { B2gmThreadCtx *ctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; B2gmPrintSearchStats(mpm_thread_ctx); if (ctx != NULL) { /* can be NULL if B2gmThreadCtx is optimized to 0 */ mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(B2gmThreadCtx); SCFree(mpm_thread_ctx->ctx); } } uint32_t B2gmSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; } uint32_t B2gmSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; #ifdef B2GM_COUNTERS B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = ctx->m - B2GM_Q + 1, matches = 0; B2GM_TYPE d; //printf("\n"); //PrintRawDataFp(stdout, buf, buflen); SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32"", buflen, ctx->m, pos); COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (uint32_t)(buflen - B2GM_Q + 1)) { uint16_t h = B2GM_HASH16(buf[pos - 1],buf[pos]); d = ctx->B2GM[h]; if (d != 0) { COUNT(tctx->stat_d0++); uint32_t j = pos; uint32_t first = pos - (ctx->m - B2GM_Q + 1); do { j = j - 1; if (d >= (uint32_t)(1 << (ctx->m - 1))) { if (j > first) pos = j; else { COUNT(tctx->stat_test_buf++); h = B2GM_HASH16(buf[j + ctx->m - 2],buf[j + ctx->m - 1]); if (unlikely(ctx->lookup[h].pminlen > 0 && (buflen - j) >= ctx->lookup[h].pminlen && BloomFilterTest(ctx->lookup[h].bloom, buf+j, ctx->lookup[h].pminlenb) == 1)) { COUNT(tctx->stat_test_buf_ok++); /* get our patterns from the hash */ B2gmPattern *hi = ctx->lookup[h].hash, *thi; for (thi = hi; thi != NULL; thi = thi->next) { if ((buflen - j) >= thi->len) { if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { if (unlikely(memcmp_lowercase(thi->pat, buf+j, thi->len) == 0)) { #ifdef PRINTMATCH printf("CI Exact match: "); prt(thi->pat, thi->len); printf(" (id %u)\n", thi->id); #endif COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (unlikely(memcmp(thi->pat, buf+j, thi->len) == 0)) { #ifdef PRINTMATCH printf("CS Exact match: "); prt(thi->pat, thi->len); printf(" (id %u)\n", thi->id); #endif COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } } } } else { COUNT(tctx->stat_test_buf_fail++); } } } if (j == 0) { break; } h = B2GM_HASH16(buf[j - 1],buf[j]); d = (d << 1) & ctx->B2GM[h]; } while (d != 0); } COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (ctx->m - B2GM_Q + 1)); pos = pos + ctx->m - B2GM_Q + 1; SCLogDebug("pos %"PRIu32"", pos); } SCLogDebug("matches %"PRIu32"", matches); return matches; } uint32_t B2gmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; #ifdef B2GM_COUNTERS B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = 0, matches = 0; B2GM_TYPE d; uint32_t j; COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (buflen - ctx->m)) { j = ctx->m - 1; d = ~0; do { uint16_t h = B2GM_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); d = ((d << 1) & ctx->B2GM[h]); j = j - 1; } while (d != 0 && j != 0); /* (partial) match, move on to verification */ if (d != 0) { COUNT(tctx->stat_d0++); //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); /* get our patterns from the hash */ uint16_t h = B2GM_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); if (ctx->lookup[h].pminlen > 0) { COUNT(tctx->stat_pminlen_calls++); if ((buflen - pos) < ctx->lookup[h].pminlen) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->lookup[h].bloom, buf+pos, ctx->lookup[h].pminlenb) == 0) { COUNT(tctx->stat_bloom_hits++); //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); goto skip_loop; } } B2gmPattern *hi = ctx->lookup[h].hash, *thi; for (thi = hi; thi != NULL; thi = thi->next) { COUNT(tctx->stat_d0_hashloop++); //B2gmPattern *p = ctx->parray[thi->idx]; if (buflen - pos < thi->len) continue; if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { if (memcmp_lowercase(thi->pat, buf+pos, thi->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (memcmp(thi->pat, buf+pos, thi->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } } } skip_loop: //pos = pos + ctx->s0; pos = pos + 1; } else { COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (j + 1)); pos = pos + j + 1; } } //printf("Total matches %" PRIu32 "\n", matches); return matches; } uint32_t B2gmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { SCEnter(); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; if (buflen == 0) SCReturnUInt(0); //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint8_t h = u8_tolower(*buf); uint16_t offset = ctx->ha1[h]; SCLogDebug("offset %u, h %02X, buf %02X", offset, h, *buf); if (offset > 0) { do { B2gmPattern1 *hdr = (B2gmPattern1 *)&ctx->patterns1[offset]; offset += (sizeof(B2gmPattern1)); SCLogDebug("hdr flags %02x, id %u, pat %02X", hdr->flags, hdr->id, hdr->pat); if (hdr->flags & B2GM_FLAG_NOCASE) { SCLogDebug("nocase compare, %02X", *buf); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); } else { SCLogDebug("case sensitive compare, %02X", *buf); if (*buf == hdr->pat) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); } } if (hdr->flags & B2GM_FLAG_FINAL) break; } while(1); } buf += 1; } //printf("B2gcSearch1: after 1byte cnt %" PRIu32 "\n", cnt); if (ctx->pat_x_cnt) { cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); } SCReturnUInt(cnt); } /* * TESTS */ #ifdef UNITTESTS static int B2gmTestInit01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); if (ctx->m == 4) result = 1; else printf("4 != %" PRIu32 " ", ctx->m); B2gmDestroyCtx(&mpm_ctx); return result; } #if 0 static int B2gmTestS0Init01 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); if (ctx->s0 == 4) result = 1; else printf("4 != %" PRIu32 " ", ctx->s0); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestS0Init02 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); if (ctx->s0 == 2) result = 1; else printf("2 != %" PRIu32 " ", ctx->s0); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestS0Init03 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); if (ctx->s0 == 1) result = 1; else printf("1 != %" PRIu32 " ", ctx->s0); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestS0Init04 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); if (ctx->s0 == 2) result = 1; else printf("2 != %" PRIu32 " ", ctx->s0); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestS0Init05 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); if (ctx->s0 == 3) result = 1; else printf("3 != %" PRIu32 " ", ctx->s0); B2gmDestroyCtx(&mpm_ctx); return result; } #endif static int B2gmTestSearch01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch02a (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch02b (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch03a (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"b", 1, 0, 0, 1, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"f", 1, 0, 0, 2, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } /* test patterns longer than 'm'. M is 4 here. */ static int B2gmTestSearch04 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } /* case insensitive test patterns longer than 'm'. M is 4 here. */ static int B2gmTestSearch05 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch05a (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 5) result = 1; else printf("5 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch06 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch07 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = 0 ; int i; for (i = 0; i<1000;i++) cnt= ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch08 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch09 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch10 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); char *buf = "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "abcdefgh" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789"; uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch11 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch13 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch17 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch18 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch19 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch20 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ //B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } static int B2gmTestSearch21 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); return result; } #endif /* UNITTESTS */ #if 0 static int B2gmTestSearchXX (void) { MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; FILE *fp = fopen("/usr/share/dict/words", "r"); if (fp == NULL) exit(1); char *word; char line[128]; int w = 0; int w_max = 4000; while((word = fgets(line, sizeof(line), fp)) != NULL) { word[strlen(word) - 1] = '\0'; B2gmAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); w++; if (w_max == w) break; } B2gmPreparePatterns(&mpm_ctx); B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; uint32_t len = strlen(text) - 1; int i; uint32_t cnt; for (i = 0; i < 100; i++) { cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); } printf("cnt %u ", cnt); B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gmDestroyCtx(&mpm_ctx); fclose(fp); return 1; } #endif void B2gmRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("B2gmTestInit01", B2gmTestInit01, 1); /* UtRegisterTest("B2gmTestS0Init01", B2gmTestS0Init01, 1); UtRegisterTest("B2gmTestS0Init02", B2gmTestS0Init02, 1); UtRegisterTest("B2gmTestS0Init03", B2gmTestS0Init03, 1); UtRegisterTest("B2gmTestS0Init04", B2gmTestS0Init04, 1); UtRegisterTest("B2gmTestS0Init05", B2gmTestS0Init05, 1); */ UtRegisterTest("B2gmTestSearch01", B2gmTestSearch01, 1); UtRegisterTest("B2gmTestSearch02", B2gmTestSearch02, 1); UtRegisterTest("B2gmTestSearch02a", B2gmTestSearch02a, 1); UtRegisterTest("B2gmTestSearch02b", B2gmTestSearch02b, 1); UtRegisterTest("B2gmTestSearch03", B2gmTestSearch03, 1); UtRegisterTest("B2gmTestSearch03a", B2gmTestSearch03a, 1); UtRegisterTest("B2gmTestSearch04", B2gmTestSearch04, 1); UtRegisterTest("B2gmTestSearch05", B2gmTestSearch05, 1); UtRegisterTest("B2gmTestSearch05a", B2gmTestSearch05a, 1); UtRegisterTest("B2gmTestSearch06", B2gmTestSearch06, 1); UtRegisterTest("B2gmTestSearch07", B2gmTestSearch07, 1); UtRegisterTest("B2gmTestSearch08", B2gmTestSearch08, 1); UtRegisterTest("B2gmTestSearch09", B2gmTestSearch09, 1); UtRegisterTest("B2gmTestSearch10", B2gmTestSearch10, 1); UtRegisterTest("B2gmTestSearch11", B2gmTestSearch11, 1); UtRegisterTest("B2gmTestSearch12", B2gmTestSearch12, 1); UtRegisterTest("B2gmTestSearch13", B2gmTestSearch13, 1); UtRegisterTest("B2gmTestSearch14", B2gmTestSearch14, 1); UtRegisterTest("B2gmTestSearch15", B2gmTestSearch15, 1); UtRegisterTest("B2gmTestSearch16", B2gmTestSearch16, 1); UtRegisterTest("B2gmTestSearch17", B2gmTestSearch17, 1); UtRegisterTest("B2gmTestSearch18", B2gmTestSearch18, 1); UtRegisterTest("B2gmTestSearch19", B2gmTestSearch19, 1); UtRegisterTest("B2gmTestSearch20", B2gmTestSearch20, 1); UtRegisterTest("B2gmTestSearch21", B2gmTestSearch21, 1); /* UtRegisterTest("B2gmTestSearchXX", B2gmTestSearchXX, 1); */ #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-filename.h0000644000000000000000000000222612253546156014226 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_FILENAME_H__ #define __DETECT_FILENAME_H__ #include "util-spm-bm.h" typedef struct DetectFilenameData { uint8_t *name; /** name of the file to match */ BmCtx *bm_ctx; /** BM context */ uint16_t len; /** name length */ uint32_t flags; } DetectFilenameData; /* prototypes */ void DetectFilenameRegister (void); #endif /* __DETECT_FILENAME_H__ */ suricata-1.4.7/src/detect-http-client-body.c0000644000000000000000000024027712253546156015641 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Anoop Saldanha * * Implements support for the http_client_body keyword */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-client-body.h" #include "stream-tcp.h" int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, char *); void DetectHttpClientBodyRegisterTests(void); void DetectHttpClientBodyFree(void *); /** * \brief Registers the keyword handlers for the "http_client_body" keyword. */ void DetectHttpClientBodyRegister(void) { sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].name = "http_client_body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].desc = "content modifier to match only on HTTP request-body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_client_body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Match = NULL; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Free = DetectHttpClientBodyFree; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].RegisterTests = DetectHttpClientBodyRegisterTests; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_PAYLOAD ; } /** * \brief The setup function for the http_client_body keyword for a signature. * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to signature for the current Signature being parsed * from the rules. * \param m Pointer to the head of the SigMatchs for the current rule * being parsed. * \param arg Pointer to the string holding the keyword value. * * \retval 0 On success * \retval -1 On failure */ int DetectHttpClientBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_client_body supplied with args"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if still we are unable to find any content previous keywords, it is an * invalid rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_client_body\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_client_body\" keyword"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_client_body should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_client_body rule can not " "be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if (s->flags & SIG_FLAG_TOCLIENT) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_client_body can not be used with flow:to_client or flow:from_server. "); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_client_body seen with a " "distance or within without a previous http_client_body " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HCBDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hcbdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HCBDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; /* enable http request body callback in the http app layer parser */ AppLayerHtpEnableRequestBodyCallback(); return 0; error: //if (cd != NULL) // DetectHttpClientBodyFree(cd); //if (sm != NULL) // SCFree(sm); return -1; } /** * \brief The function to free the http_client_body data. * * \param ptr Pointer to the http_client_body. */ void DetectHttpClientBodyFree(void *ptr) { SCEnter(); DetectContentData *hcbd = (DetectContentData *)ptr; if (hcbd == NULL) SCReturn; if (hcbd->content != NULL) SCFree(hcbd->content); BoyerMooreCtxDeInit(hcbd->bm_ctx); SCFree(hcbd); SCReturn; } /************************************Unittests*********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Test that a signature containting a http_client_body is correctly parsed * and the keyword is registered. */ static int DetectHttpClientBodyTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; SigMatch *sm = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_client_body\"; " "content:\"one\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { goto end; } sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; if (sm != NULL) { result &= (sm->type == DETECT_CONTENT); result &= (sm->next == NULL); } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a signature containing an valid http_client_body entry is * parsed. */ static int DetectHttpClientBodyTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_client_body\"; " "content:\"one\"; http_client_body:; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing no content but a http_client_body * is invalidated. */ static int DetectHttpClientBodyTest03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_client_body\"; " "http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_client_body is invalidated. */ static int DetectHttpClientBodyTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_client_body\"; " "content:\"one\"; rawbytes; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_client_body is invalidated. */ static int DetectHttpClientBodyTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_client_body\"; " "content:\"one\"; http_client_body; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_client_body content matches against a http request * which holds the content. */ static int DetectHttpClientBodyTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"message\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_client_body content matches against a http request * which holds the content. */ static int DetectHttpClientBodyTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 54\r\n" "\r\n" "This is dummy message body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"message\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched on p1 but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match on p2 but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_client_body content matches against a http request * which holds the content. */ static int DetectHttpClientBodyTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"message\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_client_body content matches against a http request * which holds the content, against a cross boundary present pattern. */ static int DetectHttpClientBodyTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1This\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_client_body content matches against a http request * against a case insensitive pattern. */ static int DetectHttpClientBodyTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy bodY1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1This\"; http_client_body; nocase;" "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the negated http_client_body content matches against a * http request which doesn't hold the content. */ static int DetectHttpClientBodyTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:!\"message1\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Negative test that the negated http_client_body content matches against a * http request which holds hold the content. */ static int DetectHttpClientBodyTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 26\r\n" "\r\n" "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:!\"message\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_client_body content matches against a http request * which holds the content. */ static int DetectHttpClientBodyTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 55\r\n" "\r\n" "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test multiple http transactions and body chunks of request handling */ static int DetectHttpClientBodyTest14(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Body one!!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("signature matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (5): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 2))) { printf("signature 2 didn't match, but should have: "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test multiple http transactions and body chunks of request handling */ static int DetectHttpClientBodyTest15(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Body one!!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("signature matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (5): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 2))) { printf("signature 2 didn't match, but should have: "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } /* hardcoded check of the transactions and it's client body chunks */ if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0); htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); HtpBodyChunk *cur = htud->request_body.first; if (htud->request_body.first == NULL) { SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); goto end; } if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; if (htud->request_body.first == NULL) { SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); goto end; } if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } int DetectHttpClientBodyTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd->id == hcbd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd->id == hcbd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_client_body; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd->id != 0 || hcbd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd->id != 1 || hcbd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; " "content:\"one\"; content:\"one\"; http_client_body; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (cd->id != 1 || hcbd1->id != 0 || hcbd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; " "content:\"one\"; content:\"one\"; http_client_body; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; if (cd->id != 2 || hcbd1->id != 0 || hcbd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"two\"; http_client_body; " "content:\"three\"; distance:10; http_client_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "two", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd1) || !DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hcbd1) || DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; pcre:/two/; " "content:\"three\"; distance:10; http_client_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hcbd1) || DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; pcre:/two/; " "content:\"three\"; distance:10; within:15; http_client_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hcbd1) || DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; pcre:/two/; " "content:\"three\"; distance:10; http_client_body; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hcbd1) || DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; offset:10; http_client_body; pcre:/two/; " "content:\"three\"; distance:10; http_client_body; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { printf ("failed: http_client_body incorrect flags"); goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hcbd1) || DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; offset:10; http_client_body; pcre:/two/; " "content:\"three\"; distance:10; http_client_body; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; pcre:/two/; " "content:\"three\"; http_client_body; depth:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != 0 || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_DEPTH || memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || !DETECT_CONTENT_IS_SINGLE(hcbd1) || DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; " "content:\"two\"; distance:0; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "two", hcbd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; " "content:\"two\"; within:5; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hcbd2->content, "two", hcbd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_client_body; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(pcre:/one/P; " "content:\"two\"; within:5; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_CLIENT_BODY) || hcbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"two\"; http_client_body; " "pcre:/one/PR; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_PCRE || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_CONTENT) { goto end; } DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_CLIENT_BODY) || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "two", hcbd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpClientBodyTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(pcre:/one/P; " "content:\"two\"; distance:5; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_CLIENT_BODY) || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ void DetectHttpClientBodyRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectHttpClientBodyTest01", DetectHttpClientBodyTest01, 1); UtRegisterTest("DetectHttpClientBodyTest02", DetectHttpClientBodyTest02, 1); UtRegisterTest("DetectHttpClientBodyTest03", DetectHttpClientBodyTest03, 1); UtRegisterTest("DetectHttpClientBodyTest04", DetectHttpClientBodyTest04, 1); UtRegisterTest("DetectHttpClientBodyTest05", DetectHttpClientBodyTest05, 1); UtRegisterTest("DetectHttpClientBodyTest06", DetectHttpClientBodyTest06, 1); UtRegisterTest("DetectHttpClientBodyTest07", DetectHttpClientBodyTest07, 1); UtRegisterTest("DetectHttpClientBodyTest08", DetectHttpClientBodyTest08, 1); UtRegisterTest("DetectHttpClientBodyTest09", DetectHttpClientBodyTest09, 1); UtRegisterTest("DetectHttpClientBodyTest10", DetectHttpClientBodyTest10, 1); UtRegisterTest("DetectHttpClientBodyTest11", DetectHttpClientBodyTest11, 1); UtRegisterTest("DetectHttpClientBodyTest12", DetectHttpClientBodyTest12, 1); UtRegisterTest("DetectHttpClientBodyTest13", DetectHttpClientBodyTest13, 1); UtRegisterTest("DetectHttpClientBodyTest14", DetectHttpClientBodyTest14, 1); UtRegisterTest("DetectHttpClientBodyTest15", DetectHttpClientBodyTest15, 1); UtRegisterTest("DetectHttpClientBodyTest16", DetectHttpClientBodyTest16, 1); UtRegisterTest("DetectHttpClientBodyTest17", DetectHttpClientBodyTest17, 1); UtRegisterTest("DetectHttpClientBodyTest18", DetectHttpClientBodyTest18, 1); UtRegisterTest("DetectHttpClientBodyTest19", DetectHttpClientBodyTest19, 1); UtRegisterTest("DetectHttpClientBodyTest20", DetectHttpClientBodyTest20, 1); UtRegisterTest("DetectHttpClientBodyTest21", DetectHttpClientBodyTest21, 1); UtRegisterTest("DetectHttpClientBodyTest22", DetectHttpClientBodyTest22, 1); UtRegisterTest("DetectHttpClientBodyTest23", DetectHttpClientBodyTest23, 1); UtRegisterTest("DetectHttpClientBodyTest24", DetectHttpClientBodyTest24, 1); UtRegisterTest("DetectHttpClientBodyTest25", DetectHttpClientBodyTest25, 1); UtRegisterTest("DetectHttpClientBodyTest26", DetectHttpClientBodyTest26, 1); UtRegisterTest("DetectHttpClientBodyTest27", DetectHttpClientBodyTest27, 1); UtRegisterTest("DetectHttpClientBodyTest28", DetectHttpClientBodyTest28, 1); UtRegisterTest("DetectHttpClientBodyTest29", DetectHttpClientBodyTest29, 1); UtRegisterTest("DetectHttpClientBodyTest30", DetectHttpClientBodyTest30, 1); UtRegisterTest("DetectHttpClientBodyTest31", DetectHttpClientBodyTest31, 1); UtRegisterTest("DetectHttpClientBodyTest32", DetectHttpClientBodyTest32, 1); UtRegisterTest("DetectHttpClientBodyTest33", DetectHttpClientBodyTest33, 1); UtRegisterTest("DetectHttpClientBodyTest34", DetectHttpClientBodyTest34, 1); UtRegisterTest("DetectHttpClientBodyTest35", DetectHttpClientBodyTest35, 1); UtRegisterTest("DetectHttpClientBodyTest36", DetectHttpClientBodyTest36, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-http-hh.c0000644000000000000000000021273512253546156014025 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Anoop Saldanha * * Implements support for the http_host keyword. */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "app-layer.h" #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-hh.h" int DetectHttpHHSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpHHRegisterTests(void); void DetectHttpHHFree(void *); /** * \brief Registers the keyword handlers for the "http_host" keyword. */ void DetectHttpHHRegister(void) { sigmatch_table[DETECT_AL_HTTP_HOST].name = "http_host"; sigmatch_table[DETECT_AL_HTTP_HOST].desc = "content modifier to match only on the HTTP hostname"; sigmatch_table[DETECT_AL_HTTP_HOST].Match = NULL; sigmatch_table[DETECT_AL_HTTP_HOST].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_HOST].Setup = DetectHttpHHSetup; sigmatch_table[DETECT_AL_HTTP_HOST].Free = DetectHttpHHFree; sigmatch_table[DETECT_AL_HTTP_HOST].RegisterTests = DetectHttpHHRegisterTests; sigmatch_table[DETECT_AL_HTTP_HOST].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_PAYLOAD ; return; } /** * \brief The setup function for the http_host keyword for a signature. * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to the signature for the current Signature being * parsed from the rules. * \param m Pointer to the head of the SigMatch for the current rule * being parsed. * \param arg Pointer to the string holding the keyword value. * * \retval 0 On success * \retval -1 On failure */ int DetectHttpHHSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_host not supplied with args"); goto error; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if we still can't find any previous content keywords, it's an invalid * rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_host\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_host\" keyword"); goto error; } cd = (DetectContentData *)sm->ctx; /* http_host should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_host rule can not " "be used with the rawbytes rule keyword"); goto error; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if (s->flags & SIG_FLAG_TOCLIENT) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_host can not be used " "with flow:to_client or flow:from_server. "); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_host seen with a " "distance or within without a previous http_host " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HHHDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hhhdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HHHDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } /** * \brief The function to free the http_host data. * * \param ptr Pointer to the http_host. */ void DetectHttpHHFree(void *ptr) { DetectContentData *hhhd = (DetectContentData *)ptr; if (hhhd == NULL) return; if (hhhd->content != NULL) SCFree(hhhd->content); BoyerMooreCtxDeInit(hhhd->bm_ctx); SCFree(hhhd); return; } /************************************Unittests*********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Test that a signature containting a http_host is correctly parsed * and the keyword is registered. */ static int DetectHttpHHTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_host\"; " "content:\"one\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a signature containing an valid http_host entry is * parsed. */ static int DetectHttpHHTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_host\"; " "content:\"one\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing no content but a * http_host is invalidated. */ static int DetectHttpHHTest03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_host\"; " "http_host; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that an invalid signature containing a rawbytes along with a * http_host is invalidated. */ static int DetectHttpHHTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_host\"; " "content:\"one\"; rawbytes; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test that a http_host with nocase is parsed. */ static int DetectHttpHHTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_host\"; " "content:\"one\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** *\test Test that the http_host content matches against a http request * which holds the content. */ static int DetectHttpHHTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy message body\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"message\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_host content matches against a http request * which holds the content. */ static int DetectHttpHHTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy message"; uint8_t http2_buf[] = "body1\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"message\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched on p1 but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match on p2 but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_host content matches against a http request * which holds the content. */ static int DetectHttpHHTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "host: This is dummy mess"; uint8_t http2_buf[] = "age body\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"message\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_host content matches against a http request * which holds the content, against a cross boundary present pattern. */ static int DetectHttpHHTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"body1this\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the http_host content matches against a http request * against a case insensitive pattern. */ static int DetectHttpHHTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy bodY1"; uint8_t http2_buf[] = "This is dummy message body2\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy bodY1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"body1this\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** *\test Test that the negated http_host content matches against a * http request which doesn't hold the content. */ static int DetectHttpHHTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy message body\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:!\"message\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Negative test that the negated http_host content matches against a * http request which holds hold the content. */ static int DetectHttpHHTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: This is dummy body\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:!\"message\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_host content matches against a http request * which holds the content. */ static int DetectHttpHHTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "User-Agent: www.openinfosecfoundation.org\r\n" "Host: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n" "Content-Type: text/html\r\n" "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host test\"; " "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test multiple http transactions and body chunks of request handling */ static int DetectHttpHHTest14(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "Cookie: dummy1\r\n"; uint8_t httpbuf3[] = "Host: Body one!!\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf5[] = "Cookie: dummy2\r\n"; uint8_t httpbuf6[] = "Host: Body two\r\n\r\n"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; http_cookie; content:\"body one\"; http_host; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"dummy2\"; http_cookie; content:\"body two\"; http_host; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) || PacketAlertCheck(p, 2)) { printf("sig 1 alerted (4): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) || !(PacketAlertCheck(p, 2))) { printf("signature 2 didn't match or sig 1 matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } int DetectHttpHHTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"one\"; http_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (cd->id == hhhd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; nocase; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (cd->id == hhhd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_host; nocase; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (cd->id != 0 || hhhd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; nocase; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (cd->id != 1 || hhhd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; nocase; " "content:\"one\"; content:\"one\"; http_host; nocase; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (cd->id != 1 || hhhd1->id != 0 || hhhd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; nocase; " "content:\"one\"; content:\"one\"; http_host; nocase; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; if (cd->id != 2 || hhhd1->id != 0 || hhhd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; http_host; " "content:\"three\"; distance:10; http_host; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "two", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hhhd2->content, "three", hhhd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd1) || !DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hhhd1) || DETECT_CONTENT_IS_SINGLE(hhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; pcre:/two/; " "content:\"three\"; distance:10; http_host; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hhhd2->content, "three", hhhd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hhhd1) || DETECT_CONTENT_IS_SINGLE(hhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; pcre:/two/; " "content:\"three\"; distance:10; within:15; http_host; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(hhhd2->content, "three", hhhd1->content_len) != 0) { goto end; } if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hhhd1) || DETECT_CONTENT_IS_SINGLE(hhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; pcre:/two/; " "content:\"three\"; distance:10; http_host; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hhhd2->content, "three", hhhd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hhhd1) || DETECT_CONTENT_IS_SINGLE(hhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_host; pcre:/two/; " "content:\"three\"; distance:10; http_host; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || memcmp(hhhd2->content, "three", hhhd1->content_len) != 0) { printf ("failed: http_host incorrect flags"); goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hhhd1) || DETECT_CONTENT_IS_SINGLE(hhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_host; pcre:/two/; " "content:\"three\"; distance:10; http_host; within:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; pcre:/two/; " "content:\"three\"; http_host; depth:10; " "content:\"four\"; distance:10; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (0) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DEPTH) || memcmp(hhhd2->content, "three", hhhd1->content_len) != 0) { goto end; } if (DETECT_CONTENT_IS_SINGLE(cd2) || !DETECT_CONTENT_IS_SINGLE(hhhd1) || DETECT_CONTENT_IS_SINGLE(hhhd2)) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; distance:0; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hhhd2->content, "two", hhhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; within:5; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hhhd2->content, "two", hhhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/W; " "content:\"two\"; within:5; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_HOST) || hhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hhhd2->content, "two", hhhd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "pcre:/one/WR; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_PCRE || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_CONTENT) { goto end; } DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_HTTP_HOST) || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "two", hhhd1->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpHHTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/W; " "content:\"two\"; distance:5; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_CONTENT || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_HTTP_HOST) || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hhhd2->content, "two", hhhd2->content_len) != 0) { goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ void DetectHttpHHRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectHttpHHTest01", DetectHttpHHTest01, 1); UtRegisterTest("DetectHttpHHTest02", DetectHttpHHTest02, 1); UtRegisterTest("DetectHttpHHTest03", DetectHttpHHTest03, 1); UtRegisterTest("DetectHttpHHTest04", DetectHttpHHTest04, 1); UtRegisterTest("DetectHttpHHTest05", DetectHttpHHTest05, 1); UtRegisterTest("DetectHttpHHTest06", DetectHttpHHTest06, 1); UtRegisterTest("DetectHttpHHTest07", DetectHttpHHTest07, 1); UtRegisterTest("DetectHttpHHTest08", DetectHttpHHTest08, 1); UtRegisterTest("DetectHttpHHTest09", DetectHttpHHTest09, 1); UtRegisterTest("DetectHttpHHTest10", DetectHttpHHTest10, 1); UtRegisterTest("DetectHttpHHTest11", DetectHttpHHTest11, 1); UtRegisterTest("DetectHttpHHTest12", DetectHttpHHTest12, 1); UtRegisterTest("DetectHttpHHTest13", DetectHttpHHTest13, 1); UtRegisterTest("DetectHttpHHTest14", DetectHttpHHTest14, 1); UtRegisterTest("DetectHttpHHTest16", DetectHttpHHTest16, 1); UtRegisterTest("DetectHttpHHTest17", DetectHttpHHTest17, 1); UtRegisterTest("DetectHttpHHTest18", DetectHttpHHTest18, 1); UtRegisterTest("DetectHttpHHTest19", DetectHttpHHTest19, 1); UtRegisterTest("DetectHttpHHTest20", DetectHttpHHTest20, 1); UtRegisterTest("DetectHttpHHTest21", DetectHttpHHTest21, 1); UtRegisterTest("DetectHttpHHTest22", DetectHttpHHTest22, 1); UtRegisterTest("DetectHttpHHTest23", DetectHttpHHTest23, 1); UtRegisterTest("DetectHttpHHTest24", DetectHttpHHTest24, 1); UtRegisterTest("DetectHttpHHTest25", DetectHttpHHTest25, 1); UtRegisterTest("DetectHttpHHTest26", DetectHttpHHTest26, 1); UtRegisterTest("DetectHttpHHTest27", DetectHttpHHTest27, 1); UtRegisterTest("DetectHttpHHTest28", DetectHttpHHTest28, 1); UtRegisterTest("DetectHttpHHTest29", DetectHttpHHTest29, 1); UtRegisterTest("DetectHttpHHTest30", DetectHttpHHTest30, 1); UtRegisterTest("DetectHttpHHTest31", DetectHttpHHTest31, 1); UtRegisterTest("DetectHttpHHTest32", DetectHttpHHTest32, 1); UtRegisterTest("DetectHttpHHTest33", DetectHttpHHTest33, 1); UtRegisterTest("DetectHttpHHTest34", DetectHttpHHTest34, 1); UtRegisterTest("DetectHttpHHTest35", DetectHttpHHTest35, 1); UtRegisterTest("DetectHttpHHTest36", DetectHttpHHTest36, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/util-mpm-wumanber.c0000644000000000000000000030014612253546156014557 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implementation of the Wu-Manber pattern matching algorithm. * * Ideas: * - the hash contains a list of patterns. Maybe we can 'train' the hash * so the most common patterns always appear first in this list. * * \todo make hash1 a array of ptr and get rid of the flag field in the * WmHashItem * \todo remove exit() calls * \todo only calc prefixci_buf for nocase patterns? -- would be in a * loop though, so probably not a performance inprovement. * \todo make sure runtime counters can be disabled (at compile time) */ #include "suricata-common.h" #include "suricata.h" #include "util-mpm.h" #include "util-mpm-wumanber.h" #include "conf.h" #include "util-unittest.h" #include "util-debug.h" #define INIT_HASH_SIZE 65535 #define HASH16_SIZE 65536 #define HASH16(a,b) (((a)<<8) | (b)) #define HASH15_SIZE 32768 #define HASH15(a,b) (((a)<<7) | (b)) #define HASH14_SIZE 16384 #define HASH14(a,b) (((a)<<6) | (b)) #define HASH12_SIZE 4096 #define HASH12(a,b) (((a)<<4) | (b)) #define HASH9_SIZE 512 #define HASH9(a,b) (((a)<<1) | (b)) static uint32_t wm_hash_size = 0; static uint32_t wm_bloom_size = 0; void WmInitCtx (MpmCtx *mpm_ctx, int); void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t); void WmDestroyCtx(MpmCtx *mpm_ctx); void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx); int WmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int WmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int WmPreparePatterns(MpmCtx *mpm_ctx); uint32_t WmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); void WmPrintInfo(MpmCtx *mpm_ctx); void WmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void WmRegisterTests(void); /* uppercase to lowercase conversion lookup table */ static uint8_t lowercasetable[256]; /* marco to do the actual lookup */ #define wm_tolower(c) lowercasetable[(c)] #ifdef WUMANBER_COUNTERS #define COUNT(counter) \ (counter) #else #define COUNT(counter) #endif /* WUMANBER_COUNTERS */ void prt (uint8_t *buf, uint16_t buflen) { uint16_t i; for (i = 0; i < buflen; i++) { if (isprint(buf[i])) printf("%c", buf[i]); else printf("\\x%" PRIX32, buf[i]); } //printf("\n"); } void WmPrintInfo(MpmCtx *mpm_ctx) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; printf("MPM WuManber Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); printf(" Sizeofs:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" WmCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(WmCtx)); printf(" WmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(WmPattern)); printf(" WmHashItem %" PRIuMAX "\n", (uintmax_t)sizeof(WmHashItem)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Max shiftlen: %" PRIu32 "\n", ctx->shiftlen); printf("Hash size: %" PRIu32 "\n", ctx->hash_size); printf("Search function: "); if (ctx->Search == WmSearch1) { printf("WmSearch1 (allows single byte patterns)\n"); printf("MBSearch funct: "); if (ctx->MBSearch == WmSearch2Hash16) printf("WmSearch2Hash16\n"); else if (ctx->MBSearch == WmSearch2Hash15) printf("WmSearch2Hash15\n"); else if (ctx->MBSearch == WmSearch2Hash14) printf("WmSearch2Hash14\n"); else if (ctx->MBSearch == WmSearch2Hash12) printf("WmSearch2Hash12\n"); else if (ctx->MBSearch == WmSearch2Hash9) printf("WmSearch2Hash9\n"); } if (ctx->Search == WmSearch2Hash16) printf("WmSearch2Hash16 (only for multibyte patterns)\n"); else if (ctx->Search == WmSearch2Hash15) printf("WmSearch2Hash15 (only for multibyte patterns)\n"); else if (ctx->Search == WmSearch2Hash14) printf("WmSearch2Hash14 (only for multibyte patterns)\n"); else if (ctx->Search == WmSearch2Hash12) printf("WmSearch2Hash12 (only for multibyte patterns)\n"); else if (ctx->Search == WmSearch2Hash9) printf("WmSearch2Hash9 (only for multibyte patterns)\n"); else printf("ERROR\n"); printf("\n"); } static inline WmPattern *WmAllocPattern(MpmCtx *mpm_ctx) { WmPattern *p = SCMalloc(sizeof(WmPattern)); if (unlikely(p == NULL)) return NULL; memset(p,0,sizeof(WmPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(WmPattern); return p; } static inline WmHashItem * WmAllocHashItem(MpmCtx *mpm_ctx) { WmHashItem *hi = SCMalloc(sizeof(WmHashItem)); if (unlikely(hi == NULL)) return NULL; memset(hi,0,sizeof(WmHashItem)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(WmHashItem); return hi; } static void WmHashFree(MpmCtx *mpm_ctx, WmHashItem *hi) { if (hi == NULL) return; WmHashItem *t = hi->nxt; WmHashFree(mpm_ctx, t); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(WmHashItem); SCFree(hi); } static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) { d[i] = wm_tolower(s[i]); } } /* * INIT HASH START */ static inline uint32_t WmInitHash(WmPattern *p) { uint32_t hash = p->len * p->cs[0]; if (p->len > 1) hash += p->cs[1]; return (hash % INIT_HASH_SIZE); } static inline uint32_t WmInitHashRaw(uint8_t *pat, uint16_t patlen) { uint32_t hash = patlen * pat[0]; if (patlen > 1) hash += pat[1]; return (hash % INIT_HASH_SIZE); } static inline int WmInitHashAdd(WmCtx *ctx, WmPattern *p) { uint32_t hash = WmInitHash(p); //printf("WmInitHashAdd: %" PRIu32 "\n", hash); if (ctx->init_hash[hash] == NULL) { ctx->init_hash[hash] = p; //printf("WmInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); return 0; } WmPattern *tt = NULL; WmPattern *t = ctx->init_hash[hash]; /* get the list tail */ do { tt = t; t = t->next; } while (t != NULL); tt->next = p; //printf("WmInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); return 0; } static inline int WmCmpPattern(WmPattern *p, uint8_t *pat, uint16_t patlen, char flags); static inline WmPattern *WmInitHashLookup(WmCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) { uint32_t hash = WmInitHashRaw(pat,patlen); //printf("WmInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); if (ctx->init_hash[hash] == NULL) { return NULL; } WmPattern *t = ctx->init_hash[hash]; for ( ; t != NULL; t = t->next) { if (WmCmpPattern(t,pat,patlen,flags) == 1) return t; } return NULL; } static inline int WmCmpPattern(WmPattern *p, uint8_t *pat, uint16_t patlen, char flags) { if (p->len != patlen) return 0; if (p->flags != flags) return 0; if (memcmp(p->cs, pat, patlen) != 0) return 0; return 1; } /* * INIT HASH END */ void WmFreePattern(MpmCtx *mpm_ctx, WmPattern *p) { if (p && p->cs && p->cs != p->ci) { SCFree(p->cs); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p && p->ci) { SCFree(p->ci); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p) { SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(WmPattern); } } /* WmAddPattern * * pat: ptr to the pattern * patlen: length of the pattern * nocase: nocase flag: 1 enabled, 0 disable * pid: pattern id * sid: signature id (internal id) */ static int WmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; // printf("WmAddPattern: ctx %p \"", mpm_ctx); prt(pat, patlen); // printf("\" id %" PRIu32 ", nocase %s\n", id, nocase ? "true" : "false"); if (patlen == 0) return 0; /* get a memory piece */ WmPattern *p = WmInitHashLookup(ctx, pat, patlen, flags); if (p == NULL) { // printf("WmAddPattern: allocing new pattern\n"); p = WmAllocPattern(mpm_ctx); if (p == NULL) goto error; p->len = patlen; p->flags = flags; p->id = pid; /* setup the case insensitive part of the pattern */ p->ci = SCMalloc(patlen); if (p->ci == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy_tolower(p->ci, pat, patlen); /* setup the case sensitive part of the pattern */ if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* nocase means no difference between cs and ci */ p->cs = p->ci; } else { if (memcmp(p->ci,pat,p->len) == 0) { /* no diff between cs and ci: pat is lowercase */ p->cs = p->ci; } else { p->cs = SCMalloc(patlen); if (p->cs == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->cs, pat, patlen); } } if (p->len > 1) { p->prefix_cs = (uint16_t)(*(p->cs)+*(p->cs+1)); p->prefix_ci = (uint16_t)(*(p->ci)+*(p->ci+1)); } //printf("WmAddPattern: ci \""); prt(p->ci,p->len); //printf("\" cs \""); prt(p->cs,p->len); //printf("\" prefix_ci %" PRIu32 ", prefix_cs %" PRIu32 "\n", p->prefix_ci, p->prefix_cs); /* put in the pattern hash */ WmInitHashAdd(ctx, p); if (mpm_ctx->pattern_cnt == 65535) { printf("Max search words reached\n"); exit(1); } mpm_ctx->pattern_cnt++; if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } return 0; error: WmFreePattern(mpm_ctx, p); return -1; } int WmAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return WmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int WmAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return WmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } static uint32_t WmBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint16_t i; uint32_t hash = (uint32_t)wm_tolower(*d); for (i = 1; i < datalen - 1; i++) { hash += (wm_tolower((*d++))) ^ i; } hash <<= (iter+1); hash %= hash_size; return hash; } /* static uint32_t BloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint32_t i; uint32_t hash = 0; for (i = 0; i < datalen; i++) { if (i == 0) hash += (((uint32_t)*d++)); else if (i == 1) hash += (((uint32_t)*d++) * datalen); else hash *= (((uint32_t)*d++) * i); } hash *= (iter + datalen); hash %= hash_size; return hash; } */ static void WmSearchPrepareHash(MpmCtx *mpm_ctx) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; uint16_t i; uint16_t idx = 0; uint8_t idx8 = 0; ctx->hash = (WmHashItem **)SCMalloc(sizeof(WmHashItem *) * ctx->hash_size); if (ctx->hash == NULL) goto error; memset(ctx->hash, 0, sizeof(WmHashItem *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(WmHashItem *) * ctx->hash_size); /* alloc the pminlen array */ ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); if (ctx->pminlen == NULL) goto error; memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if(ctx->parray[i]->len == 1) { idx8 = (uint8_t)ctx->parray[i]->ci[0]; if (ctx->hash1[idx8].flags == 0) { ctx->hash1[idx8].idx = i; ctx->hash1[idx8].flags |= 0x01; } else { WmHashItem *hi = WmAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; /* Append this HashItem to the list */ WmHashItem *thi = &ctx->hash1[idx8]; while (thi->nxt) thi = thi->nxt; thi->nxt = hi; } } else { uint16_t patlen = ctx->shiftlen; if (ctx->hash_size == HASH9_SIZE) idx = HASH9(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); else if (ctx->hash_size == HASH12_SIZE) idx = HASH12(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); else if (ctx->hash_size == HASH14_SIZE) idx = HASH14(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); else if (ctx->hash_size == HASH15_SIZE) idx = HASH15(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); else idx = HASH16(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); if (ctx->hash[idx] == NULL) { WmHashItem *hi = WmAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; ctx->pminlen[idx] = ctx->parray[i]->len; ctx->hash[idx] = hi; } else { WmHashItem *hi = WmAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; if (ctx->parray[i]->len < ctx->pminlen[idx]) ctx->pminlen[idx] = ctx->parray[i]->len; /* Append this HashItem to the list */ WmHashItem *thi = ctx->hash[idx]; while (thi->nxt) thi = thi->nxt; thi->nxt = hi; } } } /* alloc the bloom array */ ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); if (ctx->bloom == NULL) goto error; memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); uint32_t h; for (h = 0; h < ctx->hash_size; h++) { WmHashItem *hi = ctx->hash[h]; if (hi == NULL) continue; ctx->bloom[h] = BloomFilterInit(wm_bloom_size, 2, WmBloomHash); if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); if (ctx->pminlen[h] > 8) ctx->pminlen[h] = 8; WmHashItem *thi = hi; do { BloomFilterAdd(ctx->bloom[h], ctx->parray[thi->idx]->ci, ctx->pminlen[h]); thi = thi->nxt; } while (thi != NULL); } return; error: return; } static void WmSearchPrepareShiftTable(MpmCtx *mpm_ctx) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; uint16_t shift = 0, k = 0, idx = 0; uint32_t i = 0; uint16_t smallest = mpm_ctx->minlen; if (smallest > 255) smallest = 255; if (smallest < 2) smallest = 2; ctx->shiftlen = smallest; ctx->shifttable = SCMalloc(sizeof(uint16_t) * ctx->hash_size); if (ctx->shifttable == NULL) return; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(uint16_t) * ctx->hash_size); /* default shift table is set to minimal shift */ for (i = 0; i < ctx->hash_size; i++) ctx->shifttable[i] = ctx->shiftlen; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { /* ignore one byte patterns */ if (ctx->parray[i]->len == 1) continue; /* add the first character of the pattern preceeded by * every possible other character. */ for (k = 0; k < 256; k++) { shift = ctx->shiftlen - 1; if (shift > 255) shift = 255; if (ctx->hash_size == HASH9_SIZE) { idx = HASH9(ctx->parray[i]->ci[0], (uint8_t)k); //printf("HASH9 idx %" PRIu32 "\n", idx); } else if (ctx->hash_size == HASH12_SIZE) { idx = HASH12(ctx->parray[i]->ci[0], (uint8_t)k); //printf("HASH12 idx %" PRIu32 "\n", idx); } else if (ctx->hash_size == HASH14_SIZE) { idx = HASH14(ctx->parray[i]->ci[0], (uint8_t)k); //printf("HASH14 idx %" PRIu32 "\n", idx); } else if (ctx->hash_size == HASH15_SIZE) { idx = HASH15(ctx->parray[i]->ci[0], (uint8_t)k); //printf("HASH15 idx %" PRIu32 "\n", idx); } else { idx = HASH16(ctx->parray[i]->ci[0], (uint8_t)k); //printf("HASH15 idx %" PRIu32 "\n", idx); } if (shift < ctx->shifttable[idx]) { ctx->shifttable[idx] = shift; } } for (k = 0; k < ctx->shiftlen-1; k++) { shift = (ctx->shiftlen - 2 - k); if (shift > 255) shift = 255; if (ctx->hash_size == HASH9_SIZE) { idx = HASH9(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); //printf("HASH9 idx %" PRIu32 "\n", idx); } else if (ctx->hash_size == HASH12_SIZE) { idx = HASH12(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); //printf("HASH12 idx %" PRIu32 "\n", idx); } else if (ctx->hash_size == HASH14_SIZE) { idx = HASH14(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); //printf("HASH14 idx %" PRIu32 "\n", idx); } else if (ctx->hash_size == HASH15_SIZE) { idx = HASH15(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); //printf("HASH15 idx %" PRIu32 "\n", idx); } else { idx = HASH16(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); //printf("HASH15 idx %" PRIu32 "\n", idx); } if (shift < ctx->shifttable[idx]) { ctx->shifttable[idx] = shift; } //printf("WmPrepareShiftTable: i %" PRIu32 ", k %" PRIu32 ", idx %" PRIu32 ", shift set to %" PRIu32 ": \"%c%c\"\n", // i, k, idx, shift, ctx->parray[i]->ci[k], ctx->parray[i]->ci[k+1]); } } } int WmPreparePatterns(MpmCtx *mpm_ctx) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; /* alloc the pattern array */ ctx->parray = (WmPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(WmPattern *)); if (ctx->parray == NULL) goto error; memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(WmPattern *)); //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(WmPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; for (i = 0; i < INIT_HASH_SIZE; i++) { WmPattern *node = ctx->init_hash[i], *nnode = NULL; for ( ; node != NULL; ) { nnode = node->next; node->next = NULL; ctx->parray[p] = node; p++; node = nnode; } } /* we no longer need the hash, so free it's memory */ SCFree(ctx->init_hash); ctx->init_hash = NULL; /* TODO VJ these values are chosen pretty much randomly, so * we should do some performance testing * */ if (ctx->hash_size == 0) { if (mpm_ctx->pattern_cnt < 50) { ctx->hash_size = HASH9_SIZE; } else if(mpm_ctx->pattern_cnt < 300) { ctx->hash_size = HASH12_SIZE; } else if(mpm_ctx->pattern_cnt < 1200) { ctx->hash_size = HASH14_SIZE; } else if(mpm_ctx->pattern_cnt < 2400) { ctx->hash_size = HASH15_SIZE; } else { ctx->hash_size = HASH16_SIZE; } } WmSearchPrepareShiftTable(mpm_ctx); WmSearchPrepareHash(mpm_ctx); if (ctx->hash_size == HASH9_SIZE) { ctx->MBSearch = WmSearch2Hash9; ctx->Search = WmSearch2Hash9; } else if (ctx->hash_size == HASH12_SIZE) { ctx->MBSearch = WmSearch2Hash12; ctx->Search = WmSearch2Hash12; } else if (ctx->hash_size == HASH14_SIZE) { ctx->MBSearch = WmSearch2Hash14; ctx->Search = WmSearch2Hash14; } else if (ctx->hash_size == HASH15_SIZE) { ctx->MBSearch = WmSearch2Hash15; ctx->Search = WmSearch2Hash15; } else { ctx->MBSearch = WmSearch2Hash16; ctx->Search = WmSearch2Hash16; } if (mpm_ctx->minlen == 1) { ctx->Search = WmSearch1; } return 0; error: return -1; } void WmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef WUMANBER_COUNTERS WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; printf("Shift 0: %" PRIu32 "\n", tctx->stat_shift_null); printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); #endif /* WUMANBER_COUNTERS */ } static inline int memcmp_lowercase(uint8_t *s1, uint8_t *s2, uint16_t n) { size_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ for (i = n - 1; i; i--) { if (wm_tolower(*(s2+i)) != s1[i]) return 1; } return 0; } inline uint32_t WmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; return ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen); } /* SCAN FUNCTIONS */ uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; #ifdef WUMANBER_COUNTERS WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; #endif /* WUMANBER_COUNTERS */ uint32_t cnt = 0; uint8_t *bufend = buf + buflen - 1; uint16_t sl = ctx->shiftlen; uint16_t h; uint8_t shift; WmHashItem *thi, *hi; WmPattern *p; uint16_t prefixci_buf; uint16_t prefixcs_buf; if (buflen == 0) return 0; //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf(" (sl %" PRIu32 ")\n", sl); buf+=(sl-1); while (buf <= bufend) { h = HASH9(wm_tolower(*buf),(wm_tolower(*(buf-1)))); shift = ctx->shifttable[h]; //printf("%p %" PRIu32 " search: h %" PRIu32 ", shift %" PRIu32 "\n", buf, buf - bufmin, h, shift); if (shift == 0) { COUNT(tctx->stat_shift_null++); hi = ctx->hash[h]; //printf("search: hi %p\n", hi); if (hi != NULL) { /* get our patterns from the hash */ if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((bufend - (buf-sl)) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); goto skip_loop; } } } prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", // p->prefix_ci, p->prefix_cs); if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp(p->cs, buf-sl+1, p->len) == 0) { //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } } skip_loop: shift = 1; } else { COUNT(tctx->stat_total_shift += shift); COUNT(tctx->stat_num_shift++); } buf += shift; } //printf("cnt %" PRIu32 "\n", cnt); return cnt; } uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; #ifdef WUMANBER_COUNTERS WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; #endif /* WUMANBER_COUNTERS */ uint32_t cnt = 0; uint8_t *bufend = buf + buflen - 1; uint16_t sl = ctx->shiftlen; uint16_t h; uint8_t shift; WmHashItem *thi, *hi; WmPattern *p; uint16_t prefixci_buf; uint16_t prefixcs_buf; if (buflen == 0) return 0; //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); buf+=(sl-1); //buf++; while (buf <= bufend) { //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); h = HASH12(wm_tolower(*buf),(wm_tolower(*(buf-1)))); shift = ctx->shifttable[h]; //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); if (shift == 0) { COUNT(tctx->stat_shift_null++); /* get our hash item */ hi = ctx->hash[h]; //printf("search: hi %p\n", hi); if (hi != NULL) { /* get our patterns from the hash */ if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((bufend - (buf-sl)) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); goto skip_loop; } } } prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", // p->prefix_ci, p->prefix_cs); if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp(p->cs, buf-sl+1, p->len) == 0) { //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } } skip_loop: shift = 1; } else { COUNT(tctx->stat_total_shift += shift); COUNT(tctx->stat_num_shift++); } buf += shift; } return cnt; } uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; #ifdef WUMANBER_COUNTERS WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; #endif /* WUMANBER_COUNTERS */ uint32_t cnt = 0; uint8_t *bufend = buf + buflen - 1; uint16_t sl = ctx->shiftlen; uint16_t h; uint8_t shift; WmHashItem *thi, *hi; WmPattern *p; uint16_t prefixci_buf; uint16_t prefixcs_buf; if (buflen == 0) return 0; //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); buf+=(sl-1); //buf++; while (buf <= bufend) { //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); h = HASH14(wm_tolower(*buf),(wm_tolower(*(buf-1)))); shift = ctx->shifttable[h]; //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); if (shift == 0) { COUNT(tctx->stat_shift_null++); /* get our hash item */ hi = ctx->hash[h]; //printf("search: hi %p\n", hi); if (hi != NULL) { /* get our patterns from the hash */ if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((bufend - (buf-sl)) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); goto skip_loop; } } } prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", // p->prefix_ci, p->prefix_cs); if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp(p->cs, buf-sl+1, p->len) == 0) { COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } } skip_loop: shift = 1; } else { COUNT(tctx->stat_total_shift += shift); COUNT(tctx->stat_num_shift++); } buf += shift; } return cnt; } uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; #ifdef WUMANBER_COUNTERS WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; #endif /* WUMANBER_COUNTERS */ uint32_t cnt = 0; uint8_t *bufend = buf + buflen - 1; uint16_t sl = ctx->shiftlen; uint16_t h; uint8_t shift; WmHashItem *thi, *hi; WmPattern *p; uint16_t prefixci_buf; uint16_t prefixcs_buf; if (buflen == 0) return 0; //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); buf+=(sl-1); //buf++; while (buf <= bufend) { //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); h = HASH15(wm_tolower(*buf),(wm_tolower(*(buf-1)))); shift = ctx->shifttable[h]; //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); if (shift == 0) { COUNT(tctx->stat_shift_null++); /* get our hash item */ hi = ctx->hash[h]; //printf("search: hi %p\n", hi); if (hi != NULL) { /* get our patterns from the hash */ if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((bufend - (buf-sl)) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); goto skip_loop; } } } prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", // p->prefix_ci, p->prefix_cs); if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp(p->cs, buf-sl+1, p->len) == 0) { //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } } skip_loop: shift = 1; } else { COUNT(tctx->stat_total_shift += shift); COUNT(tctx->stat_num_shift++); } buf += shift; } return cnt; } uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; #ifdef WUMANBER_COUNTERS WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; #endif /* WUMANBER_COUNTERS */ uint32_t cnt = 0; uint8_t *bufend = buf + buflen - 1; uint16_t sl = ctx->shiftlen; uint16_t h; uint8_t shift; WmHashItem *thi, *hi; WmPattern *p; uint16_t prefixci_buf; uint16_t prefixcs_buf; if (buflen == 0) return 0; //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); buf+=(sl-1); //buf++; while (buf <= bufend) { //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); h = HASH16(wm_tolower(*buf),(wm_tolower(*(buf-1)))); shift = ctx->shifttable[h]; //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); if (shift == 0) { COUNT(tctx->stat_shift_null++); /* get our hash item */ hi = ctx->hash[h]; //printf("search: hi %p\n", hi); if (hi != NULL) { /* get our patterns from the hash */ if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((bufend - (buf-sl)) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); goto skip_loop; } } } prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", // p->prefix_ci, p->prefix_cs); if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) continue; if (memcmp(p->cs, buf-sl+1, p->len) == 0) { COUNT(tctx->stat_loop_match++); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } } skip_loop: shift = 1; } else { COUNT(tctx->stat_total_shift += shift); COUNT(tctx->stat_num_shift++); } buf += shift; } return cnt; } uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; WmPattern *p; WmHashItem *thi, *hi; if (buflen == 0) return 0; //printf("BUF "); prt(buf,buflen); printf("\n"); if (mpm_ctx->minlen == 1) { while (buf <= bufend) { uint8_t h = wm_tolower(*buf); hi = &ctx->hash1[h]; if (hi->flags & 0x01) { for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; if (p->len != 1) continue; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (wm_tolower(*buf) == p->ci[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } else { if (*buf == p->cs[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } } } buf += 1; } } //printf("WmSearch1: after 1byte cnt %" PRIu32 "\n", cnt); if (mpm_ctx->maxlen > 1) { /* Pass bufmin on because buf no longer points to the * start of the buffer. */ cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); //printf("WmSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); } return cnt; } /** * \brief Function to get the user defined values for wumanber algorithm from * the config file 'suricata.yaml' */ void WmGetConfig() { ConfNode *wm_conf; const char *hash_val = NULL; const char *bloom_val = NULL; /* init defaults */ wm_hash_size = HASHSIZE_LOW; wm_bloom_size = BLOOMSIZE_MEDIUM; ConfNode *pm = ConfGetNode("pattern-matcher"); if (pm != NULL) { TAILQ_FOREACH(wm_conf, &pm->head, next) { if (strncmp(wm_conf->val, "wumanber", 8) == 0) { hash_val = ConfNodeLookupChildValue(wm_conf->head.tqh_first, "hash_size"); bloom_val = ConfNodeLookupChildValue(wm_conf->head.tqh_first, "bf_size"); if (hash_val != NULL) wm_hash_size = MpmGetHashSize(hash_val); if (bloom_val != NULL) wm_bloom_size = MpmGetBloomSize(bloom_val); SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", wm_hash_size, wm_bloom_size); } } } } void WmInitCtx (MpmCtx *mpm_ctx, int module_handle) { SCLogDebug("mpm_ctx %p", mpm_ctx); mpm_ctx->ctx = SCMalloc(sizeof(WmCtx)); if (mpm_ctx->ctx == NULL) return; memset(mpm_ctx->ctx, 0, sizeof(WmCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(WmCtx); /* initialize the hash we use to speed up pattern insertions */ WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; ctx->init_hash = SCMalloc(sizeof(WmPattern *) * INIT_HASH_SIZE); if (ctx->init_hash == NULL) return; memset(ctx->init_hash, 0, sizeof(WmPattern *) * INIT_HASH_SIZE); /* Initialize the defaults value from the config file. The given check make sure that we query config file only once for config values */ if (wm_hash_size == 0) WmGetConfig(); } void WmDestroyCtx(MpmCtx *mpm_ctx) { WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->init_hash) { SCFree(ctx->init_hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(WmPattern *)); } if (ctx->parray) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { WmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(WmPattern)); } if (ctx->bloom) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); BloomFilterFree(ctx->bloom[h]); } SCFree(ctx->bloom); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); } if (ctx->hash) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->hash[h] == NULL) continue; WmHashFree(mpm_ctx, ctx->hash[h]); } SCFree(ctx->hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(WmHashItem) * ctx->hash_size); } if (ctx->shifttable) { SCFree(ctx->shifttable); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(uint16_t) * ctx->hash_size); } if (ctx->pminlen) { SCFree(ctx->pminlen); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(WmCtx); } void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); #ifdef WUMANBER_COUNTERS mpm_thread_ctx->ctx = SCMalloc(sizeof(WmThreadCtx)); if (mpm_thread_ctx->ctx == NULL) return; memset(mpm_thread_ctx->ctx, 0, sizeof(WmThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(WmThreadCtx); #endif } void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { WmThreadCtx *ctx = (WmThreadCtx *)mpm_thread_ctx->ctx; if (ctx != NULL) { /* size can be 0 when optimized */ mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(WmThreadCtx); SCFree(mpm_thread_ctx->ctx); } } void MpmWuManberRegister (void) { mpm_table[MPM_WUMANBER].name = "wumanber"; mpm_table[MPM_WUMANBER].max_pattern_length = 0; mpm_table[MPM_WUMANBER].InitCtx = WmInitCtx; mpm_table[MPM_WUMANBER].InitThreadCtx = WmThreadInitCtx; mpm_table[MPM_WUMANBER].DestroyCtx = WmDestroyCtx; mpm_table[MPM_WUMANBER].DestroyThreadCtx = WmThreadDestroyCtx; mpm_table[MPM_WUMANBER].AddPattern = WmAddPatternCS; mpm_table[MPM_WUMANBER].AddPatternNocase = WmAddPatternCI; mpm_table[MPM_WUMANBER].Prepare = WmPreparePatterns; mpm_table[MPM_WUMANBER].Search = WmSearch; mpm_table[MPM_WUMANBER].Cleanup = NULL; mpm_table[MPM_WUMANBER].PrintCtx = WmPrintInfo; mpm_table[MPM_WUMANBER].PrintThreadCtx = WmPrintSearchStats; mpm_table[MPM_WUMANBER].RegisterUnittests = WmRegisterTests; /* create table for O(1) lowercase conversion lookup */ uint8_t c = 0; for ( ; c < 255; c++) { if (c >= 'A' && c <= 'Z') lowercasetable[c] = (c + ('a' - 'A')); else lowercasetable[c] = c; } } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS int WmTestInitCtx01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); WmInitCtx(&mpm_ctx, -1); if (mpm_ctx.ctx != NULL) result = 1; WmDestroyCtx(&mpm_ctx); return result; } int WmTestInitCtx02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); WmInitCtx(&mpm_ctx, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; if (ctx->parray == NULL) result = 1; WmDestroyCtx(&mpm_ctx); return result; } int WmTestInitCtx03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); if (mpm_table[MPM_WUMANBER].Search == WmSearch) result = 1; WmDestroyCtx(&mpm_ctx); return result; } int WmTestThreadInitCtx01 (void) { #ifdef WUMANBER_COUNTERS int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); if (mpm_thread_ctx.memory_cnt == 2) result = 1; else printf("mpm_thread_ctx.memory_cnt %"PRIu32", expected 2: ", mpm_thread_ctx.memory_cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; #else return 1; #endif } int WmTestThreadInitCtx02 (void) { #ifdef WUMANBER_COUNTERS int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx.ctx; if (tctx->search_stat_shift_null == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); #else int result = 1; #endif return result; } int WmTestInitAddPattern01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); int ret = WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); if (ret == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestInitAddPattern02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); if (ctx->init_hash != NULL) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestInitAddPattern03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); if (pat != NULL) { if (pat->len == 4) result = 1; } WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestInitAddPattern04 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, MPM_PATTERN_FLAG_NOCASE); WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, MPM_PATTERN_FLAG_NOCASE); if (pat != NULL) { if (pat->flags & MPM_PATTERN_FLAG_NOCASE) result = 1; } WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestInitAddPattern05 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); if (pat != NULL) { if (!(pat->flags & MPM_PATTERN_FLAG_NOCASE)) result = 1; } WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestInitAddPattern06 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); if (pat != NULL) { if (memcmp(pat->cs, "abcd", 4) == 0) result = 1; } WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestPrepare01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); if (ctx->Search == WmSearch1) result = 1; WmDestroyCtx(&mpm_ctx); return result; } int WmTestPrepare02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; if (ctx->shiftlen == 4) result = 1; WmDestroyCtx(&mpm_ctx); return result; } int WmTestPrepare03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; if (ctx->shifttable[1] == 4) result = 1; else printf("4 != %" PRIu32 ": ", ctx->shifttable[1]); WmDestroyCtx(&mpm_ctx); return result; } int WmTestPrepare04 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); if (ctx->Search == WmSearch1) result = 1; WmDestroyCtx(&mpm_ctx); return result; } int WmTestPrepare05 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; if (ctx->shiftlen == 4) result = 1; WmDestroyCtx(&mpm_ctx); return result; } int WmTestPrepare06 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; if (ctx->shifttable[1] == 4) result = 1; else printf("4 != %" PRIu32 ": ", ctx->shifttable[1]); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //mpm_ctx.PrintCtx(&mpm_ctx); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ", cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch01Hash12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); ctx->hash_size = HASH12_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //mpm_ctx.PrintCtx(&mpm_ctx); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ", cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch01Hash14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); ctx->hash_size = HASH14_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //mpm_ctx.PrintCtx(&mpm_ctx); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ", cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch01Hash15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); ctx->hash_size = HASH15_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //mpm_ctx.PrintCtx(&mpm_ctx); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ", cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch01Hash16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); ctx->hash_size = HASH16_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //mpm_ctx.PrintCtx(&mpm_ctx); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ", cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abce", 4); if (cnt == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ", cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch04 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch05 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"efgh", 4, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch06 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"eFgH", 4, 0, 0, 0, 0, MPM_PATTERN_FLAG_NOCASE); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdEfGh", 8); if (cnt == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch07 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"eFgH", 4, 0, 0, 1, 0, MPM_PATTERN_FLAG_NOCASE); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdEfGh", 8); if (cnt == 2) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch08 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 2) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch09 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); if (cnt == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch10 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmAddPattern(&mpm_ctx, (uint8_t *)"bc", 2, 0, 0, 0, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"gh", 2, 0, 0, 1, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 2) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch11 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmAddPattern(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"d", 1, 0, 0, 1, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"h", 1, 0, 0, 2, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 3) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, MPM_PATTERN_FLAG_NOCASE); WmAddPattern(&mpm_ctx, (uint8_t *)"d", 1, 0, 0, 1, 0, MPM_PATTERN_FLAG_NOCASE); WmAddPattern(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 2, 0, MPM_PATTERN_FLAG_NOCASE); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 ": ", cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch13 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"h", 1, 0, 0, 2, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 ": ", cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, MPM_PATTERN_FLAG_NOCASE); WmAddPattern(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 0, MPM_PATTERN_FLAG_NOCASE); WmAddPattern(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 2, 0, MPM_PATTERN_FLAG_NOCASE); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); if (cnt == 2) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } /** \todo VJ disabled because it tests the old match storage */ #if 0 int WmTestSearch15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 1, 1, 0, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 1, 1, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 1, 1, 2, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); uint32_t len = mpm_thread_ctx.match[1].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPattern(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 1, 1, 0, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 1, 1, 0, 0); WmAddPattern(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 1, 1, 2, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch17 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch18Hash12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH12_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch18Hash14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH14_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch18Hash15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH15_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch18 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH16_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch18Hash16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH16_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch19 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch19Hash12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH12_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch19Hash14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH14_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch19Hash15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH15_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch19Hash16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH16_SIZE; WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch20 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch20Hash12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH12_SIZE; /* force hash12 */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch20Hash14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH14_SIZE; /* force hash14 */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch20Hash15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH15_SIZE; /* force hash15 */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch20Hash16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH16_SIZE; /* force hash16 */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 0) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } int WmTestSearch21 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } static int WmTestSearch21Hash12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH12_SIZE; /* force hash16 */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //WmPrintInfo(&mpm_ctx); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } static int WmTestSearch21Hash14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH14_SIZE; /* force hash16 */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //WmPrintInfo(&mpm_ctx); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } static int WmTestSearch21Hash15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH15_SIZE; /* force hash16 */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //WmPrintInfo(&mpm_ctx); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } static int WmTestSearch21Hash16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); ctx->hash_size = HASH16_SIZE; /* force hash16 */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); //WmPrintInfo(&mpm_ctx); ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); uint32_t len = mpm_thread_ctx.match[0].len; if (len == 1) result = 1; WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } #endif static int WmTestSearch22Hash9 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ ctx->hash_size = HASH9_SIZE; /* force hash size */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } static int WmTestSearch22Hash12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ ctx->hash_size = HASH12_SIZE; /* force hash size */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } static int WmTestSearch22Hash14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ ctx->hash_size = HASH14_SIZE; /* force hash size */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } static int WmTestSearch22Hash15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ ctx->hash_size = HASH15_SIZE; /* force hash size */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } static int WmTestSearch22Hash16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_WUMANBER, -1); WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; WmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ WmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ ctx->hash_size = HASH16_SIZE; /* force hash size */ WmPreparePatterns(&mpm_ctx); WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); WmDestroyCtx(&mpm_ctx); return result; } #endif /* UNITTESTS */ void WmRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("WmTestInitCtx01", WmTestInitCtx01, 1); UtRegisterTest("WmTestInitCtx02", WmTestInitCtx02, 1); UtRegisterTest("WmTestInitCtx03", WmTestInitCtx03, 1); UtRegisterTest("WmTestThreadInitCtx01", WmTestThreadInitCtx01, 1); UtRegisterTest("WmTestThreadInitCtx02", WmTestThreadInitCtx02, 1); UtRegisterTest("WmTestInitAddPattern01", WmTestInitAddPattern01, 1); UtRegisterTest("WmTestInitAddPattern02", WmTestInitAddPattern02, 1); UtRegisterTest("WmTestInitAddPattern03", WmTestInitAddPattern03, 1); UtRegisterTest("WmTestInitAddPattern04", WmTestInitAddPattern04, 1); UtRegisterTest("WmTestInitAddPattern05", WmTestInitAddPattern05, 1); UtRegisterTest("WmTestInitAddPattern06", WmTestInitAddPattern06, 1); UtRegisterTest("WmTestPrepare01", WmTestPrepare01, 1); UtRegisterTest("WmTestPrepare02", WmTestPrepare02, 1); UtRegisterTest("WmTestPrepare03", WmTestPrepare03, 1); UtRegisterTest("WmTestPrepare04", WmTestPrepare01, 1); UtRegisterTest("WmTestPrepare05", WmTestPrepare02, 1); UtRegisterTest("WmTestPrepare06", WmTestPrepare03, 1); UtRegisterTest("WmTestSearch01", WmTestSearch01, 1); UtRegisterTest("WmTestSearch01Hash12", WmTestSearch01Hash12, 1); UtRegisterTest("WmTestSearch01Hash14", WmTestSearch01Hash14, 1); UtRegisterTest("WmTestSearch01Hash15", WmTestSearch01Hash15, 1); UtRegisterTest("WmTestSearch01Hash16", WmTestSearch01Hash16, 1); UtRegisterTest("WmTestSearch02", WmTestSearch02, 1); UtRegisterTest("WmTestSearch03", WmTestSearch03, 1); UtRegisterTest("WmTestSearch04", WmTestSearch04, 1); UtRegisterTest("WmTestSearch05", WmTestSearch05, 1); UtRegisterTest("WmTestSearch06", WmTestSearch06, 1); UtRegisterTest("WmTestSearch07", WmTestSearch07, 1); UtRegisterTest("WmTestSearch08", WmTestSearch08, 1); UtRegisterTest("WmTestSearch09", WmTestSearch09, 1); UtRegisterTest("WmTestSearch10", WmTestSearch10, 1); UtRegisterTest("WmTestSearch11", WmTestSearch11, 1); UtRegisterTest("WmTestSearch12", WmTestSearch12, 1); UtRegisterTest("WmTestSearch13", WmTestSearch13, 1); UtRegisterTest("WmTestSearch14", WmTestSearch14, 1); #if 0 UtRegisterTest("WmTestSearch15", WmTestSearch15, 1); UtRegisterTest("WmTestSearch16", WmTestSearch16, 1); UtRegisterTest("WmTestSearch17", WmTestSearch17, 1); UtRegisterTest("WmTestSearch18", WmTestSearch18, 1); UtRegisterTest("WmTestSearch18Hash12", WmTestSearch18Hash12, 1); UtRegisterTest("WmTestSearch18Hash14", WmTestSearch18Hash14, 1); UtRegisterTest("WmTestSearch18Hash15", WmTestSearch18Hash15, 1); UtRegisterTest("WmTestSearch18Hash16", WmTestSearch18Hash16, 1); UtRegisterTest("WmTestSearch19", WmTestSearch19, 1); UtRegisterTest("WmTestSearch19Hash12", WmTestSearch19Hash12, 1); UtRegisterTest("WmTestSearch19Hash14", WmTestSearch19Hash14, 1); UtRegisterTest("WmTestSearch19Hash15", WmTestSearch19Hash15, 1); UtRegisterTest("WmTestSearch19Hash16", WmTestSearch19Hash16, 1); UtRegisterTest("WmTestSearch20", WmTestSearch20, 1); UtRegisterTest("WmTestSearch20Hash12", WmTestSearch20Hash12, 1); UtRegisterTest("WmTestSearch20Hash14", WmTestSearch20Hash14, 1); UtRegisterTest("WmTestSearch20Hash15", WmTestSearch20Hash15, 1); UtRegisterTest("WmTestSearch20Hash16", WmTestSearch20Hash16, 1); UtRegisterTest("WmTestSearch21", WmTestSearch21, 1); UtRegisterTest("WmTestSearch21Hash12", WmTestSearch21Hash12, 1); UtRegisterTest("WmTestSearch21Hash14", WmTestSearch21Hash14, 1); UtRegisterTest("WmTestSearch21Hash15", WmTestSearch21Hash15, 1); UtRegisterTest("WmTestSearch21Hash16", WmTestSearch21Hash16, 1); #endif UtRegisterTest("WmTestSearch22Hash9", WmTestSearch22Hash9, 1); UtRegisterTest("WmTestSearch22Hash12", WmTestSearch22Hash12, 1); UtRegisterTest("WmTestSearch22Hash14", WmTestSearch22Hash14, 1); UtRegisterTest("WmTestSearch22Hash15", WmTestSearch22Hash15, 1); UtRegisterTest("WmTestSearch22Hash16", WmTestSearch22Hash16, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-flow.c0000644000000000000000000010462612253546156013417 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * FLOW part of the detection engine. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "flow.h" #include "flow-var.h" #include "detect-flow.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" /** * \brief Regex for parsing our flow options */ #define PARSE_REGEX "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([A-z_]+))?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectFlowMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectFlowSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowRegisterTests(void); void DetectFlowFree(void *); /** * \brief Registration function for flow: keyword */ void DetectFlowRegister (void) { sigmatch_table[DETECT_FLOW].name = "flow"; sigmatch_table[DETECT_FLOW].desc = "match on direction and state of the flow"; sigmatch_table[DETECT_FLOW].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flow"; sigmatch_table[DETECT_FLOW].Match = DetectFlowMatch; sigmatch_table[DETECT_FLOW].Setup = DetectFlowSetup; sigmatch_table[DETECT_FLOW].Free = DetectFlowFree; sigmatch_table[DETECT_FLOW].RegisterTests = DetectFlowRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /* * returns 0: no match * 1: match * -1: error */ /** * \brief This function is used to match flow flags set on a packet with those passed via flow: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectFlowData * * \retval 0 no match * \retval 1 match */ int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { SCEnter(); SCLogDebug("pkt %p", p); if (p->flowflags & FLOW_PKT_TOSERVER) { SCLogDebug("FLOW_PKT_TOSERVER"); } else if (p->flowflags & FLOW_PKT_TOCLIENT) { SCLogDebug("FLOW_PKT_TOCLIENT"); } if (p->flowflags & FLOW_PKT_ESTABLISHED) { SCLogDebug("FLOW_PKT_ESTABLISHED"); } else if (p->flowflags & FLOW_PKT_STATELESS) { SCLogDebug("FLOW_PKT_STATELESS"); } uint8_t cnt = 0; DetectFlowData *fd = (DetectFlowData *)m->ctx; if ((fd->flags & FLOW_PKT_TOSERVER) && (p->flowflags & FLOW_PKT_TOSERVER)) { cnt++; } else if ((fd->flags & FLOW_PKT_TOCLIENT) && (p->flowflags & FLOW_PKT_TOCLIENT)) { cnt++; } if ((fd->flags & FLOW_PKT_ESTABLISHED) && (p->flowflags & FLOW_PKT_ESTABLISHED)) { cnt++; } else if (fd->flags & FLOW_PKT_STATELESS) { cnt++; } if (det_ctx->flags & DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH) { if (fd->flags & FLOW_PKT_ONLYSTREAM) cnt++; } else { if (fd->flags & FLOW_PKT_NOSTREAM) cnt++; } int ret = (fd->match_cnt == cnt) ? 1 : 0; SCLogDebug("returning %" PRId32 " cnt %" PRIu8 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", ret, cnt, fd->match_cnt, fd->flags, p->flowflags); SCReturnInt(ret); } /** * \brief This function is used to parse flow options passed via flow: keyword * * \param flowstr Pointer to the user provided flow options * * \retval fd pointer to DetectFlowData on success * \retval NULL on failure */ DetectFlowData *DetectFlowParse (char *flowstr) { DetectFlowData *fd = NULL; char *args[3] = {NULL,NULL,NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, flowstr, strlen(flowstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 ", string %s", ret, flowstr); goto error; } if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[0] = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[1] = (char *)str_ptr; } if (ret > 3) { res = pcre_get_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[2] = (char *)str_ptr; } } fd = SCMalloc(sizeof(DetectFlowData)); if (unlikely(fd == NULL)) goto error; fd->flags = 0; fd->match_cnt = 0; int i; for (i = 0; i < (ret - 1); i++) { if (args[i]) { /* inspect our options and set the flags */ if (strcasecmp(args[i], "established") == 0) { if (fd->flags & FLOW_PKT_ESTABLISHED) { SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_ESTABLISHED flag is already set"); goto error; } else if (fd->flags & FLOW_PKT_STATELESS) { SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_STATELESS already set"); goto error; } fd->flags |= FLOW_PKT_ESTABLISHED; } else if (strcasecmp(args[i], "stateless") == 0) { if (fd->flags & FLOW_PKT_STATELESS) { SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_STATELESS flag is already set"); goto error; } else if (fd->flags & FLOW_PKT_ESTABLISHED) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_STATELESS, FLOW_PKT_ESTABLISHED already set"); goto error; } fd->flags |= FLOW_PKT_STATELESS; } else if (strcasecmp(args[i], "to_client") == 0 || strcasecmp(args[i], "from_server") == 0) { if (fd->flags & FLOW_PKT_TOCLIENT) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_TOCLIENT flag is already set"); goto error; } else if (fd->flags & FLOW_PKT_TOSERVER) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_client, FLOW_PKT_TOSERVER already set"); goto error; } fd->flags |= FLOW_PKT_TOCLIENT; } else if (strcasecmp(args[i], "to_server") == 0 || strcasecmp(args[i], "from_client") == 0){ if (fd->flags & FLOW_PKT_TOSERVER) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_TOSERVER flag is already set"); goto error; } else if (fd->flags & FLOW_PKT_TOCLIENT) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_server, FLOW_PKT_TO_CLIENT flag already set"); goto error; } fd->flags |= FLOW_PKT_TOSERVER; } else if (strcasecmp(args[i], "only_stream") == 0) { if (fd->flags & FLOW_PKT_ONLYSTREAM) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag is already set"); goto error; } else if (fd->flags & FLOW_PKT_NOSTREAM) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag, FLOW_PKT_NOSTREAM already set"); goto error; } fd->flags |= FLOW_PKT_ONLYSTREAM; } else if (strcasecmp(args[i], "no_stream") == 0) { if (fd->flags & FLOW_PKT_NOSTREAM) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag is already set"); goto error; } else if (fd->flags & FLOW_PKT_ONLYSTREAM) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag, FLOW_PKT_ONLYSTREAM already set"); goto error; } fd->flags |= FLOW_PKT_NOSTREAM; } else { SCLogError(SC_ERR_INVALID_VALUE, "invalid flow option \"%s\"", args[i]); goto error; } fd->match_cnt++; //printf("args[%" PRId32 "]: %s match_cnt: %" PRId32 " flags: 0x%02X\n", i, args[i], fd->match_cnt, fd->flags); } } for (i = 0; i < (ret -1); i++){ if (args[i] != NULL) SCFree(args[i]); } return fd; error: /* ret can be higher than 3 */ for (i = 0; i < (ret - 1) && i < 3; i++){ if (args[i] != NULL) SCFree(args[i]); } if (fd != NULL) DetectFlowFree(fd); return NULL; } /** * \brief this function is used to add the parsed flowdata into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param flowstr pointer to the user provided flow options * * \retval 0 on Success * \retval -1 on Failure */ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, char *flowstr) { DetectFlowData *fd = NULL; SigMatch *sm = NULL; fd = DetectFlowParse(flowstr); if (fd == NULL) goto error; /*ensure only one flow option*/ if (s->init_flags & SIG_FLAG_INIT_FLOW) { SCLogError (SC_ERR_INVALID_SIGNATURE, "A signature may have only one flow option."); 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_FLOW; sm->ctx = (void *)fd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); /* set the signature direction flags */ if (fd->flags & FLOW_PKT_TOSERVER) { s->flags |= SIG_FLAG_TOSERVER; } else if (fd->flags & FLOW_PKT_TOCLIENT) { s->flags |= SIG_FLAG_TOCLIENT; } else { s->flags |= SIG_FLAG_TOSERVER; s->flags |= SIG_FLAG_TOCLIENT; } if (fd->flags & FLOW_PKT_ONLYSTREAM) { s->flags |= SIG_FLAG_REQUIRE_STREAM; } if (fd->flags & FLOW_PKT_NOSTREAM) { s->flags |= SIG_FLAG_REQUIRE_PACKET; } else { s->init_flags |= SIG_FLAG_INIT_FLOW; } return 0; error: if (fd != NULL) DetectFlowFree(fd); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectFlowData * * \param fd pointer to DetectFlowData */ void DetectFlowFree(void *ptr) { DetectFlowData *fd = (DetectFlowData *)ptr; SCFree(fd); } #ifdef UNITTESTS /** * \test DetectFlowTestParse01 is a test to make sure that we return "something" * when given valid flow opt */ int DetectFlowTestParse01 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established"); if (fd != NULL) { DetectFlowFree(fd); result = 1; } return result; } /** * \test DetectFlowTestParse02 is a test for setting the established flow opt */ int DetectFlowTestParse02 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established"); if (fd != NULL) { if (fd->flags == FLOW_PKT_ESTABLISHED && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse03 is a test for setting the stateless flow opt */ int DetectFlowTestParse03 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("stateless"); if (fd != NULL) { if (fd->flags == FLOW_PKT_STATELESS && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse04 is a test for setting the to_client flow opt */ int DetectFlowTestParse04 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client"); if (fd != NULL) { if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse05 is a test for setting the to_server flow opt */ int DetectFlowTestParse05 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_server"); if (fd != NULL) { if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse06 is a test for setting the from_server flow opt */ int DetectFlowTestParse06 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server"); if (fd != NULL) { if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse07 is a test for setting the from_client flow opt */ int DetectFlowTestParse07 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_client"); if (fd != NULL) { if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse08 is a test for setting the established,to_client flow opts */ int DetectFlowTestParse08 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established,to_client"); if (fd != NULL) { if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { result = 1; } else { printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse09 is a test for setting the to_client,stateless flow opts (order of state,dir reversed) */ int DetectFlowTestParse09 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,stateless"); if (fd != NULL) { if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { result = 1; } else { printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse10 is a test for setting the from_server,stateless flow opts (order of state,dir reversed) */ int DetectFlowTestParse10 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,stateless"); if (fd != NULL) { if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ result = 1; } else { printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse11 is a test for setting the from_server,stateless flow opts with spaces all around */ int DetectFlowTestParse11 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse(" from_server , stateless "); if (fd != NULL) { if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ result = 1; } else { printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase01 is a test to make sure that we return "something" * when given valid flow opt */ int DetectFlowTestParseNocase01 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED"); if (fd != NULL) { DetectFlowFree(fd); result = 1; } return result; } /** * \test DetectFlowTestParseNocase02 is a test for setting the established flow opt */ int DetectFlowTestParseNocase02 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED"); if (fd != NULL) { if (fd->flags == FLOW_PKT_ESTABLISHED && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase03 is a test for setting the stateless flow opt */ int DetectFlowTestParseNocase03 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("STATELESS"); if (fd != NULL) { if (fd->flags == FLOW_PKT_STATELESS && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase04 is a test for setting the to_client flow opt */ int DetectFlowTestParseNocase04 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_CLIENT"); if (fd != NULL) { if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase05 is a test for setting the to_server flow opt */ int DetectFlowTestParseNocase05 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_SERVER"); if (fd != NULL) { if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase06 is a test for setting the from_server flow opt */ int DetectFlowTestParseNocase06 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER"); if (fd != NULL) { if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase07 is a test for setting the from_client flow opt */ int DetectFlowTestParseNocase07 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_CLIENT"); if (fd != NULL) { if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase08 is a test for setting the established,to_client flow opts */ int DetectFlowTestParseNocase08 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED,TO_CLIENT"); if (fd != NULL) { if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { result = 1; } else { printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase09 is a test for setting the to_client,stateless flow opts (order of state,dir reversed) */ int DetectFlowTestParseNocase09 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_CLIENT,STATELESS"); if (fd != NULL) { if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { result = 1; } else { printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase10 is a test for setting the from_server,stateless flow opts (order of state,dir reversed) */ int DetectFlowTestParseNocase10 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,STATELESS"); if (fd != NULL) { if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ result = 1; } else { printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase11 is a test for setting the from_server,stateless flow opts with spaces all around */ int DetectFlowTestParseNocase11 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse(" FROM_SERVER , STATELESS "); if (fd != NULL) { if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ result = 1; } else { printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse12 is a test for setting an invalid seperator : */ int DetectFlowTestParse12 (void) { int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server:stateless"); if (fd != NULL) { printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); result = 0; DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse13 is a test for an invalid option */ int DetectFlowTestParse13 (void) { int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("invalidoptiontest"); if (fd != NULL) { printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); result = 0; DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse14 is a test for a empty option */ int DetectFlowTestParse14 (void) { int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse(""); if (fd != NULL) { printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); result = 0; DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse15 is a test for an invalid combo of options established,stateless */ int DetectFlowTestParse15 (void) { int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("established,stateless"); if (fd != NULL) { printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); result = 0; DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse16 is a test for an invalid combo of options to_client,to_server */ int DetectFlowTestParse16 (void) { int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,to_server"); if (fd != NULL) { printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); result = 0; DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse16 is a test for an invalid combo of options to_client,from_server * flowbit flags are the same */ int DetectFlowTestParse17 (void) { int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,from_server"); if (fd != NULL) { printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); result = 0; DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse18 is a test for setting the from_server,stateless,only_stream flow opts (order of state,dir reversed) */ int DetectFlowTestParse18 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,only_stream"); if (fd != NULL) { if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_ONLYSTREAM && fd->match_cnt == 3) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_ONLYSTREAM, 3, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParseNocase18 is a test for setting the from_server,stateless,only_stream flow opts (order of state,dir reversed) */ int DetectFlowTestParseNocase18 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,ONLY_STREAM"); if (fd != NULL) { if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_ONLYSTREAM && fd->match_cnt == 3) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_ONLYSTREAM, 3, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse19 is a test for one to many options passed to DetectFlowParse */ int DetectFlowTestParse19 (void) { int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,only_stream,a"); if (fd != NULL) { printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); result = 0; DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse20 is a test for setting from_server, established, no_stream */ int DetectFlowTestParse20 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,no_stream"); if (fd != NULL) { if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_NOSTREAM && fd->match_cnt == 3) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_NOSTREAM, 3, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse20 is a test for setting from_server, established, no_stream */ int DetectFlowTestParseNocase20 (void) { int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,NO_STREAM"); if (fd != NULL) { if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_NOSTREAM && fd->match_cnt == 3) { result = 1; } else { printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_NOSTREAM, 3, fd->flags, fd->match_cnt); } DetectFlowFree(fd); } return result; } /** * \test DetectFlowTestParse21 is a test for an invalid opt between to valid opts */ int DetectFlowTestParse21 (void) { int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,a,no_stream"); if (fd != NULL) { printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); result = 0; DetectFlowFree(fd); } return result; } static int DetectFlowSigTest01(void) { int result = 0; ThreadVars th_v; DecodeThreadVars dtv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; uint8_t *buf = (uint8_t *)"supernovaduper"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); if (p->flow != NULL) { printf("packet has flow set\n"); goto end; } char *sig1 = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; flow:no_stream; sid:1;)"; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("de_ctx == NULL: "); goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); if (de_ctx->sig_list == NULL) { printf("signature == NULL: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) != 1) { goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } if (p != NULL) UTHFreePacket(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectFlow */ void DetectFlowRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectFlowTestParse01", DetectFlowTestParse01, 1); UtRegisterTest("DetectFlowTestParse02", DetectFlowTestParse02, 1); UtRegisterTest("DetectFlowTestParse03", DetectFlowTestParse03, 1); UtRegisterTest("DetectFlowTestParse04", DetectFlowTestParse04, 1); UtRegisterTest("DetectFlowTestParse05", DetectFlowTestParse05, 1); UtRegisterTest("DetectFlowTestParse06", DetectFlowTestParse06, 1); UtRegisterTest("DetectFlowTestParse07", DetectFlowTestParse07, 1); UtRegisterTest("DetectFlowTestParse08", DetectFlowTestParse08, 1); UtRegisterTest("DetectFlowTestParse09", DetectFlowTestParse09, 1); UtRegisterTest("DetectFlowTestParse10", DetectFlowTestParse10, 1); UtRegisterTest("DetectFlowTestParse11", DetectFlowTestParse11, 1); UtRegisterTest("DetectFlowTestParseNocase01", DetectFlowTestParseNocase01, 1); UtRegisterTest("DetectFlowTestParseNocase02", DetectFlowTestParseNocase02, 1); UtRegisterTest("DetectFlowTestParseNocase03", DetectFlowTestParseNocase03, 1); UtRegisterTest("DetectFlowTestParseNocase04", DetectFlowTestParseNocase04, 1); UtRegisterTest("DetectFlowTestParseNocase05", DetectFlowTestParseNocase05, 1); UtRegisterTest("DetectFlowTestParseNocase06", DetectFlowTestParseNocase06, 1); UtRegisterTest("DetectFlowTestParseNocase07", DetectFlowTestParseNocase07, 1); UtRegisterTest("DetectFlowTestParseNocase08", DetectFlowTestParseNocase08, 1); UtRegisterTest("DetectFlowTestParseNocase09", DetectFlowTestParseNocase09, 1); UtRegisterTest("DetectFlowTestParseNocase10", DetectFlowTestParseNocase10, 1); UtRegisterTest("DetectFlowTestParseNocase11", DetectFlowTestParseNocase11, 1); UtRegisterTest("DetectFlowTestParse12", DetectFlowTestParse12, 1); UtRegisterTest("DetectFlowTestParse13", DetectFlowTestParse13, 1); UtRegisterTest("DetectFlowTestParse14", DetectFlowTestParse14, 1); UtRegisterTest("DetectFlowTestParse15", DetectFlowTestParse15, 1); UtRegisterTest("DetectFlowTestParse16", DetectFlowTestParse16, 1); UtRegisterTest("DetectFlowTestParse17", DetectFlowTestParse17, 1); UtRegisterTest("DetectFlowTestParse18", DetectFlowTestParse18, 1); UtRegisterTest("DetectFlowTestParseNocase18", DetectFlowTestParseNocase18, 1); UtRegisterTest("DetectFlowTestParse19", DetectFlowTestParse19, 1); UtRegisterTest("DetectFlowTestParse20", DetectFlowTestParse20, 1); UtRegisterTest("DetectFlowTestParseNocase20", DetectFlowTestParseNocase20, 1); UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21, 1); UtRegisterTest("DetectFlowSigTest01", DetectFlowSigTest01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-http-stat-code.h0000644000000000000000000000215612253546156015310 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh */ #ifndef _DETECT_HTTP_STAT_CODE_H #define _DETECT_HTTP_STAT_CODE_H /* prototypes */ int DetectHttpStatCodeMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t , void *, Signature *, SigMatch *); void DetectHttpStatCodeRegister(void); #endif /* _DETECT_HTTP_STAT_CODE_H */ suricata-1.4.7/src/util-mpm-b2gc.h0000644000000000000000000001003012253546156013547 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_MPM_B2GC_H__ #define __UTIL_MPM_B2GC_H__ #include "util-mpm.h" #include "util-bloomfilter.h" #define B2GC_HASHSHIFT_MAX 8 #define B2GC_HASHSHIFT_HIGHER 7 #define B2GC_HASHSHIFT_HIGH 6 #define B2GC_HASHSHIFT_MEDIUM 5 #define B2GC_HASHSHIFT_LOW 4 #define B2GC_HASHSHIFT_LOWEST 3 //#define B2GC_HASHSHIFT 8 //#define B2GC_HASHSHIFT 7 //#define B2GC_HASHSHIFT 6 //#define B2GC_HASHSHIFT 5 #define B2GC_HASHSHIFT 4 //#define B2GC_HASHSHIFT 3 //#define B2GC_TYPE uint64_t #define B2GC_TYPE uint32_t //#define B2GC_TYPE uint16_t //#define B2GC_TYPE uint8_t //#define B2GC_WORD_SIZE 64 #define B2GC_WORD_SIZE 32 //#define B2GC_WORD_SIZE 16 //#define B2GC_WORD_SIZE 8 #define B2GC_Q 2 #define B2GC_SEARCHFUNC B2gcSearchBNDMq //#define B2GC_SEARCHFUNC B2gcSearch //#define B2GC_SEARCH2 //#define B2GC_COUNTERS #define B2GC_FLAG_NOCASE 0x01 #define B2GC_FLAG_FINAL 0x02 #define B2GC_FLAG_RES1 0x04 #define B2GC_FLAG_RES2 0x08 /* Bits * flg len id pat * |xxxx|xxxx xxxx xx|xx xxxx xxxx xxxx xxxx|xx..xx| */ typedef struct B2gcPatternHdr_ { uint32_t np_offset; /* offset of the next pattern */ uint8_t len; uint8_t flags; PatIntId id; } B2gcPatternHdr; #define B2GC_GET_FLAGS(hdr) ((hdr)->flags) #define B2GC_GET_LEN(hdr) ((hdr)->len) #define B2GC_GET_ID(hdr) ((hdr)->id) /* 1 byte pattern structure fitting in a double word. * flg id pad pat/char * |xxxx|xxxx xxxx xxxx xxxx xx|xx|xxxx xxxx| */ typedef struct B2gcPattern1_ { uint8_t flags; uint8_t pat; PatIntId id; } B2gcPattern1; #define B2GC1_GET_FLAGS(hdr) ((hdr)->flags) #define B2GC1_GET_LEN(hdr) 1 #define B2GC1_GET_ID(hdr) ((hdr)->id) #define B2GC1_GET_CHAR(hdr) ((hdr)->pat) typedef struct B2gcPattern_ { uint16_t len; uint8_t flags; uint8_t pad0; PatIntId id; uint8_t *pat; } B2gcPattern; typedef struct B2gcCtx_ { /* we store our own multi byte search func ptr here for B2gcSearch1 */ uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* hash for looking up the idx in the pattern array */ uint16_t *ha1; uint8_t *patterns1; uint32_t pat_x_cnt; uint32_t pat_1_cnt; /* we store our own multi byte search func ptr here for B2gcSearch1 */ uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); B2GC_TYPE m; uint32_t hash_size; B2GC_TYPE *B2GC; uint8_t *pminlen; /* array containing the minimal length */ BloomFilter **bloom; uint32_t *ha; /* patterns in the format |hdr|pattern|hdr|pattern|... */ uint8_t *patterns; HashListTable *b2gc_init_hash; } B2gcCtx; typedef struct B2gcThreadCtx_ { #ifdef B2GC_COUNTERS uint32_t stat_pminlen_calls; uint32_t stat_pminlen_total; uint32_t stat_bloom_calls; uint32_t stat_bloom_hits; uint32_t stat_calls; uint32_t stat_m_total; uint32_t stat_d0; uint32_t stat_d0_hashloop; uint32_t stat_loop_match; uint32_t stat_loop_no_match; uint32_t stat_num_shift; uint32_t stat_total_shift; #endif /* B2GC_COUNTERS */ } B2gcThreadCtx; void MpmB2gcRegister(void); #endif suricata-1.4.7/src/util-byte.h0000644000000000000000000002066312253546156013123 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus */ #ifndef __UTIL_BYTE_H__ #define __UTIL_BYTE_H__ #include #define BYTE_BIG_ENDIAN 0 #define BYTE_LITTLE_ENDIAN 1 /** Wrappers for OS dependent byte swapping functions */ #ifdef OS_FREEBSD #include #define SCByteSwap16(x) bswap16(x) #define SCByteSwap32(x) bswap32(x) #define SCByteSwap64(x) bswap64(x) #elif defined __OpenBSD__ #include #define SCByteSwap16(x) swap16(x) #define SCByteSwap32(x) swap32(x) #define SCByteSwap64(x) swap64(x) #elif OS_DARWIN #include #define SCByteSwap16(x) OSSwapInt16(x) #define SCByteSwap32(x) OSSwapInt32(x) #define SCByteSwap64(x) OSSwapInt64(x) #elif defined(__WIN32) || defined(_WIN32) /* Quick & dirty solution, nothing seems to exist for this in Win32 API */ #define SCByteSwap16(x) \ ((((x) & 0xff00) >> 8) \ | (((x) & 0x00ff) << 8)) #define SCByteSwap32(x) \ ((((x) & 0xff000000) >> 24) \ | (((x) & 0x00ff0000) >> 8) \ | (((x) & 0x0000ff00) << 8) \ | (((x) & 0x000000ff) << 24)) #define SCByteSwap64(x) \ ((((x) & 0xff00000000000000ull) >> 56) \ | (((x) & 0x00ff000000000000ull) >> 40) \ | (((x) & 0x0000ff0000000000ull) >> 24) \ | (((x) & 0x000000ff00000000ull) >> 8) \ | (((x) & 0x00000000ff000000ull) << 8) \ | (((x) & 0x0000000000ff0000ull) << 24) \ | (((x) & 0x000000000000ff00ull) << 40) \ | (((x) & 0x00000000000000ffull) << 56)) #else #include #define SCByteSwap16(x) bswap_16(x) #define SCByteSwap32(x) bswap_32(x) #define SCByteSwap64(x) bswap_64(x) #endif /* OS_FREEBSD */ /** * Extract bytes from a byte string and convert to a unint64_t. * * \param res Stores result * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) * \param len Number of bytes to extract (8 max) * \param bytes Data to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractUint64(uint64_t *res, int e, uint16_t len, const uint8_t *bytes); /** * Extract bytes from a byte string and convert to a unint32_t. * * \param res Stores result * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) * \param len Number of bytes to extract (8 max) * \param bytes Data to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractUint32(uint32_t *res, int e, uint16_t len, const uint8_t *bytes); /** * Extract bytes from a byte string and convert to a unint16_t. * * \param res Stores result * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) * \param len Number of bytes to extract (8 max) * \param bytes Data to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractUint16(uint16_t *res, int e, uint16_t len, const uint8_t *bytes); /** * Extract unsigned integer value from a string. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractString(uint64_t *res, int base, uint16_t len, const char *str); /** * Extract unsigned integer value from a string as uint64_t. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param len Number of bytes to extract (23 max) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringUint64(uint64_t *res, int base, uint16_t len, const char *str); /** * Extract unsigned integer value from a string as uint32_t. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringUint32(uint32_t *res, int base, uint16_t len, const char *str); /** * Extract unsigned integer value from a string as uint16_t. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringUint16(uint16_t *res, int base, uint16_t len, const char *str); /** * Extract unsigned integer value from a string as uint8_t. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringUint8(uint8_t *res, int base, uint16_t len, const char *str); /** * Extract signed integer value from a string. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringSigned(int64_t *res, int base, uint16_t len, const char *str); /** * Extract signed integer value from a string as uint64_t. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringInt64(int64_t *res, int base, uint16_t len, const char *str); /** * Extract signed integer value from a string as uint32_t. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringInt32(int32_t *res, int base, uint16_t len, const char *str); /** * Extract signed integer value from a string as uint16_t. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringInt16(int16_t *res, int base, uint16_t len, const char *str); /** * Extract signed integer value from a string as uint8_t. * * \param res Stores result * \param base Base of the number to extract * \param len Number of bytes to extract (23 max or 0 for unbounded) * \param str String to extract from * * \return n Number of bytes extracted on success * \return -1 On error */ int ByteExtractStringInt8(int8_t *res, int base, uint16_t len, const char *str); #ifdef UNITTESTS void ByteRegisterTests(void); #endif /* UNITTESTS */ /** ------ Inline functions ----- */ static inline int ByteExtract(uint64_t *res, int e, uint16_t len, const uint8_t *bytes) { uint64_t b = 0; int i; if ((e != BYTE_BIG_ENDIAN) && (e != BYTE_LITTLE_ENDIAN)) { /** \todo Need standard return values */ return -1; } *res = 0; /* Go through each byte and merge it into the result in the correct order */ /** \todo Probably a more efficient way to do this. */ for (i = 0; i < len; i++) { if (e == BYTE_LITTLE_ENDIAN) { b = bytes[i]; } else { b = bytes[len - i - 1]; } *res |= (b << ((i & 7) << 3)); } return len; } #endif /* __UTIL_BYTE_H__ */ suricata-1.4.7/src/util-mpm-wumanber.h0000644000000000000000000000515512253546156014566 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_MPM_WUMANBER_H__ #define __UTIL_MPM_WUMANBER_H__ #include "util-mpm.h" #include "util-bloomfilter.h" //#define WUMANBER_COUNTERS typedef struct WmPattern_ { uint8_t *cs; /* case sensitive */ uint8_t *ci; /* case INsensitive */ uint16_t len; struct WmPattern_ *next; uint16_t prefix_ci; uint16_t prefix_cs; uint8_t flags; uint32_t id; /* global pattern id */ } WmPattern; typedef struct WmHashItem_ { uint8_t flags; uint16_t idx; struct WmHashItem_ *nxt; } WmHashItem; typedef struct WmCtx_ { /* hash used during ctx initialization */ WmPattern **init_hash; uint16_t shiftlen; uint32_t hash_size; WmHashItem **hash; BloomFilter **bloom; uint8_t *pminlen; /* array containing the minimal length of the patters in a hash bucket. Used for the BloomFilter. */ WmHashItem hash1[256]; /* we store our own search func ptr here for WmSearch1 */ uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* we store our own multi byte search func ptr here for WmSearch1 */ uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* pattern arrays */ WmPattern **parray; /* only used for multibyte pattern search */ uint16_t *shifttable; } WmCtx; typedef struct WmThreadCtx_ { #ifdef WUMANBER_COUNTERS uint32_t stat_pminlen_calls; uint32_t stat_pminlen_total; uint32_t stat_bloom_calls; uint32_t stat_bloom_hits; uint32_t stat_shift_null; uint32_t stat_loop_match; uint32_t stat_loop_no_match; uint32_t stat_num_shift; uint32_t stat_total_shift; #endif /* WUMANBER_COUNTERS */ } WmThreadCtx; void MpmWuManberRegister(void); #endif /* __UTIL_MPM_WUMANBER_H__ */ suricata-1.4.7/src/tm-queues.h0000644000000000000000000000226212253546156013125 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __TM_QUEUES_H__ #define __TM_QUEUES_H__ typedef struct Tmq_ { char *name; uint16_t id; uint16_t reader_cnt; uint16_t writer_cnt; /* 0 for packet-queue and 1 for data-queue */ uint8_t q_type; } Tmq; Tmq* TmqCreateQueue(char *name); Tmq* TmqGetQueueByName(char *name); void TmqDebugList(void); void TmqResetQueues(void); void TmValidateQueueState(void); #endif /* __TM_QUEUES_H__ */ suricata-1.4.7/src/detect-app-layer-event.c0000644000000000000000000002131112253546156015446 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-smtp.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "detect-app-layer-event.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "decode-events.h" #include "util-byte.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" int DetectAppLayerEventMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); int DetectAppLayerEventSetup(DetectEngineCtx *, Signature *, char *); void DetectAppLayerEventRegisterTests(void); void DetectAppLayerEventFree(void *); /** * \brief Registers the keyword handlers for the "app-layer-event" keyword. */ void DetectAppLayerEventRegister(void) { sigmatch_table[DETECT_AL_APP_LAYER_EVENT].name = "app-layer-event"; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Match = NULL; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].AppLayerMatch = DetectAppLayerEventMatch; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Setup = DetectAppLayerEventSetup; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Free = DetectAppLayerEventFree; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].RegisterTests = DetectAppLayerEventRegisterTests; return; } int DetectAppLayerEventMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); int r = 0; DetectAppLayerEventData *aled = (DetectAppLayerEventData *)m->ctx; FLOWLOCK_RDLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerGetDecoderEventsForFlow(f); if (decoder_events != NULL && AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { r = 1; } FLOWLOCK_UNLOCK(f); SCReturnInt(r); } static DetectAppLayerEventData *DetectAppLayerEventParse(const char *arg) { /* period index */ const char *p_idx; if (arg == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-event keyword supplied " "with no arguments. This keyword needs an argument."); return NULL; } while (*arg != '\0' && isspace((unsigned char)*arg)) { arg++; } p_idx = strchr(arg, '.'); if (p_idx == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-event keyword supplied " "with an argument which is not in the right format. The " "right format is \".\""); return NULL; } char buffer[50] = ""; strlcpy(buffer, arg, p_idx - arg + 1); /* + 1 for trailing \0 */ //int module_id = DecoderEventModuleGetModuleId(buffer); //uint16_t alproto = AppLayerGetProtoByName(buffer); uint16_t alproto = AppLayerDecoderEventsModuleGetAlproto(buffer); if (alproto == ALPROTO_UNKNOWN) return NULL; int event_id = AppLayerDecoderEventsModuleGetEventId(alproto, p_idx + 1); if (event_id == -1) return NULL; DetectAppLayerEventData *aled = SCMalloc(sizeof(DetectAppLayerEventData)); if (unlikely(aled == NULL)) return NULL; aled->alproto = alproto; aled->event_id = event_id; return aled; } int DetectAppLayerEventSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectAppLayerEventData *data = NULL; SigMatch *sm = NULL; data = DetectAppLayerEventParse(arg); if (data == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_AL_APP_LAYER_EVENT; sm->ctx = (void *)data; if (s->alproto != ALPROTO_UNKNOWN) { if (s->alproto != ((DetectAppLayerEventData *)sm->ctx)->alproto) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains " "conflicting keywords needing different alprotos"); goto error; } } else { s->alproto = ((DetectAppLayerEventData *)sm->ctx)->alproto; } SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); s->flags |= SIG_FLAG_APPLAYER; return 0; error: return -1; } void DetectAppLayerEventFree(void *ptr) { SCFree(ptr); return; } /**********************************Unittests***********************************/ #ifdef UNITTESTS /* UNITTESTS */ #define APP_LAYER_EVENT_TEST_MAP_EVENT1 0 #define APP_LAYER_EVENT_TEST_MAP_EVENT2 1 #define APP_LAYER_EVENT_TEST_MAP_EVENT3 2 #define APP_LAYER_EVENT_TEST_MAP_EVENT4 3 #define APP_LAYER_EVENT_TEST_MAP_EVENT5 4 #define APP_LAYER_EVENT_TEST_MAP_EVENT6 5 SCEnumCharMap app_layer_event_test_map[ ] = { { "event1", APP_LAYER_EVENT_TEST_MAP_EVENT1 }, { "event2", APP_LAYER_EVENT_TEST_MAP_EVENT2 }, { "event3", APP_LAYER_EVENT_TEST_MAP_EVENT3 }, { "event4", APP_LAYER_EVENT_TEST_MAP_EVENT4 }, { "event5", APP_LAYER_EVENT_TEST_MAP_EVENT5 }, { "event6", APP_LAYER_EVENT_TEST_MAP_EVENT6 }, }; int DetectAppLayerEventTest01(void) { AppLayerDecoderEventsModuleCreateBackup(); AppLayerDecoderEventsModuleRegister(ALPROTO_SMTP, app_layer_event_test_map); int result = 0; DetectAppLayerEventData *aled = DetectAppLayerEventParse("smtp.event1"); if (aled == NULL) goto end; if (aled->alproto != ALPROTO_SMTP || aled->event_id != APP_LAYER_EVENT_TEST_MAP_EVENT1) { printf("test failure. Holding wrong state\n"); goto end; } result = 1; end: AppLayerDecoderEventsModuleRestoreBackup(); if (aled != NULL) DetectAppLayerEventFree(aled); return result; } int DetectAppLayerEventTest02(void) { AppLayerDecoderEventsModuleCreateBackup(); AppLayerDecoderEventsModuleRegister(ALPROTO_SMTP, app_layer_event_test_map); AppLayerDecoderEventsModuleRegister(ALPROTO_HTTP, app_layer_event_test_map); AppLayerDecoderEventsModuleRegister(ALPROTO_SMB, app_layer_event_test_map); AppLayerDecoderEventsModuleRegister(ALPROTO_FTP, app_layer_event_test_map); int result = 0; DetectAppLayerEventData *aled = DetectAppLayerEventParse("smtp.event1"); if (aled == NULL) goto end; if (aled->alproto != ALPROTO_SMTP || aled->event_id != APP_LAYER_EVENT_TEST_MAP_EVENT1) { printf("test failure. Holding wrong state\n"); goto end; } aled = DetectAppLayerEventParse("smtp.event4"); if (aled == NULL) goto end; if (aled->alproto != ALPROTO_SMTP || aled->event_id != APP_LAYER_EVENT_TEST_MAP_EVENT4) { printf("test failure. Holding wrong state\n"); goto end; } aled = DetectAppLayerEventParse("http.event2"); if (aled == NULL) goto end; if (aled->alproto != ALPROTO_HTTP || aled->event_id != APP_LAYER_EVENT_TEST_MAP_EVENT2) { printf("test failure. Holding wrong state\n"); goto end; } aled = DetectAppLayerEventParse("smb.event3"); if (aled == NULL) goto end; if (aled->alproto != ALPROTO_SMB || aled->event_id != APP_LAYER_EVENT_TEST_MAP_EVENT3) { printf("test failure. Holding wrong state\n"); goto end; } aled = DetectAppLayerEventParse("ftp.event5"); if (aled == NULL) goto end; if (aled->alproto != ALPROTO_FTP || aled->event_id != APP_LAYER_EVENT_TEST_MAP_EVENT5) { printf("test failure. Holding wrong state\n"); goto end; } result = 1; end: AppLayerDecoderEventsModuleRestoreBackup(); if (aled != NULL) DetectAppLayerEventFree(aled); return result; } #endif /* UNITTESTS */ /** * \brief This function registers unit tests for "app-layer-event" keyword. */ void DetectAppLayerEventRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectAppLayerEventTest01", DetectAppLayerEventTest01, 1); UtRegisterTest("DetectAppLayerEventTest02", DetectAppLayerEventTest02, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/util-signal.h0000644000000000000000000000175712253546156013440 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_SIGNAL_H__ #define __UTIL_SIGNAL_H__ int UtilSignalBlock(int); void UtilSignalHandlerSetup(int, void (*handler)());; int UtilSignalIsHandler(int sig, void (*handler)()); #endif /* __UTIL_SIGNAL_H__ */ suricata-1.4.7/src/util-file.h0000644000000000000000000001145312253546156013074 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #ifndef __UTIL_FILE_H__ #define __UTIL_FILE_H__ #ifdef HAVE_NSS #include #endif #define FILE_TRUNCATED 0x0001 #define FILE_NOMAGIC 0x0002 #define FILE_NOMD5 0x0004 #define FILE_MD5 0x0008 #define FILE_LOGGED 0x0010 #define FILE_NOSTORE 0x0020 #define FILE_STORE 0x0040 #define FILE_STORED 0x0080 #define FILE_NOTRACK 0x0100 /**< track size of file */ typedef enum FileState_ { FILE_STATE_NONE = 0, /**< no state */ FILE_STATE_OPENED, /**< flow file is opened */ FILE_STATE_CLOSED, /**< flow file is completed, there will be no more data. */ FILE_STATE_TRUNCATED, /**< flow file is not complete, but there will be no more data. */ FILE_STATE_ERROR, /**< file is in an error state */ FILE_STATE_MAX } FileState; typedef struct FileData_ { uint8_t *data; uint32_t len; int stored; /* true if this chunk has been stored already * false otherwise */ struct FileData_ *next; } FileData; typedef struct File_ { uint16_t flags; uint16_t txid; /**< tx this file is part of */ unsigned int file_id; uint8_t *name; uint16_t name_len; int16_t state; uint64_t size; /**< size tracked so far */ char *magic; FileData *chunks_head; FileData *chunks_tail; struct File_ *next; #ifdef HAVE_NSS HASHContext *md5_ctx; uint8_t md5[MD5_LENGTH]; #endif #ifdef DEBUG uint64_t chunks_cnt; uint64_t chunks_cnt_max; #endif } File; typedef struct FileContainer_ { File *head; File *tail; } FileContainer; FileContainer *FileContainerAlloc(); void FileContainerFree(FileContainer *); void FileContainerRecycle(FileContainer *); void FileContainerAdd(FileContainer *, File *); /** * \brief Open a new File * * \param ffc flow container * \param name filename character array * \param name_len filename len * \param data initial data * \param data_len initial data len * \param flags open flags * * \retval ff flowfile object * * \note filename is not a string, so it's not nul terminated. */ File *FileOpenFile(FileContainer *, uint8_t *name, uint16_t name_len, uint8_t *data, uint32_t data_len, uint8_t flags); /** * \brief Close a File * * \param ffc the container * \param data final data if any * \param data_len data len if any * \param flags flags * * \retval 0 ok * \retval -1 error */ int FileCloseFile(FileContainer *, uint8_t *data, uint32_t data_len, uint8_t flags); /** * \brief Store a chunk of file data in the flow. The open "flowfile" * will be used. * * \param ffc the container * \param data data chunk * \param data_len data chunk len * * \retval 0 ok * \retval -1 error */ int FileAppendData(FileContainer *, uint8_t *data, uint32_t data_len); /** * \brief Tag a file for storing * * \param ff The file to store */ int FileStore(File *); /** * \brief Set the TX id for a file * * \param ff The file to store * \param txid the tx id */ int FileSetTx(File *, uint16_t txid); /** * \brief disable file storage for a flow * * \param f *LOCKED* flow */ void FileDisableStoring(struct Flow_ *, uint8_t); void FileDisableFilesize(Flow *f, uint8_t direction); /** * \brief disable file storing for a transaction * * \param f flow * \param tx_id transaction id */ void FileDisableStoringForTransaction(struct Flow_ *, uint8_t, uint16_t); void FlowFileDisableStoringForTransaction(struct Flow_ *f, uint16_t tx_id); void FilePrune(FileContainer *ffc); void FileDisableMagic(Flow *f, uint8_t); void FileForceMagicEnable(void); int FileForceMagic(void); void FileDisableMd5(Flow *f, uint8_t); void FileForceMd5Enable(void); int FileForceMd5(void); void FileForceTrackingEnable(void); void FileStoreAllFiles(FileContainer *); void FileStoreAllFilesForTx(FileContainer *, uint16_t); void FileStoreFileById(FileContainer *fc, uint16_t); void FileTruncateAllOpenFiles(FileContainer *); #endif /* __UTIL_FILE_H__ */ suricata-1.4.7/src/log-httplog.h0000644000000000000000000000202012253546156013430 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __LOG_HTTPLOG_H__ #define __LOG_HTTPLOG_H__ void TmModuleLogHttpLogRegister (void); void TmModuleLogHttpLogIPv4Register (void); void TmModuleLogHttpLogIPv6Register (void); OutputCtx *LogHttpLogInitCtx(ConfNode *); #endif /* __LOG_HTTPLOG_H__ */ suricata-1.4.7/src/decode-icmpv4.c0000644000000000000000000006027712253546156013630 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Victor Julien * * Decode ICMPv4 */ #include "suricata-common.h" #include "decode.h" #include "decode-events.h" #include "decode-ipv4.h" #include "decode-icmpv4.h" #include "flow.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "util-print.h" /** * Note, this is the IP header, plus a bit of the original packet, not the whole thing! */ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) { /** Check the sizes, the header must fit at least */ if (len < IPV4_HEADER_LEN) { SCLogDebug("DecodePartialIPV4: ICMPV4_IPV4_TRUNC_PKT"); ENGINE_SET_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); return; } IPV4Hdr *icmp4_ip4h = (IPV4Hdr*)partial_packet; /** Check the embedded version */ if (IPV4_GET_RAW_VER(icmp4_ip4h) != 4) { /** Check the embedded version */ SCLogDebug("DecodePartialIPV4: ICMPv4 contains Unknown IPV4 version " "ICMPV4_IPV4_UNKNOWN_VER"); ENGINE_SET_EVENT(p, ICMPV4_IPV4_UNKNOWN_VER); return; } /** We need to fill icmpv4vars */ p->icmpv4vars.emb_ipv4h = icmp4_ip4h; /** Get the IP address from the contained packet */ p->icmpv4vars.emb_ip4_src = IPV4_GET_RAW_IPSRC(icmp4_ip4h); p->icmpv4vars.emb_ip4_dst = IPV4_GET_RAW_IPDST(icmp4_ip4h); p->icmpv4vars.emb_ip4_hlen=IPV4_GET_RAW_HLEN(icmp4_ip4h) << 2; switch (IPV4_GET_RAW_IPPROTO(icmp4_ip4h)) { case IPPROTO_TCP: if (len >= IPV4_HEADER_LEN + TCP_HEADER_LEN ) { p->icmpv4vars.emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = ntohs(p->icmpv4vars.emb_tcph->th_sport); p->icmpv4vars.emb_dport = ntohs(p->icmpv4vars.emb_tcph->th_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else if (len >= IPV4_HEADER_LEN + 4) { /* only access th_sport and th_dport */ TCPHdr *emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_tcph = NULL; p->icmpv4vars.emb_sport = ntohs(emb_tcph->th_sport); p->icmpv4vars.emb_dport = ntohs(emb_tcph->th_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP partial header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else { SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->TCP " "header Didn't fit in the packet!"); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; } break; case IPPROTO_UDP: if (len >= IPV4_HEADER_LEN + UDP_HEADER_LEN ) { p->icmpv4vars.emb_udph = (UDPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = ntohs(p->icmpv4vars.emb_udph->uh_sport); p->icmpv4vars.emb_dport = ntohs(p->icmpv4vars.emb_udph->uh_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_UDP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->UDP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else { SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->UDP " "header Didn't fit in the packet!"); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; } break; case IPPROTO_ICMP: p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; p->icmpv4vars.emb_ip4_proto = IPPROTO_ICMP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->ICMP header"); break; } /* debug print */ #ifdef DEBUG char s[16], d[16]; PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_src), s, sizeof(s)); PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_dst), d, sizeof(d)); SCLogDebug("ICMPv4 embedding IPV4 %s->%s - PROTO: %" PRIu32 " ID: %" PRIu32 "", s,d, IPV4_GET_RAW_IPPROTO(icmp4_ip4h), IPV4_GET_RAW_IPID(icmp4_ip4h)); #endif return; } /** DecodeICMPV4 * \brief Main ICMPv4 decoding function */ void DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_icmpv4, tv->sc_perf_pca); if (len < ICMPV4_HEADER_LEN) { ENGINE_SET_EVENT(p,ICMPV4_PKT_TOO_SMALL); return; } p->icmpv4h = (ICMPV4Hdr *)pkt; SCLogDebug("ICMPV4 TYPE %" PRIu32 " CODE %" PRIu32 "", p->icmpv4h->type, p->icmpv4h->code); p->proto = IPPROTO_ICMP; p->type = p->icmpv4h->type; p->code = p->icmpv4h->code; p->payload = pkt + ICMPV4_HEADER_LEN; p->payload_len = len - ICMPV4_HEADER_LEN; ICMPV4ExtHdr* icmp4eh = (ICMPV4ExtHdr*) p->icmpv4h; switch (p->icmpv4h->type) { case ICMP_ECHOREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_DEST_UNREACH: if (p->icmpv4h->code > NR_ICMP_UNREACH) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { /* parse IP header plus 64 bytes */ if (len > ICMPV4_HEADER_PKT_OFFSET) { DecodePartialIPV4( p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { FlowHandlePacket(tv, p); } } } break; case ICMP_SOURCE_QUENCH: if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len >= ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_REDIRECT: if (p->icmpv4h->code>ICMP_REDIR_HOSTTOS) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_ECHO: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_TIME_EXCEEDED: if (p->icmpv4h->code>ICMP_EXC_FRAGTIME) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_PARAMETERPROB: if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_TIMESTAMP: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_TIMESTAMPREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_INFO_REQUEST: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_INFO_REPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_ADDRESS: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_ADDRESSREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; default: ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_TYPE); } return; } #ifdef UNITTESTS /** DecodeICMPV4test01 * \brief * \retval 1 Expected test value */ static int DecodeICMPV4test01(void) { uint8_t raw_icmpv4[] = { 0x08, 0x00, 0x78, 0x47, 0xfc, 0x55, 0x00, 0x04, 0x52, 0xab, 0x86, 0x4a, 0x84, 0x50, 0x0e, 0x00, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; IPV4Hdr ip4h; memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1");; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4");; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h = &ip4h; DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4), NULL); if (NULL!=p->icmpv4h) { if (p->icmpv4h->type==8 && p->icmpv4h->code==0) { ret = 1; } } FlowShutdown(); SCFree(p); return ret; } /** DecodeICMPV4test02 * \brief * \retval 1 Expected test value */ static int DecodeICMPV4test02(void) { uint8_t raw_icmpv4[] = { 0x00, 0x00, 0x57, 0x64, 0xfb, 0x55, 0x00, 0x03, 0x43, 0xab, 0x86, 0x4a, 0xf6, 0x49, 0x02, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; IPV4Hdr ip4h; memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1");; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4");; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h = &ip4h; DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4), NULL); if (NULL!=p->icmpv4h) { if (p->icmpv4h->type==0 && p->icmpv4h->code==0) { ret = 1; } } FlowShutdown(); SCFree(p); return ret; } /** DecodeICMPV4test03 * \brief TTL exceeded * \retval Expected test value: 1 */ static int DecodeICMPV4test03(void) { uint8_t raw_icmpv4[] = { 0x0b, 0x00, 0x6a, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x64, 0x15, 0x00, 0x00, 0x01, 0x11, 0xde, 0xfd, 0xc0, 0xa8, 0x01, 0x0d, 0xd1, 0x55, 0xe3, 0x93, 0x8b, 0x12, 0x82, 0xaa, 0x00, 0x28, 0x7c, 0xdd }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; IPV4Hdr ip4h; memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1");; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4");; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h = &ip4h; DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4), NULL); if (NULL == p->icmpv4h) { printf("NULL == p->icmpv4h: "); goto end; } /* check it's type 11 code 0 */ if (p->icmpv4h->type != 11 || p->icmpv4h->code != 0) { printf("p->icmpv4h->type %u, p->icmpv4h->code %u: ", p->icmpv4h->type, p->icmpv4h->code); goto end; } /* check it's source port 35602 to port 33450 */ if (p->icmpv4vars.emb_sport != 35602 || p->icmpv4vars.emb_dport != 33450) { printf("p->icmpv4vars.emb_sport %u, p->icmpv4vars.emb_dport %u: ", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); goto end; } /* check the src,dst IPs contained inside */ char s[16], d[16]; PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_src), s, sizeof(s)); PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_dst), d, sizeof(d)); /* ICMPv4 embedding IPV4 192.168.1.13->209.85.227.147 pass */ if (strcmp(s, "192.168.1.13") == 0 && strcmp(d, "209.85.227.147") == 0) { ret = 1; } else { printf("s %s, d %s: ", s, d); } end: FlowShutdown(); SCFree(p); return ret; } /** DecodeICMPV4test04 * \brief dest. unreachable, administratively prohibited * \retval 1 Expected test value */ static int DecodeICMPV4test04(void) { uint8_t raw_icmpv4[] = { 0x03, 0x0a, 0x36, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x62, 0xee, 0x40, 0x00, 0x33, 0x06, 0xb4, 0x8f, 0xc0, 0xa8, 0x01, 0x0d, 0x58, 0x60, 0x16, 0x29, 0xb1, 0x0a, 0x00, 0x32, 0x3e, 0x36, 0x38, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x72, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0x8a, 0x04, 0x02, 0x08, 0x0a }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; IPV4Hdr ip4h; memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1");; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4");; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h = &ip4h; DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4), NULL); if (NULL == p->icmpv4h) { goto end; } /* check the type,code pair is correct - type 3, code 10 */ if (p->icmpv4h->type != 3 || p->icmpv4h->code != 10) { goto end; } /* check it's src port 45322 to dst port 50 */ if (p->icmpv4vars.emb_sport != 45322 || p->icmpv4vars.emb_dport != 50) { goto end; } // check the src,dst IPs contained inside char s[16], d[16]; PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_src), s, sizeof(s)); PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_dst), d, sizeof(d)); // ICMPv4 embedding IPV4 192.168.1.13->88.96.22.41 if (strcmp(s, "192.168.1.13") == 0 && strcmp(d, "88.96.22.41") == 0) { ret = 1; } end: FlowShutdown(); SCFree(p); return ret; } /** DecodeICMPV4test05 * \brief dest. unreachable, administratively prohibited * \retval 1 Expected test value */ static int DecodeICMPV4test05(void) { uint8_t raw_icmpv4[] = { 0x0b, 0x00, 0x5c, 0x46, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x30, 0x02, 0x17, 0x40, 0x00, 0x01, 0x06, 0xd6, 0xbd, 0xc0, 0xa8, 0x02, 0x05, 0x3d, 0x23, 0xa1, 0x23, 0x04, 0x18, 0x00, 0x50, 0xd2, 0x08, 0xc2, 0x48, }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; IPV4Hdr ip4h; memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1");; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4");; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h = &ip4h; DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4), NULL); if (NULL == p->icmpv4h) { goto end; } /* check the type,code pair is correct - type 11, code 0 */ if (p->icmpv4h->type != 11 || p->icmpv4h->code != 0) { goto end; } /* check it's src port 1048 to dst port 80 */ if (p->icmpv4vars.emb_sport != 1048 || p->icmpv4vars.emb_dport != 80) { goto end; } // check the src,dst IPs contained inside char s[16], d[16]; PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_src), s, sizeof(s)); PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_dst), d, sizeof(d)); // ICMPv4 embedding IPV4 192.168.2.5->61.35.161.35 if (strcmp(s, "192.168.2.5") == 0 && strcmp(d, "61.35.161.35") == 0) { ret = 1; } end: FlowShutdown(); SCFree(p); return ret; } static int ICMPV4CalculateValidChecksumtest05(void) { uint16_t csum = 0; uint8_t raw_icmpv4[] = { 0x08, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; csum = *( ((uint16_t *)raw_icmpv4) + 1); return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); } static int ICMPV4CalculateInvalidChecksumtest06(void) { uint16_t csum = 0; uint8_t raw_icmpv4[] = { 0x08, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; csum = *( ((uint16_t *)raw_icmpv4) + 1); return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); } static int ICMPV4InvalidType07(void) { uint8_t raw_icmpv4[] = { 0xff, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; IPV4Hdr ip4h; memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1");; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4");; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h = &ip4h; DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4), NULL); if(ENGINE_ISSET_EVENT(p,ICMPV4_UNKNOWN_TYPE)) { ret = 1; } FlowShutdown(); SCFree(p); return ret; } /** DecodeICMPV4test08 * \brief * \retval 1 Expected test value - what we really want is not to segfault */ static int DecodeICMPV4test08(void) { uint8_t raw_icmpv4[] = { 0x08, 0x00, 0x78, 0x47, 0xfc, 0x55, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; IPV4Hdr ip4h; memset(&ip4h, 0, sizeof(IPV4Hdr)); memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); p->src.family = AF_INET; p->dst.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1");; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4");; ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; p->ip4h = &ip4h; DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4), NULL); if (NULL!=p->icmpv4h) { if (p->icmpv4h->type==8 && p->icmpv4h->code==0) { ret = 1; } } FlowShutdown(); SCFree(p); return ret; } #endif /* UNITTESTS */ /** * \brief Registers ICMPV4 unit test */ void DecodeICMPV4RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeICMPV4test01", DecodeICMPV4test01, 1); UtRegisterTest("DecodeICMPV4test02", DecodeICMPV4test02, 1); UtRegisterTest("DecodeICMPV4test03", DecodeICMPV4test03, 1); UtRegisterTest("DecodeICMPV4test04", DecodeICMPV4test04, 1); UtRegisterTest("DecodeICMPV4test05", DecodeICMPV4test05, 1); UtRegisterTest("ICMPV4CalculateValidChecksumtest05", ICMPV4CalculateValidChecksumtest05, 1); UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", ICMPV4CalculateInvalidChecksumtest06, 0); UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07, 1); UtRegisterTest("DecodeICMPV4test08", DecodeICMPV4test08, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/detect-fileext.h0000644000000000000000000000216212253546156014105 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_FILEEXT_H__ #define __DETECT_FILEEXT_H__ #include "util-spm-bm.h" typedef struct DetectFileextData_ { uint8_t *ext; /** file extension to match */ uint16_t len; /** length of the file */ uint32_t flags; } DetectFileextData; /* prototypes */ void DetectFileextRegister (void); #endif /* __DETECT_FILEEXT_H__ */ suricata-1.4.7/src/detect-fast-pattern.h0000644000000000000000000000352412253546156015060 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_FAST_PATTERN_H__ #define __DETECT_FAST_PATTERN_H__ typedef struct SCFPSupportSMList_ { /* the list id. Have a look at Signature->sm_lists[] */ int list_id; /* the next memeber in the list */ struct SCFPSupportSMList_ *next; } SCFPSupportSMList; extern SCFPSupportSMList *sm_fp_support_smlist_list; /** * \brief Checks if a particular list(Signature->sm_lists[]) is in the list * of lists that need to be searched for a keyword that has fp support. * * \param list_id The list id. * * \retval 1 If supported. * \retval 0 If not. */ static inline int FastPatternSupportEnabledForSigMatchList(int list_id) { if (sm_fp_support_smlist_list == NULL) return 0; SCFPSupportSMList *tmp_smlist_fp = sm_fp_support_smlist_list; while (tmp_smlist_fp != NULL) { if (tmp_smlist_fp->list_id == list_id) return 1; tmp_smlist_fp = tmp_smlist_fp->next; } return 0; } void SupportFastPatternForSigMatchTypes(void); void DetectFastPatternRegister(void); #endif /* __DETECT_FAST_PATTERN_H__ */ suricata-1.4.7/src/detect-stream_size.c0000644000000000000000000003472612253546156015000 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * Stream size for the engine. */ #include "suricata-common.h" #include "stream-tcp.h" #include "util-unittest.h" #include "detect.h" #include "detect-parse.h" #include "flow.h" #include "detect-stream_size.h" #include "stream-tcp-private.h" #include "util-debug.h" /** * \brief Regex for parsing our flow options */ #define PARSE_REGEX "^\\s*([A-z_]+)\\s*,\\s*([<=>!]+)\\s*,\\s*([0-9]+)\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ int DetectStreamSizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectStreamSizeSetup (DetectEngineCtx *, Signature *, char *); void DetectStreamSizeFree(void *); void DetectStreamSizeRegisterTests(void); /** * \brief Registration function for stream_size: keyword */ void DetectStreamSizeRegister(void) { sigmatch_table[DETECT_STREAM_SIZE].name = "stream_size"; sigmatch_table[DETECT_STREAM_SIZE].desc = "match on amount of bytes of a stream"; sigmatch_table[DETECT_STREAM_SIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#stream_size"; sigmatch_table[DETECT_STREAM_SIZE].Match = DetectStreamSizeMatch; sigmatch_table[DETECT_STREAM_SIZE].Setup = DetectStreamSizeSetup; sigmatch_table[DETECT_STREAM_SIZE].Free = DetectStreamSizeFree; sigmatch_table[DETECT_STREAM_SIZE].RegisterTests = DetectStreamSizeRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: if (parse_regex != NULL) SCFree(parse_regex); if (parse_regex_study != NULL) SCFree(parse_regex_study); return; } /** * \brief Function to comapre the stream size against defined size in the user * options. * * \param diff The stream size of server or client stream. * \param stream_size User defined stream size * \param mode The mode defined by user. * * \retval 1 on success and 0 on failure. */ static int DetectStreamSizeCompare (uint32_t diff, uint32_t stream_size, uint8_t mode) { int ret = 0; switch (mode) { case DETECTSSIZE_LT: if (diff < stream_size) ret = 1; break; case DETECTSSIZE_LEQ: if (diff <= stream_size) ret = 1; break; case DETECTSSIZE_EQ: if (diff == stream_size) ret = 1; break; case DETECTSSIZE_NEQ: if (diff != stream_size) ret = 1; break; case DETECTSSIZE_GEQ: if (diff >= stream_size) ret = 1; break; case DETECTSSIZE_GT: if (diff > stream_size) ret = 1; break; } return ret; } /** * \brief This function is used to match Stream size rule option on a packet with those passed via stream_size: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectStreamSizeData * * \retval 0 no match * \retval 1 match */ int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { int ret = 0; DetectStreamSizeData *sd = (DetectStreamSizeData *) m->ctx; if (!(PKT_IS_TCP(p))) return ret; uint32_t csdiff = 0; uint32_t ssdiff = 0; if (p->flow == NULL) return ret; TcpSession *ssn = (TcpSession *)p->flow->protoctx; if (ssn == NULL) return ret; if (sd->flags & STREAM_SIZE_SERVER) { /* get the server stream size */ ssdiff = ssn->server.next_seq - ssn->server.isn; ret = DetectStreamSizeCompare(ssdiff, sd->ssize, sd->mode); } else if (sd->flags & STREAM_SIZE_CLIENT) { /* get the client stream size */ csdiff = ssn->client.next_seq - ssn->client.isn; ret = DetectStreamSizeCompare(csdiff, sd->ssize, sd->mode); } else if (sd->flags & STREAM_SIZE_BOTH) { ssdiff = ssn->server.next_seq - ssn->server.isn; csdiff = ssn->client.next_seq - ssn->client.isn; if (DetectStreamSizeCompare(ssdiff, sd->ssize, sd->mode) && DetectStreamSizeCompare(csdiff, sd->ssize, sd->mode)) ret = 1; } else if (sd->flags & STREAM_SIZE_EITHER) { ssdiff = ssn->server.next_seq - ssn->server.isn; csdiff = ssn->client.next_seq - ssn->client.isn; if (DetectStreamSizeCompare(ssdiff, sd->ssize, sd->mode) || DetectStreamSizeCompare(csdiff, sd->ssize, sd->mode)) ret = 1; } return ret; } /** * \brief This function is used to parse stream options passed via stream_size: keyword * * \param streamstr Pointer to the user provided stream_size options * * \retval sd pointer to DetectStreamSizeData on success * \retval NULL on failure */ DetectStreamSizeData *DetectStreamSizeParse (char *streamstr) { DetectStreamSizeData *sd = NULL; char *arg = NULL; char *value = NULL; char *mode = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, streamstr, strlen(streamstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, streamstr); goto error; } const char *str_ptr; res = pcre_get_substring((char *)streamstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg = (char *)str_ptr; res = pcre_get_substring((char *)streamstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } mode = (char *)str_ptr; res = pcre_get_substring((char *)streamstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } value = (char *)str_ptr; sd = SCMalloc(sizeof(DetectStreamSizeData)); if (unlikely(sd == NULL)) goto error; sd->ssize = 0; sd->flags = 0; if (strlen(mode) == 0) goto error; if (mode[0] == '<') sd->mode = DETECTSSIZE_LT; else if (strcmp("<=", mode) == 0) sd->mode = DETECTSSIZE_LEQ; else if (mode[0] == '>') sd->mode = DETECTSSIZE_GT; else if (strcmp(">=", mode) == 0) sd->mode = DETECTSSIZE_GEQ; else if (strcmp("!=", mode) == 0) sd->mode = DETECTSSIZE_NEQ; else if (mode[0] == '=') sd->mode = DETECTSSIZE_EQ; else { SCLogError(SC_ERR_INVALID_OPERATOR, "Invalid operator"); goto error; } /* set the value */ sd->ssize = (uint32_t)atoi(value); /* inspect our options and set the flags */ if (strcmp(arg, "server") == 0) { sd->flags |= STREAM_SIZE_SERVER; } else if (strcmp(arg, "client") == 0) { sd->flags |= STREAM_SIZE_CLIENT; } else if ((strcmp(arg, "both") == 0)) { sd->flags |= STREAM_SIZE_BOTH; } else if (strcmp(arg, "either") == 0) { sd->flags |= STREAM_SIZE_EITHER; } else { goto error; } SCFree(mode); SCFree(arg); SCFree(value); return sd; error: if (mode != NULL) SCFree(mode); if (arg != NULL) SCFree(arg); if (value != NULL) SCFree(value); if (sd != NULL) DetectStreamSizeFree(sd); return NULL; } /** * \brief this function is used to add the parsed stream size data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param streamstr pointer to the user provided stream size options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectStreamSizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *streamstr) { DetectStreamSizeData *sd = NULL; SigMatch *sm = NULL; sd = DetectStreamSizeParse(streamstr); if (sd == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_STREAM_SIZE; sm->ctx = (void *)sd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (sd != NULL) DetectStreamSizeFree(sd); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectStreamSizeData * * \param ptr pointer to DetectStreamSizeData */ void DetectStreamSizeFree(void *ptr) { DetectStreamSizeData *sd = (DetectStreamSizeData *)ptr; SCFree(sd); } #ifdef UNITTESTS /** * \test DetectStreamSizeParseTest01 is a test to make sure that we parse the * user options correctly, when given valid stream_size options. */ static int DetectStreamSizeParseTest01 (void) { int result = 0; DetectStreamSizeData *sd = NULL; sd = DetectStreamSizeParse("server,<,6"); if (sd != NULL) { if (sd->flags & STREAM_SIZE_SERVER && sd->mode == DETECTSSIZE_LT && sd->ssize == 6) result = 1; DetectStreamSizeFree(sd); } return result; } /** * \test DetectStreamSizeParseTest02 is a test to make sure that we detect the * invalid stream_size options. */ static int DetectStreamSizeParseTest02 (void) { int result = 1; DetectStreamSizeData *sd = NULL; sd = DetectStreamSizeParse("invalidoption,<,6"); if (sd != NULL) { printf("expected: NULL got 0x%02X %" PRId16 ": ",sd->flags, sd->ssize); result = 0; DetectStreamSizeFree(sd); } return result; } /** * \test DetectStreamSizeParseTest03 is a test to make sure that we match the * packet correctly provided valid stream size. */ static int DetectStreamSizeParseTest03 (void) { int result = 0; DetectStreamSizeData *sd = NULL; TcpSession ssn; ThreadVars tv; DetectEngineThreadCtx dtx; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature s; SigMatch sm; TcpStream client; Flow f; TCPHdr tcph; memset(&ssn, 0, sizeof(TcpSession)); memset(&tv, 0, sizeof(ThreadVars)); memset(&dtx, 0, sizeof(DetectEngineThreadCtx)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&s, 0, sizeof(Signature)); memset(&sm, 0, sizeof(SigMatch)); memset(&client, 0, sizeof(TcpStream)); memset(&f, 0, sizeof(Flow)); memset(&tcph, 0, sizeof(TCPHdr)); sd = DetectStreamSizeParse("client,>,8"); if (sd != NULL) { if (!(sd->flags & STREAM_SIZE_CLIENT)) { printf("sd->flags not STREAM_SIZE_CLIENT: "); DetectStreamSizeFree(sd); SCFree(p); return 0; } if (sd->mode != DETECTSSIZE_GT) { printf("sd->mode not DETECTSSIZE_GT: "); DetectStreamSizeFree(sd); SCFree(p); return 0; } if (sd->ssize != 8) { printf("sd->ssize is %"PRIu32", not 8: ", sd->ssize); DetectStreamSizeFree(sd); SCFree(p); return 0; } } else { printf("sd == NULL: "); SCFree(p); return 0; } client.next_seq = 20; client.isn = 10; ssn.client = client; f.protoctx = &ssn; p->flow = &f; p->tcph = &tcph; sm.ctx = sd; result = DetectStreamSizeMatch(&tv, &dtx, p, &s, &sm); if (result == 0) { printf("result 0 != 1: "); } DetectStreamSizeFree(sd); SCFree(p); return result; } /** * \test DetectStreamSizeParseTest04 is a test to make sure that we match the * stream_size against invalid packet parameters. */ static int DetectStreamSizeParseTest04 (void) { int result = 0; DetectStreamSizeData *sd = NULL; TcpSession ssn; ThreadVars tv; DetectEngineThreadCtx dtx; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature s; SigMatch sm; TcpStream client; Flow f; IPV4Hdr ip4h; memset(&ssn, 0, sizeof(TcpSession)); memset(&tv, 0, sizeof(ThreadVars)); memset(&dtx, 0, sizeof(DetectEngineThreadCtx)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&s, 0, sizeof(Signature)); memset(&sm, 0, sizeof(SigMatch)); memset(&client, 0, sizeof(TcpStream)); memset(&f, 0, sizeof(Flow)); memset(&ip4h, 0, sizeof(IPV4Hdr)); sd = DetectStreamSizeParse(" client , > , 8 "); if (sd != NULL) { if (!(sd->flags & STREAM_SIZE_CLIENT) && sd->mode != DETECTSSIZE_GT && sd->ssize != 8) { SCFree(p); return 0; } } else { SCFree(p); return 0; } client.next_seq = 20; client.isn = 12; ssn.client = client; f.protoctx = &ssn; p->flow = &f; p->ip4h = &ip4h; sm.ctx = sd; if (!DetectStreamSizeMatch(&tv, &dtx, p, &s, &sm)) result = 1; SCFree(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectStreamSize */ void DetectStreamSizeRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectStreamSizeParseTest01", DetectStreamSizeParseTest01, 1); UtRegisterTest("DetectStreamSizeParseTest02", DetectStreamSizeParseTest02, 1); UtRegisterTest("DetectStreamSizeParseTest03", DetectStreamSizeParseTest03, 1); UtRegisterTest("DetectStreamSizeParseTest04", DetectStreamSizeParseTest04, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-decode-der-get.h0000644000000000000000000000366112253546156014727 00000000000000/* * Copyright (C) 2011-2012 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * \author Pierre Chifflier * */ #ifndef __UTIL_DECODE_DER_GET_H__ #define __UTIL_DECODE_DER_GET_H__ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, const uint32_t seqsz, uint32_t *errcode); int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); #endif /* __UTIL_DECODE_DER_GET_H__ */ suricata-1.4.7/src/util-coredump-config.c0000644000000000000000000001627112253546156015234 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eileen Donlon * * Coredump configuration */ #define _FILE_OFFSET_BITS 64 #include "util-coredump-config.h" #include "conf.h" #include /** * \brief Configures the core dump size. * * \retval Returns 1 on success and 0 on failure. * */ int32_t CoredumpLoadConfig (void) { /* get core dump configuration settings for suricata */ char* dump_size_config = NULL; rlim_t max_dump = 0; uint32_t unlimited = 0; size_t rlim_size = sizeof(rlim_t); if (ConfGet ("coredump.max-dump", &dump_size_config) == 0) { SCLogDebug ("core dump size not specified"); return 1; } if (strcasecmp (dump_size_config, "unlimited") == 0) { unlimited = 1; } else { /* disallow negative values */ if (strchr (dump_size_config, '-') != NULL) { SCLogInfo ("Negative value for core dump size; ignored."); return 0; } /* the size of rlim_t is platform dependent */ if (rlim_size > 8) { SCLogInfo ("Unexpected type for rlim_t"); return 0; } errno = 0; if (rlim_size == 8) { max_dump = (rlim_t) strtoull (dump_size_config, NULL, 10); } else if (rlim_size == 4) { max_dump = (rlim_t) strtoul (dump_size_config, NULL, 10); } if ((errno == ERANGE) || (errno != 0 && max_dump == 0)) { SCLogInfo ("Illegal core dump size: %s.", dump_size_config); return 0; } SCLogInfo ("Max dump is %llu", (unsigned long long) max_dump); } #if defined OS_WIN32 /* todo: use the registry to get/set dump configuration */ SCLogInfo("Configuring core dump is not yet supported on Windows."); return 0; #endif #ifdef HAVE_SYS_PRCTL_H /* Linux specific core dump configuration; set dumpable flag if needed */ int dumpable = 0; dumpable = prctl (PR_GET_DUMPABLE, 0, 0, 0, 0); if (dumpable == -1) { SCLogInfo ("Can't get core dump configuration of process."); } else if (unlimited == 1 || max_dump > 0) { /* try to enable core dump for this process */ if (prctl (PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { SCLogInfo ("Unable to make this process dumpable."); return 0; } else { SCLogDebug ("Process is dumpable."); } } /* don't clear dumpable flag since this will have other effects; * just set dump size to 0 below */ #endif /* Linux specific */ struct rlimit lim; /*existing limit*/ struct rlimit new_lim; /*desired limit*/ /* get the current core dump file configuration */ if (getrlimit (RLIMIT_CORE, &lim) == -1) { SCLogInfo ("Can't read coredump limit for this process."); return 0; } if (unlimited) { /* we want no limit on coredump size */ if (lim.rlim_max == RLIM_INFINITY && lim.rlim_cur == RLIM_INFINITY) { SCLogInfo ("Core dump size is unlimited."); return 1; } else { new_lim.rlim_max = RLIM_INFINITY; new_lim.rlim_cur = RLIM_INFINITY; if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { SCLogInfo ("Core dump size set to unlimited."); return 1; } if (errno == EPERM) { /* couldn't raise the hard limit to unlimited; * try increasing the soft limit to the hard limit instead */ if (lim.rlim_cur < lim.rlim_max) { new_lim.rlim_cur = lim.rlim_max; if (setrlimit (RLIMIT_CORE, & new_lim) == 0) { SCLogInfo ("Could not set core dump size to unlimited; core dump size set to the hard limit."); return 0; } else { SCLogInfo ("Failed to set core dump size to unlimited or to the hard limit."); return 0; } } SCLogInfo ("Could not set core dump size to unlimited; it's set to the hard limit."); return 0; } } } else { /* we want a non-infinite soft limit on coredump size */ new_lim.rlim_cur = max_dump; /* check whether the hard limit needs to be adjusted */ if (lim.rlim_max == RLIM_INFINITY) { /* keep the current value (unlimited) for the hard limit */ new_lim.rlim_max = lim.rlim_max; } #ifdef RLIM_SAVED_MAX else if (lim.rlim_max == RLIM_SAVED_MAX) { /* keep the current value (unknown) for the hard limit */ new_lim.rlim_max = lim.rlim_max; } #endif else if (lim.rlim_max < max_dump) { /* need to raise the hard coredump size limit */ new_lim.rlim_max = max_dump; } else { /* hard limit is ample */ new_lim.rlim_max = lim.rlim_max; } if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { SCLogInfo ("Core dump setting attempted is %llu", (unsigned long long) new_lim.rlim_cur); struct rlimit actual_lim; if (getrlimit (RLIMIT_CORE, &actual_lim) == 0) { if (actual_lim.rlim_cur == RLIM_INFINITY) { SCLogInfo ("Core dump size set to unlimited."); } #ifdef RLIM_SAVED_CUR else if (actual_lim.rlim_cur == RLIM_SAVED_CUR) { SCLogInfo ("Core dump size set to soft limit."); } #endif else { SCLogInfo ("Core dump size set to %llu", (unsigned long long) actual_lim.rlim_cur); } } return 1; } if (errno == EINVAL || errno == EPERM) { /* could't increase the hard limit, or the soft limit exceeded the hard * limit; try to raise the soft limit to the hard limit */ if ((lim.rlim_cur < max_dump && lim.rlim_cur < lim.rlim_max) #ifdef RLIM_SAVED_CUR || (lim.rlim_cur == RLIM_SAVED_CUR) #endif ){ new_lim.rlim_max = lim.rlim_max; new_lim.rlim_cur = lim.rlim_max; if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { SCLogInfo("Core dump size set to the hard limit."); return 0; } } } } /* failed to set the coredump limit */ SCLogInfo ("Could't set coredump size to %s.", dump_size_config); return 0; } suricata-1.4.7/src/decode-sll.c0000644000000000000000000000404612253546156013210 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Victor Julien * * Decodes Sll */ #include "suricata-common.h" #include "decode.h" #include "decode-sll.h" #include "decode-events.h" #include "util-debug.h" void DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_sll, tv->sc_perf_pca); if (len < SLL_HEADER_LEN) { ENGINE_SET_EVENT(p,SLL_PKT_TOO_SMALL); return; } SllHdr *sllh = (SllHdr *)pkt; if (sllh == NULL) return; SCLogDebug("p %p pkt %p sll_protocol %04x", p, pkt, ntohs(sllh->sll_protocol)); switch (ntohs(sllh->sll_protocol)) { case ETHERNET_TYPE_IP: DecodeIPV4(tv, dtv, p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN, pq); break; case ETHERNET_TYPE_IPV6: DecodeIPV6(tv, dtv, p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN, pq); break; case ETHERNET_TYPE_VLAN: DecodeVLAN(tv, dtv, p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN, pq); break; default: SCLogDebug("p %p pkt %p sll type %04x not supported", p, pkt, ntohs(sllh->sll_protocol)); } } /** * @} */ suricata-1.4.7/src/detect-pcre.c0000644000000000000000000036440012253546156013377 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the pcre keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "pkt-var.h" #include "flow-var.h" #include "flow-alert-sid.h" #include "flow-util.h" #include "detect-pcre.h" #include "detect-flowvar.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-sigorder.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "util-var-name.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "util-unittest.h" #include "util-print.h" #include "util-pool.h" #include "conf.h" #include "app-layer-htp.h" #include "stream.h" #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-htp.h" #include "stream.h" #define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>" #define PARSE_REGEX "(?ctx; if (pe->flags & DETECT_PCRE_RELATIVE) { ptr = payload + det_ctx->buffer_offset; len = payload_len - det_ctx->buffer_offset; } else { ptr = payload; len = payload_len; } int start_offset = 0; if (det_ctx->pcre_match_start_offset != 0) { start_offset = (payload + det_ctx->pcre_match_start_offset - ptr); } /* run the actual pcre detection */ ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, start_offset, 0, ov, MAX_SUBSTRINGS); SCLogDebug("ret %d (negating %s)", ret, (pe->flags & DETECT_PCRE_NEGATE) ? "set" : "not set"); if (ret == PCRE_ERROR_NOMATCH) { if (pe->flags & DETECT_PCRE_NEGATE) { /* regex didn't match with negate option means we * consider it a match */ ret = 1; } else { ret = 0; } } else if (ret >= 0) { if (pe->flags & DETECT_PCRE_NEGATE) { /* regex matched but we're negated, so not * considering it a match */ ret = 0; } else { /* regex matched and we're not negated, * considering it a match */ /* see if we need to do substring capturing. */ if (ret > 1 && pe->capidx != 0) { const char *str_ptr; ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (ret) { if (pe->flags & DETECT_PCRE_CAPTURE_PKT) { if (p != NULL) { PktVarAdd(p, pe->capname, (uint8_t *)str_ptr, ret); } } else if (pe->flags & DETECT_PCRE_CAPTURE_FLOW) { if (f != NULL) { /* store max 64k. Errors are ignored */ capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; (void)DetectFlowvarStoreMatch(det_ctx, pe->capidx, (uint8_t *)str_ptr, capture_len); } } } } /* update offset for pcre RELATIVE */ det_ctx->buffer_offset = (ptr + ov[1]) - payload; det_ctx->pcre_match_start_offset = (ptr + ov[0] + 1) - payload; ret = 1; } } else { SCLogDebug("pcre had matching error"); ret = 0; } SCReturnInt(ret); } DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr) { int ec; const char *eb; int eo; int opts = 0; DetectPcreData *pd = NULL; char *re = NULL, *op_ptr = NULL, *op = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; uint16_t slen = strlen(regexstr); uint16_t pos = 0; uint8_t negate = 0; uint16_t re_len = 0; uint32_t u = 0; while (pos < slen && isspace((unsigned char)regexstr[pos])) { pos++; } if (regexstr[pos] == '!') { negate = 1; pos++; } ret = pcre_exec(parse_regex, parse_regex_study, regexstr + pos, slen-pos, 0, 0, ov, MAX_SUBSTRINGS); if (ret < 0) { SCLogError(SC_ERR_PCRE_MATCH, "parse error"); goto error; } if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)regexstr + pos, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return NULL; } re = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)regexstr + pos, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return NULL; } op_ptr = op = (char *)str_ptr; } } //printf("ret %" PRId32 " re \'%s\', op \'%s\'\n", ret, re, op); pd = SCMalloc(sizeof(DetectPcreData)); if (unlikely(pd == NULL)) goto error; memset(pd, 0, sizeof(DetectPcreData)); if (negate) pd->flags |= DETECT_PCRE_NEGATE; if (op != NULL) { while (*op) { SCLogDebug("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; pd->flags |= DETECT_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 */ if (pd->flags & DETECT_PCRE_URI) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'B' inconsistent with 'U'"); goto error; } if (pd->flags & DETECT_PCRE_HEADER) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'B' inconsistent with 'H'"); goto error; } if (pd->flags & DETECT_PCRE_COOKIE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'B' inconsistent with 'C'"); goto error; } if (pd->flags & DETECT_PCRE_METHOD) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'B' inconsistent with 'M'"); goto error; } pd->flags |= DETECT_PCRE_RAWBYTES; break; case 'R': /* snort's option */ pd->flags |= DETECT_PCRE_RELATIVE; break; case 'U': /* snort's option */ if (pd->flags & DETECT_PCRE_HTTP_RAW_URI) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'U' inconsistent with 'I'"); goto error; } if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'U' inconsistent with 'B'"); goto error; } pd->flags |= DETECT_PCRE_URI; break; case 'V': if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'V' inconsistent with 'B'"); goto error; } pd->flags |= DETECT_PCRE_HTTP_USER_AGENT; break; case 'W': if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'W' inconsistent with 'B'"); goto error; } pd->flags |= DETECT_PCRE_HTTP_HOST; break; case 'Z': if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'Z' inconsistent with 'B'"); goto error; } pd->flags |= DETECT_PCRE_HTTP_RAW_HOST; break; case 'H': /* snort's option */ if (pd->flags & DETECT_PCRE_RAW_HEADER) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'H' inconsistent with 'D'"); goto error; } if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'H' inconsistent with 'B'"); goto error; } pd->flags |= DETECT_PCRE_HEADER; break; case 'I': /* snort's option */ if (pd->flags & DETECT_PCRE_URI) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'I' inconsistent with 'U'"); goto error; } if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'I' inconsistent with 'B'"); goto error; } pd->flags |= DETECT_PCRE_HTTP_RAW_URI; break; case 'D': /* snort's option */ if (pd->flags & DETECT_PCRE_HEADER) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'D' inconsistent with 'H'"); goto error; } pd->flags |= DETECT_PCRE_RAW_HEADER; break; case 'M': /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'M' inconsistent with 'B'"); goto error; } pd->flags |= DETECT_PCRE_METHOD; break; case 'C': /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'C' inconsistent with 'B'"); goto error; } pd->flags |= DETECT_PCRE_COOKIE; break; case 'O': pd->flags |= DETECT_PCRE_MATCH_LIMIT; break; case 'P': /* snort's option (http request body inspection) */ pd->flags |= DETECT_PCRE_HTTP_CLIENT_BODY; break; case 'Q': /* suricata extension (http response body inspection) */ pd->flags |= DETECT_PCRE_HTTP_SERVER_BODY; break; case 'Y': /* snort's option */ pd->flags |= DETECT_PCRE_HTTP_STAT_MSG; break; case 'S': /* snort's option */ pd->flags |= DETECT_PCRE_HTTP_STAT_CODE; break; default: SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op); goto error; } op++; } } SCLogDebug("DetectPcreParse: \"%s\"", re); if (pd->flags & DETECT_PCRE_HTTP_HOST) { if (pd->flags & DETECT_PCRE_CASELESS) { SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http host pcre(\"W\") " "specified along with \"i(caseless)\" modifier. " "Since the hostname buffer we match against " "is actually lowercase, having a " "nocase is redundant."); } else { re_len = strlen(re); for (u = 0; u < re_len; u++) { if (isupper(re[u])) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre host(\"W\") " "specified has an uppercase char. " "Since the hostname buffer we match against " "is actually lowercase, please specify an " "all lowercase based pcre."); goto error; } } } } /* Try to compile as if all (...) groups had been meant as (?:...), * which is the common case in most rules. * If we fail because a capture group is later referenced (e.g., \1), * PCRE will let us know. */ pd->re = pcre_compile2(re, opts | PCRE_NO_AUTO_CAPTURE, &ec, &eb, &eo, NULL); if (pd->re == NULL && ec == 15) { // reference to non-existent subpattern pd->re = pcre_compile(re, opts, &eb, &eo, NULL); } if(pd->re == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", regexstr, eo, eb); goto error; } #ifdef PCRE_HAVE_JIT pd->sd = pcre_study(pd->re, PCRE_STUDY_JIT_COMPILE, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb); goto error; } int jit = 0; ret = pcre_fullinfo(pd->re, pd->sd, PCRE_INFO_JIT, &jit); if (ret != 0 || jit != 1) { /* warning, so we won't print the sig after this. Adding * file and line to the message so the admin can figure * out what sig this is about */ SCLogDebug("PCRE JIT compiler does not support: %s. " "Falling back to regular PCRE handling (%s:%d)", regexstr, de_ctx->rule_file, de_ctx->rule_line); } #else pd->sd = pcre_study(pd->re, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb); goto error; } #endif /*PCRE_HAVE_JIT*/ if(pd->sd == NULL) pd->sd = (pcre_extra *) SCCalloc(1,sizeof(pcre_extra)); if(pd->sd) { if(pd->flags & DETECT_PCRE_MATCH_LIMIT) { if(pcre_match_limit >= -1) { pd->sd->match_limit = pcre_match_limit; pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT; } #ifndef NO_PCRE_MATCH_RLIMIT if(pcre_match_limit_recursion >= -1) { pd->sd->match_limit_recursion = pcre_match_limit_recursion; pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; } #endif /* NO_PCRE_MATCH_RLIMIT */ } else { pd->sd->match_limit = SC_MATCH_LIMIT_DEFAULT; pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT; #ifndef NO_PCRE_MATCH_RLIMIT pd->sd->match_limit_recursion = SC_MATCH_LIMIT_RECURSION_DEFAULT; pd->sd->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; #endif /* NO_PCRE_MATCH_RLIMIT */ } } else { goto error; } if (re != NULL) SCFree(re); if (op_ptr != NULL) SCFree(op_ptr); return pd; error: if (re != NULL) SCFree(re); if (op_ptr != NULL) SCFree(op_ptr); if (pd != NULL && pd->re != NULL) pcre_free(pd->re); if (pd != NULL && pd->sd != NULL) pcre_free(pd->sd); if (pd) SCFree(pd); return NULL; } DetectPcreData *DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd) { int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *capture_str_ptr = NULL, *type_str_ptr = NULL; if(pd == NULL) goto error; if(de_ctx == NULL) goto error; //printf("DetectPcreParseCapture: \'%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, &type_str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } res = pcre_get_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, &capture_str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } } //printf("DetectPcreParseCapture: type \'%s\'\n", type_str_ptr ? type_str_ptr : "NULL"); //printf("DetectPcreParseCapture: capture \'%s\'\n", capture_str_ptr ? capture_str_ptr : "NULL"); if (capture_str_ptr != NULL) { pd->capname = SCStrdup((char *)capture_str_ptr); } if (type_str_ptr != NULL) { if (strcmp(type_str_ptr,"pkt") == 0) { pd->flags |= DETECT_PCRE_CAPTURE_PKT; } else if (strcmp(type_str_ptr,"flow") == 0) { pd->flags |= DETECT_PCRE_CAPTURE_FLOW; } if (capture_str_ptr != NULL) { if (pd->flags & DETECT_PCRE_CAPTURE_PKT) pd->capidx = VariableNameGetIdx(de_ctx, (char *)capture_str_ptr, DETECT_PKTVAR); else if (pd->flags & DETECT_PCRE_CAPTURE_FLOW) pd->capidx = VariableNameGetIdx(de_ctx, (char *)capture_str_ptr, DETECT_FLOWVAR); } } //printf("DetectPcreParseCapture: pd->capname %s\n", pd->capname ? pd->capname : "NULL"); if (type_str_ptr != NULL) pcre_free((char *)type_str_ptr); if (capture_str_ptr != NULL) pcre_free((char *)capture_str_ptr); return pd; error: if (pd != NULL && pd->capname != NULL) SCFree(pd->capname); if (pd) SCFree(pd); return NULL; } static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexstr) { SCEnter(); DetectPcreData *pd = NULL; SigMatch *sm = NULL; SigMatch *prev_sm = NULL; pd = DetectPcreParse(de_ctx, regexstr); if (pd == NULL) goto error; if ((pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) && (s->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Can't use pcre /P with flow:from_server or flow:to_client"); goto error; } if (((pd->flags & DETECT_PCRE_URI) || (pd->flags & DETECT_PCRE_HTTP_RAW_URI)) && (s->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Can't use pcre /U or /I with flow:from_server or flow:to_client"); goto error; } /* check pcre modifiers against the signature alproto. In case they conflict * chuck out invalid signature */ switch (s->alproto) { case ALPROTO_DCERPC: if ( (pd->flags & DETECT_PCRE_URI) || (pd->flags & DETECT_PCRE_METHOD) || (pd->flags & DETECT_PCRE_HEADER) || (pd->flags & DETECT_PCRE_RAW_HEADER) || (pd->flags & DETECT_PCRE_COOKIE) || (pd->flags & DETECT_PCRE_HTTP_STAT_MSG) || (pd->flags & DETECT_PCRE_HTTP_STAT_CODE) || (pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) || (pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) || (pd->flags & DETECT_PCRE_HTTP_RAW_URI) || (pd->flags & DETECT_PCRE_HTTP_USER_AGENT) || (pd->flags & DETECT_PCRE_HTTP_HOST) || (pd->flags & DETECT_PCRE_HTTP_RAW_HOST) ) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " "DCERPC rule has pcre keyword with http related modifier."); goto error; } break; default: break; } pd = DetectPcreParseCapture(regexstr, de_ctx, pd); if (pd == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_PCRE; sm->ctx = (void *)pd; if (pd->flags & DETECT_PCRE_HEADER) { SCLogDebug("Header inspection modifier set"); s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHDMATCH); } else if (pd->flags & DETECT_PCRE_RAW_HEADER) { SCLogDebug("Raw header inspection modifier set"); s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH); } else if (pd->flags & DETECT_PCRE_COOKIE) { //sm->type = DETECT_PCRE_HTTPCOOKIE; SCLogDebug("Cookie inspection modifier set"); s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); } else if (pd->flags & DETECT_PCRE_HTTP_USER_AGENT) { SCLogDebug("User-Agent inspection modifier set on pcre"); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains " "conflicting keywords."); goto error; } s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HUADMATCH); } else if (pd->flags & DETECT_PCRE_HTTP_HOST) { SCLogDebug("Host inspection modifier set on pcre"); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains " "conflicting keywords."); goto error; } s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHHDMATCH); } else if (pd->flags & DETECT_PCRE_HTTP_RAW_HOST) { SCLogDebug("Raw Host inspection modifier set on pcre"); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains " "conflicting keywords."); goto error; } s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHHDMATCH); } else if (pd->flags & DETECT_PCRE_METHOD) { //sm->type = DETECT_PCRE_HTTPMETHOD; SCLogDebug("Method inspection modifier set"); s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HMDMATCH); } else if (pd->flags & DETECT_PCRE_HTTP_CLIENT_BODY) { SCLogDebug("Request body inspection modifier set"); s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; AppLayerHtpEnableRequestBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); } else if (pd->flags & DETECT_PCRE_HTTP_SERVER_BODY) { SCLogDebug("Response body inspection modifier set"); s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else if (pd->flags & DETECT_PCRE_URI) { s->flags |= SIG_FLAG_APPLAYER; if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting" " keywords."); goto error; } s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); } else if (pd->flags & DETECT_PCRE_HTTP_RAW_URI) { s->flags |= SIG_FLAG_APPLAYER; if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting" " keywords."); goto error; } s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); } else if (pd->flags & DETECT_PCRE_HTTP_STAT_MSG) { s->flags |= SIG_FLAG_APPLAYER; if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting" " keywords."); goto error; } s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSMDMATCH); } else if (pd->flags & DETECT_PCRE_HTTP_STAT_CODE) { s->flags |= SIG_FLAG_APPLAYER; if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting" " keywords."); goto error; } s->alproto = ALPROTO_HTTP; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSCDMATCH); } else { if (s->alproto == ALPROTO_DCERPC && (pd->flags & DETECT_PCRE_RELATIVE)) { SigMatch *pm = NULL; SigMatch *dm = NULL; pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (dm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (pm->idx > dm->idx) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } } else { if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { SCLogDebug("adding to http server body list because of file data"); s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } } } if (!(pd->flags & DETECT_PCRE_RELATIVE)) { SCReturnInt(0); } prev_sm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); if (prev_sm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is an alproto sig."); SCReturnInt(0); } else { if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { SCLogDebug("removing relative flag as we are relative to file_data"); pd->flags &= ~DETECT_PCRE_RELATIVE; SCReturnInt(0); } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "No preceding content " "or uricontent or pcre option"); SCReturnInt(-1); } } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (prev_sm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_sm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "content not setup properly"); SCReturnInt(-1); } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; break; case DETECT_PCRE: pe = (DetectPcreData *) prev_sm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre not setup properly"); SCReturnInt(-1); } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "prev sigmatch has unknown type: %"PRIu16, prev_sm->type); SCReturnInt(-1); break; } /* switch (prev_sm->type) */ if (pd->capidx != 0) { if (DetectFlowvarPostMatchSetup(s, pd->capidx) < 0) goto error; } SCReturnInt(0); error: if (pd != NULL) DetectPcreFree(pd); if (sm != NULL) SCFree(sm); SCReturnInt(-1); } void DetectPcreFree(void *ptr) { DetectPcreData *pd = (DetectPcreData *)ptr; if (pd->capname != NULL) SCFree(pd->capname); if (pd->re != NULL) pcre_free(pd->re); if (pd->sd != NULL) pcre_free(pd->sd); SCFree(pd); return; } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectPcreParseTest01 make sure we don't allow invalid opts 7. */ static int DetectPcreParseTest01 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/blah/7"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd != NULL) { printf("expected NULL: got %p", pd); result = 0; DetectPcreFree(pd); } DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest02 make sure we don't allow invalid opts Ui$. */ static int DetectPcreParseTest02 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/blah/Ui$"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd != NULL) { printf("expected NULL: got %p", pd); result = 0; DetectPcreFree(pd); } DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest03 make sure we don't allow invalid opts UZi. */ static int DetectPcreParseTest03 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/blah/UNi"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd != NULL) { printf("expected NULL: got %p", pd); result = 0; DetectPcreFree(pd); } DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest04 make sure we allow escaped " */ static int DetectPcreParseTest04 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/b\\\"lah/i"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd == NULL) { printf("expected %p: got NULL", pd); result = 0; } DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest05 make sure we parse pcre with no opts */ static int DetectPcreParseTest05 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/b(l|a)h/"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd == NULL) { printf("expected %p: got NULL", pd); result = 0; } DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest06 make sure we parse pcre with smi opts */ static int DetectPcreParseTest06 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/b(l|a)h/smi"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd == NULL) { printf("expected %p: got NULL", pd); result = 0; } DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest07 make sure we parse pcre with /Ui opts */ static int DetectPcreParseTest07 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/blah/Ui"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd == NULL) { printf("expected %p: got NULL", pd); result = 0; } DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest08 make sure we parse pcre with O opts */ static int DetectPcreParseTest08 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/b(l|a)h/O"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd == NULL) { printf("expected %p: got NULL", pd); result = 0; } DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectPcreParseTest09 make sure we parse pcre with a content * that has slashes */ static int DetectPcreParseTest09 (void) { int result = 1; DetectPcreData *pd = NULL; char *teststring = "/lala\\\\/"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) return 0; pd = DetectPcreParse(de_ctx, teststring); if (pd == NULL) { printf("expected %p: got NULL", pd); result = 0; } DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test pcre option for dce sig(yeah I'm bored of writing test titles). */ int DetectPcreParseTest10(void) { Signature *s = SigAlloc(); int result = 1; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { result = 0; goto end; } s->alproto = ALPROTO_DCERPC; result &= (DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); s = SigAlloc(); /* failure since we have no preceding content/pcre/bytejump */ result &= (DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); end: SigFree(s); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test pcre option for dce sig. */ int DetectPcreParseTest11(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/R; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE) || data->flags & DETECT_PCRE_URI) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/R; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE) || data->flags & DETECT_PCRE_URI) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/RB; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (!(data->flags & DETECT_PCRE_RAWBYTES) || !(data->flags & DETECT_PCRE_RELATIVE) || data->flags & DETECT_PCRE_URI) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; pcre:/bamboo/; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test pcre option with file data. pcre is relative to file_data, * so relative flag should be unset. */ static int DetectPcreParseTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; pcre:/abc/R; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("empty server body list: "); goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { printf("last sm not pcre: "); goto end; } data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (data->flags & DETECT_PCRE_RAWBYTES || data->flags & DETECT_PCRE_RELATIVE || data->flags & DETECT_PCRE_URI) { printf("flags not right: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test pcre option with file data. */ static int DetectPcreParseTest13(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"abc\"; pcre:/def/R; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("empty server body list: "); goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { printf("last sm not pcre: "); goto end; } data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (data->flags & DETECT_PCRE_RAWBYTES || !(data->flags & DETECT_PCRE_RELATIVE) || data->flags & DETECT_PCRE_URI) { printf("flags not right: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test pcre option with file data. */ static int DetectPcreParseTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; pcre:/def/; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("empty server body list: "); goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { printf("last sm not pcre: "); goto end; } data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (data->flags & DETECT_PCRE_RAWBYTES || data->flags & DETECT_PCRE_RELATIVE || data->flags & DETECT_PCRE_URI) { printf("flags not right: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with pcre relative method */ int DetectPcreParseTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_method\"; " "content:\"GET\"; " "http_method; pcre:\"/abc/RM\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with pcre relative cookie */ int DetectPcreParseTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_cookie\"; " "content:\"test\"; " "http_cookie; pcre:\"/abc/RC\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with pcre relative raw header */ int DetectPcreParseTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_raw_header\"; " "flow:to_server; content:\"test\"; " "http_raw_header; pcre:\"/abc/RD\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with pcre relative header */ int DetectPcreParseTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_header\"; " "content:\"test\"; " "http_header; pcre:\"/abc/RH\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with pcre relative client-body */ int DetectPcreParseTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relativie http_client_body\"; " "content:\"test\"; " "http_client_body; pcre:\"/abc/RP\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with pcre relative raw uri */ int DetectPcreParseTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_uri\"; " "content:\"test\"; " "http_raw_uri; pcre:\"/abc/RI\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with pcre relative uricontent */ int DetectPcreParseTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative uricontent\"; " "uricontent:\"test\"; " "pcre:\"/abc/RU\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with pcre relative http_uri */ int DetectPcreParseTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing pcre relative http_uri\"; " "content:\"test\"; " "http_uri; pcre:\"/abc/RU\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with inconsistent pcre relative */ int DetectPcreParseTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre relative\"; " "content:\"GET\"; " "http_cookie; pcre:\"/abc/RM\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } else { printf("sig parse should have failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with inconsistent pcre modifiers */ int DetectPcreParseTest24(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/UI\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } else { printf("sig parse should have failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with inconsistent pcre modifiers */ int DetectPcreParseTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/DH\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } else { printf("sig parse should have failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } static int DetectPcreTestSig01Real(int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; Flow f; memset(&f, 0, sizeof(f)); memset(&th_v, 0, sizeof(th_v)); memset(&ssn, 0, sizeof(TcpSession)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_HTTP; p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 1) { result = 1; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectPcreTestSig01B2g (void) { return DetectPcreTestSig01Real(MPM_B2G); } static int DetectPcreTestSig01B3g (void) { return DetectPcreTestSig01Real(MPM_B3G); } static int DetectPcreTestSig01Wm (void) { return DetectPcreTestSig01Real(MPM_WUMANBER); } static int DetectPcreTestSig02Real(int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; Flow f; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); FLOW_INITIALIZE(&f); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; pcre_match_limit = 100; pcre_match_limit_recursion = 100; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/two/O\"; sid:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 2) == 1) { result = 1; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FLOW_DESTROY(&f); end: UTHFreePackets(&p, 1); return result; } static int DetectPcreTestSig02B2g (void) { return DetectPcreTestSig02Real(MPM_B2G); } static int DetectPcreTestSig02B3g (void) { return DetectPcreTestSig02Real(MPM_B3G); } static int DetectPcreTestSig02Wm (void) { return DetectPcreTestSig02Real(MPM_WUMANBER); } /** * \test DetectPcreTestSig03Real negation test ! outside of "" this sig should not match */ static int DetectPcreTestSig03Real(int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 1; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { result = 0; goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"GET\"; pcre:!\"/two/\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)){ printf("sid 1 matched even though it shouldn't have:"); result = 0; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int DetectPcreTestSig03B2g (void) { return DetectPcreTestSig03Real(MPM_B2G); } static int DetectPcreTestSig03B3g (void) { return DetectPcreTestSig03Real(MPM_B3G); } static int DetectPcreTestSig03Wm (void) { return DetectPcreTestSig03Real(MPM_WUMANBER); } /** * \test Check the signature with pcre modifier P (match with L7 to http body data) */ static int DetectPcreModifPTest04(void) { int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "X-Powered-By: PHP/5.2.5\r\n" "P3P: CP=\"NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM\"\r\n" "Expires: Mon, 1 Jan 2001 00:00:00 GMT\r\n" "Last-Modified: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" "Pragma: no-cache\r\n" "Keep-Alive: timeout=15, max=100\r\n" "Connection: Keep-Alive\r\n" "Transfer-Encoding: chunked\r\n" "Content-Type: text/html; charset=utf-8\r\n" "\r\n" "15" "\r\n" "flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"Pcre modifier P\"; pcre:\"/DOCTYPE/P\"; " "sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"" "Pcre modifier P (no match)\"; pcre:\"/blah/P\"; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sid 2 matched but shouldn't: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Check the signature with pcre modifier P (match with L7 to http body data) * over fragmented chunks (DOCTYPE fragmented) */ static int DetectPcreModifPTest05(void) { int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "X-Powered-By: PHP/5.2.5\r\n" "P3P: CP=\"NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM\"\r\n" "Expires: Mon, 1 Jan 2001 00:00:00 GMT\r\n" "Last-Modified: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" "Pragma: no-cache\r\n" "Keep-Alive: timeout=15, max=100\r\n" "Connection: Keep-Alive\r\n" "Transfer-Encoding: chunked\r\n" "Content-Type: text/html; charset=utf-8\r\n" "\r\n" "15" "\r\n" "flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"Pcre modifier P\"; pcre:\"/DOC/P\"; " "sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"" "Pcre modifier P (no match)\"; pcre:\"/DOCTYPE/P\"; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } if (PacketAlertCheck(p1, 1)) { printf("sid 1 didn't match on p1 but should have: "); goto end; } if (PacketAlertCheck(p1, 2)) { printf("sid 2 did match on p1 but shouldn't have: "); /* It's a partial match over 2 chunks*/ goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect for p2 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 did match on p2 but should have: "); goto end; } if (!(PacketAlertCheck(p2, 2))) { printf("sid 2 didn't match on p2 but should have: "); /* It's a partial match over 2 chunks*/ goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } int DetectPcreTestSig06() { uint8_t *buf = (uint8_t *) "lalala lalala\\ lala\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/ lalala\\\\/\"; sid:1;)"; if (UTHPacketMatchSig(p, sig) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** \test anchored pcre */ int DetectPcreTestSig07() { uint8_t *buf = (uint8_t *) "lalala\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)"; if (UTHPacketMatchSig(p, sig) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** \test anchored pcre */ int DetectPcreTestSig08() { /* test it also without ending in a newline "\n" */ uint8_t *buf = (uint8_t *) "lalala"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)"; if (UTHPacketMatchSig(p, sig) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } /** \test Check the signature working to alert when cookie modifier is * passed to pcre */ static int DetectPcreTestSig09(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; pcre:\"/dummy/C\"; " " sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 failed to match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when cookie modifier is * passed to a negated pcre */ static int DetectPcreTestSig10(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; pcre:!\"/dummy/C\"; " " sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 should match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when method modifier is * passed to pcre */ static int DetectPcreTestSig11(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP method\"; pcre:\"/POST/M\"; " " sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 failed to match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when method modifier is * passed to a negated pcre */ static int DetectPcreTestSig12(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP method\"; pcre:!\"/POST/M\"; " " sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 should match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when header modifier is * passed to pcre */ static int DetectPcreTestSig13(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP header\"; pcre:\"/User[-_]Agent[:]?\\sMozilla/H\"; " " sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 failed to match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when header modifier is * passed to a negated pcre */ static int DetectPcreTestSig14(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: IEXPLORER/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP header\"; pcre:!\"/User-Agent[:]?\\s+Mozilla/H\"; " " sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 should match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when cookie and relative modifiers are * passed to pcre */ static int DetectPcreTestSig15(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy 1234\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"pcre relative HTTP cookie\"; content:\"dummy\";" " http_cookie; pcre:\"/1234/RC\"; " " sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 failed to match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when method and relative modifiers are * passed to pcre */ static int DetectPcreTestSig16(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy 1234\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"pcre relative HTTP method\"; content:\"PO\";" " http_method; pcre:\"/ST/RM\"; " " sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 failed to match: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Test tracking of body chunks per transactions (on requests) */ static int DetectPcreTxBodyChunksTest01(void) { int result = 0; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Body one!!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); AppLayerHtpEnableRequestBodyCallback(); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* Now we should have 2 transactions, each with it's own list * of request body chunks (let's test it) */ HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } /* hardcoded check of the transactions and it's client body chunks */ if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0); htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); if (htud == NULL) { printf("No body data in t1 (it should be removed only when the tx is destroyed): "); goto end; } HtpBodyChunk *cur = htud->request_body.first; if (htud->request_body.first == NULL) { SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); goto end; } if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; if (htud->request_body.first == NULL) { SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); goto end; } if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test test pcre P modifier with multiple pipelined http transactions */ static int DetectPcreTxBodyChunksTest02(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Body one!!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("signature matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (5): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 2))) { printf("signature 2 didn't match, but should have: "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } /* hardcoded check of the transactions and it's client body chunks */ if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0); htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); HtpBodyChunk *cur = htud->request_body.first; if (htud->request_body.first == NULL) { SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); goto end; } if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; if (htud->request_body.first == NULL) { SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); goto end; } if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** \test multiple http transactions and body chunks of request handling */ static int DetectPcreTxBodyChunksTest03(void) { int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; Flow f; TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n"; uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n"; uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n"; uint8_t httpbuf4[] = "Body one!!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n"; uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n"; uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */ memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("signature matched, but shouldn't have: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't alert: "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (5): "); goto end; } p->alerts.cnt = 0; r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { printf("sig 1 alerted (request 2, chunk 6): "); goto end; } p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 2))) { printf("signature 2 didn't match, but should have: "); goto end; } p->alerts.cnt = 0; HtpState *htp_state = f.alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } if (list_size(htp_state->connp->conn->transactions) != 2) { printf("The http app layer doesn't have 2 transactions, but it should: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); return result; } /** * \test flowvar capture on http buffer */ static int DetectPcreFlowvarCapture01(void) { int result = 0; uint8_t uabuf1[] = "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13"; uint32_t ualen1 = sizeof(uabuf1) - 1; /* minus the \0 */ uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "\r\n" "flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } DetectPcreData *pd = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match on p1 but should have: "); goto end; } FlowVar *fv = FlowVarGet(&f, pd->capidx); if (fv == NULL) { printf("no flowvar: "); goto end; } if (fv->data.fv_str.value_len != ualen1) { printf("%u != %u: ", fv->data.fv_str.value_len, ualen1); goto end; } if (memcmp(fv->data.fv_str.value, uabuf1, ualen1) != 0) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("buffer mismatch: "); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } /** * \test flowvar capture on http buffer, capture overwrite */ static int DetectPcreFlowvarCapture02(void) { int result = 0; uint8_t uabuf1[] = "Apache"; uint32_t ualen1 = sizeof(uabuf1) - 1; /* minus the \0 */ uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "\r\n" "flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:1; sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:3; sid:2;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } DetectPcreData *pd2 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; if (pd1->capidx != pd2->capidx) { printf("capidx mismatch, %u != %u: ", pd1->capidx, pd2->capidx); goto end; } SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match on p1 but should have: "); goto end; } FlowVar *fv = FlowVarGet(&f, pd1->capidx); if (fv == NULL) { printf("no flowvar: "); goto end; } if (fv->data.fv_str.value_len != ualen1) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("%u != %u: ", fv->data.fv_str.value_len, ualen1); goto end; } if (memcmp(fv->data.fv_str.value, uabuf1, ualen1) != 0) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("buffer mismatch: "); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } /** * \test flowvar capture on http buffer, capture overwrite + no matching sigs, so flowvars should not be set. */ static int DetectPcreFlowvarCapture03(void) { int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8\r\n" "Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Date: Tue, 22 Sep 2009 19:24:48 GMT\r\n" "Server: Apache\r\n" "\r\n" "flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:1; sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } DetectPcreData *pd1 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:3; sid:2;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { goto end; } DetectPcreData *pd2 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; if (pd1->capidx != pd2->capidx) { printf("capidx mismatch, %u != %u: ", pd1->capidx, pd2->capidx); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched on p1 but shouldn't have: "); goto end; } FlowVar *fv = FlowVarGet(&f, pd1->capidx); if (fv != NULL) { printf("flowvar, shouldn't have one: "); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectPcre */ void DetectPcreRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01, 1); UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02, 1); UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03, 1); UtRegisterTest("DetectPcreParseTest04", DetectPcreParseTest04, 1); UtRegisterTest("DetectPcreParseTest05", DetectPcreParseTest05, 1); UtRegisterTest("DetectPcreParseTest06", DetectPcreParseTest06, 1); UtRegisterTest("DetectPcreParseTest07", DetectPcreParseTest07, 1); UtRegisterTest("DetectPcreParseTest08", DetectPcreParseTest08, 1); UtRegisterTest("DetectPcreParseTest09", DetectPcreParseTest09, 1); UtRegisterTest("DetectPcreParseTest10", DetectPcreParseTest10, 1); UtRegisterTest("DetectPcreParseTest11", DetectPcreParseTest11, 1); UtRegisterTest("DetectPcreParseTest12", DetectPcreParseTest12, 1); UtRegisterTest("DetectPcreParseTest13", DetectPcreParseTest13, 1); UtRegisterTest("DetectPcreParseTest14", DetectPcreParseTest14, 1); UtRegisterTest("DetectPcreParseTest15", DetectPcreParseTest15, 1); UtRegisterTest("DetectPcreParseTest16", DetectPcreParseTest16, 1); UtRegisterTest("DetectPcreParseTest17", DetectPcreParseTest17, 1); UtRegisterTest("DetectPcreParseTest18", DetectPcreParseTest18, 1); UtRegisterTest("DetectPcreParseTest19", DetectPcreParseTest19, 1); UtRegisterTest("DetectPcreParseTest20", DetectPcreParseTest20, 1); UtRegisterTest("DetectPcreParseTest21", DetectPcreParseTest21, 1); UtRegisterTest("DetectPcreParseTest22", DetectPcreParseTest22, 1); UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23, 1); UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24, 1); UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25, 1); UtRegisterTest("DetectPcreTestSig01B2g -- pcre test", DetectPcreTestSig01B2g, 1); UtRegisterTest("DetectPcreTestSig01B3g -- pcre test", DetectPcreTestSig01B3g, 1); UtRegisterTest("DetectPcreTestSig01Wm -- pcre test", DetectPcreTestSig01Wm, 1); UtRegisterTest("DetectPcreTestSig02B2g -- pcre test", DetectPcreTestSig02B2g, 1); UtRegisterTest("DetectPcreTestSig02B3g -- pcre test", DetectPcreTestSig02B3g, 1); UtRegisterTest("DetectPcreTestSig02Wm -- pcre test", DetectPcreTestSig02Wm, 1); UtRegisterTest("DetectPcreTestSig03B2g -- negated pcre test", DetectPcreTestSig03B2g, 1); UtRegisterTest("DetectPcreTestSig03B3g -- negated pcre test", DetectPcreTestSig03B3g, 1); UtRegisterTest("DetectPcreTestSig03Wm -- negated pcre test", DetectPcreTestSig03Wm, 1); UtRegisterTest("DetectPcreModifPTest04 -- Modifier P", DetectPcreModifPTest04, 1); UtRegisterTest("DetectPcreModifPTest05 -- Modifier P fragmented", DetectPcreModifPTest05, 1); UtRegisterTest("DetectPcreTestSig06", DetectPcreTestSig06, 1); UtRegisterTest("DetectPcreTestSig07 -- anchored pcre", DetectPcreTestSig07, 1); UtRegisterTest("DetectPcreTestSig08 -- anchored pcre", DetectPcreTestSig08, 1); UtRegisterTest("DetectPcreTestSig09 -- Cookie modifier", DetectPcreTestSig09, 1); UtRegisterTest("DetectPcreTestSig10 -- negated Cookie modifier", DetectPcreTestSig10, 1); UtRegisterTest("DetectPcreTestSig11 -- Method modifier", DetectPcreTestSig11, 1); UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", DetectPcreTestSig12, 1); UtRegisterTest("DetectPcreTestSig13 -- Header modifier", DetectPcreTestSig13, 1); UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", DetectPcreTestSig14, 1); UtRegisterTest("DetectPcreTestSig15 -- relative Cookie modifier", DetectPcreTestSig15, 1); UtRegisterTest("DetectPcreTestSig16 -- relative Method modifier", DetectPcreTestSig16, 1); UtRegisterTest("DetectPcreTxBodyChunksTest01", DetectPcreTxBodyChunksTest01, 1); UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest02, 1); UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest03, 1); UtRegisterTest("DetectPcreFlowvarCapture01 -- capture for http_header", DetectPcreFlowvarCapture01, 1); UtRegisterTest("DetectPcreFlowvarCapture02 -- capture for http_header", DetectPcreFlowvarCapture02, 1); UtRegisterTest("DetectPcreFlowvarCapture03 -- capture for http_header", DetectPcreFlowvarCapture03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-path.h0000644000000000000000000000164612253546156013114 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #ifndef __UTIL_PATH_H__ #define __UTIL_PATH_H__ int PathIsAbsolute(const char *); int PathIsRelative(const char *); #endif /* __UTIL_PATH_H__ */ suricata-1.4.7/src/app-layer-ftp.c0000644000000000000000000003731012253546156013656 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * * App Layer Parser for FTP */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "flow-util.h" #include "detect-engine-state.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-ftp.h" #include "util-spm.h" #include "util-unittest.h" #include "util-debug.h" #include "util-memcmp.h" /** * \brief This function is called to determine and set which command is being * transfered to the ftp server * \param ftp_state the ftp state structure for the parser * \param input input line of the command * \param len of the command * * \retval 1 when the command is parsed, 0 otherwise */ static int FTPParseRequestCommand(void *ftp_state, uint8_t *input, uint32_t input_len) { SCEnter(); FtpState *fstate = (FtpState *)ftp_state; if (input_len >= 4) { if (SCMemcmpLowercase("port", input, 4) == 0) { fstate->command = FTP_COMMAND_PORT; } /* else { * Add the ftp commands you need here * } */ } return 1; } /** * \brief This function is called to retrieve the request line and parse it * \param ftp_state the ftp state structure for the parser * \param input input line of the command * \param input_len length of the request * \param output the resulting output * * \retval 1 when the command is parsed, 0 otherwise */ static int FTPParseRequestCommandLine(Flow *f, void *ftp_state, AppLayerParserState *pstate, uint8_t *input,uint32_t input_len, void *local_data, AppLayerParserResult *output) { SCEnter(); //PrintRawDataFp(stdout, input,input_len); FtpState *fstate = (FtpState *)ftp_state; uint16_t max_fields = 2; uint16_t u = 0; uint32_t offset = 0; if (pstate == NULL) return -1; for (u = pstate->parse_field; u < max_fields; u++) { switch(u) { case 0: /* REQUEST COMMAND */ { const uint8_t delim[] = { 0x20, }; int r = AlpParseFieldByDelimiter(output, pstate, FTP_FIELD_REQUEST_COMMAND, delim, sizeof(delim), input, input_len, &offset); if (r == 0) { pstate->parse_field = 0; return 0; } fstate->arg_offset = offset; FTPParseRequestCommand(ftp_state, input, input_len); break; } case 1: /* REQUEST COMMAND ARG */ { switch (fstate->command) { case FTP_COMMAND_PORT: /* We don't need to parse args, we are going to check * the ftpbounce condition directly from detect-ftpbounce */ if (fstate->port_line != NULL) SCFree(fstate->port_line); fstate->port_line = SCMalloc(input_len); if (fstate->port_line == NULL) return 0; fstate->port_line = memcpy(fstate->port_line, input, input_len); fstate->port_line_len = input_len; break; default: break; } /* end switch command specified args */ break; } } } pstate->parse_field = 0; return 1; } /** * \brief This function is called to retrieve a ftp request * \param ftp_state the ftp state structure for the parser * \param input input line of the command * \param input_len length of the request * \param output the resulting output * * \retval 1 when the command is parsed, 0 otherwise */ static int FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SCEnter(); /* PrintRawDataFp(stdout, input,input_len); */ uint32_t offset = 0; if (pstate == NULL) return -1; //PrintRawDataFp(stdout, pstate->store, pstate->store_len); const uint8_t delim[] = { 0x0D, 0x0A }; int r = AlpParseFieldByDelimiter(output, pstate, FTP_FIELD_REQUEST_LINE, delim, sizeof(delim), input, input_len, &offset); if (r == 0) { pstate->parse_field = 0; return 0; } if (pstate->store_len) PrintRawDataFp(stdout, pstate->store, pstate->store_len); pstate->parse_field = 0; return 1; } /** * \brief This function is called to retrieve a ftp response * \param ftp_state the ftp state structure for the parser * \param input input line of the command * \param input_len length of the request * \param output the resulting output * * \retval 1 when the command is parsed, 0 otherwise */ static int FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SCEnter(); //PrintRawDataFp(stdout, input,input_len); uint32_t offset = 0; FtpState *fstate = (FtpState *)ftp_state; if (pstate == NULL) return -1; const uint8_t delim[] = { 0x0D, 0x0A }; int r = AlpParseFieldByDelimiter(output, pstate, FTP_FIELD_RESPONSE_LINE, delim, sizeof(delim), input, input_len, &offset); if (r == 0) { pstate->parse_field = 0; return 0; } char rcode[5]; memcpy(rcode, input, 4); rcode[4] = '\0'; fstate->response_code = atoi(rcode); SCLogDebug("Response: %u\n", fstate->response_code); pstate->parse_field = 0; return 1; } #ifdef DEBUG static SCMutex ftp_state_mem_lock = PTHREAD_MUTEX_INITIALIZER; static uint64_t ftp_state_memuse = 0; static uint64_t ftp_state_memcnt = 0; #endif static void *FTPStateAlloc(void) { void *s = SCMalloc(sizeof(FtpState)); if (unlikely(s == NULL)) return NULL; memset(s, 0, sizeof(FtpState)); #ifdef DEBUG SCMutexLock(&ftp_state_mem_lock); ftp_state_memcnt++; ftp_state_memuse+=sizeof(FtpState); SCMutexUnlock(&ftp_state_mem_lock); #endif return s; } static void FTPStateFree(void *s) { FtpState *fstate = (FtpState *) s; if (fstate->port_line != NULL) SCFree(fstate->port_line); SCFree(s); #ifdef DEBUG SCMutexLock(&ftp_state_mem_lock); ftp_state_memcnt--; ftp_state_memuse-=sizeof(FtpState); SCMutexUnlock(&ftp_state_mem_lock); #endif } void RegisterFTPParsers(void) { char *proto_name = "ftp"; /** FTP */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_FTP, "USER ", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_FTP, "PASS ", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_FTP, "PORT ", 5, 0, STREAM_TOSERVER); AppLayerRegisterProto(proto_name, ALPROTO_FTP, STREAM_TOSERVER, FTPParseRequest); AppLayerRegisterProto(proto_name, ALPROTO_FTP, STREAM_TOCLIENT, FTPParseResponse); AppLayerRegisterParser("ftp.request_command_line", ALPROTO_FTP, FTP_FIELD_REQUEST_LINE, FTPParseRequestCommandLine, "ftp"); AppLayerRegisterStateFuncs(ALPROTO_FTP, FTPStateAlloc, FTPStateFree); } void FTPAtExitPrintStats(void) { #ifdef DEBUG SCMutexLock(&ftp_state_mem_lock); SCLogDebug("ftp_state_memcnt %"PRIu64", ftp_state_memuse %"PRIu64"", ftp_state_memcnt, ftp_state_memuse); SCMutexUnlock(&ftp_state_mem_lock); #endif } /* UNITTESTS */ #ifdef UNITTESTS /** \test Send a get request in one chunk. */ int FTPParserTest01(void) { int result = 1; Flow f; uint8_t ftpbuf[] = "PORT 192,168,1,1,0,80\r\n"; uint32_t ftplen = sizeof(ftpbuf) - 1; /* minus the \0 */ TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf, ftplen); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { SCLogDebug("no ftp state: "); result = 0; goto end; } if (ftp_state->command != FTP_COMMAND_PORT) { SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** \test Send a splitted get request. */ int FTPParserTest03(void) { int result = 1; Flow f; uint8_t ftpbuf1[] = "POR"; uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */ uint8_t ftpbuf2[] = "T 192,168,1"; uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */ uint8_t ftpbuf3[] = "1,1,10,20\r\n"; uint32_t ftplen3 = sizeof(ftpbuf3) - 1; /* minus the \0 */ TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { SCLogDebug("no ftp state: "); result = 0; goto end; } if (ftp_state->command != FTP_COMMAND_PORT) { SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); return result; } /** \test See how it deals with an incomplete request. */ int FTPParserTest06(void) { int result = 1; Flow f; uint8_t ftpbuf1[] = "PORT"; uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */ TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { SCLogDebug("no ftp state: "); result = 0; goto end; } if (ftp_state->command != FTP_COMMAND_UNKNOWN) { SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_UNKNOWN, ftp_state->command); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** \test See how it deals with an incomplete request in multiple chunks. */ int FTPParserTest07(void) { int result = 1; Flow f; uint8_t ftpbuf1[] = "PO"; uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */ uint8_t ftpbuf2[] = "RT\r\n"; uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */ TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { SCLogDebug("no ftp state: "); result = 0; goto end; } if (ftp_state->command != FTP_COMMAND_UNKNOWN) { SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_UNKNOWN, ftp_state->command); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** \test Test case where chunks are smaller than the delim length and the * last chunk is supposed to match the delim. */ int FTPParserTest10(void) { int result = 1; Flow f; uint8_t ftpbuf1[] = "PORT 1,2,3,4,5,6\r\n"; uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */ TcpSession ssn; int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < ftplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (ftplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, &f, ALPROTO_FTP, flags, &ftpbuf1[u], 1); if (r != 0) { SCLogDebug("toserver chunk %" PRIu32 " returned %" PRId32 ", expected 0: ", u, r); result = 0; goto end; } } FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { SCLogDebug("no ftp state: "); result = 0; goto end; } if (ftp_state->command != FTP_COMMAND_PORT) { SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } #endif /* UNITTESTS */ void FTPParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FTPParserTest01", FTPParserTest01, 1); UtRegisterTest("FTPParserTest03", FTPParserTest03, 1); UtRegisterTest("FTPParserTest06", FTPParserTest06, 1); UtRegisterTest("FTPParserTest07", FTPParserTest07, 1); UtRegisterTest("FTPParserTest10", FTPParserTest10, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-profiling-locks.h0000644000000000000000000000223212253546156015252 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_PROFILE_LOCKS_H__ #define __UTIL_PROFILE_LOCKS_H__ #ifdef PROFILING #define PROFILING_MAX_LOCKS 64 enum { LOCK_MUTEX, LOCK_SPIN, LOCK_RWW, /**< rwlock, writer */ LOCK_RWR, /**< rwlock, reader */ }; void SCProfilingAddPacketLocks(void *); int LockRecordInitHash(); void LockRecordFreeHash(); #endif /* PROFILING */ #endif /* __UTIL_PROFILE_LOCKS_H__ */ suricata-1.4.7/src/flow.c0000644000000000000000000010545112253546156012146 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Flow implementation. */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "conf.h" #include "threadvars.h" #include "tm-threads.h" #include "runmodes.h" #include "util-random.h" #include "util-time.h" #include "flow.h" #include "flow-queue.h" #include "flow-hash.h" #include "flow-util.h" #include "flow-var.h" #include "flow-private.h" #include "flow-timeout.h" #include "flow-manager.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-byte.h" #include "util-misc.h" #include "util-debug.h" #include "util-privs.h" #include "detect.h" #include "detect-engine-state.h" #include "stream.h" #include "app-layer-parser.h" #define FLOW_DEFAULT_EMERGENCY_RECOVERY 30 //#define FLOW_DEFAULT_HASHSIZE 262144 #define FLOW_DEFAULT_HASHSIZE 65536 //#define FLOW_DEFAULT_MEMCAP 128 * 1024 * 1024 /* 128 MB */ #define FLOW_DEFAULT_MEMCAP (32 * 1024 * 1024) /* 32 MB */ #define FLOW_DEFAULT_PREALLOC 10000 /** atomic int that is used when freeing a flow from the hash. In this * case we walk the hash to find a flow to free. This var records where * we left off in the hash. Without this only the top rows of the hash * are freed. This isn't just about fairness. Under severe presure, the * hash rows on top would be all freed and the time to find a flow to * free increased with every run. */ SC_ATOMIC_DECLARE(unsigned int, flow_prune_idx); /** atomic flags */ SC_ATOMIC_DECLARE(unsigned char, flow_flags); void FlowRegisterTests(void); void FlowInitFlowProto(); int FlowSetProtoTimeout(uint8_t , uint32_t ,uint32_t ,uint32_t); int FlowSetProtoEmergencyTimeout(uint8_t , uint32_t ,uint32_t ,uint32_t); int FlowSetProtoFreeFunc(uint8_t, void (*Free)(void *)); int FlowSetFlowStateFunc(uint8_t , int (*GetProtoState)(void *)); /* Run mode selected at suricata.c */ extern int run_mode; void FlowCleanupAppLayer(Flow *f) { if (f == NULL) return; AppLayerParserCleanupState(f); return; } /** \brief Make sure we have enough spare flows. * * Enforce the prealloc parameter, so keep at least prealloc flows in the * spare queue and free flows going over the limit. * * \retval 1 if the queue was properly updated (or if it already was in good shape) * \retval 0 otherwise. */ int FlowUpdateSpareFlows(void) { SCEnter(); uint32_t toalloc = 0, tofree = 0, len; FQLOCK_LOCK(&flow_spare_q); len = flow_spare_q.len; FQLOCK_UNLOCK(&flow_spare_q); if (len < flow_config.prealloc) { toalloc = flow_config.prealloc - len; uint32_t i; for (i = 0; i < toalloc; i++) { Flow *f = FlowAlloc(); if (f == NULL) return 0; FlowEnqueue(&flow_spare_q,f); } } else if (len > flow_config.prealloc) { tofree = len - flow_config.prealloc; uint32_t i; for (i = 0; i < tofree; i++) { /* FlowDequeue locks the queue */ Flow *f = FlowDequeue(&flow_spare_q); if (f == NULL) return 1; FlowFree(f); } } return 1; } /** \brief Set the IPOnly scanned flag for 'direction'. This function * handles the locking too. * \param f Flow to set the flag in * \param direction direction to set the flag in */ void FlowSetIPOnlyFlag(Flow *f, char direction) { FLOWLOCK_WRLOCK(f); direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) : (f->flags |= FLOW_TOCLIENT_IPONLY_SET); FLOWLOCK_UNLOCK(f); return; } /** \brief Set the IPOnly scanned flag for 'direction'. * * \param f Flow to set the flag in * \param direction direction to set the flag in */ void FlowSetIPOnlyFlagNoLock(Flow *f, char direction) { direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) : (f->flags |= FLOW_TOCLIENT_IPONLY_SET); return; } /** * \brief increase the use cnt of a flow * * \param f flow to decrease use cnt for */ void FlowIncrUsecnt(Flow *f) { if (f == NULL) return; (void) SC_ATOMIC_ADD(f->use_cnt, 1); return; } /** * \brief decrease the use cnt of a flow * * \param f flow to decrease use cnt for */ void FlowDecrUsecnt(Flow *f) { if (f == NULL) return; (void) SC_ATOMIC_SUB(f->use_cnt, 1); return; } /** * \brief determine the direction of the packet compared to the flow * \retval 0 to_server * \retval 1 to_client */ int FlowGetPacketDirection(Flow *f, Packet *p) { if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { if (!(CMP_PORT(p->sp,p->dp))) { /* update flags and counters */ if (CMP_PORT(f->sp,p->sp)) { return TOSERVER; } else { return TOCLIENT; } } else { if (CMP_ADDR(&f->src,&p->src)) { return TOSERVER; } else { return TOCLIENT; } } } else if (p->proto == IPPROTO_ICMP || p->proto == IPPROTO_ICMPV6) { if (CMP_ADDR(&f->src,&p->src)) { return TOSERVER; } else { return TOCLIENT; } } /* default to toserver */ return TOSERVER; } /** * \brief Check to update "seen" flags * * \param p packet * * \retval 1 true * \retval 0 false */ static inline int FlowUpdateSeenFlag(Packet *p) { if (PKT_IS_ICMPV4(p)) { if (ICMPV4_IS_ERROR_MSG(p)) { return 0; } } return 1; } /** \brief Entry point for packet flow handling * * This is called for every packet. * * \param tv threadvars * \param p packet to handle flow for */ void FlowHandlePacket (ThreadVars *tv, Packet *p) { /* Get this packet's flow from the hash. FlowHandlePacket() will setup * a new flow if nescesary. If we get NULL, we're out of flow memory. * The returned flow is locked. */ Flow *f = FlowGetFlowFromHash(p); if (f == NULL) return; /* update the last seen timestamp of this flow */ f->lastts_sec = p->ts.tv_sec; /* update flags and counters */ if (FlowGetPacketDirection(f,p) == TOSERVER) { if (FlowUpdateSeenFlag(p)) { f->flags |= FLOW_TO_DST_SEEN; } #ifdef DEBUG f->todstpktcnt++; #endif p->flowflags |= FLOW_PKT_TOSERVER; } else { if (FlowUpdateSeenFlag(p)) { f->flags |= FLOW_TO_SRC_SEEN; } #ifdef DEBUG f->tosrcpktcnt++; #endif p->flowflags |= FLOW_PKT_TOCLIENT; } #ifdef DEBUG f->bytecnt += GET_PKT_LEN(p); #endif if ((f->flags & FLOW_TO_DST_SEEN) && (f->flags & FLOW_TO_SRC_SEEN)) { SCLogDebug("pkt %p FLOW_PKT_ESTABLISHED", p); p->flowflags |= FLOW_PKT_ESTABLISHED; } /*set the detection bypass flags*/ if (f->flags & FLOW_NOPACKET_INSPECTION) { SCLogDebug("setting FLOW_NOPACKET_INSPECTION flag on flow %p", f); DecodeSetNoPacketInspectionFlag(p); } if (f->flags & FLOW_NOPAYLOAD_INSPECTION) { SCLogDebug("setting FLOW_NOPAYLOAD_INSPECTION flag on flow %p", f); DecodeSetNoPayloadInspectionFlag(p); } FLOWLOCK_UNLOCK(f); /* set the flow in the packet */ p->flags |= PKT_HAS_FLOW; return; } /** \brief initialize the configuration * \warning Not thread safe */ void FlowInitConfig(char quiet) { SCLogDebug("initializing flow engine..."); memset(&flow_config, 0, sizeof(flow_config)); SC_ATOMIC_INIT(flow_flags); SC_ATOMIC_INIT(flow_memuse); SC_ATOMIC_INIT(flow_prune_idx); FlowQueueInit(&flow_spare_q); unsigned int seed = RandomTimePreseed(); /* set defaults */ flow_config.hash_rand = (int)( FLOW_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); flow_config.hash_size = FLOW_DEFAULT_HASHSIZE; flow_config.memcap = FLOW_DEFAULT_MEMCAP; flow_config.prealloc = FLOW_DEFAULT_PREALLOC; /* If we have specific config, overwrite the defaults with them, * otherwise, leave the default values */ intmax_t val = 0; if (ConfGetInt("flow.emergency-recovery", &val) == 1) { if (val <= 100 && val >= 1) { flow_config.emergency_recovery = (uint8_t)val; } else { SCLogError(SC_ERR_INVALID_VALUE, "flow.emergency-recovery must be in the range of 1 and 100 (as percentage)"); flow_config.emergency_recovery = FLOW_DEFAULT_EMERGENCY_RECOVERY; } } else { SCLogDebug("flow.emergency-recovery, using default value"); flow_config.emergency_recovery = FLOW_DEFAULT_EMERGENCY_RECOVERY; } /* Check if we have memcap and hash_size defined at config */ char *conf_val; uint32_t configval = 0; /** set config values for memcap, prealloc and hash_size */ if ((ConfGet("flow.memcap", &conf_val)) == 1) { if (ParseSizeStringU64(conf_val, &flow_config.memcap) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing flow.memcap " "from conf file - %s. Killing engine", conf_val); exit(EXIT_FAILURE); } } if ((ConfGet("flow.hash-size", &conf_val)) == 1) { if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { flow_config.hash_size = configval; } } if ((ConfGet("flow.prealloc", &conf_val)) == 1) { if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { flow_config.prealloc = configval; } } SCLogDebug("Flow config from suricata.yaml: memcap: %"PRIu64", hash-size: " "%"PRIu32", prealloc: %"PRIu32, flow_config.memcap, flow_config.hash_size, flow_config.prealloc); /* alloc hash memory */ uint64_t hash_size = flow_config.hash_size * sizeof(FlowBucket); if (!(FLOW_CHECK_MEMCAP(hash_size))) { SCLogError(SC_ERR_FLOW_INIT, "allocating flow hash failed: " "max flow memcap is smaller than projected hash size. " "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate " "total hash size by multiplying \"flow.hash-size\" with %"PRIuMAX", " "which is the hash bucket size.", flow_config.memcap, hash_size, (uintmax_t)sizeof(FlowBucket)); exit(EXIT_FAILURE); } flow_hash = SCCalloc(flow_config.hash_size, sizeof(FlowBucket)); if (unlikely(flow_hash == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in FlowInitConfig. Exiting..."); exit(EXIT_FAILURE); } memset(flow_hash, 0, flow_config.hash_size * sizeof(FlowBucket)); uint32_t i = 0; for (i = 0; i < flow_config.hash_size; i++) { FBLOCK_INIT(&flow_hash[i]); } (void) SC_ATOMIC_ADD(flow_memuse, (flow_config.hash_size * sizeof(FlowBucket))); if (quiet == FALSE) { SCLogInfo("allocated %llu bytes of memory for the flow hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(flow_memuse), flow_config.hash_size, (uintmax_t)sizeof(FlowBucket)); } /* pre allocate flows */ for (i = 0; i < flow_config.prealloc; i++) { if (!(FLOW_CHECK_MEMCAP(sizeof(Flow)))) { SCLogError(SC_ERR_FLOW_INIT, "preallocating flows failed: " "max flow memcap reached. Memcap %"PRIu64", " "Memuse %"PRIu64".", flow_config.memcap, ((uint64_t)SC_ATOMIC_GET(flow_memuse) + (uint64_t)sizeof(Flow))); exit(EXIT_FAILURE); } Flow *f = FlowAlloc(); if (f == NULL) { SCLogError(SC_ERR_FLOW_INIT, "preallocating flow failed: %s", strerror(errno)); exit(EXIT_FAILURE); } FlowEnqueue(&flow_spare_q,f); } if (quiet == FALSE) { SCLogInfo("preallocated %" PRIu32 " flows of size %" PRIuMAX "", flow_spare_q.len, (uintmax_t)sizeof(Flow)); SCLogInfo("flow memory usage: %llu bytes, maximum: %"PRIu64, SC_ATOMIC_GET(flow_memuse), flow_config.memcap); } FlowInitFlowProto(); return; } /** \brief print some flow stats * \warning Not thread safe */ static void FlowPrintStats (void) { #ifdef FLOWBITS_STATS SCLogInfo("flowbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", flowbits_added, flowbits_removed, flowbits_memuse_max); #endif /* FLOWBITS_STATS */ return; } /** \brief shutdown the flow engine * \warning Not thread safe */ void FlowShutdown(void) { Flow *f; uint32_t u; FlowPrintStats(); /* free spare queue */ while((f = FlowDequeue(&flow_spare_q))) { FlowFree(f); } /* clear and free the hash */ if (flow_hash != NULL) { /* clean up flow mutexes */ for (u = 0; u < flow_config.hash_size; u++) { Flow *f = flow_hash[u].head; while (f) { #ifdef DEBUG_VALIDATION BUG_ON(SC_ATOMIC_GET(f->use_cnt) != 0); #endif Flow *n = f->hnext; uint8_t proto_map = FlowGetProtoMapping(f->proto); FlowClearMemory(f, proto_map); FlowFree(f); f = n; } FBLOCK_DESTROY(&flow_hash[u]); } SCFree(flow_hash); flow_hash = NULL; } (void) SC_ATOMIC_SUB(flow_memuse, flow_config.hash_size * sizeof(FlowBucket)); FlowQueueDestroy(&flow_spare_q); SC_ATOMIC_DESTROY(flow_prune_idx); SC_ATOMIC_DESTROY(flow_memuse); SC_ATOMIC_DESTROY(flow_flags); return; } /** * \brief Function to set the default timeout, free function and flow state * function for all supported flow_proto. */ void FlowInitFlowProto(void) { /*Default*/ flow_proto[FLOW_PROTO_DEFAULT].new_timeout = FLOW_DEFAULT_NEW_TIMEOUT; flow_proto[FLOW_PROTO_DEFAULT].est_timeout = FLOW_DEFAULT_EST_TIMEOUT; flow_proto[FLOW_PROTO_DEFAULT].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_DEFAULT].emerg_new_timeout = FLOW_DEFAULT_EMERG_NEW_TIMEOUT; flow_proto[FLOW_PROTO_DEFAULT].emerg_est_timeout = FLOW_DEFAULT_EMERG_EST_TIMEOUT; flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout = FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_DEFAULT].Freefunc = NULL; flow_proto[FLOW_PROTO_DEFAULT].GetProtoState = NULL; /*TCP*/ flow_proto[FLOW_PROTO_TCP].new_timeout = FLOW_IPPROTO_TCP_NEW_TIMEOUT; flow_proto[FLOW_PROTO_TCP].est_timeout = FLOW_IPPROTO_TCP_EST_TIMEOUT; flow_proto[FLOW_PROTO_TCP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_TCP].emerg_new_timeout = FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT; flow_proto[FLOW_PROTO_TCP].emerg_est_timeout = FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT; flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout = FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_TCP].Freefunc = NULL; flow_proto[FLOW_PROTO_TCP].GetProtoState = NULL; /*UDP*/ flow_proto[FLOW_PROTO_UDP].new_timeout = FLOW_IPPROTO_UDP_NEW_TIMEOUT; flow_proto[FLOW_PROTO_UDP].est_timeout = FLOW_IPPROTO_UDP_EST_TIMEOUT; flow_proto[FLOW_PROTO_UDP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_UDP].emerg_new_timeout = FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT; flow_proto[FLOW_PROTO_UDP].emerg_est_timeout = FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT; flow_proto[FLOW_PROTO_UDP].emerg_closed_timeout = FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_UDP].Freefunc = NULL; flow_proto[FLOW_PROTO_UDP].GetProtoState = NULL; /*ICMP*/ flow_proto[FLOW_PROTO_ICMP].new_timeout = FLOW_IPPROTO_ICMP_NEW_TIMEOUT; flow_proto[FLOW_PROTO_ICMP].est_timeout = FLOW_IPPROTO_ICMP_EST_TIMEOUT; flow_proto[FLOW_PROTO_ICMP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_ICMP].emerg_new_timeout = FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT; flow_proto[FLOW_PROTO_ICMP].emerg_est_timeout = FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT; flow_proto[FLOW_PROTO_ICMP].emerg_closed_timeout = FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; flow_proto[FLOW_PROTO_ICMP].Freefunc = NULL; flow_proto[FLOW_PROTO_ICMP].GetProtoState = NULL; /* Let's see if we have custom timeouts defined from config */ const char *new = NULL; const char *established = NULL; const char *closed = NULL; const char *emergency_new = NULL; const char *emergency_established = NULL; const char *emergency_closed = NULL; ConfNode *flow_timeouts = ConfGetNode("flow-timeouts"); if (flow_timeouts != NULL) { ConfNode *proto = NULL; uint32_t configval = 0; /* Defaults. */ proto = ConfNodeLookupChild(flow_timeouts, "default"); if (proto != NULL) { new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); closed = ConfNodeLookupChildValue(proto, "closed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); emergency_closed = ConfNodeLookupChildValue(proto, "emergency-closed"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { flow_proto[FLOW_PROTO_DEFAULT].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { flow_proto[FLOW_PROTO_DEFAULT].est_timeout = configval; } if (closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(closed), closed) > 0) { flow_proto[FLOW_PROTO_DEFAULT].closed_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { flow_proto[FLOW_PROTO_DEFAULT].emerg_new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { flow_proto[FLOW_PROTO_DEFAULT].emerg_est_timeout= configval; } if (emergency_closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_closed), emergency_closed) > 0) { flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout = configval; } } /* TCP. */ proto = ConfNodeLookupChild(flow_timeouts, "tcp"); if (proto != NULL) { new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); closed = ConfNodeLookupChildValue(proto, "closed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); emergency_closed = ConfNodeLookupChildValue(proto, "emergency-closed"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { flow_proto[FLOW_PROTO_TCP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { flow_proto[FLOW_PROTO_TCP].est_timeout = configval; } if (closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(closed), closed) > 0) { flow_proto[FLOW_PROTO_TCP].closed_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { flow_proto[FLOW_PROTO_TCP].emerg_new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { flow_proto[FLOW_PROTO_TCP].emerg_est_timeout = configval; } if (emergency_closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_closed), emergency_closed) > 0) { flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout = configval; } } /* UDP. */ proto = ConfNodeLookupChild(flow_timeouts, "udp"); if (proto != NULL) { new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { flow_proto[FLOW_PROTO_UDP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { flow_proto[FLOW_PROTO_UDP].est_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { flow_proto[FLOW_PROTO_UDP].emerg_new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { flow_proto[FLOW_PROTO_UDP].emerg_est_timeout = configval; } } /* ICMP. */ proto = ConfNodeLookupChild(flow_timeouts, "icmp"); if (proto != NULL) { new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { flow_proto[FLOW_PROTO_ICMP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { flow_proto[FLOW_PROTO_ICMP].est_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { flow_proto[FLOW_PROTO_ICMP].emerg_new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { flow_proto[FLOW_PROTO_ICMP].emerg_est_timeout = configval; } } } return; } /** * \brief Function clear the flow memory before queueing it to spare flow * queue. * * \param f pointer to the flow needed to be cleared. * \param proto_map mapped value of the protocol to FLOW_PROTO's. */ int FlowClearMemory(Flow* f, uint8_t proto_map) { SCEnter(); /* call the protocol specific free function if we have one */ if (flow_proto[proto_map].Freefunc != NULL) { flow_proto[proto_map].Freefunc(f->protoctx); } FLOW_RECYCLE(f); SCReturnInt(1); } /** * \brief Function to set the function to get protocol specific flow state. * * \param proto protocol of which function is needed to be set. * \param Free Function pointer which will be called to free the protocol * specific memory. */ int FlowSetProtoFreeFunc (uint8_t proto, void (*Free)(void *)) { uint8_t proto_map; proto_map = FlowGetProtoMapping(proto); flow_proto[proto_map].Freefunc = Free; return 1; } /** * \brief Function to set the function to get protocol specific flow state. * * \param proto protocol of which function is needed to be set. * \param GetFlowState Function pointer which will be called to get state. */ int FlowSetFlowStateFunc (uint8_t proto, int (*GetProtoState)(void *)) { uint8_t proto_map; proto_map = FlowGetProtoMapping(proto); flow_proto[proto_map].GetProtoState = GetProtoState; return 1; } /** * \brief Function to set the timeout values for the specified protocol. * * \param proto protocol of which timeout value is needed to be set. * \param new_timeout timeout value for the new flows. * \param est_timeout timeout value for the established flows. * \param closed_timeout timeout value for the closed flows. */ int FlowSetProtoTimeout(uint8_t proto, uint32_t new_timeout, uint32_t est_timeout, uint32_t closed_timeout) { uint8_t proto_map; proto_map = FlowGetProtoMapping(proto); flow_proto[proto_map].new_timeout = new_timeout; flow_proto[proto_map].est_timeout = est_timeout; flow_proto[proto_map].closed_timeout = closed_timeout; return 1; } /** * \brief Function to set the emergency timeout values for the specified * protocol. * * \param proto protocol of which timeout value is needed to be set. * \param emerg_new_timeout timeout value for the new flows. * \param emerg_est_timeout timeout value for the established flows. * \param emerg_closed_timeout timeout value for the closed flows. */ int FlowSetProtoEmergencyTimeout(uint8_t proto, uint32_t emerg_new_timeout, uint32_t emerg_est_timeout, uint32_t emerg_closed_timeout) { uint8_t proto_map; proto_map = FlowGetProtoMapping(proto); flow_proto[proto_map].emerg_new_timeout = emerg_new_timeout; flow_proto[proto_map].emerg_est_timeout = emerg_est_timeout; flow_proto[proto_map].emerg_closed_timeout = emerg_closed_timeout; return 1; } /************************************Unittests*******************************/ #ifdef UNITTESTS #include "stream-tcp-private.h" #include "threads.h" /** * \test Test the setting of the per protocol timeouts. * * \retval On success it returns 1 and on failure 0. */ static int FlowTest01 (void) { uint8_t proto_map; FlowInitFlowProto(); proto_map = FlowGetProtoMapping(IPPROTO_TCP); if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_TCP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_TCP_EST_TIMEOUT) && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT)){ printf ("failed in setting TCP flow timeout"); return 0; } proto_map = FlowGetProtoMapping(IPPROTO_UDP); if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_UDP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_UDP_EST_TIMEOUT) && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT)){ printf ("failed in setting UDP flow timeout"); return 0; } proto_map = FlowGetProtoMapping(IPPROTO_ICMP); if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_ICMP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_ICMP_EST_TIMEOUT) && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT)){ printf ("failed in setting ICMP flow timeout"); return 0; } proto_map = FlowGetProtoMapping(IPPROTO_DCCP); if ((flow_proto[proto_map].new_timeout != FLOW_DEFAULT_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_DEFAULT_EST_TIMEOUT) && (flow_proto[proto_map].emerg_new_timeout != FLOW_DEFAULT_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_DEFAULT_EMERG_EST_TIMEOUT)){ printf ("failed in setting default flow timeout"); return 0; } return 1; } /*Test function for the unit test FlowTest02*/ void test(void *f){} /** * \test Test the setting of the per protocol free function to free the * protocol specific memory. * * \retval On success it returns 1 and on failure 0. */ static int FlowTest02 (void) { FlowSetProtoFreeFunc(IPPROTO_DCCP, test); FlowSetProtoFreeFunc(IPPROTO_TCP, test); FlowSetProtoFreeFunc(IPPROTO_UDP, test); FlowSetProtoFreeFunc(IPPROTO_ICMP, test); if (flow_proto[FLOW_PROTO_DEFAULT].Freefunc != test) { printf("Failed in setting default free function\n"); return 0; } if (flow_proto[FLOW_PROTO_TCP].Freefunc != test) { printf("Failed in setting TCP free function\n"); return 0; } if (flow_proto[FLOW_PROTO_UDP].Freefunc != test) { printf("Failed in setting UDP free function\n"); return 0; } if (flow_proto[FLOW_PROTO_ICMP].Freefunc != test) { printf("Failed in setting ICMP free function\n"); return 0; } return 1; } /** * \test Test flow allocations when it reach memcap * * * \retval On success it returns 1 and on failure 0. */ static int FlowTest07 (void) { int result = 0; FlowInitConfig(FLOW_QUIET); FlowConfig backup; memcpy(&backup, &flow_config, sizeof(FlowConfig)); uint32_t ini = 0; uint32_t end = flow_spare_q.len; flow_config.memcap = 10000; flow_config.prealloc = 100; /* Let's get the flow_spare_q empty */ UTHBuildPacketOfFlows(ini, end, 0); /* And now let's try to reach the memcap val */ while (FLOW_CHECK_MEMCAP(sizeof(Flow))) { ini = end + 1; end = end + 2; UTHBuildPacketOfFlows(ini, end, 0); } /* should time out normal */ TimeSetIncrementTime(2000); ini = end + 1; end = end + 2;; UTHBuildPacketOfFlows(ini, end, 0); /* This means that the engine entered emerg mode: should happen as easy * with flow mgr activated */ if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) result = 1; memcpy(&flow_config, &backup, sizeof(FlowConfig)); FlowShutdown(); return result; } /** * \test Test flow allocations when it reach memcap * * * \retval On success it returns 1 and on failure 0. */ static int FlowTest08 (void) { int result = 0; FlowInitConfig(FLOW_QUIET); FlowConfig backup; memcpy(&backup, &flow_config, sizeof(FlowConfig)); uint32_t ini = 0; uint32_t end = flow_spare_q.len; flow_config.memcap = 10000; flow_config.prealloc = 100; /* Let's get the flow_spare_q empty */ UTHBuildPacketOfFlows(ini, end, 0); /* And now let's try to reach the memcap val */ while (FLOW_CHECK_MEMCAP(sizeof(Flow))) { ini = end + 1; end = end + 2; UTHBuildPacketOfFlows(ini, end, 0); } /* By default we use 30 for timing out new flows. This means * that the Emergency mode should be set */ TimeSetIncrementTime(20); ini = end + 1; end = end + 2; UTHBuildPacketOfFlows(ini, end, 0); /* This means that the engine released 5 flows by emergency timeout */ if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) result = 1; memcpy(&flow_config, &backup, sizeof(FlowConfig)); FlowShutdown(); return result; } /** * \test Test flow allocations when it reach memcap * * * \retval On success it returns 1 and on failure 0. */ static int FlowTest09 (void) { int result = 0; FlowInitConfig(FLOW_QUIET); FlowConfig backup; memcpy(&backup, &flow_config, sizeof(FlowConfig)); uint32_t ini = 0; uint32_t end = flow_spare_q.len; flow_config.memcap = 10000; flow_config.prealloc = 100; /* Let's get the flow_spare_q empty */ UTHBuildPacketOfFlows(ini, end, 0); /* And now let's try to reach the memcap val */ while (FLOW_CHECK_MEMCAP(sizeof(Flow))) { ini = end + 1; end = end + 2; UTHBuildPacketOfFlows(ini, end, 0); } /* No timeout will work */ TimeSetIncrementTime(5); ini = end + 1; end = end + 2; UTHBuildPacketOfFlows(ini, end, 0); /* engine in emerg mode */ if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) result = 1; memcpy(&flow_config, &backup, sizeof(FlowConfig)); FlowShutdown(); return result; } #endif /* UNITTESTS */ /** * \brief Function to register the Flow Unitests. */ void FlowRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("FlowTest01 -- Protocol Specific Timeouts", FlowTest01, 1); UtRegisterTest("FlowTest02 -- Setting Protocol Specific Free Function", FlowTest02, 1); UtRegisterTest("FlowTest07 -- Test flow Allocations when it reach memcap", FlowTest07, 1); UtRegisterTest("FlowTest08 -- Test flow Allocations when it reach memcap", FlowTest08, 1); UtRegisterTest("FlowTest09 -- Test flow Allocations when it reach memcap", FlowTest09, 1); FlowMgrRegisterTests(); #endif /* UNITTESTS */ } suricata-1.4.7/src/source-erf-dag.c0000644000000000000000000004665312253546156014012 00000000000000/* Copyright (C) 2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited. * \author Jason MacLulich * * Support for reading ERF records from a DAG card. * * Only ethernet supported at this time. */ #include "suricata-common.h" #include "suricata.h" #include "tm-threads.h" #include "util-privs.h" #include "tmqh-packetpool.h" #ifndef HAVE_DAG TmEcode NoErfDagSupportExit(ThreadVars *, void *, void **); void TmModuleReceiveErfDagRegister (void) { tmm_modules[TMM_RECEIVEERFDAG].name = "ReceiveErfDag"; tmm_modules[TMM_RECEIVEERFDAG].ThreadInit = NoErfDagSupportExit; tmm_modules[TMM_RECEIVEERFDAG].Func = NULL; tmm_modules[TMM_RECEIVEERFDAG].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVEERFDAG].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEERFDAG].RegisterTests = NULL; tmm_modules[TMM_RECEIVEERFDAG].cap_flags = SC_CAP_NET_ADMIN; tmm_modules[TMM_RECEIVEERFDAG].flags = TM_FLAG_RECEIVE_TM; } void TmModuleDecodeErfDagRegister (void) { tmm_modules[TMM_DECODEERFDAG].name = "DecodeErfDag"; tmm_modules[TMM_DECODEERFDAG].ThreadInit = NoErfDagSupportExit; tmm_modules[TMM_DECODEERFDAG].Func = NULL; tmm_modules[TMM_DECODEERFDAG].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEERFDAG].ThreadDeinit = NULL; tmm_modules[TMM_DECODEERFDAG].RegisterTests = NULL; tmm_modules[TMM_DECODEERFDAG].cap_flags = 0; tmm_modules[TMM_DECODEERFDAG].flags = TM_FLAG_DECODE_TM; } TmEcode NoErfDagSupportExit(ThreadVars *tv, void *initdata, void **data) { SCLogError(SC_ERR_DAG_NOSUPPORT, "Error creating thread %s: you do not have support for DAG cards " "enabled please recompile with --enable-dag", tv->name); exit(EXIT_FAILURE); } #else /* Implied we do have DAG support */ #include "source-erf-dag.h" #include extern int max_pending_packets; extern uint8_t suricata_ctl_flags; typedef struct ErfDagThreadVars_ { ThreadVars *tv; TmSlot *slot; int dagfd; int dagstream; char dagname[DAGNAME_BUFSIZE]; struct timeval maxwait, poll; /* Could possibly be made static */ uint64_t bytes; uint16_t packets; uint16_t drops; /* Current location in the DAG stream input buffer. */ uint8_t *top; uint8_t *btm; } ErfDagThreadVars; static inline TmEcode ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read); static inline TmEcode ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec); TmEcode ReceiveErfDagLoop(ThreadVars *, void *data, void *slot); TmEcode ReceiveErfDagThreadInit(ThreadVars *, void *, void **); void ReceiveErfDagThreadExitStats(ThreadVars *, void *); TmEcode ReceiveErfDagThreadDeinit(ThreadVars *, void *); TmEcode DecodeErfDagThreadInit(ThreadVars *, void *, void **); TmEcode DecodeErfDag(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); void ReceiveErfDagCloseStream(int dagfd, int stream); /** * \brief Register the ERF file receiver (reader) module. */ void TmModuleReceiveErfDagRegister(void) { tmm_modules[TMM_RECEIVEERFDAG].name = "ReceiveErfDag"; tmm_modules[TMM_RECEIVEERFDAG].ThreadInit = ReceiveErfDagThreadInit; tmm_modules[TMM_RECEIVEERFDAG].Func = NULL; tmm_modules[TMM_RECEIVEERFDAG].PktAcqLoop = ReceiveErfDagLoop; tmm_modules[TMM_RECEIVEERFDAG].ThreadExitPrintStats = ReceiveErfDagThreadExitStats; tmm_modules[TMM_RECEIVEERFDAG].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEERFDAG].RegisterTests = NULL; tmm_modules[TMM_RECEIVEERFDAG].cap_flags = 0; tmm_modules[TMM_RECEIVEERFDAG].flags = TM_FLAG_RECEIVE_TM; } /** * \brief Register the ERF file decoder module. */ void TmModuleDecodeErfDagRegister(void) { tmm_modules[TMM_DECODEERFDAG].name = "DecodeErfDag"; tmm_modules[TMM_DECODEERFDAG].ThreadInit = DecodeErfDagThreadInit; tmm_modules[TMM_DECODEERFDAG].Func = DecodeErfDag; tmm_modules[TMM_DECODEERFDAG].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEERFDAG].ThreadDeinit = NULL; tmm_modules[TMM_DECODEERFDAG].RegisterTests = NULL; tmm_modules[TMM_DECODEERFDAG].cap_flags = 0; tmm_modules[TMM_DECODEERFDAG].flags = TM_FLAG_DECODE_TM; } /** * \brief Initialize the ERF receiver thread, generate a single * ErfDagThreadVar structure for each thread, this will * contain a DAG file descriptor which is read when the * thread executes. * * \param tv Thread variable to ThreadVars * \param initdata Initial data to the interface passed from the user, * this is processed by the user. * * We assume that we have only a single name for the DAG * interface. * * \param data data pointer gets populated with * */ TmEcode ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); int stream_count = 0; if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Error: No DAG interface provided."); SCReturnInt(TM_ECODE_FAILED); } ErfDagThreadVars *ewtn = SCMalloc(sizeof(ErfDagThreadVars)); if (unlikely(ewtn == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for ERF DAG thread vars."); exit(EXIT_FAILURE); } memset(ewtn, 0, sizeof(*ewtn)); /* dag_parse_name will return a DAG device name and stream number * to open for this thread. */ if (dag_parse_name(initdata, ewtn->dagname, DAGNAME_BUFSIZE, &ewtn->dagstream) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to parse DAG interface: %s", (char*)initdata); SCFree(ewtn); exit(EXIT_FAILURE); } SCLogInfo("Opening DAG: %s on stream: %d for processing", ewtn->dagname, ewtn->dagstream); if ((ewtn->dagfd = dag_open(ewtn->dagname)) < 0) { SCLogError(SC_ERR_ERF_DAG_OPEN_FAILED, "Failed to open DAG: %s", ewtn->dagname); SCFree(ewtn); SCReturnInt(TM_ECODE_FAILED); } /* Check to make sure the card has enough available streams to * support reading from the one specified. */ if ((stream_count = dag_rx_get_stream_count(ewtn->dagfd)) < 0) { SCLogError(SC_ERR_ERF_DAG_OPEN_FAILED, "Failed to open stream: %d, DAG: %s, could not query stream count", ewtn->dagstream, ewtn->dagname); SCFree(ewtn); SCReturnInt(TM_ECODE_FAILED); } /* Check to make sure we have enough rx streams to open the stream * the user is asking for. */ if (ewtn->dagstream > stream_count*2) { SCLogError(SC_ERR_ERF_DAG_OPEN_FAILED, "Failed to open stream: %d, DAG: %s, insufficient streams: %d", ewtn->dagstream, ewtn->dagname, stream_count); SCFree(ewtn); SCReturnInt(TM_ECODE_FAILED); } /* If we are transmitting into a soft DAG card then set the stream * to act in reverse mode. */ if (0 != (ewtn->dagstream & 0x01)) { /* Setting reverse mode for using with soft dag from daemon side */ if(dag_set_mode(ewtn->dagfd, ewtn->dagstream, DAG_REVERSE_MODE)) { SCLogError(SC_ERR_ERF_DAG_STREAM_OPEN_FAILED, "Failed to set mode to DAG_REVERSE_MODE on stream: %d, DAG: %s", ewtn->dagstream, ewtn->dagname); SCFree(ewtn); SCReturnInt(TM_ECODE_FAILED); } } if (dag_attach_stream(ewtn->dagfd, ewtn->dagstream, 0, 0) < 0) { SCLogError(SC_ERR_ERF_DAG_STREAM_OPEN_FAILED, "Failed to open DAG stream: %d, DAG: %s", ewtn->dagstream, ewtn->dagname); SCFree(ewtn); SCReturnInt(TM_ECODE_FAILED); } if (dag_start_stream(ewtn->dagfd, ewtn->dagstream) < 0) { SCLogError(SC_ERR_ERF_DAG_STREAM_START_FAILED, "Failed to start DAG stream: %d, DAG: %s", ewtn->dagstream, ewtn->dagname); SCFree(ewtn); SCReturnInt(TM_ECODE_FAILED); } SCLogInfo("Attached and started stream: %d on DAG: %s", ewtn->dagstream, ewtn->dagname); /* * Initialise DAG Polling parameters. */ timerclear(&ewtn->maxwait); ewtn->maxwait.tv_usec = 20 * 1000; /* 20ms timeout */ timerclear(&ewtn->poll); ewtn->poll.tv_usec = 1 * 1000; /* 1ms poll interval */ /* 32kB minimum data to return -- we still restrict the number of * pkts that are processed to a maximum of dag_max_read_packets. */ if (dag_set_stream_poll(ewtn->dagfd, ewtn->dagstream, 32*1024, &(ewtn->maxwait), &(ewtn->poll)) < 0) { SCLogError(SC_ERR_ERF_DAG_STREAM_SET_FAILED, "Failed to set poll parameters for stream: %d, DAG: %s", ewtn->dagstream, ewtn->dagname); SCFree(ewtn); SCReturnInt(TM_ECODE_FAILED); } ewtn->packets = SCPerfTVRegisterCounter("capture.dag_packets", tv, SC_PERF_TYPE_UINT64, "NULL"); ewtn->drops = SCPerfTVRegisterCounter("capture.dag_drops", tv, SC_PERF_TYPE_UINT64, "NULL"); ewtn->tv = tv; *data = (void *)ewtn; SCLogInfo("Starting processing packets from stream: %d on DAG: %s", ewtn->dagstream, ewtn->dagname); SCReturnInt(TM_ECODE_OK); } /** * \brief Receives packets from a DAG interface. * * \param tv pointer to ThreadVars * \param data pointer to ErfDagThreadVars * \param slot slot containing task information * * \retval TM_ECODE_OK on success * \retval TM_ECODE_FAILED on failure */ TmEcode ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); ErfDagThreadVars *dtv = (ErfDagThreadVars *)data; uint32_t diff = 0; int err; uint8_t *top = NULL; uint32_t pkts_read = 0; TmSlot *s = (TmSlot *)slot; dtv->slot = s->slot_next; while (1) { if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } top = dag_advance_stream(dtv->dagfd, dtv->dagstream, &(dtv->btm)); if (top == NULL) { if (errno == EAGAIN) { if (dtv->dagstream & 0x1) { usleep(10 * 1000); dtv->btm = dtv->top; } continue; } else { SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED, "Failed to read from stream: %d, DAG: %s when " "using dag_advance_stream", dtv->dagstream, dtv->dagname); SCReturnInt(TM_ECODE_FAILED); } } diff = top - dtv->btm; if (diff == 0) { continue; } assert(diff >= dag_record_size); err = ProcessErfDagRecords(dtv, top, &pkts_read); if (err == TM_ECODE_FAILED) { SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED, "Failed to read from stream: %d, DAG: %s", dtv->dagstream, dtv->dagname); ReceiveErfDagCloseStream(dtv->dagfd, dtv->dagstream); SCReturnInt(TM_ECODE_FAILED); } SCPerfSyncCountersIfSignalled(tv, 0); SCLogDebug("Read %d records from stream: %d, DAG: %s", pkts_read, dtv->dagstream, dtv->dagname); } SCReturnInt(TM_ECODE_OK); } /** * \brief Process a chunk of records read from a DAG interface. * * This function takes a pointer to buffer read from the DAG interface * and processes it individual records. */ static inline TmEcode ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) { SCEnter(); int err = 0; dag_record_t *dr = NULL; char *prec = NULL; int rlen; char hdr_type = 0; int processed = 0; int packet_q_len = 0; *pkts_read = 0; while (((top - ewtn->btm) >= dag_record_size) && ((processed + dag_record_size) < 4*1024*1024)) { /* Make sure we have at least one packet in the packet pool, * to prevent us from alloc'ing packets at line rate. */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); prec = (char *)ewtn->btm; dr = (dag_record_t*)prec; rlen = ntohs(dr->rlen); hdr_type = dr->type; /* If we don't have enough data to finsih processing this ERF record * return and maybe next time we will. */ if ((top - ewtn->btm) < rlen) SCReturnInt(TM_ECODE_OK); ewtn->btm += rlen; processed += rlen; /* Only support ethernet at this time. */ switch (hdr_type & 0x7f) { case TYPE_PAD: /* Skip. */ continue; case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_ETH: case TYPE_COLOR_HASH_ETH: /* In these types the color value overwrites the lctr * (drop count). */ break; case TYPE_ETH: if (dr->lctr) { SCPerfCounterIncr(ewtn->drops, ewtn->tv->sc_perf_pca); } break; default: SCLogError(SC_ERR_UNIMPLEMENTED, "Processing of DAG record type: %d not implemented.", dr->type); SCReturnInt(TM_ECODE_FAILED); } err = ProcessErfDagRecord(ewtn, prec); if (err != TM_ECODE_OK) { SCReturnInt(TM_ECODE_FAILED); } (*pkts_read)++; } SCReturnInt(TM_ECODE_OK); } /** * \brief Process a DAG record into a TM packet buffer. * \param prec pointer to a DAG record. * \param */ static inline TmEcode ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) { SCEnter(); int wlen = 0; int rlen = 0; int hdr_num = 0; char hdr_type = 0; dag_record_t *dr = (dag_record_t*)prec; erf_payload_t *pload; Packet *p; hdr_type = dr->type; wlen = ntohs(dr->wlen); rlen = ntohs(dr->rlen); /* count extension headers */ while (hdr_type & 0x80) { if (rlen < (dag_record_size + (hdr_num * 8))) { SCLogError(SC_ERR_UNIMPLEMENTED, "Insufficient captured packet length."); SCReturnInt(TM_ECODE_FAILED); } hdr_type = prec[(dag_record_size + (hdr_num * 8))]; hdr_num++; } /* Check that the whole frame was captured */ if (rlen < (dag_record_size + (8 * hdr_num) + 2 + wlen)) { SCLogInfo("Incomplete frame captured."); SCReturnInt(TM_ECODE_OK); } /* skip over extension headers */ pload = (erf_payload_t *)(prec + dag_record_size + (8 * hdr_num)); p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate a Packet on stream: %d, DAG: %s", ewtn->dagstream, ewtn->dagname); SCReturnInt(TM_ECODE_FAILED); } PKT_SET_SRC(p, PKT_SRC_WIRE); SET_PKT_LEN(p, wlen); p->datalink = LINKTYPE_ETHERNET; /* Take into account for link type Ethernet ETH frame starts * after ther ERF header + pad. */ if (unlikely(PacketCopyData(p, pload->eth.dst, GET_PKT_LEN(p)))) { TmqhOutputPacketpool(ewtn->tv, p); SCReturnInt(TM_ECODE_FAILED); } /* Convert ERF time to timeval - from libpcap. */ uint64_t ts = dr->ts; p->ts.tv_sec = ts >> 32; ts = (ts & 0xffffffffULL) * 1000000; ts += 0x80000000; /* rounding */ p->ts.tv_usec = ts >> 32; if (p->ts.tv_usec >= 1000000) { p->ts.tv_usec -= 1000000; p->ts.tv_sec++; } SCPerfCounterIncr(ewtn->packets, ewtn->tv->sc_perf_pca); ewtn->bytes += wlen; if (TmThreadsSlotProcessPkt(ewtn->tv, ewtn->slot, p) != TM_ECODE_OK) { TmqhOutputPacketpool(ewtn->tv, p); SCReturnInt(TM_ECODE_FAILED); } SCReturnInt(TM_ECODE_OK); } /** * \brief Print some stats to the log at program exit. * * \param tv Pointer to ThreadVars. * \param data Pointer to data, ErfFileThreadVars. */ void ReceiveErfDagThreadExitStats(ThreadVars *tv, void *data) { ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; SCLogInfo("Stream: %d; Bytes: %"PRIu64"; Packets: %"PRIu64 "; Drops: %"PRIu64, ewtn->dagstream, ewtn->bytes, (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->sc_perf_pca), (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->sc_perf_pca)); } /** * \brief Deinitializes the DAG card. * \param tv pointer to ThreadVars * \param data pointer that gets cast into PcapThreadVars for ptv */ TmEcode ReceiveErfDagThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; ReceiveErfDagCloseStream(ewtn->dagfd, ewtn->dagstream); SCReturnInt(TM_ECODE_OK); } void ReceiveErfDagCloseStream(int dagfd, int stream) { dag_stop_stream(dagfd, stream); dag_detach_stream(dagfd, stream); dag_close(dagfd); } /** Decode ErfDag */ /** * \brief This function passes off to link type decoders. * * DecodeErfDag reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param t pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into PcapThreadVars for ptv * \param pq pointer to the current PacketQueue */ TmEcode DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodeErfDag", p->datalink); break; } SCReturnInt(TM_ECODE_OK); } TmEcode DecodeErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if(dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; SCReturnInt(TM_ECODE_OK); } #endif /* HAVE_DAG */ suricata-1.4.7/src/detect-engine-hhd.c0000644000000000000000000027057012253546156014460 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP header match * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-hhd.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "util-memcmp.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" #define BUFFER_STEP 50 static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) { if (size > det_ctx->hhd_buffers_size) { det_ctx->hhd_buffers = SCRealloc(det_ctx->hhd_buffers, (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint8_t *)); if (det_ctx->hhd_buffers == NULL) { det_ctx->hhd_buffers_size = 0; det_ctx->hhd_buffers_list_len = 0; return -1; } memset(det_ctx->hhd_buffers + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint8_t *)); det_ctx->hhd_buffers_len = SCRealloc(det_ctx->hhd_buffers_len, (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint32_t)); if (det_ctx->hhd_buffers_len == NULL) { det_ctx->hhd_buffers_size = 0; det_ctx->hhd_buffers_list_len = 0; return -1; } memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint32_t)); det_ctx->hhd_buffers_size += BUFFER_STEP; } memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_list_len, 0, (size - det_ctx->hhd_buffers_list_len) * sizeof(uint32_t)); return 0; } static uint8_t *DetectEngineHHDGetBufferForTX(int tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, uint32_t *buffer_len) { uint8_t *headers_buffer = NULL; int index = 0; *buffer_len = 0; if (det_ctx->hhd_buffers_list_len == 0) { if (HHDCreateSpace(det_ctx, 1) < 0) goto end; index = 0; if (det_ctx->hhd_buffers_list_len == 0) { det_ctx->hhd_start_tx_id = tx_id; } det_ctx->hhd_buffers_list_len++; } else { if ((tx_id - det_ctx->hhd_start_tx_id) < det_ctx->hhd_buffers_list_len) { if (det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)] != 0) { *buffer_len = det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)]; return det_ctx->hhd_buffers[(tx_id - det_ctx->hhd_start_tx_id)]; } } else { if (HHDCreateSpace(det_ctx, (tx_id - det_ctx->hhd_start_tx_id) + 1) < 0) goto end; if (det_ctx->hhd_buffers_list_len == 0) { det_ctx->hhd_start_tx_id = tx_id; } det_ctx->hhd_buffers_list_len++; } index = (tx_id - det_ctx->hhd_start_tx_id); } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL) { SCLogDebug("no tx"); goto end; } table_t *headers; if (flags & STREAM_TOSERVER) { headers = tx->request_headers; } else { headers = tx->response_headers; } if (headers == NULL) goto end; htp_header_t *h = NULL; headers_buffer = det_ctx->hhd_buffers[index]; size_t headers_buffer_len = 0; table_iterator_reset(headers); while (table_iterator_next(headers, (void **)&h) != NULL) { size_t size1 = bstr_size(h->name); size_t size2 = bstr_size(h->value); if (flags & STREAM_TOSERVER) { if (size1 == 6 && SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { continue; } } else { if (size1 == 10 && SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { continue; } } /* the extra 4 bytes if for ": " and "\r\n" */ headers_buffer = SCRealloc(headers_buffer, headers_buffer_len + size1 + size2 + 4); if (headers_buffer == NULL) { det_ctx->hhd_buffers[index] = NULL; det_ctx->hhd_buffers_len[index] = 0; goto end; } memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->name), size1); headers_buffer_len += size1; headers_buffer[headers_buffer_len] = ':'; headers_buffer[headers_buffer_len + 1] = ' '; headers_buffer_len += 2; memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->value), size2); headers_buffer_len += size2 + 2; /* \r */ headers_buffer[headers_buffer_len - 2] = '\r'; /* \n */ headers_buffer[headers_buffer_len - 1] = '\n'; } /* store the buffers. We will need it for further inspection */ det_ctx->hhd_buffers[index] = headers_buffer; det_ctx->hhd_buffers_len[index] = headers_buffer_len; *buffer_len = (uint32_t)headers_buffer_len; end: return headers_buffer; } int DetectEngineRunHttpHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { uint32_t cnt = 0; if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } FLOWLOCK_WRLOCK(f); if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } /* get the transaction id */ int idx = AppLayerTransactionGetInspectId(f); /* error! get out of here */ if (idx == -1) goto end; int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { uint32_t buffer_len = 0; uint8_t *buffer = DetectEngineHHDGetBufferForTX(idx, NULL, det_ctx, f, htp_state, flags, &buffer_len); if (buffer_len == 0) continue; cnt += HttpHeaderPatternSearch(det_ctx, buffer, buffer_len, flags); } end: FLOWLOCK_UNLOCK(f); return cnt; } int DetectEngineInspectHttpHeader(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx_id, de_ctx, det_ctx, f, htp_state, flags, &buffer_len); if (buffer_len == 0) return 0; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HHDMATCH], f, buffer, buffer_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHD, NULL); if (r == 1) return 1; return 0; } void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx) { if (det_ctx->hhd_buffers_list_len != 0) { int i; for (i = 0; i < det_ctx->hhd_buffers_list_len; i++) { det_ctx->hhd_buffers_len[i] = 0; } det_ctx->hhd_buffers_list_len = 0; } det_ctx->hhd_start_tx_id = 0; return; } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest01(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest02(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; depth:15; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest03(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"one\"; depth:5; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest04(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; depth:5; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest05(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"one\"; depth:15; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; offset:10; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest07(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"one\"; offset:15; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest08(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; offset:15; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest09(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"one\"; offset:10; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest10(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:\"three\"; http_header; within:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:!\"three\"; http_header; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:!\"three\"; http_header; within:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:\"three\"; http_header; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest14(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:\"five\"; http_header; distance:7; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest15(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:!\"five\"; http_header; distance:15; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest16(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:!\"five\"; http_header; distance:7; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest17(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:\"five\"; http_header; distance:15; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest18(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http_buf[] = "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; content:\"five\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = HttpHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); if (r != 2) { printf("expected result 2, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** *\test Test that the http_header content matches against a http request * which holds the content. */ static int DetectEngineHttpHeaderTest19(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http_buf[] = "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"one\"; http_header; fast_pattern; content:\"five\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); uint32_t r = HttpHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); if (r != 1) { printf("expected result 1, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHeaderTest20(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/H; " "content:!\"dummy\"; http_header; within:7; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest21(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/H; " "content:!\"dummy\"; within:7; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest22(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/H; " "content:!\"dummy\"; distance:3; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest23(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/H; " "content:!\"dummy\"; distance:13; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest24(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/H; " "content:\"dummy\"; within:15; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest25(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/H; " "content:\"dummy\"; within:10; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest26(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/H; " "content:\"dummy\"; distance:8; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest27(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: This_is_dummy_body1"; uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/H; " "content:\"dummy\"; distance:14; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest28(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Content-Length: 6\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpHeaderTest29(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Content-Length: 7\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } #if 0 static int DetectEngineHttpHeaderTest30(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(msg:\"http header test\"; " "content:\"Content-Length: 6\"; http_header; " "content:\"User-Agent: Mozilla\"; http_header; " "sid:1;)"); if (de_ctx->sig_list != NULL) { goto end; } result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } #endif /* #if 0 */ static int DetectEngineHttpHeaderTest30(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" "Set-Cookie: dummycookieset\r\n" "Content-Type: text/html\r\n" "Content-Length: 6\r\n" "\r\n" "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"dummycookieset\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /** \test reassembly bug where headers with names of length 6 were * skipped */ static int DetectEngineHttpHeaderTest31(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Accept: blah\r\n" "Cookie: blah\r\n" "Crazy6: blah\r\n" "SixZix: blah\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(content:\"Accept|3a|\"; http_header; " "content:!\"Cookie|3a|\"; http_header; " "content:\"Crazy6|3a|\"; http_header; " "content:\"SixZix|3a|\"; http_header; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpHeaderRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpHeaderTest01", DetectEngineHttpHeaderTest01, 1); UtRegisterTest("DetectEngineHttpHeaderTest02", DetectEngineHttpHeaderTest02, 1); UtRegisterTest("DetectEngineHttpHeaderTest03", DetectEngineHttpHeaderTest03, 1); UtRegisterTest("DetectEngineHttpHeaderTest04", DetectEngineHttpHeaderTest04, 1); UtRegisterTest("DetectEngineHttpHeaderTest05", DetectEngineHttpHeaderTest05, 1); UtRegisterTest("DetectEngineHttpHeaderTest06", DetectEngineHttpHeaderTest06, 1); UtRegisterTest("DetectEngineHttpHeaderTest07", DetectEngineHttpHeaderTest07, 1); UtRegisterTest("DetectEngineHttpHeaderTest08", DetectEngineHttpHeaderTest08, 1); UtRegisterTest("DetectEngineHttpHeaderTest09", DetectEngineHttpHeaderTest09, 1); UtRegisterTest("DetectEngineHttpHeaderTest10", DetectEngineHttpHeaderTest10, 1); UtRegisterTest("DetectEngineHttpHeaderTest11", DetectEngineHttpHeaderTest11, 1); UtRegisterTest("DetectEngineHttpHeaderTest12", DetectEngineHttpHeaderTest12, 1); UtRegisterTest("DetectEngineHttpHeaderTest13", DetectEngineHttpHeaderTest13, 1); UtRegisterTest("DetectEngineHttpHeaderTest14", DetectEngineHttpHeaderTest14, 1); UtRegisterTest("DetectEngineHttpHeaderTest15", DetectEngineHttpHeaderTest15, 1); UtRegisterTest("DetectEngineHttpHeaderTest16", DetectEngineHttpHeaderTest16, 1); UtRegisterTest("DetectEngineHttpHeaderTest17", DetectEngineHttpHeaderTest17, 1); UtRegisterTest("DetectEngineHttpHeaderTest18", DetectEngineHttpHeaderTest18, 1); UtRegisterTest("DetectEngineHttpHeaderTest19", DetectEngineHttpHeaderTest19, 1); UtRegisterTest("DetectEngineHttpHeaderTest20", DetectEngineHttpHeaderTest20, 1); UtRegisterTest("DetectEngineHttpHeaderTest21", DetectEngineHttpHeaderTest21, 1); UtRegisterTest("DetectEngineHttpHeaderTest22", DetectEngineHttpHeaderTest22, 1); UtRegisterTest("DetectEngineHttpHeaderTest23", DetectEngineHttpHeaderTest23, 1); UtRegisterTest("DetectEngineHttpHeaderTest24", DetectEngineHttpHeaderTest24, 1); UtRegisterTest("DetectEngineHttpHeaderTest25", DetectEngineHttpHeaderTest25, 1); UtRegisterTest("DetectEngineHttpHeaderTest26", DetectEngineHttpHeaderTest26, 1); UtRegisterTest("DetectEngineHttpHeaderTest27", DetectEngineHttpHeaderTest27, 1); UtRegisterTest("DetectEngineHttpHeaderTest28", DetectEngineHttpHeaderTest28, 1); UtRegisterTest("DetectEngineHttpHeaderTest29", DetectEngineHttpHeaderTest29, 1); UtRegisterTest("DetectEngineHttpHeaderTest30", DetectEngineHttpHeaderTest30, 1); UtRegisterTest("DetectEngineHttpHeaderTest31", DetectEngineHttpHeaderTest31, 1); #if 0 UtRegisterTest("DetectEngineHttpHeaderTest30", DetectEngineHttpHeaderTest30, 1); #endif #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/runmode-nfq.h0000644000000000000000000000206612253546156013435 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien */ #ifndef __RUNMODE_NFQ_H__ #define __RUNMODE_NFQ_H__ int RunModeIpsNFQAuto(DetectEngineCtx *); int RunModeIpsNFQAutoFp(DetectEngineCtx *); int RunModeIpsNFQWorker(DetectEngineCtx *); void RunModeIpsNFQRegister(void); const char *RunModeIpsNFQGetDefaultMode(void); #endif /* __RUNMODE_NFQ_H__ */ suricata-1.4.7/src/flow-util.h0000644000000000000000000001045012253546156013120 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __FLOW_UTIL_H__ #define __FLOW_UTIL_H__ #include "detect-engine-state.h" #include "tmqh-flow.h" #define COPY_TIMESTAMP(src,dst) ((dst)->tv_sec = (src)->tv_sec, (dst)->tv_usec = (src)->tv_usec) #ifdef DEBUG #define RESET_COUNTERS(f) do { \ (f)->todstpktcnt = 0; \ (f)->tosrcpktcnt = 0; \ (f)->bytecnt = 0; \ } while (0) #else #define RESET_COUNTERS(f) #endif #define FLOW_INITIALIZE(f) do { \ (f)->sp = 0; \ (f)->dp = 0; \ SC_ATOMIC_INIT((f)->use_cnt); \ (f)->probing_parser_toserver_al_proto_masks = 0; \ (f)->probing_parser_toclient_al_proto_masks = 0; \ (f)->flags = 0; \ (f)->lastts_sec = 0; \ FLOWLOCK_INIT((f)); \ (f)->protoctx = NULL; \ (f)->alproto = 0; \ (f)->de_ctx_id = 0; \ (f)->alparser = NULL; \ (f)->alstate = NULL; \ (f)->de_state = NULL; \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ (f)->tag_list = NULL; \ (f)->flowvar = NULL; \ SCMutexInit(&(f)->de_state_m, NULL); \ (f)->hnext = NULL; \ (f)->hprev = NULL; \ (f)->lnext = NULL; \ (f)->lprev = NULL; \ SC_ATOMIC_INIT((f)->autofp_tmqh_flow_qid); \ (void) SC_ATOMIC_SET((f)->autofp_tmqh_flow_qid, -1); \ RESET_COUNTERS((f)); \ } while (0) /** \brief macro to recycle a flow before it goes into the spare queue for reuse. * * Note that the lnext, lprev, hnext, hprev fields are untouched, those are * managed by the queueing code. Same goes for fb (FlowBucket ptr) field. */ #define FLOW_RECYCLE(f) do { \ (f)->sp = 0; \ (f)->dp = 0; \ SC_ATOMIC_RESET((f)->use_cnt); \ (f)->probing_parser_toserver_al_proto_masks = 0; \ (f)->probing_parser_toclient_al_proto_masks = 0; \ (f)->flags = 0; \ (f)->lastts_sec = 0; \ (f)->protoctx = NULL; \ FlowCleanupAppLayer((f)); \ (f)->alparser = NULL; \ (f)->alstate = NULL; \ (f)->alproto = 0; \ (f)->de_ctx_id = 0; \ if ((f)->de_state != NULL) { \ DetectEngineStateReset((f)->de_state); \ } \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ DetectTagDataListFree((f)->tag_list); \ (f)->tag_list = NULL; \ GenericVarFree((f)->flowvar); \ (f)->flowvar = NULL; \ if (SC_ATOMIC_GET((f)->autofp_tmqh_flow_qid) != -1) { \ (void) SC_ATOMIC_SET((f)->autofp_tmqh_flow_qid, -1); \ } \ RESET_COUNTERS((f)); \ } while(0) #define FLOW_DESTROY(f) do { \ SC_ATOMIC_DESTROY((f)->use_cnt); \ \ FLOWLOCK_DESTROY((f)); \ FlowCleanupAppLayer((f)); \ if ((f)->de_state != NULL) { \ DetectEngineStateFree((f)->de_state); \ } \ DetectTagDataListFree((f)->tag_list); \ GenericVarFree((f)->flowvar); \ SCMutexDestroy(&(f)->de_state_m); \ SC_ATOMIC_DESTROY((f)->autofp_tmqh_flow_qid); \ (f)->tag_list = NULL; \ } while(0) /** \brief check if a memory alloc would fit in the memcap * * \param size memory allocation size to check * * \retval 1 it fits * \retval 0 no fit */ #define FLOW_CHECK_MEMCAP(size) \ ((((uint64_t)SC_ATOMIC_GET(flow_memuse) + (uint64_t)(size)) <= flow_config.memcap)) Flow *FlowAlloc(void); Flow *FlowAllocDirect(void); void FlowFree(Flow *); uint8_t FlowGetProtoMapping(uint8_t); void FlowInit(Flow *, Packet *); #endif /* __FLOW_UTIL_H__ */ suricata-1.4.7/src/source-nfq.c0000644000000000000000000010170612253546156013260 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Eric Leblond * * Netfilter's netfilter_queue support for reading packets from the * kernel and setting verdicts back to it (inline mode). * Supported on Linux and Windows. * * \todo test if Receive and Verdict if both are present */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "tm-queuehandlers.h" #include "tmqh-packetpool.h" #include "conf.h" #include "config.h" #include "conf-yaml-loader.h" #include "source-nfq-prototypes.h" #include "action-globals.h" #include "util-debug.h" #include "util-error.h" #include "util-byte.h" #include "util-privs.h" #include "util-device.h" #include "runmodes.h" #include "source-nfq.h" #ifndef NFQ /** Handle the case where no NFQ support is compiled in. * */ TmEcode NoNFQSupportExit(ThreadVars *, void *, void **); void TmModuleReceiveNFQRegister (void) { tmm_modules[TMM_RECEIVENFQ].name = "ReceiveNFQ"; tmm_modules[TMM_RECEIVENFQ].ThreadInit = NoNFQSupportExit; tmm_modules[TMM_RECEIVENFQ].Func = NULL; tmm_modules[TMM_RECEIVENFQ].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVENFQ].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVENFQ].RegisterTests = NULL; tmm_modules[TMM_RECEIVENFQ].cap_flags = SC_CAP_NET_ADMIN; tmm_modules[TMM_RECEIVENFQ].flags = TM_FLAG_RECEIVE_TM; } void TmModuleVerdictNFQRegister (void) { tmm_modules[TMM_VERDICTNFQ].name = "VerdictNFQ"; tmm_modules[TMM_VERDICTNFQ].ThreadInit = NoNFQSupportExit; tmm_modules[TMM_VERDICTNFQ].Func = NULL; tmm_modules[TMM_VERDICTNFQ].ThreadExitPrintStats = NULL; tmm_modules[TMM_VERDICTNFQ].ThreadDeinit = NULL; tmm_modules[TMM_VERDICTNFQ].RegisterTests = NULL; tmm_modules[TMM_VERDICTNFQ].cap_flags = SC_CAP_NET_ADMIN; } void TmModuleDecodeNFQRegister (void) { tmm_modules[TMM_DECODENFQ].name = "DecodeNFQ"; tmm_modules[TMM_DECODENFQ].ThreadInit = NoNFQSupportExit; tmm_modules[TMM_DECODENFQ].Func = NULL; tmm_modules[TMM_DECODENFQ].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODENFQ].ThreadDeinit = NULL; tmm_modules[TMM_DECODENFQ].RegisterTests = NULL; tmm_modules[TMM_DECODENFQ].cap_flags = 0; tmm_modules[TMM_DECODENFQ].flags = TM_FLAG_DECODE_TM; } TmEcode NoNFQSupportExit(ThreadVars *tv, void *initdata, void **data) { SCLogError(SC_ERR_NFQ_NOSUPPORT,"Error creating thread %s: you do not have support for nfqueue " "enabled please recompile with --enable-nfqueue", tv->name); exit(EXIT_FAILURE); } #else /* implied we do have NFQ support */ extern int max_pending_packets; #define MAX_ALREADY_TREATED 5 #define NFQ_VERDICT_RETRY_TIME 3 int already_seen_warning; #define NFQ_BURST_FACTOR 4 #ifndef SOL_NETLINK #define SOL_NETLINK 270 #endif //#define NFQ_DFT_QUEUE_LEN NFQ_BURST_FACTOR * MAX_PENDING //#define NFQ_NF_BUFSIZE 1500 * NFQ_DFT_QUEUE_LEN typedef struct NFQThreadVars_ { uint16_t nfq_index; ThreadVars *tv; TmSlot *slot; char *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ } NFQThreadVars; /* shared vars for all for nfq queues and threads */ static NFQGlobalVars nfq_g; static NFQThreadVars nfq_t[NFQ_MAX_QUEUE]; static NFQQueueVars nfq_q[NFQ_MAX_QUEUE]; static uint16_t receive_queue_num = 0; static SCMutex nfq_init_lock; TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot); TmEcode ReceiveNFQThreadInit(ThreadVars *, void *, void **); TmEcode ReceiveNFQThreadDeinit(ThreadVars *, void *); void ReceiveNFQThreadExitStats(ThreadVars *, void *); TmEcode VerdictNFQ(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode VerdictNFQThreadInit(ThreadVars *, void *, void **); TmEcode VerdictNFQThreadDeinit(ThreadVars *, void *); TmEcode DecodeNFQ(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode DecodeNFQThreadInit(ThreadVars *, void *, void **); typedef enum NFQMode_ { NFQ_ACCEPT_MODE, NFQ_REPEAT_MODE, NFQ_ROUTE_MODE, } NFQMode; #define NFQ_FLAG_FAIL_OPEN (1 << 0) typedef struct NFQCnf_ { NFQMode mode; uint32_t mark; uint32_t mask; uint32_t next_queue; uint32_t flags; } NFQCnf; NFQCnf nfq_config; void TmModuleReceiveNFQRegister (void) { /* XXX create a general NFQ setup function */ memset(&nfq_g, 0, sizeof(nfq_g)); SCMutexInit(&nfq_init_lock, NULL); tmm_modules[TMM_RECEIVENFQ].name = "ReceiveNFQ"; tmm_modules[TMM_RECEIVENFQ].ThreadInit = ReceiveNFQThreadInit; tmm_modules[TMM_RECEIVENFQ].Func = NULL; tmm_modules[TMM_RECEIVENFQ].PktAcqLoop = ReceiveNFQLoop; tmm_modules[TMM_RECEIVENFQ].ThreadExitPrintStats = ReceiveNFQThreadExitStats; tmm_modules[TMM_RECEIVENFQ].ThreadDeinit = ReceiveNFQThreadDeinit; tmm_modules[TMM_RECEIVENFQ].RegisterTests = NULL; tmm_modules[TMM_RECEIVENFQ].flags = TM_FLAG_RECEIVE_TM; } void TmModuleVerdictNFQRegister (void) { tmm_modules[TMM_VERDICTNFQ].name = "VerdictNFQ"; tmm_modules[TMM_VERDICTNFQ].ThreadInit = VerdictNFQThreadInit; tmm_modules[TMM_VERDICTNFQ].Func = VerdictNFQ; tmm_modules[TMM_VERDICTNFQ].ThreadExitPrintStats = NULL; tmm_modules[TMM_VERDICTNFQ].ThreadDeinit = VerdictNFQThreadDeinit; tmm_modules[TMM_VERDICTNFQ].RegisterTests = NULL; } void TmModuleDecodeNFQRegister (void) { tmm_modules[TMM_DECODENFQ].name = "DecodeNFQ"; tmm_modules[TMM_DECODENFQ].ThreadInit = DecodeNFQThreadInit; tmm_modules[TMM_DECODENFQ].Func = DecodeNFQ; tmm_modules[TMM_DECODENFQ].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODENFQ].ThreadDeinit = NULL; tmm_modules[TMM_DECODENFQ].RegisterTests = NULL; tmm_modules[TMM_DECODENFQ].flags = TM_FLAG_DECODE_TM; } /** \brief To initialize the NFQ global configuration data * * \param quiet It tells the mode of operation, if it is TRUE nothing will * be get printed. */ void NFQInitConfig(char quiet) { intmax_t value = 0; char* nfq_mode = NULL; int boolval; SCLogDebug("Initializing NFQ"); memset(&nfq_config, 0, sizeof(nfq_config)); if ((ConfGet("nfq.mode", &nfq_mode)) == 0) { nfq_config.mode = NFQ_ACCEPT_MODE; } else { if (!strcmp("accept", nfq_mode)) { nfq_config.mode = NFQ_ACCEPT_MODE; } else if (!strcmp("repeat", nfq_mode)) { nfq_config.mode = NFQ_REPEAT_MODE; } else if (!strcmp("route", nfq_mode)) { nfq_config.mode = NFQ_ROUTE_MODE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Unknown nfq.mode"); exit(EXIT_FAILURE); } } (void)ConfGetBool("nfq.fail-open", (int *)&boolval); if (boolval) { #ifdef HAVE_NFQ_SET_QUEUE_FLAGS SCLogInfo("Enabling fail-open on queue"); nfq_config.flags |= NFQ_FLAG_FAIL_OPEN; #else SCLogError(SC_ERR_NFQ_NOSUPPORT, "nfq.fail-open set but NFQ library has no support for it."); #endif } if ((ConfGetInt("nfq.repeat-mark", &value)) == 1) { nfq_config.mark = (uint32_t)value; } if ((ConfGetInt("nfq.repeat-mask", &value)) == 1) { nfq_config.mask = (uint32_t)value; } if ((ConfGetInt("nfq.route-queue", &value)) == 1) { nfq_config.next_queue = ((uint32_t)value) << 16; } if (!quiet) { switch (nfq_config.mode) { case NFQ_ACCEPT_MODE: SCLogInfo("NFQ running in standard ACCEPT/DROP mode"); break; case NFQ_REPEAT_MODE: SCLogInfo("NFQ running in REPEAT mode with mark %"PRIu32"/%"PRIu32, nfq_config.mark, nfq_config.mask); break; case NFQ_ROUTE_MODE: SCLogInfo("NFQ running in route mode with next queue %"PRIu32, nfq_config.next_queue); break; } } } static inline void NFQMutexInit(NFQQueueVars *nq) { char *active_runmode = RunmodeGetActive(); if (active_runmode && !strcmp("workers", active_runmode)) { nq->use_mutex = 0; SCLogInfo("NFQ running in 'workers' runmode, will not use mutex."); } else { nq->use_mutex = 1; } if (nq->use_mutex) SCMutexInit(&nq->mutex_qh, NULL); } #define NFQMutexLock(nq) do { \ if ((nq)->use_mutex) \ SCMutexLock(&(nq)->mutex_qh); \ } while (0) #define NFQMutexUnlock(nq) do { \ if ((nq)->use_mutex) \ SCMutexUnlock(&(nq)->mutex_qh); \ } while (0) int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) { struct nfq_data *tb = (struct nfq_data *)data; int ret; char *pktdata; struct nfqnl_msg_packet_hdr *ph; ph = nfq_get_msg_packet_hdr(tb); if (ph != NULL) { p->nfq_v.id = ntohl(ph->packet_id); //p->nfq_v.hw_protocol = ntohs(p->nfq_v.ph->hw_protocol); p->nfq_v.hw_protocol = ph->hw_protocol; } p->nfq_v.mark = nfq_get_nfmark(tb); if (nfq_config.mode == NFQ_REPEAT_MODE) { if ((nfq_config.mark & nfq_config.mask) == (p->nfq_v.mark & nfq_config.mask)) { int iter = 0; if (already_seen_warning < MAX_ALREADY_TREATED) SCLogInfo("Packet seems already treated by suricata"); already_seen_warning++; do { ret = nfq_set_verdict(qh, p->nfq_v.id, NF_ACCEPT, 0, NULL); } while ((ret < 0) && (iter++ < NFQ_VERDICT_RETRY_TIME)); if (ret < 0) { SCLogWarning(SC_ERR_NFQ_SET_VERDICT, "nfq_set_verdict of %p failed %" PRId32 "", p, ret); } return -1 ; } } p->nfq_v.ifi = nfq_get_indev(tb); p->nfq_v.ifo = nfq_get_outdev(tb); #ifdef NFQ_GET_PAYLOAD_SIGNED ret = nfq_get_payload(tb, &pktdata); #else ret = nfq_get_payload(tb, (unsigned char **) &pktdata); #endif /* NFQ_GET_PAYLOAD_SIGNED */ if (ret > 0) { /* nfq_get_payload returns a pointer to a part of memory * that is not preserved over the lifetime of our packet. * So we need to copy it. */ if (ret > 65536) { /* Will not be able to copy data ! Set length to 0 * to trigger an error in packet decoding. * This is unlikely to happen */ SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "NFQ sent too big packet"); SET_PKT_LEN(p, 0); } else { PacketCopyData(p, (uint8_t *)pktdata, ret); } } else if (ret == -1) { /* unable to get pointer to data, ensure packet length is zero. * This will trigger an error in packet decoding */ SET_PKT_LEN(p, 0); } ret = nfq_get_timestamp(tb, &p->ts); if (ret != 0) { memset (&p->ts, 0, sizeof(struct timeval)); gettimeofday(&p->ts, NULL); } p->datalink = DLT_RAW; return 0; } static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { NFQThreadVars *ntv = (NFQThreadVars *)data; ThreadVars *tv = ntv->tv; int ret; /* grab a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (p == NULL) { return -1; } PKT_SET_SRC(p, PKT_SRC_WIRE); p->nfq_v.nfq_index = ntv->nfq_index; ret = NFQSetupPkt(p, qh, (void *)nfa); if (ret == -1) { #ifdef COUNTERS NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index); nfq_q->errs++; nfq_q->pkts++; nfq_q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ /* recycle Packet and leave */ TmqhOutputPacketpool(tv, p); return 0; } #ifdef COUNTERS NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index); nfq_q->pkts++; nfq_q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ if (ntv->slot) { if (TmThreadsSlotProcessPkt(tv, ntv->slot, p) != TM_ECODE_OK) { TmqhOutputPacketpool(ntv->tv, p); return -1; } } else { /* pass on... */ tv->tmqh_out(tv, p); } return 0; } TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) { #ifndef OS_WIN32 struct timeval tv; int opt; #endif NFQQueueVars *nfq_q = NFQGetQueue(nfq_t->nfq_index); if (nfq_q == NULL) { SCLogError(SC_ERR_NFQ_OPEN, "no queue for given index"); return TM_ECODE_FAILED; } SCLogDebug("opening library handle"); nfq_q->h = nfq_open(); if (!nfq_q->h) { SCLogError(SC_ERR_NFQ_OPEN, "nfq_open() failed"); return TM_ECODE_FAILED; } if (nfq_g.unbind == 0) { /* VJ: on my Ubuntu Hardy system this fails the first time it's * run. Ignoring the error seems to have no bad effects. */ SCLogDebug("unbinding existing nf_queue handler for AF_INET (if any)"); if (nfq_unbind_pf(nfq_q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } if (nfq_unbind_pf(nfq_q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } nfq_g.unbind = 1; SCLogDebug("binding nfnetlink_queue as nf_queue handler for AF_INET and AF_INET6"); if (nfq_bind_pf(nfq_q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } if (nfq_bind_pf(nfq_q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } } SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", nfq_t->nfq_index, nfq_q->queue_num); /* pass the thread memory as a void ptr so the * callback function has access to it. */ nfq_q->qh = nfq_create_queue(nfq_q->h, nfq_q->queue_num, &NFQCallBack, (void *)nfq_t); if (nfq_q->qh == NULL) { SCLogError(SC_ERR_NFQ_CREATE_QUEUE, "nfq_create_queue failed"); return TM_ECODE_FAILED; } SCLogDebug("setting copy_packet mode"); /* 05DC = 1500 */ //if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) { if (nfq_set_mode(nfq_q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) { SCLogError(SC_ERR_NFQ_SET_MODE, "can't set packet_copy mode"); return TM_ECODE_FAILED; } #ifdef HAVE_NFQ_MAXLEN if (queue_maxlen > 0) { SCLogInfo("setting queue length to %" PRId32 "", queue_maxlen); /* non-fatal if it fails */ if (nfq_set_queue_maxlen(nfq_q->qh, queue_maxlen) < 0) { SCLogWarning(SC_ERR_NFQ_MAXLEN, "can't set queue maxlen: your kernel probably " "doesn't support setting the queue length"); } } #endif /* HAVE_NFQ_MAXLEN */ #ifndef OS_WIN32 /* set netlink buffer size to a decent value */ nfnl_rcvbufsiz(nfq_nfnlh(nfq_q->h), queue_maxlen * 1500); SCLogInfo("setting nfnl bufsize to %" PRId32 "", queue_maxlen * 1500); nfq_q->nh = nfq_nfnlh(nfq_q->h); nfq_q->fd = nfnl_fd(nfq_q->nh); NFQMutexInit(nfq_q); /* Set some netlink specific option on the socket to increase performance */ opt = 1; #ifdef NETLINK_BROADCAST_SEND_ERROR setsockopt(nfq_q->fd, SOL_NETLINK, NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)); #endif /* Don't send error about no buffer space available but drop the packets instead */ #ifdef NETLINK_NO_ENOBUFS setsockopt(nfq_q->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(int)); #endif #ifdef HAVE_NFQ_SET_QUEUE_FLAGS if (nfq_config.flags & NFQ_FLAG_FAIL_OPEN) { uint32_t flags = NFQA_CFG_F_FAIL_OPEN; uint32_t mask = NFQA_CFG_F_FAIL_OPEN; int r = nfq_set_queue_flags(nfq_q->qh, mask, flags); if (r == -1) { SCLogWarning(SC_ERR_NFQ_SET_MODE, "can't set fail-open mode: %s", strerror(errno)); } else { SCLogInfo("fail-open mode should be set on queue"); } } #endif /* set a timeout to the socket so we can check for a signal * in case we don't get packets for a longer period. */ tv.tv_sec = 1; tv.tv_usec = 0; if(setsockopt(nfq_q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set socket timeout: %s", strerror(errno)); } SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "", nfq_q->h, nfq_q->nh, nfq_q->qh, nfq_q->fd); #else /* OS_WIN32 */ NFQMutexInit(nfq_q); nfq_q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); nfq_q->fd = nfq_fd(nfq_q->h); SCLogDebug("nfq_q->h %p, nfq_q->qh %p, nfq_q->fd %p", nfq_q->h, nfq_q->qh, nfq_q->fd); #endif /* OS_WIN32 */ return TM_ECODE_OK; } TmEcode ReceiveNFQThreadInit(ThreadVars *tv, void *initdata, void **data) { SCMutexLock(&nfq_init_lock); #ifndef OS_WIN32 sigset_t sigs; sigfillset(&sigs); pthread_sigmask(SIG_BLOCK, &sigs, NULL); #endif /* OS_WIN32 */ NFQThreadVars *ntv = (NFQThreadVars *) initdata; /* store the ThreadVars pointer in our NFQ thread context * as we will need it in our callback function */ ntv->tv = tv; int r = NFQInitThread(ntv, (max_pending_packets * NFQ_BURST_FACTOR)); if (r < 0) { SCLogError(SC_ERR_NFQ_THREAD_INIT, "nfq thread failed to initialize"); SCMutexUnlock(&nfq_init_lock); exit(EXIT_FAILURE); } #define T_DATA_SIZE 70000 ntv->data = SCMalloc(T_DATA_SIZE); if (ntv->data == NULL) { SCMutexUnlock(&nfq_init_lock); return TM_ECODE_FAILED; } ntv->datalen = T_DATA_SIZE; #undef T_DATA_SIZE *data = (void *)ntv; SCMutexUnlock(&nfq_init_lock); return TM_ECODE_OK; } TmEcode ReceiveNFQThreadDeinit(ThreadVars *t, void *data) { NFQThreadVars *ntv = (NFQThreadVars *)data; NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index); if (ntv->data != NULL) { SCFree(ntv->data); ntv->data = NULL; } ntv->datalen = 0; NFQMutexLock(nq); SCLogDebug("starting... will close queuenum %" PRIu32 "", nq->queue_num); if (nq->qh) { nfq_destroy_queue(nq->qh); nq->qh = NULL; } NFQMutexUnlock(nq); return TM_ECODE_OK; } TmEcode VerdictNFQThreadInit(ThreadVars *tv, void *initdata, void **data) { *data = (void *)initdata; return TM_ECODE_OK; } TmEcode VerdictNFQThreadDeinit(ThreadVars *tv, void *data) { NFQThreadVars *ntv = (NFQThreadVars *)data; NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index); SCLogDebug("starting... will close queuenum %" PRIu32 "", nq->queue_num); NFQMutexLock(nq); if (nq->qh) { nfq_destroy_queue(nq->qh); nq->qh = NULL; } NFQMutexUnlock(nq); return TM_ECODE_OK; } /** * \brief Add a Netfilter queue * * \param string with the queue name * * \retval 0 on success. * \retval -1 on failure. */ int NFQRegisterQueue(char *queue) { NFQThreadVars *ntv = NULL; NFQQueueVars *nq = NULL; /* Extract the queue number from the specified command line argument */ uint16_t queue_num = 0; if ((ByteExtractStringUint16(&queue_num, 10, strlen(queue), queue)) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified queue number %s is not " "valid", queue); return -1; } SCMutexLock(&nfq_init_lock); if (receive_queue_num >= NFQ_MAX_QUEUE) { SCLogError(SC_ERR_INVALID_ARGUMENT, "too much Netfilter queue registered (%d)", receive_queue_num); SCMutexUnlock(&nfq_init_lock); return -1; } if (receive_queue_num == 0) { memset(&nfq_t, 0, sizeof(nfq_t)); memset(&nfq_q, 0, sizeof(nfq_q)); } ntv = &nfq_t[receive_queue_num]; ntv->nfq_index = receive_queue_num; nq = &nfq_q[receive_queue_num]; nq->queue_num = queue_num; receive_queue_num++; SCMutexUnlock(&nfq_init_lock); LiveRegisterDevice(queue); SCLogDebug("Queue \"%s\" registered.", queue); return 0; } /** * \brief Get a pointer to the NFQ queue at index * * \param number idx of the queue in our array * * \retval ptr pointer to the NFQThreadVars at index * \retval NULL on error */ void *NFQGetQueue(int number) { if (number >= receive_queue_num) return NULL; return (void *)&nfq_q[number]; } /** * \brief Get a pointer to the NFQ thread at index * * This function is temporary used as configuration parser. * * \param number idx of the queue in our array * * \retval ptr pointer to the NFQThreadVars at index * \retval NULL on error */ void *NFQGetThread(int number) { if (number >= receive_queue_num) return NULL; return (void *)&nfq_t[number]; } /** * \brief NFQ function to get a packet from the kernel * * \note separate functions for Linux and Win32 for readability. */ #ifndef OS_WIN32 void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv) { int rv, ret; /* XXX what happens on rv == 0? */ rv = recv(t->fd, tv->data, tv->datalen, 0); if (rv < 0) { if (errno == EINTR || errno == EWOULDBLOCK) { /* no error on timeout */ } else { #ifdef COUNTERS NFQMutexLock(t); t->errs++; NFQMutexUnlock(t); #endif /* COUNTERS */ } } else if(rv == 0) { SCLogWarning(SC_ERR_NFQ_RECV, "recv got returncode 0"); } else { #ifdef DBG_PERF if (rv > t->dbg_maxreadsize) t->dbg_maxreadsize = rv; #endif /* DBG_PERF */ //printf("NFQRecvPkt: t %p, rv = %" PRId32 "\n", t, rv); NFQMutexLock(t); if (t->qh != NULL) { ret = nfq_handle_packet(t->h, tv->data, rv); } else { SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "NFQ handle has been destroyed"); ret = -1; } NFQMutexUnlock(t); if (ret != 0) { SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "nfq_handle_packet error %" PRId32 "", ret); } } } #else /* WIN32 version of NFQRecvPkt */ void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv) { int rv, ret; static int timeouted = 0; if (timeouted) { if (WaitForSingleObject(t->ovr.hEvent, 1000) == WAIT_TIMEOUT) { rv = -1; errno = EINTR; goto process_rv; } timeouted = 0; } read_packet_again: if (!ReadFile(t->fd, tv->buf, sizeof(tv->buf), (DWORD*)&rv, &t->ovr)) { if (GetLastError() != ERROR_IO_PENDING) { rv = -1; errno = EIO; } else { if (WaitForSingleObject(t->ovr.hEvent, 1000) == WAIT_TIMEOUT) { rv = -1; errno = EINTR; timeouted = 1; } else { /* We needn't to call GetOverlappedResult() because it always * fail with our error code ERROR_MORE_DATA. */ goto read_packet_again; } } } process_rv: if (rv < 0) { if (errno == EINTR) { /* no error on timeout */ } else { #ifdef COUNTERS t->errs++; #endif /* COUNTERS */ } } else if(rv == 0) { SCLogWarning(SC_ERR_NFQ_RECV, "recv got returncode 0"); } else { #ifdef DBG_PERF if (rv > t->dbg_maxreadsize) t->dbg_maxreadsize = rv; #endif /* DBG_PERF */ //printf("NFQRecvPkt: t %p, rv = %" PRId32 "\n", t, rv); NFQMutexLock(t); if (t->qh) { ret = nfq_handle_packet(t->h, buf, rv); } else { SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "NFQ handle has been destroyed"); ret = -1; } NFQMutexUnlock(t); if (ret != 0) { SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "nfq_handle_packet error %" PRId32 "", ret); } } } #endif /* OS_WIN32 */ /** * \brief Main NFQ reading Loop function */ TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); NFQThreadVars *ntv = (NFQThreadVars *)data; NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index); ntv->slot = ((TmSlot *) slot)->slot_next; while(1) { if (suricata_ctl_flags != 0) { NFQMutexLock(nq); if (nq->qh) { nfq_destroy_queue(nq->qh); nq->qh = NULL; } NFQMutexUnlock(nq); break; } NFQRecvPkt(nq, ntv); SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); } /** * \brief NFQ receive module stats printing function */ void ReceiveNFQThreadExitStats(ThreadVars *tv, void *data) { NFQThreadVars *ntv = (NFQThreadVars *)data; NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index); #ifdef COUNTERS SCLogInfo("(%s) Pkts %" PRIu32 ", Bytes %" PRIu64 ", Errors %" PRIu32 "", tv->name, nq->pkts, nq->bytes, nq->errs); SCLogInfo("Pkts accepted %"PRIu32", dropped %"PRIu32", replaced %"PRIu32, nq->accepted, nq->dropped, nq->replaced); #endif } /** * \brief NFQ verdict function */ TmEcode NFQSetVerdict(Packet *p) { int iter = 0; int ret = 0; uint32_t verdict = NF_ACCEPT; /* we could also have a direct pointer but we need to have a ref counf in this case */ NFQQueueVars *t = nfq_q + p->nfq_v.nfq_index; /** \todo add a test on validity of the entry NFQQueueVars could have been * wipeout */ /* can't verdict a "fake" packet */ if (p->flags & PKT_PSEUDO_STREAM_END) { return TM_ECODE_OK; } //printf("%p verdicting on queue %" PRIu32 "\n", t, t->queue_num); NFQMutexLock(t); if (t->qh == NULL) { /* Somebody has started a clean-up, we leave */ NFQMutexUnlock(t); return TM_ECODE_OK; } if (PACKET_TEST_ACTION(p, ACTION_DROP)) { verdict = NF_DROP; #ifdef COUNTERS t->dropped++; #endif /* COUNTERS */ } else { switch (nfq_config.mode) { default: case NFQ_ACCEPT_MODE: verdict = NF_ACCEPT; break; case NFQ_REPEAT_MODE: verdict = NF_REPEAT; break; case NFQ_ROUTE_MODE: verdict = ((uint32_t) NF_QUEUE) | nfq_config.next_queue; break; } if (p->flags & PKT_STREAM_MODIFIED) { #ifdef COUNTERS t->replaced++; #endif /* COUNTERS */ } #ifdef COUNTERS t->accepted++; #endif /* COUNTERS */ } do { switch (nfq_config.mode) { default: case NFQ_ACCEPT_MODE: case NFQ_ROUTE_MODE: if (p->flags & PKT_MARK_MODIFIED) { #ifdef HAVE_NFQ_SET_VERDICT2 if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, p->nfq_v.mark, GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, p->nfq_v.mark, 0, NULL); } #else /* fall back to old function */ if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, htonl(p->nfq_v.mark), GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, htonl(p->nfq_v.mark), 0, NULL); } #endif /* HAVE_NFQ_SET_VERDICT2 */ } else { if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL); } } break; case NFQ_REPEAT_MODE: #ifdef HAVE_NFQ_SET_VERDICT2 if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, (nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask), GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, (nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask), 0, NULL); } #else /* fall back to old function */ if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)), GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)), 0, NULL); } #endif /* HAVE_NFQ_SET_VERDICT2 */ break; } } while ((ret < 0) && (iter++ < NFQ_VERDICT_RETRY_TIME)); NFQMutexUnlock(t); if (ret < 0) { SCLogWarning(SC_ERR_NFQ_SET_VERDICT, "nfq_set_verdict of %p failed %" PRId32 "", p, ret); return TM_ECODE_FAILED; } return TM_ECODE_OK; } /** * \brief NFQ verdict module packet entry function */ TmEcode VerdictNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { int ret; /* if this is a tunnel packet we check if we are ready to verdict * already. */ if (IS_TUNNEL_PKT(p)) { char verdict = 1; //printf("VerdictNFQ: tunnel pkt: %p %s\n", p, p->root ? "upper layer" : "root"); SCMutex *m = p->root ? &p->root->tunnel_mutex : &p->tunnel_mutex; SCMutexLock(m); /* if there are more tunnel packets than ready to verdict packets, * we won't verdict this one */ if (TUNNEL_PKT_TPR(p) > TUNNEL_PKT_RTV(p)) { SCLogDebug("not ready to verdict yet: TUNNEL_PKT_TPR(p) > " "TUNNEL_PKT_RTV(p) = %" PRId32 " > %" PRId32, TUNNEL_PKT_TPR(p), TUNNEL_PKT_RTV(p)); verdict = 0; } SCMutexUnlock(m); /* don't verdict if we are not ready */ if (verdict == 1) { //printf("VerdictNFQ: setting verdict\n"); ret = NFQSetVerdict(p->root ? p->root : p); if (ret != TM_ECODE_OK) return ret; } else { TUNNEL_INCR_PKT_RTV(p); } } else { /* no tunnel, verdict normally */ ret = NFQSetVerdict(p); if (ret != TM_ECODE_OK) return ret; } return TM_ECODE_OK; } /** * \brief Decode a packet coming from NFQ */ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p); IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0); #endif if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if(IPV6_GET_RAW_VER(ip6h) == 6) { SCLogDebug("IPv6 packet"); DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else { SCLogDebug("packet unsupported by NFQ, first byte: %02x", *GET_PKT_DATA(p)); } return TM_ECODE_OK; } /** * \brief Initialize the NFQ Decode threadvars */ TmEcode DecodeNFQThreadInit(ThreadVars *tv, void *initdata, void **data) { DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if (dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; return TM_ECODE_OK; } #endif /* NFQ */ suricata-1.4.7/src/detect-engine-content-inspection.c0000644000000000000000000005205412253546156017533 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Performs content inspection on any buffer supplied. */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "detect-content.h" #include "detect-pcre.h" #include "detect-isdataat.h" #include "detect-bytetest.h" #include "detect-bytejump.h" #include "detect-byte-extract.h" #include "detect-replace.h" #include "detect-engine-content-inspection.h" #include "detect-uricontent.h" #include "detect-urilen.h" #include "detect-luajit.h" #include "app-layer-dcerpc.h" #include "util-spm.h" #include "util-spm-bm.h" #include "util-debug.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" /** * \brief Run the actual payload match functions * * The following keywords are inspected: * - content, including all the http and dce modified contents * - isdaatat * - pcre * - bytejump * - bytetest * - byte_extract * - urilen * - * * All keywords are evaluated against the buffer with buffer_len. * * For accounting the last match in relative matching the * det_ctx->buffer_offset int is used. * * \param de_ctx Detection engine context * \param det_ctx Detection engine thread context * \param s Signature to inspect * \param sm SigMatch to inspect * \param f Flow (for pcre flowvar storage) * \param buffer Ptr to the buffer to inspect * \param buffer_len Length of the payload * \param stream_start_offset Indicates the start of the current buffer in * the whole buffer stream inspected. This * applies if the current buffer is inspected * in chunks. * \param inspection_mode Refers to the engine inspection mode we are currently * inspecting. Can be payload, stream, one of the http * buffer inspection modes or dce inspection mode. * \param data Used to send some custom data. For example in * payload inspection mode, data contains packet ptr, * and under dce inspection mode, contains dce state. * * \retval 0 no match * \retval 1 match */ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t inspection_mode, void *data) { SCEnter(); det_ctx->inspection_recursion_counter++; if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) { det_ctx->discontinue_matching = 1; SCReturnInt(0); } if (sm == NULL || buffer_len == 0) { SCReturnInt(0); } /* \todo unify this which is phase 2 of payload inspection unification */ if (sm->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)sm->ctx; SCLogDebug("inspecting content %"PRIu32" buffer_len %"PRIu32, cd->id, buffer_len); /* we might have already have this content matched by the mpm. * (if there is any other reason why we'd want to avoid checking * it here, please fill it in) */ //if (cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED) { // goto match; //} /* rule parsers should take care of this */ #ifdef DEBUG BUG_ON(cd->depth != 0 && cd->depth <= cd->offset); #endif /* search for our pattern, checking the matches recursively. * if we match we look for the next SigMatch as well */ uint8_t *found = NULL; uint32_t offset = 0; uint32_t depth = buffer_len; uint32_t prev_offset = 0; /**< used in recursive searching */ uint32_t prev_buffer_offset = det_ctx->buffer_offset; do { if ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN)) { SCLogDebug("det_ctx->buffer_offset %"PRIu32, det_ctx->buffer_offset); offset = prev_buffer_offset; depth = buffer_len; int distance = cd->distance; if (cd->flags & DETECT_CONTENT_DISTANCE) { if (cd->flags & DETECT_CONTENT_DISTANCE_BE) { distance = det_ctx->bj_values[cd->distance]; } if (distance < 0 && (uint32_t)(abs(distance)) > offset) offset = 0; else offset += distance; SCLogDebug("cd->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32, distance, offset, depth); } if (cd->flags & DETECT_CONTENT_WITHIN) { if (cd->flags & DETECT_CONTENT_WITHIN_BE) { if ((int32_t)depth > (int32_t)(prev_buffer_offset + det_ctx->bj_values[cd->within] + distance)) { depth = prev_buffer_offset + det_ctx->bj_values[cd->within] + distance; } } else { if ((int32_t)depth > (int32_t)(prev_buffer_offset + cd->within + distance)) { depth = prev_buffer_offset + cd->within + distance; } SCLogDebug("cd->within %"PRIi32", det_ctx->buffer_offset %"PRIu32", depth %"PRIu32, cd->within, prev_buffer_offset, depth); } if (stream_start_offset != 0 && prev_buffer_offset == 0) { if (depth <= stream_start_offset) { SCReturnInt(0); } else if (depth >= (stream_start_offset + buffer_len)) { ; } else { depth = depth - stream_start_offset; } } } if (cd->flags & DETECT_CONTENT_DEPTH_BE) { if ((det_ctx->bj_values[cd->depth] + prev_buffer_offset) < depth) { depth = prev_buffer_offset + det_ctx->bj_values[cd->depth]; } } else { if (cd->depth != 0) { if ((cd->depth + prev_buffer_offset) < depth) { depth = prev_buffer_offset + cd->depth; } SCLogDebug("cd->depth %"PRIu32", depth %"PRIu32, cd->depth, depth); } } if (cd->flags & DETECT_CONTENT_OFFSET_BE) { if (det_ctx->bj_values[cd->offset] > offset) offset = det_ctx->bj_values[cd->offset]; } else { if (cd->offset > offset) { offset = cd->offset; SCLogDebug("setting offset %"PRIu32, offset); } } } else { /* implied no relative matches */ /* set depth */ if (cd->flags & DETECT_CONTENT_DEPTH_BE) { depth = det_ctx->bj_values[cd->depth]; } else { if (cd->depth != 0) { depth = cd->depth; } } if (stream_start_offset != 0 && cd->flags & DETECT_CONTENT_DEPTH) { if (depth <= stream_start_offset) { SCReturnInt(0); } else if (depth >= (stream_start_offset + buffer_len)) { ; } else { depth = depth - stream_start_offset; } } /* set offset */ if (cd->flags & DETECT_CONTENT_OFFSET_BE) offset = det_ctx->bj_values[cd->offset]; else offset = cd->offset; prev_buffer_offset = 0; } /* update offset with prev_offset if we're searching for * matches after the first occurence. */ SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, offset, prev_offset); if (prev_offset != 0) offset = prev_offset; SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth); if (depth > buffer_len) depth = buffer_len; /* if offset is bigger than depth we can never match on a pattern. * We can however, "match" on a negated pattern. */ if (offset > depth || depth == 0) { if (cd->flags & DETECT_CONTENT_NEGATED) { goto match; } else { SCReturnInt(0); } } uint8_t *sbuffer = buffer + offset; uint32_t sbuffer_len = depth - offset; uint32_t match_offset = 0; SCLogDebug("sbuffer_len %"PRIu32, sbuffer_len); #ifdef DEBUG BUG_ON(sbuffer_len > buffer_len); #endif /* \todo Add another optimization here. If cd->content_len is * greater than sbuffer_len found is anyways NULL */ /* do the actual search */ if (cd->flags & DETECT_CONTENT_NOCASE) found = BoyerMooreNocase(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx->bmGs, cd->bm_ctx->bmBc); else found = BoyerMoore(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx->bmGs, cd->bm_ctx->bmBc); /* next we evaluate the result in combination with the * negation flag. */ SCLogDebug("found %p cd negated %s", found, cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); if (found == NULL && !(cd->flags & DETECT_CONTENT_NEGATED)) { SCReturnInt(0); } else if (found == NULL && (cd->flags & DETECT_CONTENT_NEGATED)) { goto match; } else if (found != NULL && (cd->flags & DETECT_CONTENT_NEGATED)) { SCLogDebug("content %"PRIu32" matched at offset %"PRIu32", but negated so no match", cd->id, match_offset); /* don't bother carrying recursive matches now, for preceding * relative keywords */ if (DETECT_CONTENT_IS_SINGLE(cd)) det_ctx->discontinue_matching = 1; SCReturnInt(0); } else { match_offset = (uint32_t)((found - buffer) + cd->content_len); SCLogDebug("content %"PRIu32" matched at offset %"PRIu32"", cd->id, match_offset); det_ctx->buffer_offset = match_offset; /* Match branch, add replace to the list if needed */ if (cd->flags & DETECT_CONTENT_REPLACE) { if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) { /* we will need to replace content if match is confirmed */ det_ctx->replist = DetectReplaceAddToList(det_ctx->replist, found, cd); } else { SCLogWarning(SC_ERR_INVALID_VALUE, "Can't modify payload without packet"); } } if (!(cd->flags & DETECT_CONTENT_RELATIVE_NEXT)) { SCLogDebug("no relative match coming up, so this is a match"); goto match; } /* bail out if we have no next match. Technically this is an * error, as the current cd has the DETECT_CONTENT_RELATIVE_NEXT * flag set. */ if (sm->next == NULL) { SCReturnInt(0); } SCLogDebug("content %"PRIu32, cd->id); /* see if the next buffer keywords match. If not, we will * search for another occurence of this content and see * if the others match then until we run out of matches */ int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } if (det_ctx->discontinue_matching) SCReturnInt(0); /* set the previous match offset to the start of this match + 1 */ prev_offset = (match_offset - (cd->content_len - 1)); SCLogDebug("trying to see if there is another match after prev_offset %"PRIu32, prev_offset); } } while(1); } else if (sm->type == DETECT_ISDATAAT) { SCLogDebug("inspecting isdataat"); DetectIsdataatData *id = (DetectIsdataatData *)sm->ctx; if (id->flags & ISDATAAT_RELATIVE) { if (det_ctx->buffer_offset + id->dataat > buffer_len) { SCLogDebug("det_ctx->buffer_offset + id->dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + id->dataat, buffer_len); if (id->flags & ISDATAAT_NEGATED) goto match; SCReturnInt(0); } else { SCLogDebug("relative isdataat match"); if (id->flags & ISDATAAT_NEGATED) SCReturnInt(0); goto match; } } else { if (id->dataat < buffer_len) { SCLogDebug("absolute isdataat match"); if (id->flags & ISDATAAT_NEGATED) SCReturnInt(0); goto match; } else { SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", buffer_len %"PRIu32"", id->dataat, buffer_len); if (id->flags & ISDATAAT_NEGATED) goto match; SCReturnInt(0); } } } else if (sm->type == DETECT_PCRE) { SCLogDebug("inspecting pcre"); DetectPcreData *pe = (DetectPcreData *)sm->ctx; uint32_t prev_buffer_offset = det_ctx->buffer_offset; uint32_t prev_offset = 0; int r = 0; det_ctx->pcre_match_start_offset = 0; do { Packet *p = NULL; if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) p = (Packet *)data; r = DetectPcrePayloadMatch(det_ctx, s, sm, p, f, buffer, buffer_len); if (r == 0) { SCReturnInt(0); } if (!(pe->flags & DETECT_PCRE_RELATIVE_NEXT)) { SCLogDebug("no relative match coming up, so this is a match"); goto match; } /* save it, in case we need to do a pcre match once again */ prev_offset = det_ctx->pcre_match_start_offset; /* see if the next payload keywords match. If not, we will * search for another occurence of this pcre and see * if the others match, until we run out of matches */ r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } if (det_ctx->discontinue_matching) SCReturnInt(0); det_ctx->buffer_offset = prev_buffer_offset; det_ctx->pcre_match_start_offset = prev_offset; } while (1); } else if (sm->type == DETECT_BYTETEST) { DetectBytetestData *btd = (DetectBytetestData *)sm->ctx; uint8_t flags = btd->flags; int32_t offset = btd->offset; uint64_t value = btd->value; if (flags & DETECT_BYTETEST_OFFSET_BE) { offset = det_ctx->bj_values[offset]; } if (flags & DETECT_BYTETEST_VALUE_BE) { value = det_ctx->bj_values[value]; } /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if (flags & DETECT_BYTETEST_DCE) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ flags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ? DETECT_BYTETEST_LITTLE: 0); } if (DetectBytetestDoMatch(det_ctx, s, sm, buffer, buffer_len, flags, offset, value) != 1) { SCReturnInt(0); } goto match; } else if (sm->type == DETECT_BYTEJUMP) { DetectBytejumpData *bjd = (DetectBytejumpData *)sm->ctx; uint8_t flags = bjd->flags; int32_t offset = bjd->offset; if (flags & DETECT_BYTEJUMP_OFFSET_BE) { offset = det_ctx->bj_values[offset]; } /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if (flags & DETECT_BYTEJUMP_DCE) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ flags |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] & 0x10) ? DETECT_BYTEJUMP_LITTLE: 0); } if (DetectBytejumpDoMatch(det_ctx, s, sm, buffer, buffer_len, flags, offset) != 1) { SCReturnInt(0); } goto match; } else if (sm->type == DETECT_BYTE_EXTRACT) { DetectByteExtractData *bed = (DetectByteExtractData *)sm->ctx; uint8_t endian = bed->endian; /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) && endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ endian |= ((dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] == 0x10) ? DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG); } if (DetectByteExtractDoMatch(det_ctx, sm, s, buffer, buffer_len, &det_ctx->bj_values[bed->local_id], endian) != 1) { SCReturnInt(0); } goto match; /* we should never get here, but bail out just in case */ } else if (sm->type == DETECT_AL_URILEN) { SCLogDebug("inspecting uri len"); int r = 0; DetectUrilenData *urilend = (DetectUrilenData *) sm->ctx; switch (urilend->mode) { case DETECT_URILEN_EQ: if (buffer_len == urilend->urilen1) r = 1; break; case DETECT_URILEN_LT: if (buffer_len < urilend->urilen1) r = 1; break; case DETECT_URILEN_GT: if (buffer_len > urilend->urilen1) r = 1; break; case DETECT_URILEN_RA: if (buffer_len > urilend->urilen1 && buffer_len < urilend->urilen2) { r = 1; } break; } if (r == 1) { goto match; } SCReturnInt(0); #ifdef HAVE_LUAJIT } else if (sm->type == DETECT_LUAJIT) { if (DetectLuajitMatchBuffer(det_ctx, s, sm, buffer, buffer_len, det_ctx->buffer_offset) != 1) { SCReturnInt(0); } goto match; #endif } else { SCLogDebug("sm->type %u", sm->type); #ifdef DEBUG BUG_ON(1); #endif } SCReturnInt(0); match: /* this sigmatch matched, inspect the next one. If it was the last, * the buffer portion of the signature matched. */ if (sm->next != NULL) { int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); SCReturnInt(r); } else { SCReturnInt(1); } } suricata-1.4.7/src/util-pool.h0000644000000000000000000000366312253546156013132 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup utilpool * * @{ */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_POOL_H__ #define __UTIL_POOL_H__ #define POOL_BUCKET_PREALLOCATED (1 << 0) /* pool bucket structure */ typedef struct PoolBucket_ { void *data; uint8_t flags; struct PoolBucket_ *next; } PoolBucket; /* pool structure */ typedef struct Pool_ { uint32_t max_buckets; uint32_t preallocated; uint32_t allocated; PoolBucket *alloc_list; uint32_t alloc_list_size; PoolBucket *empty_list; uint32_t empty_list_size; PoolBucket *pb_buffer; void *data_buffer; int data_buffer_size; void *(*Alloc)(); int (*Init)(void *, void *); void *InitData; void (*Cleanup)(void *); void (*Free)(void *); uint32_t elt_size; uint32_t outstanding; uint32_t max_outstanding; } Pool; /* prototypes */ Pool* PoolInit(uint32_t, uint32_t, uint32_t, void *(*Alloc)(), int (*Init)(void *, void *), void *, void (*Cleanup)(void *), void (*Free)(void *)); void PoolFree(Pool *); void PoolPrint(Pool *); void PoolPrintSaturation(Pool *p); void *PoolGet(Pool *); void PoolReturn(Pool *, void *); void PoolRegisterTests(void); #endif /* __UTIL_POOL_H__ */ /** * @} */ suricata-1.4.7/src/util-strlcpyu.c0000644000000000000000000000512212253546156014031 00000000000000/* * Copyright (c) 1998 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* $Id: strlcpyu.c,v 1.4 2003/10/20 15:03:27 chrisgreen Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_STRLCPY #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(dst, src, siz) char *dst; const char *src; size_t siz; { register char *d = dst; register const char *s = src; register size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif suricata-1.4.7/src/decode-udp.c0000644000000000000000000001541612253546156013211 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Victor Julien * * Decode UDP */ #include "suricata-common.h" #include "decode.h" #include "decode-udp.h" #include "decode-teredo.h" #include "decode-events.h" #include "util-unittest.h" #include "util-debug.h" #include "flow.h" #include "app-layer.h" static int DecodeUDPPacket(ThreadVars *t, Packet *p, uint8_t *pkt, uint16_t len) { if (len < UDP_HEADER_LEN) { ENGINE_SET_EVENT(p, UDP_HLEN_TOO_SMALL); return -1; } p->udph = (UDPHdr *)pkt; if (len < UDP_GET_LEN(p)) { ENGINE_SET_EVENT(p, UDP_PKT_TOO_SMALL); return -1; } if (len != UDP_GET_LEN(p)) { ENGINE_SET_EVENT(p, UDP_HLEN_INVALID); return -1; } SET_UDP_SRC_PORT(p,&p->sp); SET_UDP_DST_PORT(p,&p->dp); p->payload = pkt + UDP_HEADER_LEN; p->payload_len = len - UDP_HEADER_LEN; p->proto = IPPROTO_UDP; return 0; } void DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_udp, tv->sc_perf_pca); if (DecodeUDPPacket(tv, p,pkt,len) < 0) { p->udph = NULL; return; } SCLogDebug("UDP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 "", UDP_GET_SRC_PORT(p), UDP_GET_DST_PORT(p), UDP_HEADER_LEN, p->payload_len); if (DecodeTeredo(tv, dtv, p, p->payload, p->payload_len, pq) == 1) { /* Here we have a Teredo packet and don't need to handle app * layer */ FlowHandlePacket(tv, p); return; } /* Flow is an integral part of us */ FlowHandlePacket(tv, p); /* handle the app layer part of the UDP packet payload */ if (p->flow != NULL) { AppLayerHandleUdp(&dtv->udp_dp_ctx, p->flow, p); } return; } #ifdef UNITTESTS static int UDPV4CalculateValidChecksumtest01(void) { uint16_t csum = 0; uint8_t raw_ipshdr[] = { 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x3}; uint8_t raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x26}; csum = *( ((uint16_t *)raw_udp) + 3); return (csum == UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_udp, sizeof(raw_udp))); } static int UDPV4CalculateInvalidChecksumtest02(void) { uint16_t csum = 0; uint8_t raw_ipshdr[] = { 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x3}; uint8_t raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x27}; csum = *( ((uint16_t *)raw_udp) + 3); return (csum == UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, (uint16_t *)raw_udp, sizeof(raw_udp))); } static int UDPV6CalculateValidChecksumtest03(void) { uint16_t csum = 0; static uint8_t raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x00}; csum = *( ((uint16_t *)(raw_ipv6 + 60))); return (csum == UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 20)); } static int UDPV6CalculateInvalidChecksumtest04(void) { uint16_t csum = 0; static uint8_t raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x01}; csum = *( ((uint16_t *)(raw_ipv6 + 60))); return (csum == UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 20)); } #endif /* UNITTESTS */ void DecodeUDPV4RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("UDPV4CalculateValidChecksumtest01", UDPV4CalculateValidChecksumtest01, 1); UtRegisterTest("UDPV4CalculateInvalidChecksumtest02", UDPV4CalculateInvalidChecksumtest02, 0); UtRegisterTest("UDPV6CalculateValidChecksumtest03", UDPV6CalculateValidChecksumtest03, 1); UtRegisterTest("UDPV6CalculateInvalidChecksumtest04", UDPV6CalculateInvalidChecksumtest04, 0); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/util-mpm-b3g.c0000644000000000000000000015371612253546156013423 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * 3 gram implementation of the (S)BNDMq pattern matching algorithm. * * Ideas: * - B3g does a full match in the search of up to 'm' characters, * in case of a case insensitive search we could say it's match if * the pattern is of len 'm' or just compare the rest of the chars. * * \todo Try to get the S0 calculation right. */ #include "suricata-common.h" #include "suricata.h" #include "util-bloomfilter.h" #include "util-mpm-b3g.h" #include "util-unittest.h" #include "conf.h" #include "util-debug.h" #define INIT_HASH_SIZE 65536 #ifdef B3G_COUNTERS #define COUNT(counter) \ (counter) #else #define COUNT(counter) #endif /* B3G_COUNTERS */ static uint32_t b3g_hash_size = 0; static uint32_t b3g_bloom_size = 0; static uint8_t b3g_hash_shift = 0; static uint8_t b3g_hash_shift2 = 0; static void *b3g_func; #define B3G_HASH(a,b,c) (((a) << b3g_hash_shift) | (b) << (b3g_hash_shift2) |(c)) void B3gInitCtx (MpmCtx *, int); void B3gThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void B3gDestroyCtx(MpmCtx *); void B3gThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); int B3gAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B3gAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B3gPreparePatterns(MpmCtx *); uint32_t B3gSearchWrap(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t B3gSearch1(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t B3gSearch2(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t B3gSearch12(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t B3gSearch(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t B3gSearchBNDMq(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); void B3gPrintInfo(MpmCtx *); void B3gPrintSearchStats(MpmThreadCtx *); void B3gRegisterTests(void); /** \todo XXX Unused??? */ #if 0 static void prt (uint8_t *buf, uint16_t buflen) { uint16_t i; for (i = 0; i < buflen; i++) { if (isprint(buf[i])) printf("%c", buf[i]); else printf("\\x%" PRIX32, buf[i]); } //printf("\n"); } #endif void B3gPrintInfo(MpmCtx *mpm_ctx) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; printf("MPM B3g Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); printf(" Sizeofs:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" B3gCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B3gCtx)); printf(" B3gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B3gPattern)); printf(" B3gHashItem %" PRIuMAX "\n", (uintmax_t)sizeof(B3gHashItem)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Hash size: %" PRIu32 "\n", ctx->hash_size); printf("\n"); } static inline B3gPattern *B3gAllocPattern(MpmCtx *mpm_ctx) { B3gPattern *p = SCMalloc(sizeof(B3gPattern)); if (unlikely(p == NULL)) return NULL; memset(p,0,sizeof(B3gPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B3gPattern); return p; } static inline B3gHashItem * B3gAllocHashItem(MpmCtx *mpm_ctx) { B3gHashItem *hi = SCMalloc(sizeof(B3gHashItem)); if (unlikely(hi == NULL)) return NULL; memset(hi,0,sizeof(B3gHashItem)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B3gHashItem); return hi; } static void B3gHashFree(MpmCtx *mpm_ctx, B3gHashItem *hi) { if (hi == NULL) return; B3gHashItem *t = hi->nxt; B3gHashFree(mpm_ctx, t); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B3gHashItem); SCFree(hi); } static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) { d[i] = u8_tolower(s[i]); } } /* * INIT HASH START */ static inline uint32_t B3gInitHash(B3gPattern *p) { uint32_t hash = p->len * p->cs[0]; if (p->len > 1) hash += p->cs[1]; return (hash % INIT_HASH_SIZE); } static inline uint32_t B3gInitHashRaw(uint8_t *pat, uint16_t patlen) { uint32_t hash = patlen * pat[0]; if (patlen > 1) hash += pat[1]; return (hash % INIT_HASH_SIZE); } static inline int B3gInitHashAdd(B3gCtx *ctx, B3gPattern *p) { uint32_t hash = B3gInitHash(p); //printf("B3gInitHashAdd: %" PRIu32 "\n", hash); if (ctx->init_hash[hash] == NULL) { ctx->init_hash[hash] = p; //printf("B3gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); return 0; } B3gPattern *tt = NULL; B3gPattern *t = ctx->init_hash[hash]; /* get the list tail */ do { tt = t; t = t->next; } while (t != NULL); tt->next = p; //printf("B3gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); return 0; } static inline int B3gCmpPattern(B3gPattern *p, uint8_t *pat, uint16_t patlen, char flags); static inline B3gPattern *B3gInitHashLookup(B3gCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) { uint32_t hash = B3gInitHashRaw(pat,patlen); //printf("B3gInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); if (ctx->init_hash[hash] == NULL) { return NULL; } B3gPattern *t = ctx->init_hash[hash]; for ( ; t != NULL; t = t->next) { if (B3gCmpPattern(t,pat,patlen,flags) == 1) return t; } return NULL; } static inline int B3gCmpPattern(B3gPattern *p, uint8_t *pat, uint16_t patlen, char flags) { if (p->len != patlen) return 0; if (p->flags != flags) return 0; if (memcmp(p->cs, pat, patlen) != 0) return 0; return 1; } /* * INIT HASH END */ void B3gFreePattern(MpmCtx *mpm_ctx, B3gPattern *p) { if (p && p->cs && p->cs != p->ci) { SCFree(p->cs); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p && p->ci) { SCFree(p->ci); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p) { SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B3gPattern); } } /* B3gAddPattern * * pat: ptr to the pattern * patlen: length of the pattern * nocase: nocase flag: 1 enabled, 0 disable * pid: pattern id * sid: signature id (internal id) */ static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; if (patlen == 0) return 0; /* get a memory piece */ B3gPattern *p = B3gInitHashLookup(ctx, pat, patlen, flags); if (p == NULL) { p = B3gAllocPattern(mpm_ctx); if (p == NULL) goto error; p->len = patlen; p->flags = flags; p->id = pid; /* setup the case insensitive part of the pattern */ p->ci = SCMalloc(patlen); if (p->ci == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy_tolower(p->ci, pat, patlen); /* setup the case sensitive part of the pattern */ if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* nocase means no difference between cs and ci */ p->cs = p->ci; } else { if (memcmp(p->ci,pat,p->len) == 0) { /* no diff between cs and ci: pat is lowercase */ p->cs = p->ci; } else { p->cs = SCMalloc(patlen); if (p->cs == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->cs, pat, patlen); } } //printf("B3gAddPattern: ci \""); prt(p->ci,p->len); //printf("\" cs \""); prt(p->cs,p->len); //printf("\" prefix_ci %" PRIu32 ", prefix_cs %" PRIu32 "\n", p->prefix_ci, p->prefix_cs); /* put in the pattern hash */ B3gInitHashAdd(ctx, p); if (mpm_ctx->pattern_cnt == 65535) { printf("Max search words reached\n"); exit(1); } mpm_ctx->pattern_cnt++; if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } return 0; error: B3gFreePattern(mpm_ctx, p); return -1; } int B3gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return B3gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int B3gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return B3gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } static uint32_t B3gBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint16_t i; uint32_t hash = (uint32_t)u8_tolower(*d); for (i = 1; i < datalen; i++) { d++; hash += (u8_tolower(*d)) ^ i; } hash <<= (iter+1); hash %= hash_size; return hash; } static void B3gPrepareHash(MpmCtx *mpm_ctx) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; uint16_t i; uint16_t idx = 0; uint8_t idx8 = 0; ctx->hash = (B3gHashItem **)SCMalloc(sizeof(B3gHashItem *) * ctx->hash_size); if (ctx->hash == NULL) goto error; memset(ctx->hash, 0, sizeof(B3gHashItem *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B3gHashItem *) * ctx->hash_size); /* 2 byte pattern hash */ ctx->hash2 = (B3gHashItem **)SCMalloc(sizeof(B3gHashItem *) * ctx->hash_size); if (ctx->hash2 == NULL) goto error; memset(ctx->hash2, 0, sizeof(B3gHashItem *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B3gHashItem *) * ctx->hash_size); /* alloc the pminlen array */ ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); if (ctx->pminlen == NULL) goto error; memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if(ctx->parray[i]->len == 1) { idx8 = (uint8_t)ctx->parray[i]->ci[0]; if (ctx->hash1[idx8].flags == 0) { ctx->hash1[idx8].idx = i; ctx->hash1[idx8].flags |= 0x01; } else { B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; /* Append this HashItem to the list */ B3gHashItem *thi = &ctx->hash1[idx8]; while (thi->nxt) thi = thi->nxt; thi->nxt = hi; } ctx->pat_1_cnt++; } else if(ctx->parray[i]->len == 2) { idx = (uint16_t)(ctx->parray[i]->ci[0] << b3g_hash_shift | ctx->parray[i]->ci[1]); if (ctx->hash2[idx] == NULL) { B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; ctx->hash2[idx] = hi; } else { B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; /* Append this HashItem to the list */ B3gHashItem *thi = ctx->hash2[idx]; while (thi->nxt) thi = thi->nxt; thi->nxt = hi; } ctx->pat_2_cnt++; } else { idx = B3G_HASH(ctx->parray[i]->ci[ctx->m - 3], ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); //printf("idx %" PRIu32 ", %c.%c.%c\n", idx, ctx->parray[i]->ci[ctx->m - 3], ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); if (ctx->hash[idx] == NULL) { B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; ctx->pminlen[idx] = ctx->parray[i]->len; ctx->hash[idx] = hi; } else { B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; if (ctx->parray[i]->len < ctx->pminlen[idx]) ctx->pminlen[idx] = ctx->parray[i]->len; /* Append this HashItem to the list */ B3gHashItem *thi = ctx->hash[idx]; while (thi->nxt) thi = thi->nxt; thi->nxt = hi; } ctx->pat_x_cnt++; } } /* alloc the bloom array */ ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); if (ctx->bloom == NULL) goto error; memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); uint32_t h; for (h = 0; h < ctx->hash_size; h++) { B3gHashItem *hi = ctx->hash[h]; if (hi == NULL) continue; ctx->bloom[h] = BloomFilterInit(b3g_bloom_size, 2, B3gBloomHash); if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); if (ctx->pminlen[h] > 8) ctx->pminlen[h] = 8; B3gHashItem *thi = hi; do { BloomFilterAdd(ctx->bloom[h], ctx->parray[thi->idx]->ci, ctx->pminlen[h]); thi = thi->nxt; } while (thi != NULL); } return; error: return; } int B3gBuildMatchArray(MpmCtx *mpm_ctx) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; ctx->B3G = SCMalloc(sizeof(B3G_TYPE) * ctx->hash_size); if (ctx->B3G == NULL) return -1; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B3G_TYPE) * ctx->hash_size); memset(ctx->B3G,0, b3g_hash_size * sizeof(B3G_TYPE)); uint32_t j; uint32_t a; /* fill the match array */ for (j = 0; j <= (ctx->m - B3G_Q); j++) { for (a = 0; a < mpm_ctx->pattern_cnt; a++) { if (ctx->parray[a]->len < ctx->m) continue; uint16_t h = B3G_HASH(u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1]), u8_tolower(ctx->parray[a]->ci[j+2])); //printf("B3gBuildMatchArray: h %" PRIu32 ", %c.%c.%c\n", h, u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1]), u8_tolower(ctx->parray[a]->ci[j+2])); ctx->B3G[h] = ctx->B3G[h] | (1 << (ctx->m - j)); } } ctx->s0 = 1; return 0; } int B3gPreparePatterns(MpmCtx *mpm_ctx) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; /* alloc the pattern array */ ctx->parray = (B3gPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); if (ctx->parray == NULL) goto error; memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; for (i = 0; i < INIT_HASH_SIZE; i++) { B3gPattern *node = ctx->init_hash[i], *nnode = NULL; for ( ; node != NULL; ) { nnode = node->next; node->next = NULL; ctx->parray[p] = node; p++; node = nnode; } } /* we no longer need the hash, so free it's memory */ SCFree(ctx->init_hash); ctx->init_hash = NULL; /* set 'm' to the smallest pattern size */ ctx->m = mpm_ctx->minlen; /* make sure 'm' stays in bounds m can be max WORD_SIZE - 1 */ if (ctx->m >= B3G_WORD_SIZE) { ctx->m = B3G_WORD_SIZE - 1; } if (ctx->m < 3) ctx->m = 3; ctx->hash_size = b3g_hash_size; B3gPrepareHash(mpm_ctx); B3gBuildMatchArray(mpm_ctx); if (ctx->pat_1_cnt) { ctx->Search = B3gSearch1; if (ctx->pat_2_cnt) { ctx->Search = B3gSearch12; ctx->MBSearch = b3g_func; } ctx->MBSearch = b3g_func; } else if (ctx->pat_2_cnt) { ctx->Search = B3gSearch2; ctx->MBSearch = b3g_func; } return 0; error: return -1; } void B3gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef B3G_COUNTERS B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; printf("B3g Thread Search stats (tctx %p)\n", tctx); printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); printf("Avg pminlen: %0.2f\n\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); #endif /* B3G_COUNTERS */ } static inline int memcmp_lowercase(uint8_t *s1, uint8_t *s2, uint16_t n) { size_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ for (i = n - 1; i; i--) { if (u8_tolower(*(s2+i)) != s1[i]) return 1; } return 0; } /** * \brief Function to get the user defined values for b3g algorithm from the * config file 'suricata.yaml' */ void B3gGetConfig() { ConfNode *b3g_conf; const char *hash_val = NULL; const char *bloom_val = NULL; const char *algo = NULL; /* init defaults */ b3g_hash_size = HASHSIZE_LOW; b3g_bloom_size = BLOOMSIZE_MEDIUM; b3g_func = B3G_SEARCHFUNC; ConfNode *pm = ConfGetNode("pattern-matcher"); if (pm != NULL) { TAILQ_FOREACH(b3g_conf, &pm->head, next) { if (strncmp(b3g_conf->val, "b3g", 3) == 0) { algo = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, "algo"); hash_val = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, "hash_size"); bloom_val = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, "bf_size"); if (algo != NULL) { if (strcmp(algo, "B3gSearch") == 0) { b3g_func = B3gSearch; } else if (strcmp(algo, "B3gSearchBNDMq") == 0) { b3g_func = B3gSearchBNDMq; } } if (hash_val != NULL) { b3g_hash_size = MpmGetHashSize(hash_val); switch (b3g_hash_size) { case HASHSIZE_LOWEST: b3g_hash_shift = B3G_HASHSHIFT_LOWEST; b3g_hash_shift2 = B3G_HASHSHIFT_LOWEST2; break; case HASHSIZE_LOW: b3g_hash_shift = B3G_HASHSHIFT_LOW; b3g_hash_shift2 = B3G_HASHSHIFT_LOW2; break; case HASHSIZE_MEDIUM: b3g_hash_shift = B3G_HASHSHIFT_MEDIUM; b3g_hash_shift2 = B3G_HASHSHIFT_MEDIUM2; break; case HASHSIZE_HIGH: b3g_hash_shift = B3G_HASHSHIFT_HIGH; b3g_hash_shift2 = B3G_HASHSHIFT_HIGH2; break; case HASHSIZE_HIGHER: b3g_hash_shift = B3G_HASHSHIFT_HIGHER; b3g_hash_shift2 = B3G_HASHSHIFT_HIGHER2; break; case HASHSIZE_MAX: b3g_hash_shift = B3G_HASHSHIFT_MAX; b3g_hash_shift2 = B3G_HASHSHIFT_MAX2; break; } } if (bloom_val != NULL) b3g_bloom_size = MpmGetBloomSize(bloom_val); SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", b3g_hash_size, b3g_bloom_size); } } } } void B3gInitCtx (MpmCtx *mpm_ctx, int module_handle) { //printf("B3gInitCtx: mpm_ctx %p\n", mpm_ctx); mpm_ctx->ctx = SCMalloc(sizeof(B3gCtx)); if (mpm_ctx->ctx == NULL) return; memset(mpm_ctx->ctx, 0, sizeof(B3gCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B3gCtx); /* initialize the hash we use to speed up pattern insertions */ B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; ctx->init_hash = SCMalloc(sizeof(B3gPattern *) * INIT_HASH_SIZE); if (ctx->init_hash == NULL) return; memset(ctx->init_hash, 0, sizeof(B3gPattern *) * INIT_HASH_SIZE); /* Initialize the defaults value from the config file. The given check make sure that we query config file only once for config values */ if (b3g_hash_size == 0) B3gGetConfig(); /* init default */ ctx->Search = b3g_func; } void B3gDestroyCtx(MpmCtx *mpm_ctx) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->init_hash) { SCFree(ctx->init_hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B3gPattern *)); } if (ctx->parray) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { B3gFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B3gPattern)); } if (ctx->B3G) { SCFree(ctx->B3G); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B3G_TYPE) * ctx->hash_size); } if (ctx->bloom) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); BloomFilterFree(ctx->bloom[h]); } SCFree(ctx->bloom); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); } if (ctx->hash) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->hash[h] == NULL) continue; B3gHashFree(mpm_ctx, ctx->hash[h]); } SCFree(ctx->hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B3gHashItem) * ctx->hash_size); } if (ctx->hash2) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->hash2[h] == NULL) continue; B3gHashFree(mpm_ctx, ctx->hash2[h]); } SCFree(ctx->hash2); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B3gHashItem) * ctx->hash_size); } if (ctx->pminlen) { SCFree(ctx->pminlen); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B3gCtx); } void B3gThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); if (sizeof(B3gThreadCtx) > 0) { /* size can be 0 when optimized */ mpm_thread_ctx->ctx = SCMalloc(sizeof(B3gThreadCtx)); if (mpm_thread_ctx->ctx == NULL) return; memset(mpm_thread_ctx->ctx, 0, sizeof(B3gThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(B3gThreadCtx); } } void B3gThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { B3gThreadCtx *ctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; B3gPrintSearchStats(mpm_thread_ctx); if (ctx != NULL) { /* can be NULL when optimized */ mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(B3gThreadCtx); SCFree(mpm_thread_ctx->ctx); } } inline uint32_t B3gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; return ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen); } uint32_t B3gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; #ifdef B3G_COUNTERS B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = ctx->m - B3G_Q + 1, matches = 0; B3G_TYPE d; COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (uint32_t)(buflen - B3G_Q + 1)) { uint16_t h = B3G_HASH(u8_tolower(buf[pos - 1]), u8_tolower(buf[pos]),u8_tolower(buf[pos + 1])); d = ctx->B3G[h]; if (d != 0) { COUNT(tctx->stat_d0++); uint32_t j = pos; uint32_t first = pos - (ctx->m - B3G_Q + 1); do { j = j - 1; if (d >= (uint32_t)(1 << (ctx->m - 1))) { if (j > first) pos = j; else { /* get our patterns from the hash */ h = B3G_HASH(u8_tolower(buf[j + ctx->m - 3]), u8_tolower(buf[j + ctx->m - 2]),u8_tolower(buf[j + ctx->m - 1])); if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((buflen - j) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf+j, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); goto skip_loop; } } } B3gHashItem *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->nxt) { COUNT(tctx->stat_d0_hashloop++); B3gPattern *p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (buflen - j < p->len) continue; if (memcmp_lowercase(p->ci, buf+j, p->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (buflen - j < p->len) continue; if (memcmp(p->cs, buf+j, p->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } skip_loop: //printf("output at pos %" PRIu32 ": ", j); prt(buf + (j), ctx->m); printf("\n"); ; // gcc doesn't like the goto label without this :-S } } if (j == 0) break; h = B3G_HASH(u8_tolower(buf[j - 1]), u8_tolower(buf[j - 0]),u8_tolower(buf[j+1])); d = (d << 1) & ctx->B3G[h]; } while (d != 0); } COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (ctx->m - B3G_Q + 1)); pos = pos + ctx->m - B3G_Q + 1; } return matches; } uint32_t B3gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; #ifdef B3G_COUNTERS B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = 0, matches = 0; B3G_TYPE d; uint32_t j; COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (buflen - ctx->m)) { j = ctx->m - 2; d = ~0; do { uint16_t h = B3G_HASH(u8_tolower(buf[pos + j - 1]), u8_tolower(buf[pos + j - 0]),u8_tolower(buf[pos + j + 1])); d = ((d << 1) & ctx->B3G[h]); j = j - 1; } while (d != 0 && j != 0); /* (partial) match, move on to verification */ if (d != 0) { COUNT(tctx->stat_d0++); //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); /* get our patterns from the hash */ uint16_t h = B3G_HASH(u8_tolower(buf[pos + ctx->m - 3]), u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((buflen - pos) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf+pos, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); goto skip_loop; } } } B3gHashItem *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->nxt) { COUNT(tctx->stat_d0_hashloop++); B3gPattern *p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (buflen - pos < p->len) continue; if (memcmp_lowercase(p->ci, buf+pos, p->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (buflen - pos < p->len) continue; if (memcmp(p->cs, buf+pos, p->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } skip_loop: pos = pos + 1; //pos = pos + ctx->s0; } else { COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (j + 1)); pos = pos + j + 1; } } //printf("Total matches %" PRIu32 "\n", matches); return matches; } uint32_t B3gSearch12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; B3gPattern *p; B3gHashItem *thi, *hi; //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint8_t h8 = u8_tolower(*buf); hi = &ctx->hash1[h8]; if (hi->flags & 0x01) { for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } else { if (*buf == p->cs[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } } } if (buf != bufend) { /* save one conversion by reusing h8 */ uint16_t h16 = (uint16_t)(h8 << b3g_hash_shift | u8_tolower(*(buf+1))); hi = ctx->hash2[h16]; for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } else { if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } } } buf += 1; } //printf("B3gSearch12: after 1/2byte cnt %" PRIu32 "\n", cnt); if (ctx->pat_x_cnt > 0) { /* Pass bufmin on because buf no longer points to the * start of the buffer. */ cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); //printf("B3gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); } return cnt; } uint32_t B3gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; B3gPattern *p; B3gHashItem *thi, *hi; if (buflen < 2) return 0; //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint16_t h = u8_tolower(*buf) << b3g_hash_shift | u8_tolower(*(buf+1)); hi = ctx->hash2[h]; if (hi != NULL) { for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; if (p->len != 2) continue; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (u8_tolower(*buf) == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B3gSearch1)\n"); if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) cnt++; } } else { if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B3gSearch1)\n"); if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) cnt++; } } } } buf += 1; } //printf("B3gSearch2: after 2byte cnt %" PRIu32 "\n", cnt); if (ctx->pat_x_cnt) { /* Pass bufmin on because buf no longer points to the * start of the buffer. */ cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); //printf("B3gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); } return cnt; } uint32_t B3gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; B3gPattern *p; B3gHashItem *thi, *hi; if (buflen == 0) return 0; //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint8_t h = u8_tolower(*buf); hi = &ctx->hash1[h]; if (hi->flags & 0x01) { for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; if (p->len != 1) continue; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (u8_tolower(*buf) == p->ci[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } else { if (*buf == p->cs[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } } } buf += 1; } if (ctx->pat_2_cnt) { /* Pass bufmin on because buf no longer points to the * start of the buffer. */ cnt += ctx->MBSearch2(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); } else if (ctx->pat_x_cnt) { cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); } return cnt; } void MpmB3gRegister (void) { mpm_table[MPM_B3G].name = "b3g"; mpm_table[MPM_B3G].max_pattern_length = B3G_WORD_SIZE; mpm_table[MPM_B3G].InitCtx = B3gInitCtx; mpm_table[MPM_B3G].InitThreadCtx = B3gThreadInitCtx; mpm_table[MPM_B3G].DestroyCtx = B3gDestroyCtx; mpm_table[MPM_B3G].DestroyThreadCtx = B3gThreadDestroyCtx; mpm_table[MPM_B3G].AddPattern = B3gAddPatternCS; mpm_table[MPM_B3G].AddPatternNocase = B3gAddPatternCI; mpm_table[MPM_B3G].Prepare = B3gPreparePatterns; mpm_table[MPM_B3G].Search = B3gSearchWrap; mpm_table[MPM_B3G].Cleanup = NULL; mpm_table[MPM_B3G].PrintCtx = B3gPrintInfo; mpm_table[MPM_B3G].PrintThreadCtx = B3gPrintSearchStats; mpm_table[MPM_B3G].RegisterUnittests = B3gRegisterTests; } /* * TESTS */ #ifdef UNITTESTS static int B3gTestInit01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); if (ctx->m == 4) result = 1; else printf("4 != %" PRIu32 " ", ctx->m); B3gDestroyCtx(&mpm_ctx); return result; } #if 0 static int B3gTestS0Init01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); if (ctx->s0 == 4) result = 1; else printf("4 != %" PRIu32 " ", ctx->s0); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestS0Init02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); if (ctx->s0 == 2) result = 1; else printf("2 != %" PRIu32 " ", ctx->s0); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestS0Init03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); if (ctx->s0 == 1) result = 1; else printf("1 != %" PRIu32 " ", ctx->s0); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestS0Init04 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); if (ctx->s0 == 2) result = 1; else printf("2 != %" PRIu32 " ", ctx->s0); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestS0Init05 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); if (ctx->s0 == 3) result = 1; else printf("3 != %" PRIu32 " ", ctx->s0); B3gDestroyCtx(&mpm_ctx); return result; } #endif static int B3gTestSearch01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } /* test patterns longer than 'm'. M is 4 here. */ static int B3gTestSearch04 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } /* case insensitive test patterns longer than 'm'. M is 4 here. */ static int B3gTestSearch05 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ B3gAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch06 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch07 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch08 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch09 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch10 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); char *input = "012345679012345679012345679012345679012345679012345679" "012345679012345679012345679012345679abcdefgh0123456790" "123456790123456790123456790123456790123456790123456790" "12345679012345679012345679"; uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)input, strlen(input)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch11 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } static int B3gTestSearch12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B3G, -1); B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; B3gAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ B3gAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ B3gPreparePatterns(&mpm_ctx); B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B3gDestroyCtx(&mpm_ctx); return result; } #endif /* UNITTESTS */ void B3gRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("B3gTestInit01", B3gTestInit01, 1); /* UtRegisterTest("B3gTestS0Init01", B3gTestS0Init01, 1); UtRegisterTest("B3gTestS0Init02", B3gTestS0Init02, 1); UtRegisterTest("B3gTestS0Init03", B3gTestS0Init03, 1); UtRegisterTest("B3gTestS0Init04", B3gTestS0Init04, 1); UtRegisterTest("B3gTestS0Init05", B3gTestS0Init05, 1); */ UtRegisterTest("B3gTestSearch01", B3gTestSearch01, 1); UtRegisterTest("B3gTestSearch02", B3gTestSearch02, 1); UtRegisterTest("B3gTestSearch03", B3gTestSearch03, 1); UtRegisterTest("B3gTestSearch04", B3gTestSearch04, 1); UtRegisterTest("B3gTestSearch05", B3gTestSearch05, 1); UtRegisterTest("B3gTestSearch06", B3gTestSearch06, 1); UtRegisterTest("B3gTestSearch07", B3gTestSearch07, 1); UtRegisterTest("B3gTestSearch08", B3gTestSearch08, 1); UtRegisterTest("B3gTestSearch09", B3gTestSearch09, 1); UtRegisterTest("B3gTestSearch10", B3gTestSearch10, 1); UtRegisterTest("B3gTestSearch11", B3gTestSearch11, 1); UtRegisterTest("B3gTestSearch12", B3gTestSearch12, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-pkt-data.h0000644000000000000000000000163512253546156014156 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_PKTDATA_H__ #define __DETECT_PKTDATA_H__ /* prototypes */ void DetectPktDataRegister (void); #endif /* __DETECT_PKTDATA_H__ */ suricata-1.4.7/src/suricata.h0000644000000000000000000001153412253546156013015 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \mainpage Doxygen documentation * * \section intro_sec Introduction * * The Suricata Engine is an Open Source Next Generation Intrusion Detection * and Prevention Engine. This engine is not intended to just replace or * emulate the existing tools in the industry, but will bring new ideas and * technologies to the field. * * \section dev_doc Developer documentation * * You've reach the automically generated documentation of Suricata. This * document contains information about architecture and code structure. It * is attended for developers wanting to understand or contribute to Suricata. * * \subsection modules Modules * * Documentation is generate from comments placed in all parts of the code. * But you will also find some groups describing specific functional parts: * - \ref decode * - \ref httplayer * - \ref sigstate * - \ref threshold * * \section archi Architecture * * \subsection datastruct Data structures * * Regarding matching, there is three main data structures which are: * - ::Packet: Data relative to an individual packet with information about * linked structure such as the ::Flow the ::Packet belongs to. * - ::Flow: Information about a flow for example a TCP session * - ::StreamMsg: structure containing the reassembled data * * \subsection runmode Running mode * * Suricata is multithreaded and running modes define how the different * threads are working together. You can see util-runmodes.c for example * of running mode. */ /** * \file * * \author Victor Julien */ #ifndef __SURICATA_H__ #define __SURICATA_H__ #include "suricata-common.h" #include "packet-queue.h" #include "data-queue.h" /* the name of our binary */ #define PROG_NAME "Suricata" #define PROG_VER "1.4.7" /* workaround SPlint error (don't know __gnuc_va_list) */ #ifdef S_SPLINT_S # include # define CONFIG_DIR "/etc/suricata" #endif #define DEFAULT_CONF_FILE CONFIG_DIR "/suricata.yaml" #define DEFAULT_PID_DIR LOCAL_STATE_DIR "/run/" #define DEFAULT_PID_BASENAME "suricata.pid" #define DEFAULT_PID_FILENAME DEFAULT_PID_DIR DEFAULT_PID_BASENAME /* runtime engine control flags */ #define SURICATA_STOP (1 << 0) /**< gracefully stop the engine: process all outstanding packets first */ #define SURICATA_KILL (1 << 1) /**< shut down asap, discarding outstanding packets. */ #define SURICATA_DONE (1 << 2) /**< packets capture ended */ /* Engine stage/status*/ enum { SURICATA_INIT = 0, SURICATA_RUNTIME, SURICATA_DEINIT }; /* Engine is acting as */ enum { ENGINE_MODE_IDS, ENGINE_MODE_IPS, }; /** You can use this macros to set/check if we have real drop capabilities */ #define SET_ENGINE_MODE_IPS(engine_mode) do { \ (engine_mode) = ENGINE_MODE_IPS; \ } while (0) #define SET_ENGINE_MODE_IDS(engine_mode) do { \ (engine_mode) = ENGINE_MODE_IDS; \ } while (0) #define IS_ENGINE_MODE_IPS(engine_mode) ((engine_mode) == ENGINE_MODE_IPS) #define IS_ENGINE_MODE_IDS(engine_mode) ((engine_mode) == ENGINE_MODE_IDS) /* queue's between various other threads * XXX move to the TmQueue structure later */ PacketQueue trans_q[256]; SCDQDataQueue data_queues[256]; /* memset to zeros, and mutex init! */ void GlobalInits(); extern uint8_t suricata_ctl_flags; /* uppercase to lowercase conversion lookup table */ uint8_t g_u8_lowercasetable[256]; extern char *conf_filename; /* marco to do the actual lookup */ //#define u8_tolower(c) g_u8_lowercasetable[(c)] // these 2 are slower: //#define u8_tolower(c) ((c) >= 'A' && (c) <= 'Z') ? g_u8_lowercasetable[(c)] : (c) //#define u8_tolower(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) + ('a' - 'A')) : (c)) /* this is faster than the table lookup */ #include #define u8_tolower(c) tolower((uint8_t)(c)) void EngineStop(void); void EngineKill(void); void EngineDone(void); /* live rule swap required this to be made static */ void SignalHandlerSigusr2(int); void SignalHandlerSigusr2EngineShutdown(int); void SignalHandlerSigusr2Idle(int sig); int RunmodeIsUnittests(void); int RunmodeGetCurrent(void); extern int run_mode; #endif /* __SURICATA_H__ */ suricata-1.4.7/src/counters.h0000644000000000000000000002032712253546156013044 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __COUNTERS_H__ #define __COUNTERS_H__ /* forward declaration of the ThreadVars structure */ struct ThreadVars_; /* Time interval for syncing the local counters with the global ones */ #define SC_PERF_WUT_TTS 3 /* Time interval at which the mgmt thread o/p the stats */ #define SC_PERF_MGMTT_TTS 8 /** * \brief Data type for different kind of Perf counters that can be registered */ enum { SC_PERF_TYPE_UINT64, SC_PERF_TYPE_DOUBLE, SC_PERF_TYPE_STR, SC_PERF_TYPE_MAX, }; /** * \brief Different kinds of qualifier that can be used to modify the behaviour * of the Perf counter to be registered */ enum { SC_PERF_TYPE_Q_NORMAL = 0x01, SC_PERF_TYPE_Q_AVERAGE = 0x02, SC_PERF_TYPE_Q_MAXIMUM = 0x04, SC_PERF_TYPE_Q_TIMEBASED = 0x08, SC_PERF_TYPE_Q_MAX = 0x10, }; /** * \brief Different output interfaces made available by the Perf counter API */ enum { SC_PERF_IFACE_FILE, SC_PERF_IFACE_CONSOLE, SC_PERF_IFACE_SYSLOG, SC_PERF_IFACE_MAX, }; /** * \brief Name of the counter. Basically like a primary key for a counter */ typedef struct SCPerfCounterName_ { char *cname; char *tm_name; } SCPerfCounterName; /** * \brief Holds the counter value, type, and the size of the type */ typedef struct SCPerfCounterValue_ { void *cvalue; uint32_t size; uint32_t type; } SCPerfCounterValue; /** * \brief Container that holds the type qualifier for a counter */ typedef struct SCPerfCounterTypeQ_ { int type; int hours; int minutes; int seconds; int total_secs; /* the time interval that corresponds to the value stored for this counter. * Used for time_based_counters(tbc). This represents the time period over * which the value in this counter was accumulated. */ uint8_t tbc_secs; } SCPerfCounterTypeQ; /** * \brief Container to hold the counter variable */ typedef struct SCPerfCounter_ { SCPerfCounterName *name; SCPerfCounterValue *value; /* local id for this counter in this tm */ uint16_t id; /* description of this counter */ char *desc; /* no of times the local counter has been synced with this counter */ uint64_t updated; /* flag that indicates if this counter should be displayed or not */ int disp; /* counter qualifier */ SCPerfCounterTypeQ *type_q; /* the next perfcounter for this tv's tm instance */ struct SCPerfCounter_ *next; } SCPerfCounter; /** * \brief Holds the Perf Context for a ThreadVars instance */ typedef struct SCPerfContext_ { /* pointer to the head of a list of counters assigned under this context */ SCPerfCounter *head; /* flag set by the wakeup thread, to inform the client threads to sync */ uint32_t perf_flag; /* holds the total no of counters already assigned for this perf context */ uint16_t curr_id; /* mutex to prevent simultaneous access during update_counter/output_stat */ SCMutex m; } SCPerfContext; /** * \brief Node elements used by the SCPerfCounterArray(PCA) Node */ typedef struct SCPCAElem_ { /* pointer to the PerfCounter that corresponds to this PCAElem */ SCPerfCounter *pc; /* counter id of the above counter(pc) */ uint16_t id; union { uint64_t ui64_cnt; double d_cnt; }; /* no of times the local counter has been updated */ uint64_t syncs; /* indicates the times syncs has overflowed */ uint64_t wrapped_syncs; /* timestamp to indicate the time, when the counter was last used to update * the global counter. It is used for timebased counter calculations */ struct timeval ts; } SCPCAElem; /** * \brief The SCPerfCounterArray used to hold the local version of the counters * registered */ typedef struct SCPerfCounterArray_ { /* points to the array holding PCAElems */ SCPCAElem *head; /* no of PCAElems in head */ uint32_t size; } SCPerfCounterArray; /** * \brief Holds multiple instances of the same TM together, used when the stats * have to be clubbed based on TM, before being sent out */ typedef struct SCPerfClubTMInst_ { char *tm_name; SCPerfContext **head; uint32_t size; struct SCPerfClubTMInst_ *next; } SCPerfClubTMInst; /** * \brief Holds the output interface context for the counter api */ typedef struct SCPerfOPIfaceContext_ { /* the iface to be used for output */ uint32_t iface; /* the file to be used if the output interface used is SC_PERF_IFACE_FILE */ char *file; /* more interfaces to be supported later. For now just a file */ FILE *fp; /* indicates whether the counter values from the same threading module * should be clubbed or not, during output */ uint32_t club_tm; SCPerfClubTMInst *pctmi; SCMutex pctmi_lock; } SCPerfOPIfaceContext; /* the initialization functions */ void SCPerfInitCounterApi(void); void SCPerfSpawnThreads(void); /* the ThreadVars counter registration functions */ uint16_t SCPerfTVRegisterCounter(char *, struct ThreadVars_ *, int, char *); uint16_t SCPerfTVRegisterAvgCounter(char *, struct ThreadVars_ *, int, char *); uint16_t SCPerfTVRegisterMaxCounter(char *, struct ThreadVars_ *, int, char *); uint16_t SCPerfTVRegisterIntervalCounter(char *, struct ThreadVars_ *, int, char *, char *); /* the non-ThreadVars counter registration functions */ uint16_t SCPerfRegisterCounter(char *, char *, int, char *, SCPerfContext *); uint16_t SCPerfRegisterAvgCounter(char *, char *, int, char *, SCPerfContext *); uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfContext *); uint16_t SCPerfRegisterIntervalCounter(char *, char *, int, char *, SCPerfContext *, char *); /* utility functions */ int SCPerfAddToClubbedTMTable(char *, SCPerfContext *); SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t, uint16_t, SCPerfContext *); SCPerfCounterArray * SCPerfGetAllCountersArray(SCPerfContext *); int SCPerfCounterDisplay(uint16_t, SCPerfContext *, int); int SCPerfUpdateCounterArray(SCPerfCounterArray *, SCPerfContext *, int); double SCPerfGetLocalCounterValue(uint16_t, SCPerfCounterArray *); void SCPerfOutputCounters(void); /* functions used to free the resources alloted by the Perf counter API */ void SCPerfReleaseResources(void); void SCPerfReleasePerfCounterS(SCPerfCounter *); void SCPerfReleasePCA(SCPerfCounterArray *); void SCPerfCounterSetUI64(uint16_t, SCPerfCounterArray *, uint64_t); void SCPerfCounterSetDouble(uint16_t, SCPerfCounterArray *, double); void SCPerfCounterIncr(uint16_t, SCPerfCounterArray *); void SCPerfRegisterTests(void); /* functions used to update local counter values */ void SCPerfCounterAddUI64(uint16_t, SCPerfCounterArray *, uint64_t); void SCPerfCounterAddDouble(uint16_t, SCPerfCounterArray *, double); #define SCPerfSyncCounters(tv, reset_lc) \ SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->sc_perf_pctx, (reset_lc)); \ #define SCPerfSyncCountersIfSignalled(tv, reset_lc) \ do { \ if ((tv)->sc_perf_pctx.perf_flag == 1) { \ SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->sc_perf_pctx, (reset_lc)); \ } \ } while (0) #ifdef BUILD_UNIX_SOCKET #include TmEcode SCPerfOutputCounterSocket(json_t *cmd, json_t *answer, void *data); #endif #endif /* __COUNTERS_H__ */ suricata-1.4.7/src/util-mpm-ac-gfbs.h0000644000000000000000000000602112253546156014241 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * */ #define SC_AC_GFBS_STATE_TYPE_U16 uint16_t #define SC_AC_GFBS_STATE_TYPE_U32 uint32_t typedef struct SCACGfbsPattern_ { /* length of the pattern */ uint16_t len; /* flags decribing the pattern */ uint8_t flags; /* holds the original pattern that was added */ uint8_t *original_pat; /* case sensitive */ uint8_t *cs; /* case INsensitive */ uint8_t *ci; /* pattern id */ uint32_t id; struct SCACGfbsPattern_ *next; } SCACGfbsPattern; typedef struct SCACGfbsPatternList_ { uint8_t *cs; uint16_t patlen; uint16_t case_state; } SCACGfbsPatternList; typedef struct SCACGfbsOutputTable_ { /* list of pattern sids */ uint32_t *pids; /* no of entries we have in pids */ uint32_t no_of_entries; } SCACGfbsOutputTable; typedef struct SCACGfbsGotoTableMod_ { /* each of these below declarations will be of type uint32_t, if the state * count exceeds 65535, the maximum value a 16 bit unsigned var can hold */ /* no of entries stored below */ uint16_t no_of_entries; /* the ascii codes over which we have state transitions */ uint16_t *ascii_codes; /* the states that correspond to the ascii_codes above */ uint16_t *states; } SCACGfbsGotoTableMod_; typedef struct SCACGfbsCtx_ { /* hash used during ctx initialization */ SCACGfbsPattern **init_hash; /* pattern arrays. We need this only during the goto table creation phase */ SCACGfbsPattern **parray; /* no of states used by ac */ int32_t state_count; /* the modified goto_table */ uint8_t *goto_table_mod; uint8_t **goto_table_mod_pointers; /* goto_table, failure table and output table. Needed to create state_table. * Will be freed, once we have created the goto_table_mod */ int32_t (*goto_table)[256]; int32_t *failure_table; SCACGfbsOutputTable *output_table; SCACGfbsPatternList *pid_pat_list; /* the size of each state */ uint16_t single_state_size; uint16_t max_pat_id; } SCACGfbsCtx; typedef struct SCACGfbsThreadCtx_ { /* the total calls we make to the search function */ uint32_t total_calls; /* the total patterns that we ended up matching against */ uint64_t total_matches; } SCACGfbsThreadCtx; void MpmACGfbsRegister(void); suricata-1.4.7/src/app-layer-ssl.h0000644000000000000000000001071012253546156013666 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * \author Pierre Chifflier * */ #ifndef __APP_LAYER_SSL_H__ #define __APP_LAYER_SSL_H__ #include "decode-events.h" #include "queue.h" enum { /* TLS protocol messages */ TLS_DECODER_EVENT_INVALID_SSLV2_HEADER, TLS_DECODER_EVENT_INVALID_TLS_HEADER, TLS_DECODER_EVENT_INVALID_RECORD_TYPE, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE, /* Certificates decoding messages */ TLS_DECODER_EVENT_INVALID_CERTIFICATE, TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT, TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT, TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH, TLS_DECODER_EVENT_CERTIFICATE_INVALID_STRING, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED, TLS_DECODER_EVENT_INVALID_SSL_RECORD, }; /* Flag to indicate that server will now on send encrypted msgs */ #define SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC 0x0001 /* Flag to indicate that client will now on send encrypted msgs */ #define SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC 0x0002 #define SSL_AL_FLAG_CHANGE_CIPHER_SPEC 0x0004 /* SSL related flags */ #define SSL_AL_FLAG_SSL_CLIENT_HS 0x0008 #define SSL_AL_FLAG_SSL_SERVER_HS 0x0010 #define SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY 0x0020 #define SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED 0x0040 #define SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED 0x0080 #define SSL_AL_FLAG_SSL_NO_SESSION_ID 0x0100 /* flags specific to detect-ssl-state keyword */ #define SSL_AL_FLAG_STATE_CLIENT_HELLO 0x0200 #define SSL_AL_FLAG_STATE_SERVER_HELLO 0x0400 #define SSL_AL_FLAG_STATE_CLIENT_KEYX 0x0800 #define SSL_AL_FLAG_STATE_SERVER_KEYX 0x1000 #define SSL_AL_FLAG_STATE_UNKNOWN 0x2000 #define SSL_TLS_LOG_PEM (1 << 0) /* SSL versions. We'll use a unified format for all, with the top byte * holding the major version and the lower byte the minor version */ enum { TLS_VERSION_UNKNOWN = 0x0000, SSL_VERSION_2 = 0x0200, SSL_VERSION_3 = 0x0300, TLS_VERSION_10 = 0x0301, TLS_VERSION_11 = 0x0302, TLS_VERSION_12 = 0x0303, }; typedef struct SSLCertsChain_ { uint8_t *cert_data; uint32_t cert_len; TAILQ_ENTRY(SSLCertsChain_) next; } SSLCertsChain; typedef struct SSLStateConnp_ { /* record length */ uint32_t record_length; /* record length's length for SSLv2 */ uint32_t record_lengths_length; /* offset of the beginning of the current message (including header) */ uint32_t message_start; uint32_t message_length; uint16_t version; uint8_t content_type; uint8_t handshake_type; uint32_t handshake_length; /* the no of bytes processed in the currently parsed record */ uint16_t bytes_processed; /* the no of bytes processed in the currently parsed handshake */ uint16_t hs_bytes_processed; /* sslv2 client hello session id length */ uint16_t session_id_length; char *cert0_subject; char *cert0_issuerdn; char *cert0_fingerprint; uint8_t *cert_input; uint32_t cert_input_len; TAILQ_HEAD(, SSLCertsChain_) certs; uint32_t cert_log_flag; /* buffer for the tls record. * We use a malloced buffer, if the record is fragmented */ uint8_t *trec; uint32_t trec_len; uint32_t trec_pos; } SSLStateConnp; /** * \brief SSLv[2.0|3.[0|1|2|3]] state structure. * * Structure to store the SSL state values. */ typedef struct SSLState_ { Flow *f; /* holds some state flags we need */ uint32_t flags; SSLStateConnp *curr_connp; SSLStateConnp client_connp; SSLStateConnp server_connp; } SSLState; void RegisterSSLParsers(void); void SSLParserRegisterTests(void); #endif /* __APP_LAYER_SSL_H__ */ suricata-1.4.7/src/stream-tcp-sack.c0000644000000000000000000005533612253546156014203 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Stream engine TCP SACK handling. */ #include "suricata-common.h" #include "stream-tcp-private.h" #include "stream-tcp-sack.h" #include "util-unittest.h" #ifdef DEBUG void StreamTcpSackPrintList(TcpStream *stream) { StreamTcpSackRecord *rec = stream->sack_head; for (; rec != NULL; rec = rec->next) { SCLogDebug("record %8u - %8u", rec->le, rec->re); } } #endif /* DEBUG */ /** * \brief insert a SACK range * * \param le left edge in host order * \param re right edge in host order * * \retval 0 all is good * \retval -1 error */ static int StreamTcpSackInsertRange(TcpStream *stream, uint32_t le, uint32_t re) { SCLogDebug("le %u, re %u", le, re); #ifdef DEBUG StreamTcpSackPrintList(stream); #endif if (stream->sack_head != NULL) { StreamTcpSackRecord *rec; for (rec = stream->sack_head; rec != NULL; rec = rec->next) { SCLogDebug("rec %p, le %u, re %u", rec, rec->le, rec->re); if (SEQ_LT(le, rec->le)) { SCLogDebug("SEQ_LT(le, rec->le)"); if (SEQ_LT(re, rec->le)) { SCLogDebug("SEQ_LT(re, rec->le)"); // entirely before, prepend StreamTcpSackRecord *stsr = SCMalloc(sizeof(StreamTcpSackRecord)); if (unlikely(stsr == NULL)) { SCReturnInt(-1); } stsr->le = le; stsr->re = re; stsr->next = stream->sack_head; stream->sack_head = stsr; goto end; } else if (SEQ_EQ(re, rec->le)) { SCLogDebug("SEQ_EQ(re, rec->le)"); // starts before, ends on rec->le, expand rec->le = le; } else if (SEQ_GT(re, rec->le)) { SCLogDebug("SEQ_GT(re, rec->le)"); // starts before, ends beyond rec->le if (SEQ_LEQ(re, rec->re)) { SCLogDebug("SEQ_LEQ(re, rec->re)"); // ends before rec->re, expand rec->le = le; } else { // implied if (re > rec->re) SCLogDebug("implied if (re > rec->re), le set to %u", rec->re); le = rec->re; continue; } } } else if (SEQ_EQ(le, rec->le)) { SCLogDebug("SEQ_EQ(le, rec->le)"); if (SEQ_LEQ(re, rec->re)) { SCLogDebug("SEQ_LEQ(re, rec->re)"); // new record fully overlapped SCReturnInt(0); } else { // implied re > rec->re SCLogDebug("implied re > rec->re"); if (rec->next != NULL) { if (SEQ_LEQ(re, rec->next->le)) { rec->re = re; goto end; } else { rec->re = rec->next->le; le = rec->next->le; SCLogDebug("le is now %u", le); continue; } } else { rec->re = re; goto end; } } } else { // implied (le > rec->le) SCLogDebug("implied (le > rec->le)"); if (SEQ_LT(le, rec->re)) { SCLogDebug("SEQ_LT(le, rec->re))"); // new record fully overlapped if (SEQ_GT(re, rec->re)) { SCLogDebug("SEQ_GT(re, rec->re)"); if (rec->next != NULL) { if (SEQ_LEQ(re, rec->next->le)) { rec->re = re; goto end; } else { rec->re = rec->next->le; le = rec->next->le; continue; } } else { rec->re = re; goto end; } } SCLogDebug("new range fully overlapped"); SCReturnInt(0); } else if (SEQ_EQ(le, rec->re)) { SCLogDebug("here"); // new record fully overlapped //int r = StreamTcpSackInsertRange(stream, rec->re+1, re); //SCReturnInt(r); le = rec->re; continue; } else { /* implied le > rec->re */ SCLogDebug("implied le > rec->re"); if (rec->next == NULL) { SCLogDebug("rec->next == NULL"); StreamTcpSackRecord *stsr = SCMalloc(sizeof(StreamTcpSackRecord)); if (unlikely(stsr == NULL)) { SCReturnInt(-1); } stsr->le = le; stsr->re = re; stsr->next = NULL; stream->sack_tail->next = stsr; stream->sack_tail = stsr; goto end; } else { SCLogDebug("implied rec->next != NULL"); if (SEQ_LT(le, rec->next->le) && SEQ_LT(re, rec->next->le)) { SCLogDebug("SEQ_LT(le, rec->next->le) && SEQ_LT(re, rec->next->le)"); StreamTcpSackRecord *stsr = SCMalloc(sizeof(StreamTcpSackRecord)); if (unlikely(stsr == NULL)) { SCReturnInt(-1); } stsr->le = le; stsr->re = re; stsr->next = rec->next; rec->next = stsr; } else if (SEQ_LT(le, rec->next->le) && SEQ_GEQ(re, rec->next->le)) { SCLogDebug("SEQ_LT(le, rec->next->le) && SEQ_GEQ(re, rec->next->le)"); StreamTcpSackRecord *stsr = SCMalloc(sizeof(StreamTcpSackRecord)); if (unlikely(stsr == NULL)) { SCReturnInt(-1); } stsr->le = le; stsr->re = rec->next->le; stsr->next = rec->next; rec->next = stsr; le = rec->next->le; } } } } } } else { SCLogDebug("implied empty list"); StreamTcpSackRecord *stsr = SCMalloc(sizeof(StreamTcpSackRecord)); if (unlikely(stsr == NULL)) { SCReturnInt(-1); } stsr->le = le; stsr->re = re; stsr->next = NULL; stream->sack_head = stsr; stream->sack_tail = stsr; } end: SCReturnInt(0); } /** * \brief Update stream with SACK records from a TCP packet. * * \param stream The stream to update. * \param p packet to get the SACK records from * * \retval -1 error * \retval 0 ok */ int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p) { int records = TCP_GET_SACK_CNT(p); int record = 0; TCPOptSackRecord *sack_rec = (TCPOptSackRecord *)(TCP_GET_SACK_PTR(p)); for (record = 0; record < records; record++) { SCLogDebug("%p last_ack %u, left edge %u, right edge %u", sack_rec, stream->last_ack, ntohl(sack_rec->le), ntohl(sack_rec->re)); if (SEQ_LEQ(ntohl(sack_rec->re), stream->last_ack)) { SCLogDebug("record before last_ack"); goto next; } /** \todo need a metric to a check for a right edge limit */ /* if (SEQ_GT(ntohl(sack_rec->re), stream->next_seq)) { SCLogDebug("record beyond next_seq %u", stream->next_seq); goto next; } */ if (SEQ_GEQ(ntohl(sack_rec->le), ntohl(sack_rec->re))) { SCLogDebug("invalid record: le >= re"); goto next; } if (StreamTcpSackInsertRange(stream, ntohl(sack_rec->le), ntohl(sack_rec->re)) == -1) { SCReturnInt(-1); } next: sack_rec++; } #ifdef DEBUG StreamTcpSackPrintList(stream); #endif SCReturnInt(0); } void StreamTcpSackPruneList(TcpStream *stream) { SCEnter(); StreamTcpSackRecord *rec = stream->sack_head; while (rec != NULL) { if (SEQ_LT(rec->re, stream->last_ack)) { SCLogDebug("removing le %u re %u", rec->le, rec->re); if (rec->next != NULL) { stream->sack_head = rec->next; SCFree(rec); rec = stream->sack_head; continue; } else { stream->sack_head = NULL; stream->sack_tail = NULL; SCFree(rec); break; } } else if (SEQ_LT(rec->le, stream->last_ack)) { SCLogDebug("adjusting record to le %u re %u", rec->le, rec->re); /* last ack inside this record, update */ rec->le = stream->last_ack; break; } else { SCLogDebug("record beyond last_ack, nothing to do. Bailing out."); break; } } #ifdef DEBUG StreamTcpSackPrintList(stream); #endif SCReturn; } /** * \brief Free SACK list from a stream * * \param stream Stream to cleanup */ void StreamTcpSackFreeList(TcpStream *stream) { SCEnter(); StreamTcpSackRecord *rec = stream->sack_head; StreamTcpSackRecord *next = NULL; while (rec != NULL) { next = rec->next; SCFree(rec); rec = next; } stream->sack_head = NULL; stream->sack_tail = NULL; SCReturn; } #ifdef UNITTESTS /** * \test Test the insertion of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest01 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 1, 10); StreamTcpSackInsertRange(&stream, 10, 20); StreamTcpSackInsertRange(&stream, 10, 20); StreamTcpSackInsertRange(&stream, 1, 20); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 1 || stream.sack_head->re != 20) { printf("list in weird state, head le %u, re %u: ", stream.sack_head->le, stream.sack_head->re); goto end; } if (StreamTcpSackedSize(&stream) != 19) { printf("size should be 19, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the insertion of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest02 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 10, 20); StreamTcpSackInsertRange(&stream, 1, 20); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 1 || stream.sack_head->re != 20) { printf("list in weird state, head le %u, re %u: ", stream.sack_head->le, stream.sack_head->re); goto end; } if (StreamTcpSackedSize(&stream) != 19) { printf("size should be 19, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the insertion of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest03 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 10, 20); StreamTcpSackInsertRange(&stream, 5, 15); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ StreamTcpSackInsertRange(&stream, 15, 25); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 5) { goto end; } if (StreamTcpSackedSize(&stream) != 20) { printf("size should be 20, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the insertion of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest04 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 0, 20); StreamTcpSackInsertRange(&stream, 30, 50); StreamTcpSackInsertRange(&stream, 10, 25); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 0) { goto end; } if (StreamTcpSackedSize(&stream) != 45) { printf("size should be 45, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the insertion of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest05 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 0, 20); StreamTcpSackInsertRange(&stream, 30, 50); StreamTcpSackInsertRange(&stream, 10, 35); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 0) { goto end; } if (StreamTcpSackedSize(&stream) != 50) { printf("size should be 50, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the insertion of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest06 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 0, 9); StreamTcpSackInsertRange(&stream, 11, 19); StreamTcpSackInsertRange(&stream, 21, 29); StreamTcpSackInsertRange(&stream, 31, 39); StreamTcpSackInsertRange(&stream, 0, 40); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 0) { goto end; } if (StreamTcpSackedSize(&stream) != 40) { printf("size should be 40, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the pruning of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest07 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 0, 9); StreamTcpSackInsertRange(&stream, 11, 19); StreamTcpSackInsertRange(&stream, 21, 29); StreamTcpSackInsertRange(&stream, 31, 39); StreamTcpSackInsertRange(&stream, 0, 40); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 0) { goto end; } if (StreamTcpSackedSize(&stream) != 40) { printf("size should be 40, is %u: ", StreamTcpSackedSize(&stream)); goto end; } stream.last_ack = 10; StreamTcpSackPruneList(&stream); if (StreamTcpSackedSize(&stream) != 30) { printf("size should be 30, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the pruning of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest08 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 0, 9); StreamTcpSackInsertRange(&stream, 11, 19); StreamTcpSackInsertRange(&stream, 21, 29); StreamTcpSackInsertRange(&stream, 31, 39); StreamTcpSackInsertRange(&stream, 0, 40); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 0) { goto end; } if (StreamTcpSackedSize(&stream) != 40) { printf("size should be 40, is %u: ", StreamTcpSackedSize(&stream)); goto end; } stream.last_ack = 41; StreamTcpSackPruneList(&stream); if (StreamTcpSackedSize(&stream) != 0) { printf("size should be 0, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the pruning of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest09 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 0, 9); StreamTcpSackInsertRange(&stream, 11, 19); StreamTcpSackInsertRange(&stream, 21, 29); StreamTcpSackInsertRange(&stream, 31, 39); StreamTcpSackInsertRange(&stream, 0, 40); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 0) { goto end; } if (StreamTcpSackedSize(&stream) != 40) { printf("size should be 40, is %u: ", StreamTcpSackedSize(&stream)); goto end; } stream.last_ack = 39; StreamTcpSackPruneList(&stream); if (StreamTcpSackedSize(&stream) != 1) { printf("size should be 1, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the pruning of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest10 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 100, 119); StreamTcpSackInsertRange(&stream, 111, 119); StreamTcpSackInsertRange(&stream, 121, 129); StreamTcpSackInsertRange(&stream, 131, 139); StreamTcpSackInsertRange(&stream, 100, 140); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 100) { goto end; } if (StreamTcpSackedSize(&stream) != 40) { printf("size should be 40, is %u: ", StreamTcpSackedSize(&stream)); goto end; } stream.last_ack = 99; StreamTcpSackPruneList(&stream); if (StreamTcpSackedSize(&stream) != 40) { printf("size should be 40, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the pruning of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest11 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 100, 119); StreamTcpSackInsertRange(&stream, 111, 119); StreamTcpSackInsertRange(&stream, 121, 129); StreamTcpSackInsertRange(&stream, 131, 139); StreamTcpSackInsertRange(&stream, 101, 140); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 100) { goto end; } if (StreamTcpSackedSize(&stream) != 40) { printf("size should be 40, is %u: ", StreamTcpSackedSize(&stream)); goto end; } stream.last_ack = 99; StreamTcpSackPruneList(&stream); if (StreamTcpSackedSize(&stream) != 40) { printf("size should be 40, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } /** * \test Test the pruning of SACK ranges. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpSackTest12 (void) { TcpStream stream; int retval = 0; memset(&stream, 0, sizeof(stream)); StreamTcpSackInsertRange(&stream, 800, 1000); StreamTcpSackInsertRange(&stream, 700, 900); StreamTcpSackInsertRange(&stream, 600, 800); StreamTcpSackInsertRange(&stream, 500, 700); StreamTcpSackInsertRange(&stream, 100, 600); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ if (stream.sack_head->le != 100) { goto end; } if (StreamTcpSackedSize(&stream) != 900) { printf("size should be 900, is %u: ", StreamTcpSackedSize(&stream)); goto end; } StreamTcpSackInsertRange(&stream, 0, 1000); if (StreamTcpSackedSize(&stream) != 1000) { printf("size should be 1000, is %u: ", StreamTcpSackedSize(&stream)); goto end; } stream.last_ack = 500; StreamTcpSackPruneList(&stream); if (StreamTcpSackedSize(&stream) != 500) { printf("size should be 500, is %u: ", StreamTcpSackedSize(&stream)); goto end; } retval = 1; end: SCReturnInt(retval); } #endif /* UNITTESTS */ void StreamTcpSackRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("StreamTcpSackTest01 -- Insertion", StreamTcpSackTest01, 1); UtRegisterTest("StreamTcpSackTest02 -- Insertion", StreamTcpSackTest02, 1); UtRegisterTest("StreamTcpSackTest03 -- Insertion", StreamTcpSackTest03, 1); UtRegisterTest("StreamTcpSackTest04 -- Insertion", StreamTcpSackTest04, 1); UtRegisterTest("StreamTcpSackTest05 -- Insertion", StreamTcpSackTest05, 1); UtRegisterTest("StreamTcpSackTest06 -- Insertion", StreamTcpSackTest06, 1); UtRegisterTest("StreamTcpSackTest07 -- Pruning", StreamTcpSackTest07, 1); UtRegisterTest("StreamTcpSackTest08 -- Pruning", StreamTcpSackTest08, 1); UtRegisterTest("StreamTcpSackTest09 -- Pruning", StreamTcpSackTest09, 1); UtRegisterTest("StreamTcpSackTest10 -- Pruning", StreamTcpSackTest10, 1); UtRegisterTest("StreamTcpSackTest11 -- Insertion && Pruning", StreamTcpSackTest11, 1); UtRegisterTest("StreamTcpSackTest12 -- Insertion && Pruning", StreamTcpSackTest12, 1); #endif } suricata-1.4.7/src/decode-vlan.c0000644000000000000000000001444412253546156013361 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Breno Silva * * Decode 802.1q */ #include "suricata-common.h" #include "decode.h" #include "decode-vlan.h" #include "decode-events.h" #include "flow.h" #include "util-unittest.h" #include "util-debug.h" /** * \internal * \brief this function is used to decode IEEE802.1q packets * * \param tv pointer to the thread vars * \param dtv pointer code thread vars * \param p pointer to the packet struct * \param pkt pointer to the raw packet * \param len packet len * \param pq pointer to the packet queue * */ void DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); if(len < VLAN_HEADER_LEN) { ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_SMALL); return; } p->vlanh = (VLANHdr *)pkt; if(p->vlanh == NULL) return; SCLogDebug("p %p pkt %p VLAN protocol %04x VLAN PRI %d VLAN CFI %d VLAN ID %d Len: %" PRId32 "", p, pkt, GET_VLAN_PROTO(p->vlanh), GET_VLAN_PRIORITY(p->vlanh), GET_VLAN_CFI(p->vlanh), GET_VLAN_ID(p->vlanh), len); switch (GET_VLAN_PROTO(p->vlanh)) { case ETHERNET_TYPE_IP: DecodeIPV4(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_IPV6: DecodeIPV6(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_SESS: DecodePPPOESession(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_DISC: DecodePPPOEDiscovery(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_VLAN: DecodeVLAN(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; default: SCLogDebug("unknown VLAN type: %" PRIx32 "",GET_VLAN_PROTO(p->vlanh)); ENGINE_SET_EVENT(p,VLAN_UNKNOWN_TYPE); return; } return; } #ifdef UNITTESTS /** \todo Must GRE+VLAN and Multi-Vlan packets to * create more tests */ /** * \test DecodeVLANTest01 test if vlan header is too small. * * \retval 1 on success * \retval 0 on failure */ static int DecodeVLANtest01 (void) { uint8_t raw_vlan[] = { 0x00, 0x20, 0x08 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL); if(ENGINE_ISSET_EVENT(p,VLAN_HEADER_TOO_SMALL)) { SCFree(p); return 1; } SCFree(p); return 0; } /** * \test DecodeVLANTest02 test if vlan header has unknown type. * * \retval 1 on success * \retval 0 on failure */ static int DecodeVLANtest02 (void) { uint8_t raw_vlan[] = { 0x00, 0x20, 0x01, 0x00, 0x45, 0x00, 0x00, 0x34, 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, 0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15, 0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55, 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL); if(ENGINE_ISSET_EVENT(p,VLAN_UNKNOWN_TYPE)) { SCFree(p); return 1; } SCFree(p); return 0; } /** * \test DecodeVLANTest02 test a good vlan header. * * \retval 1 on success * \retval 0 on failure */ static int DecodeVLANtest03 (void) { uint8_t raw_vlan[] = { 0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, 0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15, 0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55, 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3}; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL); FlowShutdown(); if(p->vlanh == NULL) { SCFree(p); return 0; } if(ENGINE_ISSET_EVENT(p,VLAN_HEADER_TOO_SMALL)) { SCFree(p); return 0; } if(ENGINE_ISSET_EVENT(p,VLAN_UNKNOWN_TYPE)) { SCFree(p); return 0; } SCFree(p); return 1; } #endif /* UNITTESTS */ void DecodeVLANRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01, 1); UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02, 1); UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/detect-pktvar.h0000644000000000000000000000205112253546156013751 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_PKTVAR_H__ #define __DETECT_PKTVAR_H__ typedef struct DetectPktvarData_ { char *name; uint8_t *content; uint8_t content_len; uint8_t flags; } DetectPktvarData; /* prototypes */ void DetectPktvarRegister (void); #endif /* __DETECT_PKTVAR_H__ */ suricata-1.4.7/src/detect-threshold.c0000644000000000000000000012342212253546156014437 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup threshold * @{ */ /** * \file * * \author Breno Silva * * Implements the threshold keyword. * * The feature depends on what is provided * by detect-engine-threshold.c and util-threshold-config.c */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "host.h" #include "detect.h" #include "detect-parse.h" #include "flow-var.h" #include "decode-events.h" #include "stream-tcp.h" #include "detect-threshold.h" #include "detect-parse.h" #include "detect-engine-address.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-byte.h" #include "util-debug.h" #ifdef UNITTESTS #include "util-cpu.h" #endif #define PARSE_REGEX "^\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|\\d+)\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|\\d+)\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|\\d+)\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|\\d+)\\s*" static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectThresholdMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectThresholdSetup (DetectEngineCtx *, Signature *, char *); static void DetectThresholdFree(void *); /** * \brief Registration function for threshold: keyword */ void DetectThresholdRegister (void) { sigmatch_table[DETECT_THRESHOLD].name = "threshold"; sigmatch_table[DETECT_THRESHOLD].desc = "control the rule's alert frequency"; sigmatch_table[DETECT_THRESHOLD].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Rule-Thresholding#threshold"; sigmatch_table[DETECT_THRESHOLD].Match = DetectThresholdMatch; sigmatch_table[DETECT_THRESHOLD].Setup = DetectThresholdSetup; sigmatch_table[DETECT_THRESHOLD].Free = DetectThresholdFree; sigmatch_table[DETECT_THRESHOLD].RegisterTests = ThresholdRegisterTests; /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_THRESHOLD].flags |= SIGMATCH_IPONLY_COMPAT; const char *eb; int opts = 0; int eo; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } error: return; } static int DetectThresholdMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) { return 1; } /** * \internal * \brief This function is used to parse threshold options passed via threshold: keyword * * \param rawstr Pointer to the user provided threshold options * * \retval de pointer to DetectThresholdData on success * \retval NULL on failure */ static DetectThresholdData *DetectThresholdParse (char *rawstr) { DetectThresholdData *de = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr = NULL; char *args[9] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; char *copy_str = NULL, *threshold_opt = NULL; int second_found = 0, count_found = 0; int type_found = 0, track_found = 0; int second_pos = 0, count_pos = 0; uint16_t pos = 0; int i = 0; copy_str = SCStrdup(rawstr); if (unlikely(copy_str == NULL)) { goto error; } for(pos = 0, threshold_opt = strtok(copy_str,","); pos < strlen(copy_str) && threshold_opt != NULL; pos++, threshold_opt = strtok(NULL,",")) { if(strstr(threshold_opt,"count")) count_found++; if(strstr(threshold_opt,"second")) second_found++; if(strstr(threshold_opt,"type")) type_found++; if(strstr(threshold_opt,"track")) track_found++; } SCFree(copy_str); copy_str = NULL; if(count_found != 1 || second_found != 1 || type_found != 1 || track_found != 1) goto error; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 5) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); goto error; } de = SCMalloc(sizeof(DetectThresholdData)); if (unlikely(de == NULL)) goto error; memset(de,0,sizeof(DetectThresholdData)); for (i = 0; i < (ret - 1); i++) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS,i + 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i] = (char *)str_ptr; if (strncasecmp(args[i],"limit",strlen("limit")) == 0) de->type = TYPE_LIMIT; if (strncasecmp(args[i],"both",strlen("both")) == 0) de->type = TYPE_BOTH; if (strncasecmp(args[i],"threshold",strlen("threshold")) == 0) de->type = TYPE_THRESHOLD; if (strncasecmp(args[i],"by_dst",strlen("by_dst")) == 0) de->track = TRACK_DST; if (strncasecmp(args[i],"by_src",strlen("by_src")) == 0) de->track = TRACK_SRC; if (strncasecmp(args[i],"count",strlen("count")) == 0) count_pos = i+1; if (strncasecmp(args[i],"seconds",strlen("seconds")) == 0) second_pos = i+1; } if (args[count_pos] == NULL || args[second_pos] == NULL) { goto error; } if (ByteExtractStringUint32(&de->count, 10, strlen(args[count_pos]), args[count_pos]) <= 0) { goto error; } if (ByteExtractStringUint32(&de->seconds, 10, strlen(args[second_pos]), args[second_pos]) <= 0) { goto error; } for (i = 0; i < (ret - 1); i++){ if (args[i] != NULL) SCFree(args[i]); } return de; error: for (i = 0; i < (ret - 1); i++){ if (args[i] != NULL) SCFree(args[i]); } if (de != NULL) SCFree(de); return NULL; } /** * \internal * \brief this function is used to add the parsed threshold into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param rawstr pointer to the user provided threshold options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectThresholdSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectThresholdData *de = NULL; SigMatch *sm = NULL; SigMatch *tmpm = NULL; /* checks if there is a previous instance of detection_filter */ tmpm = SigMatchGetLastSMFromLists(s, 2, DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_MATCH]); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and \"threshold\" are not allowed in the same rule"); SCReturnInt(-1); } de = DetectThresholdParse(rawstr); if (de == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_THRESHOLD; sm->ctx = (void *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); return 0; error: if (de) SCFree(de); if (sm) SCFree(sm); return -1; } /** * \internal * \brief this function will free memory associated with DetectThresholdData * * \param de pointer to DetectThresholdData */ static void DetectThresholdFree(void *de_ptr) { DetectThresholdData *de = (DetectThresholdData *)de_ptr; if (de) { DetectAddressFree(de->addr); SCFree(de); } } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-threshold.h" #include "util-time.h" #include "util-hashlist.h" /** * \test ThresholdTestParse01 is a test for a valid threshold options * * \retval 1 on succces * \retval 0 on failure */ static int ThresholdTestParse01 (void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("type limit,track by_dst,count 10,seconds 60"); if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); return 1; } return 0; } /** * \test ThresholdTestParse02 is a test for a invalid threshold options * * \retval 1 on succces * \retval 0 on failure */ static int ThresholdTestParse02 (void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("type any,track by_dst,count 10,seconds 60"); if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); return 1; } return 0; } /** * \test ThresholdTestParse03 is a test for a valid threshold options in any order * * \retval 1 on succces * \retval 0 on failure */ static int ThresholdTestParse03 (void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("track by_dst, type limit, seconds 60, count 10"); if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); return 1; } return 0; } /** * \test ThresholdTestParse04 is a test for an invalid threshold options in any order * * \retval 1 on succces * \retval 0 on failure */ static int ThresholdTestParse04 (void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("count 10, track by_dst, seconds 60, type both, count 10"); if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); return 1; } return 0; } /** * \test ThresholdTestParse05 is a test for a valid threshold options in any order * * \retval 1 on succces * \retval 0 on failure */ static int ThresholdTestParse05 (void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("count 10, track by_dst, seconds 60, type both"); if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); return 1; } return 0; } /** * \test DetectThresholdTestSig1 is a test for checking the working of limit keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. * * \retval 1 on succces * \retval 0 on failure */ static int DetectThresholdTestSig1(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; HostInitConfig(HOST_QUIET); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; content:\"A\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); if (s->flags & SIG_FLAG_IPONLY) { printf("signature is ip-only: "); goto end; } DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); if (alerts != 1) { printf("alerts %"PRIi32", expected 1: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 2) { printf("alerts %"PRIi32", expected 2: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 3) { printf("alerts %"PRIi32", expected 3: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 4) { printf("alerts %"PRIi32", expected 4: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { printf("alerts %"PRIi32", expected 5: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { printf("alerts %"PRIi32", expected 5: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { printf("alerts %"PRIi32", expected 5: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { printf("alerts %"PRIi32", expected 5: ", alerts); } if(alerts == 5) result = 1; else printf("alerts %"PRIi32", expected 5: ", alerts); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); HostShutdown(); end: return result; } /** * \test DetectThresholdTestSig2 is a test for checking the working of threshold keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. * * \retval 1 on succces * \retval 0 on failure */ static int DetectThresholdTestSig2(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; HostInitConfig(HOST_QUIET); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold\"; threshold: type threshold, track by_dst, count 5, seconds 60; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts == 2) result = 1; else goto cleanup; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test DetectThresholdTestSig3 is a test for checking the working of limit keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. * * \retval 1 on succces * \retval 0 on failure */ static int DetectThresholdTestSig3(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; struct timeval ts; DetectThresholdEntry *lookup_tsh = NULL; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); Host *host = HostLookupHostFromHash(&p->dst); if (host == NULL) { printf("host not found: "); goto cleanup; } lookup_tsh = (DetectThresholdEntry *)host->threshold; if (lookup_tsh == NULL) { HostRelease(host); printf("lookup_tsh is NULL: "); goto cleanup; } HostRelease(host); TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); host = HostLookupHostFromHash(&p->dst); if (host == NULL) { printf("host not found: "); goto cleanup; } HostRelease(host); lookup_tsh = (DetectThresholdEntry *)host->threshold; if (lookup_tsh == NULL) { HostRelease(host); printf("lookup_tsh is NULL: "); goto cleanup; } alerts = lookup_tsh->current_count; if (alerts == 3) result = 1; else { printf("alerts %u != 3: ", alerts); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test DetectThresholdTestSig4 is a test for checking the working of both keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. * * \retval 1 on succces * \retval 0 on failure */ static int DetectThresholdTestSig4(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold both\"; threshold: type both, track by_dst, count 2, seconds 60; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); if (alerts == 2) result = 1; else goto cleanup; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test DetectThresholdTestSig5 is a test for checking the working of limit keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. * * \retval 1 on succces * \retval 0 on failure */ static int DetectThresholdTestSig5(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; HostInitConfig(HOST_QUIET); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); if(alerts == 10) result = 1; else { printf("alerts %d != 10: ", alerts); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } static int DetectThresholdTestSig6Ticks(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; HostInitConfig(HOST_QUIET); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); uint64_t ticks_start = 0; uint64_t ticks_end = 0; ticks_start = UtilCpuGetTicks(); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); ticks_end = UtilCpuGetTicks(); printf("test run %"PRIu64"\n", (ticks_end - ticks_start)); if(alerts == 10) result = 1; else goto cleanup; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test Test drop action being set even if thresholded */ static int DetectThresholdTestSig7(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; int drops = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type limit, track by_src, count 1, seconds 300; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; if (alerts == 1 && drops == 6) result = 1; else { if (alerts != 1) printf("alerts: %d != 1: ", alerts); if (drops != 6) printf("drops: %d != 6: ", drops); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test Test drop action being set even if thresholded */ static int DetectThresholdTestSig8(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; int drops = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type limit, track by_src, count 2, seconds 300; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; if (alerts == 2 && drops == 6) result = 1; else { if (alerts != 1) printf("alerts: %d != 1: ", alerts); if (drops != 6) printf("drops: %d != 6: ", drops); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test Test drop action being set even if thresholded */ static int DetectThresholdTestSig9(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; int drops = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type threshold, track by_src, count 3, seconds 100; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; if (alerts == 2 && drops == 2) result = 1; else { if (alerts != 2) printf("alerts: %d != 2: ", alerts); if (drops != 2) printf("drops: %d != 2: ", drops); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test Test drop action being set even if thresholded */ static int DetectThresholdTestSig10(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; int drops = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type threshold, track by_src, count 5, seconds 300; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; if (alerts == 1 && drops == 1) result = 1; else { if (alerts != 1) printf("alerts: %d != 1: ", alerts); if (drops != 1) printf("drops: %d != 1: ", drops); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test Test drop action being set even if thresholded */ static int DetectThresholdTestSig11(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; int drops = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type both, track by_src, count 3, seconds 300; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; if (alerts == 1 && drops == 4) result = 1; else { if (alerts != 1) printf("alerts: %d != 1: ", alerts); if (drops != 4) printf("drops: %d != 4: ", drops); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test Test drop action being set even if thresholded */ static int DetectThresholdTestSig12(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; int drops = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type both, track by_src, count 5, seconds 300; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; if (alerts == 1 && drops == 2) result = 1; else { if (alerts != 1) printf("alerts: %d != 1: ", alerts); if (drops != 2) printf("drops: %d != 2: ", drops); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } #endif /* UNITTESTS */ void ThresholdRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("ThresholdTestParse01", ThresholdTestParse01, 1); UtRegisterTest("ThresholdTestParse02", ThresholdTestParse02, 0); UtRegisterTest("ThresholdTestParse03", ThresholdTestParse03, 1); UtRegisterTest("ThresholdTestParse04", ThresholdTestParse04, 0); UtRegisterTest("ThresholdTestParse05", ThresholdTestParse05, 1); UtRegisterTest("DetectThresholdTestSig1", DetectThresholdTestSig1, 1); UtRegisterTest("DetectThresholdTestSig2", DetectThresholdTestSig2, 1); UtRegisterTest("DetectThresholdTestSig3", DetectThresholdTestSig3, 1); UtRegisterTest("DetectThresholdTestSig4", DetectThresholdTestSig4, 1); UtRegisterTest("DetectThresholdTestSig5", DetectThresholdTestSig5, 1); UtRegisterTest("DetectThresholdTestSig6Ticks", DetectThresholdTestSig6Ticks, 1); UtRegisterTest("DetectThresholdTestSig7", DetectThresholdTestSig7, 1); UtRegisterTest("DetectThresholdTestSig8", DetectThresholdTestSig8, 1); UtRegisterTest("DetectThresholdTestSig9", DetectThresholdTestSig9, 1); UtRegisterTest("DetectThresholdTestSig10", DetectThresholdTestSig10, 1); UtRegisterTest("DetectThresholdTestSig11", DetectThresholdTestSig11, 1); UtRegisterTest("DetectThresholdTestSig12", DetectThresholdTestSig12, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/source-pcap.c0000644000000000000000000006357112253546156013426 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Live pcap packet acquisition support */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "source-pcap.h" #include "conf.h" #include "util-debug.h" #include "util-error.h" #include "util-privs.h" #include "util-device.h" #include "util-optimize.h" #include "util-checksum.h" #include "util-ioctl.h" #include "tmqh-packetpool.h" extern uint8_t suricata_ctl_flags; #define PCAP_STATE_DOWN 0 #define PCAP_STATE_UP 1 #define PCAP_RECONNECT_TIMEOUT 500000 /** * \brief Structure to hold thread specific variables. */ typedef struct PcapThreadVars_ { /* thread specific handle */ pcap_t *pcap_handle; /* handle state */ unsigned char pcap_state; /* thread specific bpf */ struct bpf_program filter; /* ptr to string from config */ char *bpf_filter; /* data link type for the thread */ int datalink; /* counters */ uint32_t pkts; uint64_t bytes; uint32_t errs; uint16_t capture_kernel_packets; uint16_t capture_kernel_drops; uint16_t capture_kernel_ifdrops; ThreadVars *tv; TmSlot *slot; /** callback result -- set if one of the thread module failed. */ int cb_result; /* pcap buffer size */ int pcap_buffer_size; int pcap_snaplen; ChecksumValidationMode checksum_mode; #if LIBPCAP_VERSION_MAJOR == 0 char iface[PCAP_IFACE_NAME_LENGTH]; #endif LiveDevice *livedev; } PcapThreadVars; TmEcode ReceivePcapThreadInit(ThreadVars *, void *, void **); void ReceivePcapThreadExitStats(ThreadVars *, void *); TmEcode ReceivePcapThreadDeinit(ThreadVars *, void *); TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot); TmEcode DecodePcapThreadInit(ThreadVars *, void *, void **); TmEcode DecodePcap(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); /** protect pcap_compile and pcap_setfilter, as they are not thread safe: * http://seclists.org/tcpdump/2009/q1/62 */ static SCMutex pcap_bpf_compile_lock = PTHREAD_MUTEX_INITIALIZER; /** * \brief Registration Function for RecievePcap. * \todo Unit tests are needed for this module. */ void TmModuleReceivePcapRegister (void) { tmm_modules[TMM_RECEIVEPCAP].name = "ReceivePcap"; tmm_modules[TMM_RECEIVEPCAP].ThreadInit = ReceivePcapThreadInit; tmm_modules[TMM_RECEIVEPCAP].Func = NULL; tmm_modules[TMM_RECEIVEPCAP].PktAcqLoop = ReceivePcapLoop; tmm_modules[TMM_RECEIVEPCAP].ThreadExitPrintStats = ReceivePcapThreadExitStats; tmm_modules[TMM_RECEIVEPCAP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEPCAP].RegisterTests = NULL; tmm_modules[TMM_RECEIVEPCAP].cap_flags = SC_CAP_NET_RAW; tmm_modules[TMM_RECEIVEPCAP].flags = TM_FLAG_RECEIVE_TM; } /** * \brief Registration Function for DecodePcap. * \todo Unit tests are needed for this module. */ void TmModuleDecodePcapRegister (void) { tmm_modules[TMM_DECODEPCAP].name = "DecodePcap"; tmm_modules[TMM_DECODEPCAP].ThreadInit = DecodePcapThreadInit; tmm_modules[TMM_DECODEPCAP].Func = DecodePcap; tmm_modules[TMM_DECODEPCAP].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEPCAP].ThreadDeinit = NULL; tmm_modules[TMM_DECODEPCAP].RegisterTests = NULL; tmm_modules[TMM_DECODEPCAP].cap_flags = 0; tmm_modules[TMM_DECODEPCAP].flags = TM_FLAG_DECODE_TM; } static inline void PcapDumpCounters(PcapThreadVars *ptv) { struct pcap_stat pcap_s; if (likely((pcap_stats(ptv->pcap_handle, &pcap_s) >= 0))) { SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, pcap_s.ps_recv); SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, pcap_s.ps_drop); (void) SC_ATOMIC_SET(ptv->livedev->drop, pcap_s.ps_drop); SCPerfCounterSetUI64(ptv->capture_kernel_ifdrops, ptv->tv->sc_perf_pca, pcap_s.ps_ifdrop); } } #if LIBPCAP_VERSION_MAJOR == 1 static int PcapTryReopen(PcapThreadVars *ptv) { int pcap_activate_r; ptv->pcap_state = PCAP_STATE_DOWN; pcap_activate_r = pcap_activate(ptv->pcap_handle); if (pcap_activate_r != 0) { return pcap_activate_r; } /* set bpf filter if we have one */ if (ptv->bpf_filter != NULL) { if(pcap_compile(ptv->pcap_handle,&ptv->filter,ptv->bpf_filter,1,0) < 0) { SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(ptv->pcap_handle)); return -1; } if(pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) { SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(ptv->pcap_handle)); return -1; } } SCLogInfo("Recovering interface listening"); ptv->pcap_state = PCAP_STATE_UP; return 0; } #else /* implied LIBPCAP_VERSION_MAJOR == 0 */ static int PcapTryReopen(PcapThreadVars *ptv) { char errbuf[PCAP_ERRBUF_SIZE] = ""; ptv->pcap_state = PCAP_STATE_DOWN; pcap_close(ptv->pcap_handle); ptv->pcap_handle = pcap_open_live((char *)ptv->iface, ptv->pcap_snaplen, LIBPCAP_PROMISC, LIBPCAP_COPYWAIT, errbuf); if (ptv->pcap_handle == NULL) { SCLogError(SC_ERR_PCAP_OPEN_LIVE, "Problem creating pcap handler for live mode, error %s", errbuf); return -1; } /* set bpf filter if we have one */ if (ptv->bpf_filter != NULL) { SCLogInfo("using bpf-filter \"%s\"", ptv->bpf_filter); if(pcap_compile(ptv->pcap_handle,&ptv->filter,ptv->bpf_filter,1,0) < 0) { SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(ptv->pcap_handle)); return -1; } if(pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) { SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(ptv->pcap_handle)); return -1; } } SCLogInfo("Recovering interface listening"); ptv->pcap_state = PCAP_STATE_UP; return 0; } #endif void PcapCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { SCEnter(); PcapThreadVars *ptv = (PcapThreadVars *)user; Packet *p = PacketGetFromQueueOrAlloc(); time_t last_dump = 0; struct timeval current_time; if (unlikely(p == NULL)) { SCReturn; } PKT_SET_SRC(p, PKT_SRC_WIRE); p->ts.tv_sec = h->ts.tv_sec; p->ts.tv_usec = h->ts.tv_usec; SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); p->datalink = ptv->datalink; ptv->pkts++; ptv->bytes += h->caplen; (void) SC_ATOMIC_ADD(ptv->livedev->pkts, 1); p->livedev = ptv->livedev; if (unlikely(PacketCopyData(p, pkt, h->caplen))) { TmqhOutputPacketpool(ptv->tv, p); SCReturn; } switch (ptv->checksum_mode) { case CHECKSUM_VALIDATION_AUTO: if (ptv->livedev->ignore_checksum) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (ChecksumAutoModeCheck(ptv->pkts, SC_ATOMIC_GET(ptv->livedev->pkts), SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { ptv->livedev->ignore_checksum = 1; p->flags |= PKT_IGNORE_CHECKSUM; } break; case CHECKSUM_VALIDATION_DISABLE: p->flags |= PKT_IGNORE_CHECKSUM; break; default: break; } if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { pcap_breakloop(ptv->pcap_handle); ptv->cb_result = TM_ECODE_FAILED; } /* Trigger one dump of stats every second */ TimeGet(¤t_time); if (current_time.tv_sec != last_dump) { PcapDumpCounters(ptv); last_dump = current_time.tv_sec; } SCReturn; } /** * \brief Main PCAP reading Loop function */ TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); uint16_t packet_q_len = 0; PcapThreadVars *ptv = (PcapThreadVars *)data; int r; TmSlot *s = (TmSlot *)slot; ptv->slot = s->slot_next; ptv->cb_result = TM_ECODE_OK; while (1) { if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); /* Right now we just support reading packets one at a time. */ r = pcap_dispatch(ptv->pcap_handle, (int)packet_q_len, (pcap_handler)PcapCallbackLoop, (u_char *)ptv); if (unlikely(r < 0)) { int dbreak = 0; SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s", r, pcap_geterr(ptv->pcap_handle)); #ifdef PCAP_ERROR_BREAK if (r == PCAP_ERROR_BREAK) { SCReturnInt(ptv->cb_result); } #endif do { usleep(PCAP_RECONNECT_TIMEOUT); if (suricata_ctl_flags != 0) { dbreak = 1; break; } r = PcapTryReopen(ptv); } while (r < 0); if (dbreak) { break; } } else if (ptv->cb_result == TM_ECODE_FAILED) { SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapCallbackLoop failed"); SCReturnInt(TM_ECODE_FAILED); } SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); } /** * \brief Init function for ReceivePcap. * * This is a setup function for recieving packets * via libpcap. There are two versions of this function * depending on the major version of libpcap used. * For versions prior to 1.x we use open_pcap_live, * for versions 1.x and greater we use pcap_create + pcap_activate. * * \param tv pointer to ThreadVars * \param initdata pointer to the interface passed from the user * \param data pointer gets populated with PcapThreadVars * * \todo Create a general pcap setup function. */ #if LIBPCAP_VERSION_MAJOR == 1 TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); PcapIfaceConfig *pcapconfig = initdata; if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL"); SCReturnInt(TM_ECODE_FAILED); } PcapThreadVars *ptv = SCMalloc(sizeof(PcapThreadVars)); if (unlikely(ptv == NULL)) { pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } memset(ptv, 0, sizeof(PcapThreadVars)); ptv->tv = tv; ptv->livedev = LiveGetDevice(pcapconfig->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } SCLogInfo("using interface %s", (char *)pcapconfig->iface); ptv->checksum_mode = pcapconfig->checksum_mode; if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { SCLogInfo("Running in 'auto' checksum mode. Detection of interface state will require " xstr(CHECKSUM_SAMPLE_COUNT) " packets."); } /* XXX create a general pcap setup function */ char errbuf[PCAP_ERRBUF_SIZE]; ptv->pcap_handle = pcap_create((char *)pcapconfig->iface, errbuf); if (ptv->pcap_handle == NULL) { if (strlen(errbuf)) { SCLogError(SC_ERR_PCAP_CREATE, "Couldn't create a new pcap handler for %s, error %s", (char *)pcapconfig->iface, errbuf); } else { SCLogError(SC_ERR_PCAP_CREATE, "Couldn't create a new pcap handler for %s", (char *)pcapconfig->iface); } SCFree(ptv); pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } if (pcapconfig->snaplen == 0) { /* We set snaplen if we can get the MTU */ ptv->pcap_snaplen = GetIfaceMTU(pcapconfig->iface); } else { ptv->pcap_snaplen = pcapconfig->snaplen; } if (ptv->pcap_snaplen > 0) { /* set Snaplen. Must be called before pcap_activate */ int pcap_set_snaplen_r = pcap_set_snaplen(ptv->pcap_handle, ptv->pcap_snaplen); if (pcap_set_snaplen_r != 0) { SCLogError(SC_ERR_PCAP_SET_SNAPLEN, "Couldn't set snaplen, error: %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } SCLogInfo("Set snaplen to %d for '%s'", ptv->pcap_snaplen, pcapconfig->iface); } /* set Promisc, and Timeout. Must be called before pcap_activate */ int pcap_set_promisc_r = pcap_set_promisc(ptv->pcap_handle, pcapconfig->promisc); //printf("ReceivePcapThreadInit: pcap_set_promisc(%p) returned %" PRId32 "\n", ptv->pcap_handle, pcap_set_promisc_r); if (pcap_set_promisc_r != 0) { SCLogError(SC_ERR_PCAP_SET_PROMISC, "Couldn't set promisc mode, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } int pcap_set_timeout_r = pcap_set_timeout(ptv->pcap_handle,LIBPCAP_COPYWAIT); //printf("ReceivePcapThreadInit: pcap_set_timeout(%p) returned %" PRId32 "\n", ptv->pcap_handle, pcap_set_timeout_r); if (pcap_set_timeout_r != 0) { SCLogError(SC_ERR_PCAP_SET_TIMEOUT, "Problems setting timeout, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } #ifdef HAVE_PCAP_SET_BUFF ptv->pcap_buffer_size = pcapconfig->buffer_size; if (ptv->pcap_buffer_size >= 0 && ptv->pcap_buffer_size <= INT_MAX) { if (ptv->pcap_buffer_size > 0) SCLogInfo("Going to use pcap buffer size of %" PRId32 "", ptv->pcap_buffer_size); int pcap_set_buffer_size_r = pcap_set_buffer_size(ptv->pcap_handle,ptv->pcap_buffer_size); //printf("ReceivePcapThreadInit: pcap_set_timeout(%p) returned %" PRId32 "\n", ptv->pcap_handle, pcap_set_buffer_size_r); if (pcap_set_buffer_size_r != 0) { SCLogError(SC_ERR_PCAP_SET_BUFF_SIZE, "Problems setting pcap buffer size, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } } #endif /* HAVE_PCAP_SET_BUFF */ /* activate the handle */ int pcap_activate_r = pcap_activate(ptv->pcap_handle); //printf("ReceivePcapThreadInit: pcap_activate(%p) returned %" PRId32 "\n", ptv->pcap_handle, pcap_activate_r); if (pcap_activate_r != 0) { SCLogError(SC_ERR_PCAP_ACTIVATE_HANDLE, "Couldn't activate the pcap handler, error %s", pcap_geterr(ptv->pcap_handle)); SCFree(ptv); pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } else { ptv->pcap_state = PCAP_STATE_UP; } /* set bpf filter if we have one */ if (pcapconfig->bpf_filter) { SCMutexLock(&pcap_bpf_compile_lock); ptv->bpf_filter = pcapconfig->bpf_filter; if (pcap_compile(ptv->pcap_handle,&ptv->filter,ptv->bpf_filter,1,0) < 0) { SCLogError(SC_ERR_BPF, "bpf compilation error %s", pcap_geterr(ptv->pcap_handle)); SCMutexUnlock(&pcap_bpf_compile_lock); SCFree(ptv); pcapconfig->DerefFunc(pcapconfig); return TM_ECODE_FAILED; } if (pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) { SCLogError(SC_ERR_BPF, "could not set bpf filter %s", pcap_geterr(ptv->pcap_handle)); SCMutexUnlock(&pcap_bpf_compile_lock); SCFree(ptv); pcapconfig->DerefFunc(pcapconfig); return TM_ECODE_FAILED; } SCMutexUnlock(&pcap_bpf_compile_lock); } ptv->datalink = pcap_datalink(ptv->pcap_handle); pcapconfig->DerefFunc(pcapconfig); ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", ptv->tv, SC_PERF_TYPE_UINT64, "NULL"); ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", ptv->tv, SC_PERF_TYPE_UINT64, "NULL"); ptv->capture_kernel_ifdrops = SCPerfTVRegisterCounter("capture.kernel_ifdrops", ptv->tv, SC_PERF_TYPE_UINT64, "NULL"); *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); } #else /* implied LIBPCAP_VERSION_MAJOR == 0 */ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); PcapIfaceConfig *pcapconfig = initdata; if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL"); SCReturnInt(TM_ECODE_FAILED); } PcapThreadVars *ptv = SCMalloc(sizeof(PcapThreadVars)); if (unlikely(ptv == NULL)) { pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } memset(ptv, 0, sizeof(PcapThreadVars)); ptv->tv = tv; ptv->livedev = LiveGetDevice(pcapconfig->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); SCReturnInt(TM_ECODE_FAILED); } SCLogInfo("using interface %s", pcapconfig->iface); if (strlen(pcapconfig->iface) > PCAP_IFACE_NAME_LENGTH) { SCFree(ptv); /* Dereference config */ pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } strlcpy(ptv->iface, pcapconfig->iface, PCAP_IFACE_NAME_LENGTH); if (pcapconfig->snaplen == 0) { /* We try to set snaplen from MTU value */ ptv->pcap_snaplen = GetIfaceMTU(pcapconfig->iface); /* be conservative with old pcap lib to mimic old tcpdump behavior when MTU was not available. */ if (ptv->pcap_snaplen <= 0) ptv->pcap_snaplen = LIBPCAP_SNAPLEN; } else { ptv->pcap_snaplen = pcapconfig->snaplen; } char errbuf[PCAP_ERRBUF_SIZE] = ""; ptv->pcap_handle = pcap_open_live(ptv->iface, ptv->pcap_snaplen, LIBPCAP_PROMISC, LIBPCAP_COPYWAIT, errbuf); if (ptv->pcap_handle == NULL) { SCLogError(SC_ERR_PCAP_OPEN_LIVE, "Problem creating pcap handler for live mode, error %s", errbuf); SCFree(ptv); /* Dereference config */ pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_FAILED); } /* set bpf filter if we have one */ if (pcapconfig->bpf_filter) { SCMutexLock(&pcap_bpf_compile_lock); ptv->bpf_filter = pcapconfig->bpf_filter; SCLogInfo("using bpf-filter \"%s\"", ptv->bpf_filter); if(pcap_compile(ptv->pcap_handle,&ptv->filter, ptv->bpf_filter,1,0) < 0) { SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(ptv->pcap_handle)); SCMutexUnlock(&pcap_bpf_compile_lock); SCFree(ptv); /* Dereference config */ pcapconfig->DerefFunc(pcapconfig); return TM_ECODE_FAILED; } if(pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) { SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(ptv->pcap_handle)); SCMutexUnlock(&pcap_bpf_compile_lock); SCFree(ptv); /* Dereference config */ pcapconfig->DerefFunc(pcapconfig); return TM_ECODE_FAILED; } SCMutexUnlock(&pcap_bpf_compile_lock); } ptv->datalink = pcap_datalink(ptv->pcap_handle); *data = (void *)ptv; /* Dereference config */ pcapconfig->DerefFunc(pcapconfig); SCReturnInt(TM_ECODE_OK); } #endif /* LIBPCAP_VERSION_MAJOR */ /** * \brief This function prints stats to the screen at exit. * \param tv pointer to ThreadVars * \param data pointer that gets cast into PcapThreadVars for ptv */ void ReceivePcapThreadExitStats(ThreadVars *tv, void *data) { SCEnter(); PcapThreadVars *ptv = (PcapThreadVars *)data; struct pcap_stat pcap_s; if (pcap_stats(ptv->pcap_handle, &pcap_s) < 0) { SCLogError(SC_ERR_STAT,"(%s) Failed to get pcap_stats: %s", tv->name, pcap_geterr(ptv->pcap_handle)); SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); return; } else { SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); /* these numbers are not entirely accurate as ps_recv contains packets that are still waiting to be processed at exit. * ps_drop only contains packets dropped by the driver and not any packets dropped by the interface. * Additionally see http://tracker.icir.org/bro/ticket/18 * * Note: ps_recv includes dropped packets and should be considered total. * Unless we start to look at ps_ifdrop which isn't supported everywhere. */ SCLogInfo("(%s) Pcap Total:%" PRIu64 " Recv:%" PRIu64 " Drop:%" PRIu64 " (%02.1f%%).", tv->name, (uint64_t)pcap_s.ps_recv, (uint64_t)pcap_s.ps_recv - (uint64_t)pcap_s.ps_drop, (uint64_t)pcap_s.ps_drop, (((float)(uint64_t)pcap_s.ps_drop)/(float)(uint64_t)pcap_s.ps_recv)*100); return; } } /** * \brief DeInit function closes pcap_handle at exit. * \param tv pointer to ThreadVars * \param data pointer that gets cast into PcapThreadVars for ptv */ TmEcode ReceivePcapThreadDeinit(ThreadVars *tv, void *data) { PcapThreadVars *ptv = (PcapThreadVars *)data; pcap_close(ptv->pcap_handle); SCReturnInt(TM_ECODE_OK); } /** * \brief This function passes off to link type decoders. * * DecodePcap reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param t pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into PcapThreadVars for ptv * \param pq pointer to the current PacketQueue */ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { case LINKTYPE_LINUX_SLL: DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p,GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; case LINKTYPE_PPP: DecodePPP(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; case LINKTYPE_RAW: DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodePcap", p->datalink); break; } SCReturnInt(TM_ECODE_OK); } TmEcode DecodePcapThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if (dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; SCReturnInt(TM_ECODE_OK); } void PcapTranslateIPToDevice(char *pcap_dev, size_t len) { char errbuf[PCAP_ERRBUF_SIZE]; pcap_if_t *alldevsp = NULL; pcap_if_t *devsp = NULL; struct addrinfo aiHints; struct addrinfo *aiList = NULL; int retVal = 0; memset(&aiHints, 0, sizeof(aiHints)); aiHints.ai_family = AF_UNSPEC; aiHints.ai_flags = AI_NUMERICHOST; /* try to translate IP */ if ((retVal = getaddrinfo(pcap_dev, NULL, &aiHints, &aiList)) != 0) { return; } if (pcap_findalldevs(&alldevsp, errbuf)) { freeaddrinfo(aiList); return; } for (devsp = alldevsp; devsp ; devsp = devsp->next) { pcap_addr_t *ip = NULL; for (ip = devsp->addresses; ip ; ip = ip->next) { if (aiList->ai_family != ip->addr->sa_family) { continue; } if (ip->addr->sa_family == AF_INET) { if (memcmp(&((struct sockaddr_in*)aiList->ai_addr)->sin_addr, &((struct sockaddr_in*)ip->addr)->sin_addr, sizeof(struct in_addr))) { continue; } } else if (ip->addr->sa_family == AF_INET6) { if (memcmp(&((struct sockaddr_in6*)aiList->ai_addr)->sin6_addr, &((struct sockaddr_in6*)ip->addr)->sin6_addr, sizeof(struct in6_addr))) { continue; } } else { continue; } freeaddrinfo(aiList); memset(pcap_dev, 0, len); strlcpy(pcap_dev, devsp->name, len); pcap_freealldevs(alldevsp); return; } } freeaddrinfo(aiList); pcap_freealldevs(alldevsp); } /* eof */ suricata-1.4.7/src/detect-engine-event.c0000644000000000000000000002473612253546156015037 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * * Implements the decode-event keyword */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "flow-var.h" #include "decode-events.h" #include "util-debug.h" #include "stream-tcp.h" /* Need to get the DEvents[] array */ #define DETECT_EVENTS #include "detect-engine-event.h" #include "util-unittest.h" #define PARSE_REGEX "\\S[0-9A-z_]+[.][A-z0-9_+]+$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectEngineEventMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectEngineEventSetup (DetectEngineCtx *, Signature *, char *); static int DetectDecodeEventSetup (DetectEngineCtx *, Signature *, char *); static int DetectStreamEventSetup (DetectEngineCtx *, Signature *, char *); void EngineEventRegisterTests(void); /** * \brief Registration function for decode-event: keyword */ void DetectEngineEventRegister (void) { sigmatch_table[DETECT_ENGINE_EVENT].name = "engine-event"; sigmatch_table[DETECT_ENGINE_EVENT].Match = DetectEngineEventMatch; sigmatch_table[DETECT_ENGINE_EVENT].Setup = DetectEngineEventSetup; sigmatch_table[DETECT_ENGINE_EVENT].Free = NULL; sigmatch_table[DETECT_ENGINE_EVENT].RegisterTests = EngineEventRegisterTests; sigmatch_table[DETECT_DECODE_EVENT].name = "decode-event"; sigmatch_table[DETECT_DECODE_EVENT].Match = DetectEngineEventMatch; sigmatch_table[DETECT_DECODE_EVENT].Setup = DetectDecodeEventSetup; sigmatch_table[DETECT_DECODE_EVENT].Free = NULL; sigmatch_table[DETECT_DECODE_EVENT].flags |= SIGMATCH_DEONLY_COMPAT; sigmatch_table[DETECT_STREAM_EVENT].name = "stream-event"; sigmatch_table[DETECT_STREAM_EVENT].Match = DetectEngineEventMatch; sigmatch_table[DETECT_STREAM_EVENT].Setup = DetectStreamEventSetup; sigmatch_table[DETECT_STREAM_EVENT].Free = NULL; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s\n", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s\n", eb); goto error; } return; error: return; } /** * \brief This function is used to match decoder event flags set on a packet with those passed via decode-event: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param s pointer to the Signature * \param m pointer to the sigmatch * * \retval 0 no match * \retval 1 match */ int DetectEngineEventMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { SCEnter(); DetectEngineEventData *de = (DetectEngineEventData *)m->ctx; if (ENGINE_ISSET_EVENT(p, de->event)) { SCLogDebug("de->event matched %u", de->event); SCReturnInt(1); } SCReturnInt(0); } /** * \brief This function is used to parse decoder events options passed via decode-event: keyword * * \param rawstr Pointer to the user provided decode-event options * * \retval de pointer to DetectFlowData on success * \retval NULL on failure */ DetectEngineEventData *DetectEngineEventParse (char *rawstr) { int i; DetectEngineEventData *de = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0, found = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); goto error; } const char *str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 0, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } for (i = 0; DEvents[i].event_name != NULL; i++) { if (strcasecmp(DEvents[i].event_name,str_ptr) == 0) { found = 1; break; } } if (found == 0) { SCLogError(SC_ERR_UNKNOWN_DECODE_EVENT, "unknown decode event \"%s\"", str_ptr); goto error; } de = SCMalloc(sizeof(DetectEngineEventData)); if (unlikely(de == NULL)) goto error; de->event = DEvents[i].code; if (de->event == STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA) { StreamTcpReassembleConfigEnableOverlapCheck(); } return de; error: if (de) SCFree(de); return NULL; } /** * \brief this function is used to add the parsed decode-event into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param rawstr pointer to the user provided decode-event options * * \retval 0 on Success * \retval -1 on Failure */ static int _DetectEngineEventSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr, int smtype) { DetectEngineEventData *de = NULL; SigMatch *sm = NULL; de = DetectEngineEventParse(rawstr); if (de == NULL) goto error; SCLogDebug("rawstr %s %u", rawstr, de->event); sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = smtype; sm->ctx = (void *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: if (de) SCFree(de); if (sm) SCFree(sm); return -1; } static int DetectEngineEventSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { return _DetectEngineEventSetup (de_ctx, s, rawstr, DETECT_ENGINE_EVENT); } /** * \brief this function will free memory associated with DetectEngineEventData * * \param de pointer to DetectEngineEventData */ void DetectEngineEventFree(DetectEngineEventData *de) { if(de) SCFree(de); } /** * \brief this function Setup the 'decode-event' keyword by setting the correct * signature type */ static int DetectDecodeEventSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { return _DetectEngineEventSetup(de_ctx, s, rawstr, DETECT_DECODE_EVENT); } /** * \brief this function Setup the 'stream-event' keyword by resolving the alias */ static int DetectStreamEventSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { char srawstr[MAX_SUBSTRINGS * 2] = "stream."; /* stream:$EVENT alias command develop as decode-event:stream.$EVENT */ strlcat(srawstr, rawstr, 2 * MAX_SUBSTRINGS - strlen("stream.") - 1); return DetectEngineEventSetup(de_ctx, s, srawstr); } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS /** * \test EngineEventTestParse01 is a test for a valid decode-event value */ int EngineEventTestParse01 (void) { DetectEngineEventData *de = NULL; de = DetectEngineEventParse("ipv4.pkt_too_small"); if (de) { DetectEngineEventFree(de); return 1; } return 0; } /** * \test EngineEventTestParse02 is a test for a valid upper + lower case decode-event value */ int EngineEventTestParse02 (void) { DetectEngineEventData *de = NULL; de = DetectEngineEventParse("PPP.pkt_too_small"); if (de) { DetectEngineEventFree(de); return 1; } return 0; } /** * \test EngineEventTestParse03 is a test for a valid upper case decode-event value */ int EngineEventTestParse03 (void) { DetectEngineEventData *de = NULL; de = DetectEngineEventParse("IPV6.PKT_TOO_SMALL"); if (de) { DetectEngineEventFree(de); return 1; } return 0; } /** * \test EngineEventTestParse04 is a test for an invalid upper case decode-event value */ int EngineEventTestParse04 (void) { DetectEngineEventData *de = NULL; de = DetectEngineEventParse("IPV6.INVALID_EVENT"); if (de) { DetectEngineEventFree(de); return 1; } return 0; } /** * \test EngineEventTestParse05 is a test for an invalid char into the decode-event value */ int EngineEventTestParse05 (void) { DetectEngineEventData *de = NULL; de = DetectEngineEventParse("IPV-6,INVALID_CHAR"); if (de) { DetectEngineEventFree(de); return 1; } return 0; } /** * \test EngineEventTestParse06 is a test for match function with valid decode-event value */ int EngineEventTestParse06 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectEngineEventData *de = NULL; SigMatch *sm = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); ENGINE_SET_EVENT(p,PPP_PKT_TOO_SMALL); de = DetectEngineEventParse("ppp.pkt_too_small"); if (de == NULL) goto error; de->event = PPP_PKT_TOO_SMALL; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_DECODE_EVENT; sm->ctx = (void *)de; ret = DetectEngineEventMatch(&tv,NULL,p,NULL,sm); if(ret) { SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for EngineEvent */ void EngineEventRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("EngineEventTestParse01", EngineEventTestParse01, 1); UtRegisterTest("EngineEventTestParse02", EngineEventTestParse02, 1); UtRegisterTest("EngineEventTestParse03", EngineEventTestParse03, 1); UtRegisterTest("EngineEventTestParse04", EngineEventTestParse04, 0); UtRegisterTest("EngineEventTestParse05", EngineEventTestParse05, 0); UtRegisterTest("EngineEventTestParse06", EngineEventTestParse06, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-ioctl.h0000644000000000000000000000153112253546156013263 00000000000000/* Copyright (C) 2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ int GetIfaceMTU(char *pcap_dev); int GetIfaceMaxPayloadSize(char *pcap_dev); suricata-1.4.7/src/util-print.h0000644000000000000000000000461012253546156013306 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_PRINT_H__ #define __UTIL_PRINT_H__ #define PrintBufferData(buf, buf_offset_ptr, buf_size, ...) do { \ int cw = snprintf((buf) + *(buf_offset_ptr), \ (buf_size) - *(buf_offset_ptr), \ __VA_ARGS__); \ if (cw >= 0) { \ if ( (*(buf_offset_ptr) + cw) >= buf_size) { \ SCLogDebug("Truncating data write since it exceeded buffer " \ "limit of - %"PRIu32"\n", buf_size); \ *(buf_offset_ptr) = buf_size - 1; \ } else { \ *(buf_offset_ptr) += cw; \ } \ } \ } while (0) void PrintRawLineHexFp(FILE *, uint8_t *, uint32_t); void PrintRawUriFp(FILE *, uint8_t *, uint32_t); void PrintRawUriBuf(char *, uint32_t *, uint32_t, uint8_t *, uint32_t); void PrintRawJsonFp(FILE *, uint8_t *, uint32_t); void PrintRawDataFp(FILE *, uint8_t *, uint32_t); void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, uint8_t *src_buf, uint32_t src_buf_len); void PrintRawLineHexBuf(char *, uint32_t, uint8_t *, uint32_t ); const char *PrintInet(int , const void *, char *, socklen_t); #endif /* __UTIL_PRINT_H__ */ suricata-1.4.7/src/detect-gid.h0000644000000000000000000000216612253546156013214 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * * Implements the gid keyword */ #ifndef __DETECT_GID_H__ #define __DETECT_GID_H__ #include "decode-events.h" #include "decode-ipv4.h" #include "decode-tcp.h" /** * Registration function for gid: keyword */ void DetectGidRegister (void); /** * This function registers unit tests for Gid */ void GidRegisterTests(void); #endif /*__DETECT_GID_H__ */ suricata-1.4.7/src/detect-engine-payload.h0000644000000000000000000000230412253546156015337 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_PAYLOAD_H__ #define __DETECT_ENGINE_PAYLOAD_H__ int DetectEngineInspectPacketPayload(DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, Packet *); int DetectEngineInspectStreamPayload(DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t *, uint32_t); void PayloadRegisterTests(void); #endif /* __DETECT_ENGINE_PAYLOAD_H__ */ suricata-1.4.7/src/util-mpm-b2g-cuda.c0000644000000000000000000037372412253546156014337 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * \author Martin Beyer */ #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "detect-engine-mpm.h" #include "util-bloomfilter.h" #include "util-mpm-b2g-cuda.h" #include "util-mpm.h" #include "util-print.h" #include "threadvars.h" #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" #include "conf.h" #include "util-cuda-handlers.h" #include "util-cuda.h" #include "util-cpu.h" #include "tm-threads.h" #include "threads.h" #include "tmqh-simple.h" #include "detect-engine-address.h" #include "detect-engine-port.h" #include "detect-engine.h" #include "detect-parse.h" #include "cuda-packet-batcher.h" /* macros decides if cuda is enabled for the platform or not */ #ifdef __SC_CUDA_SUPPORT__ #define INIT_HASH_SIZE 65536 #ifdef B2G_CUDA_COUNTERS #define COUNT(counter) (counter) #else #define COUNT(counter) #endif /* B2G_CUDA_COUNTERS */ static uint32_t b2g_hash_size = 0; static uint32_t b2g_bloom_size = 0; static void *b2g_func; /* threadvars Cuda(C) Mpm(M) B2G(B) Rules(R) Content(C) */ ThreadVars *tv_CMB2_RC = NULL; void B2gCudaInitCtx(MpmCtx *, int); void B2gCudaThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void B2gCudaDestroyCtx(MpmCtx *); void B2gCudaThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); int B2gCudaAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B2gCudaAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B2gCudaPreparePatterns(MpmCtx *mpm_ctx); uint32_t B2gCudaSearchWrap(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t B2gCudaSearch1(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); #ifdef B2G_CUDA_SEARCH2 uint32_t B2gCudaSearch2(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); #endif uint32_t B2gCudaSearch(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t B2gCudaSearchBNDMq(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); void B2gCudaPrintInfo(MpmCtx *); void B2gCudaPrintSearchStats(MpmThreadCtx *); void B2gCudaRegisterTests(void); /** * \brief Register the CUDA B2g Mpm. */ void MpmB2gCudaRegister(void) { mpm_table[MPM_B2G_CUDA].name = "b2g_cuda"; mpm_table[MPM_B2G_CUDA].max_pattern_length = B2G_CUDA_WORD_SIZE; mpm_table[MPM_B2G_CUDA].InitCtx = B2gCudaInitCtx; mpm_table[MPM_B2G_CUDA].InitThreadCtx = B2gCudaThreadInitCtx; mpm_table[MPM_B2G_CUDA].DestroyCtx = B2gCudaDestroyCtx; mpm_table[MPM_B2G_CUDA].DestroyThreadCtx = B2gCudaThreadDestroyCtx; mpm_table[MPM_B2G_CUDA].AddPattern = B2gCudaAddPatternCS; mpm_table[MPM_B2G_CUDA].AddPatternNocase = B2gCudaAddPatternCI; mpm_table[MPM_B2G_CUDA].Prepare = B2gCudaPreparePatterns; mpm_table[MPM_B2G_CUDA].Search = B2gCudaSearchWrap; mpm_table[MPM_B2G_CUDA].Cleanup = NULL; mpm_table[MPM_B2G_CUDA].PrintCtx = B2gCudaPrintInfo; mpm_table[MPM_B2G_CUDA].PrintThreadCtx = B2gCudaPrintSearchStats; mpm_table[MPM_B2G_CUDA].RegisterUnittests = B2gCudaRegisterTests; } void B2gCudaPrintInfo(MpmCtx *mpm_ctx) { #ifdef DEBUG B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; SCLogDebug("MPM B2g Cuda Information:"); SCLogDebug("Memory allocs: %" PRIu32, mpm_ctx->memory_cnt); SCLogDebug("Memory alloced: %" PRIu32, mpm_ctx->memory_size); SCLogDebug(" Sizeofs:"); SCLogDebug(" MpmCtx %" PRIuMAX, (uintmax_t)sizeof(MpmCtx)); SCLogDebug(" B2gCudaCtx %" PRIuMAX, (uintmax_t)sizeof(B2gCudaCtx)); SCLogDebug(" B2gCudaPattern %" PRIuMAX, (uintmax_t)sizeof(B2gCudaPattern)); SCLogDebug(" B2gCudaHashItem %" PRIuMAX, (uintmax_t)sizeof(B2gCudaHashItem)); SCLogDebug("Unique Patterns: %" PRIu32, mpm_ctx->pattern_cnt); SCLogDebug("Smallest: %" PRIu32, mpm_ctx->minlen); SCLogDebug("Largest: %" PRIu32, mpm_ctx->maxlen); SCLogDebug("Hash size: %" PRIu32, ctx->hash_size); #endif return; } static inline B2gCudaPattern *B2gCudaAllocPattern(MpmCtx *mpm_ctx) { B2gCudaPattern *p = SCMalloc(sizeof(B2gCudaPattern)); if (unlikely(p == NULL)) return NULL; memset(p, 0, sizeof(B2gCudaPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gCudaPattern); return p; } static inline B2gCudaHashItem *B2gCudaAllocHashItem(MpmCtx *mpm_ctx) { B2gCudaHashItem *hi = SCMalloc(sizeof(B2gCudaHashItem)); if (unlikely(hi == NULL)) return NULL; memset(hi, 0, sizeof(B2gCudaHashItem)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gCudaHashItem); return hi; } static void B2gCudaHashFree(MpmCtx *mpm_ctx, B2gCudaHashItem *hi) { if (hi == NULL) return; B2gCudaHashItem *t = hi->nxt; B2gCudaHashFree(mpm_ctx, t); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gCudaHashItem); SCFree(hi); return; } static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) d[i] = u8_tolower(s[i]); return; } static inline uint32_t B2gCudaInitHash(B2gCudaPattern *p) { uint32_t hash = p->len * p->original_pat[0]; if (p->len > 1) hash += p->original_pat[1]; return (hash % INIT_HASH_SIZE); } static inline uint32_t B2gCudaInitHashRaw(uint8_t *pat, uint16_t patlen) { uint32_t hash = patlen * pat[0]; if (patlen > 1) hash += pat[1]; return (hash % INIT_HASH_SIZE); } static inline int B2gCudaInitHashAdd(B2gCudaCtx *ctx, B2gCudaPattern *p) { uint32_t hash = B2gCudaInitHash(p); if (ctx->init_hash[hash] == NULL) { ctx->init_hash[hash] = p; return 0; } B2gCudaPattern *tt = NULL; B2gCudaPattern *t = ctx->init_hash[hash]; /* get the list tail */ do { tt = t; t = t->next; } while (t != NULL); tt->next = p; return 0; } static inline int B2gCudaCmpPattern(B2gCudaPattern *p, uint8_t *pat, uint16_t patlen, char flags) { if (p->len != patlen) return 0; if (p->flags != flags) return 0; if (memcmp(p->cs, pat, patlen) != 0) return 0; return 1; } static inline B2gCudaPattern *B2gCudaInitHashLookup(B2gCudaCtx *ctx, uint8_t *pat, uint16_t patlen, char flags, uint32_t pid) { uint32_t hash = B2gCudaInitHashRaw(pat, patlen); if (ctx->init_hash[hash] == NULL) return NULL; B2gCudaPattern *t = ctx->init_hash[hash]; for ( ; t != NULL; t = t->next) { //if (B2gCudaCmpPattern(t, pat, patlen, flags) == 1) if (t->flags == flags && t->id == pid) return t; } return NULL; } void B2gCudaFreePattern(MpmCtx *mpm_ctx, B2gCudaPattern *p) { if (p != NULL && p->cs != NULL && p->cs != p->ci) { SCFree(p->cs); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL && p->ci != NULL) { SCFree(p->ci); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL) { SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gCudaPattern); } return; } static inline int B2gCudaAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); if (patlen == 0) return 0; /* get a memory piece */ B2gCudaPattern *p = B2gCudaInitHashLookup(ctx, pat, patlen, flags, pid); if (p == NULL) { SCLogDebug("allocing new pattern"); p = B2gCudaAllocPattern(mpm_ctx); if (p == NULL) goto error; p->len = patlen; p->flags = flags; p->id = pid; p->original_pat = SCMalloc(patlen); if (p->original_pat == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->original_pat, pat, patlen); /* setup the case insensitive part of the pattern */ p->ci = SCMalloc(patlen); if (p->ci == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy_tolower(p->ci, pat, patlen); /* setup the case sensitive part of the pattern */ if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* nocase means no difference between cs and ci */ p->cs = p->ci; } else { if (memcmp(p->ci,pat,p->len) == 0) { /* no diff between cs and ci: pat is lowercase */ p->cs = p->ci; } else { p->cs = SCMalloc(patlen); if (p->cs == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->cs, pat, patlen); } } //printf("B2gAddPattern: ci \""); prt(p->ci,p->len); //printf("\" cs \""); prt(p->cs,p->len); //printf("\"\n"); /* put in the pattern hash */ B2gCudaInitHashAdd(ctx, p); if (mpm_ctx->pattern_cnt == 65535) { printf("Max search words reached\n"); exit(1); } mpm_ctx->pattern_cnt++; if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } return 0; error: B2gCudaFreePattern(mpm_ctx, p); return -1; } int B2gCudaAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return B2gCudaAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int B2gCudaAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return B2gCudaAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } static inline uint32_t B2gCudaBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint16_t i; uint32_t hash = (uint32_t)u8_tolower(*d); for (i = 1; i < datalen; i++) { d++; hash += (u8_tolower(*d)) ^ i; } hash <<= (iter+1); hash %= hash_size; return hash; } static void B2gCudaPrepareHash(MpmCtx *mpm_ctx) { B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; uint16_t i = 0; uint16_t idx = 0; uint8_t idx8 = 0; ctx->hash = (B2gCudaHashItem **)SCMalloc(sizeof(B2gCudaHashItem *) * ctx->hash_size); if (ctx->hash == NULL) goto error; memset(ctx->hash, 0, sizeof(B2gCudaHashItem *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B2gCudaHashItem *) * ctx->hash_size); #ifdef B2G_CUDA_SEARCH2 ctx->hash2 = (B2gCudaHashItem **)SCMalloc(sizeof(B2gCudaHashItem *) * ctx->hash_size); if (ctx->hash2 == NULL) goto error; memset(ctx->hash2, 0, sizeof(B2gCudaHashItem *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B2gCudaHashItem *) * ctx->hash_size); #endif /* alloc the pminlen array */ ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); if (ctx->pminlen == NULL) goto error; memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if(ctx->parray[i]->len == 1) { idx8 = (uint8_t)ctx->parray[i]->ci[0]; if (ctx->hash1[idx8].flags == 0) { ctx->hash1[idx8].idx = i; ctx->hash1[idx8].flags |= 0x01; } else { B2gCudaHashItem *hi = B2gCudaAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; /* Append this HashItem to the list */ B2gCudaHashItem *thi = &ctx->hash1[idx8]; while (thi->nxt) thi = thi->nxt; thi->nxt = hi; } ctx->pat_1_cnt++; #ifdef B2G_CUDA_SEARCH2 } else if(ctx->parray[i]->len == 2) { idx = B2G_CUDA_HASH16(ctx->parray[i]->ci[0], ctx->parray[i]->ci[1]); if (ctx->hash2[idx] == NULL) { B2gCudaHashItem *hi = B2gCudaAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; ctx->hash2[idx] = hi; } else { B2gCudaHashItem *hi = B2gCudaAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; /* Append this HashItem to the list */ B2gCudaHashItem *thi = ctx->hash2[idx]; while (thi->nxt) thi = thi->nxt; thi->nxt = hi; } ctx->pat_2_cnt++; #endif } else { idx = B2G_CUDA_HASH16(ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); SCLogDebug("idx %" PRIu32 ", %c.%c", idx, ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); if (ctx->hash[idx] == NULL) { B2gCudaHashItem *hi = B2gCudaAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; ctx->pminlen[idx] = ctx->parray[i]->len; ctx->hash[idx] = hi; } else { B2gCudaHashItem *hi = B2gCudaAllocHashItem(mpm_ctx); if (hi == NULL) goto error; hi->idx = i; hi->flags |= 0x01; if (ctx->parray[i]->len < ctx->pminlen[idx]) ctx->pminlen[idx] = ctx->parray[i]->len; /* Append this HashItem to the list */ B2gCudaHashItem *thi = ctx->hash[idx]; while (thi->nxt) thi = thi->nxt; thi->nxt = hi; } ctx->pat_x_cnt++; } } /* alloc the bloom array */ ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); if (ctx->bloom == NULL) goto error; memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); uint32_t h; for (h = 0; h < ctx->hash_size; h++) { B2gCudaHashItem *hi = ctx->hash[h]; if (hi == NULL) continue; ctx->bloom[h] = BloomFilterInit(b2g_bloom_size, 2, B2gCudaBloomHash); if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); if (ctx->pminlen[h] > 8) ctx->pminlen[h] = 8; B2gCudaHashItem *thi = hi; do { SCLogDebug("adding \"%c%c\" to the bloom", ctx->parray[thi->idx]->ci[0], ctx->parray[thi->idx]->ci[1]); BloomFilterAdd(ctx->bloom[h], ctx->parray[thi->idx]->ci, ctx->pminlen[h]); thi = thi->nxt; } while (thi != NULL); } return; error: return; } int B2gCudaBuildMatchArray(MpmCtx *mpm_ctx) { SCEnter(); B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; ctx->B2G = SCMalloc(sizeof(B2G_CUDA_TYPE) * ctx->hash_size); if (ctx->B2G == NULL) return -1; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B2G_CUDA_TYPE) * ctx->hash_size); memset(ctx->B2G, 0, b2g_hash_size * sizeof(B2G_CUDA_TYPE)); uint32_t j; uint32_t a; /* fill the match array */ for (j = 0; j <= (ctx->m - B2G_CUDA_Q); j++) { for (a = 0; a < mpm_ctx->pattern_cnt; a++) { if (ctx->parray[a]->len < ctx->m) continue; uint16_t h = B2G_CUDA_HASH16(u8_tolower(ctx->parray[a]->ci[j]), u8_tolower(ctx->parray[a]->ci[j + 1])); ctx->B2G[h] = ctx->B2G[h] | (1 << (ctx->m - j)); SCLogDebug("h %" PRIu16 ", ctx->B2G[h] %" PRIu32, h, ctx->B2G[h]); } } ctx->s0 = 1; SCReturnInt(0); } int B2gCudaSetDeviceBuffers(MpmCtx *mpm_ctx) { B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; /* search kernel */ if (SCCudaMemAlloc(&ctx->cuda_B2G, sizeof(B2G_CUDA_TYPE) * ctx->hash_size) == -1) { goto error; } if (SCCudaMemcpyHtoD(ctx->cuda_B2G, ctx->B2G, sizeof(B2G_CUDA_TYPE) * ctx->hash_size) == -1) { goto error; } return 0; error: return -1; } int B2gCudaSetKernelArgs(MpmCtx *mpm_ctx) { return 0; } int B2gCudaPreparePatterns(MpmCtx *mpm_ctx) { B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ ctx->parray = (B2gCudaPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B2gCudaPattern *)); if (ctx->parray == NULL) goto error; memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B2gCudaPattern *)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B2gCudaPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; for (i = 0; i < INIT_HASH_SIZE; i++) { B2gCudaPattern *node = ctx->init_hash[i]; B2gCudaPattern *nnode = NULL; for ( ; node != NULL; ) { nnode = node->next; node->next = NULL; ctx->parray[p] = node; p++; node = nnode; } } /* we no longer need the hash, so free it's memory */ SCFree(ctx->init_hash); ctx->init_hash = NULL; /* set 'm' to the smallest pattern size */ ctx->m = mpm_ctx->minlen; /* make sure 'm' stays in bounds m can be max WORD_SIZE - 1 */ if (ctx->m >= B2G_CUDA_WORD_SIZE) { ctx->m = B2G_CUDA_WORD_SIZE - 1; } if (ctx->m < 2) ctx->m = 2; ctx->hash_size = b2g_hash_size; B2gCudaPrepareHash(mpm_ctx); B2gCudaBuildMatchArray(mpm_ctx); if (B2gCudaSetDeviceBuffers(mpm_ctx) == -1) goto error; if (B2gCudaSetKernelArgs(mpm_ctx) == -1) goto error; SCLogDebug("ctx->pat_1_cnt %" PRIu16, ctx->pat_1_cnt); if (ctx->pat_1_cnt) { ctx->Search = B2gCudaSearch1; #ifdef B2G_CUDA_SEARCH2 ctx->Search = B2gCudaSearch2; if (ctx->pat_2_cnt) { ctx->MBSearch2 = B2gCudaSearch2; } #endif ctx->MBSearch = b2g_func; #ifdef B2G_SEARCH2 } else if (ctx->pat_2_cnt) { ctx->Search = B2gSearch2; ctx->MBSearch = b2g_cuda_func; #endif } return 0; error: return -1; } void B2gCudaPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef B2G_CUDA_COUNTERS B2gCudaThreadCtx *tctx = (B2gCudaThreadCtx *)mpm_thread_ctx->ctx; printf("B2g Thread Search stats (tctx %p)\n", tctx); printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); printf("Avg m/search: %0.2f\n", (tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0)); printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); printf("Avg shifts: %0.2f\n", (tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift)) : 0); printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", (tctx->stat_bloom_calls ? ((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls) * 100) : 0, tctx->stat_bloom_hits); printf("Avg pminlen: %0.2f\n\n", (tctx->stat_pminlen_calls ? ((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls)) : 0); #endif /* B2G_CUDA_COUNTERS */ } static inline int memcmp_lowercase(uint8_t *s1, uint8_t *s2, uint16_t n) { size_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ for (i = n - 1; i; i--) { if (u8_tolower(*(s2 + i)) != s1[i]) return 1; } return 0; } /** * \brief Function to get the user defined values for b2g algorithm from the * config file 'suricata.yaml' */ static void B2gGetConfig() { ConfNode *b2g_conf; const char *hash_val = NULL; const char *bloom_val = NULL; const char *algo = NULL; /* init defaults */ b2g_hash_size = HASHSIZE_LOW; b2g_bloom_size = BLOOMSIZE_MEDIUM; b2g_func = B2G_CUDA_SEARCHFUNC; ConfNode *pm = ConfGetNode("pattern-matcher"); if (pm != NULL) { TAILQ_FOREACH(b2g_conf, &pm->head, next) { if (strncmp(b2g_conf->val, "b2g", 3) == 0) { algo = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "algo"); hash_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "hash_size"); bloom_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "bf_size"); if (algo != NULL) { if (strcmp(algo, "B2gSearch") == 0) { b2g_func = B2gCudaSearch; } else if (strcmp(algo, "B2gSearchBNDMq") == 0) { b2g_func = B2gCudaSearchBNDMq; } } if (hash_val != NULL) b2g_hash_size = MpmGetHashSize(hash_val); if (bloom_val != NULL) b2g_bloom_size = MpmGetBloomSize(bloom_val); SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", b2g_hash_size, b2g_bloom_size); } } } } void B2gCudaInitCtx(MpmCtx *mpm_ctx, int module_handle) { if (mpm_ctx->ctx != NULL) return; SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); mpm_ctx->ctx = SCMalloc(sizeof(B2gCudaCtx)); if (mpm_ctx->ctx == NULL) return; memset(mpm_ctx->ctx, 0, sizeof(B2gCudaCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gCudaCtx); /* initialize the hash we use to speed up pattern insertions */ B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; /* hold the cuda module handle against which we are registered. This is our * only reference to know our place of birth */ ctx->module_handle = module_handle; ctx->init_hash = SCMalloc(sizeof(B2gCudaPattern *) * INIT_HASH_SIZE); if (ctx->init_hash == NULL) return; memset(ctx->init_hash, 0, sizeof(B2gCudaPattern *) * INIT_HASH_SIZE); /* Initialize the defaults value from the config file. The given check make sure that we query config file only once for config values */ if (b2g_hash_size == 0) B2gGetConfig(); /* init defaults search functions */ ctx->Search = b2g_func; return; } void B2gCudaDestroyCtx(MpmCtx *mpm_ctx) { SCLogDebug("mpm_ctx %p", mpm_ctx); B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->init_hash) { SCFree(ctx->init_hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B2gCudaPattern *)); } if (ctx->parray) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { B2gCudaFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gCudaPattern)); } if (ctx->B2G) { SCFree(ctx->B2G); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B2G_CUDA_TYPE) * ctx->hash_size); } if (ctx->bloom) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); BloomFilterFree(ctx->bloom[h]); } SCFree(ctx->bloom); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); } if (ctx->hash) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->hash[h] == NULL) continue; B2gCudaHashFree(mpm_ctx, ctx->hash[h]); } SCFree(ctx->hash); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B2gCudaHashItem) * ctx->hash_size); } if (ctx->pminlen) { SCFree(ctx->pminlen); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); } CUcontext dummy_context; SCCudaHlModuleData *module_data = SCCudaHlGetModuleData(ctx->module_handle); if (module_data == NULL) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "How did we even fail to get a " "module_data if we are having a module_handle"); goto error; } if (SCCudaHlGetCudaContext(&dummy_context, "mpm", ctx->module_handle) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error getting a cuda context for the " "module %s", module_data->name); goto error; } SCCudaCtxPushCurrent(dummy_context); if (ctx->cuda_B2G != 0) { if (SCCudaMemFree(ctx->cuda_B2G) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error freeing ctx->cuda_B2G "); goto error; } ctx->cuda_B2G = 0; } SCCudaCtxPopCurrent(&dummy_context); SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gCudaCtx); error: return; } void B2gCudaThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); /* size can be null when optimized */ if (sizeof(B2gCudaThreadCtx) > 0) { mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gCudaThreadCtx)); if (mpm_thread_ctx->ctx == NULL) return; memset(mpm_thread_ctx->ctx, 0, sizeof(B2gCudaThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(B2gCudaThreadCtx); } return; } void B2gCudaThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { B2gCudaThreadCtx *ctx = (B2gCudaThreadCtx *)mpm_thread_ctx->ctx; B2gCudaPrintSearchStats(mpm_thread_ctx); /* can be NULL if B2gThreadCtx is optimized to 0 */ if (ctx != NULL) { mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(B2gCudaThreadCtx); SCFree(mpm_thread_ctx->ctx); } return; } inline uint32_t B2gCudaSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; } uint32_t B2gCudaSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; #ifdef B2G_COUNTERS B2gCudaThreadCtx *tctx = (B2gCudaThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = ctx->m - B2G_CUDA_Q + 1, matches = 0; B2G_CUDA_TYPE d; //printf("\n"); //PrintRawDataFp(stdout, buf, buflen); SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32"", buflen, ctx->m, pos); COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (uint32_t)(buflen - B2G_CUDA_Q + 1)) { uint16_t h = B2G_CUDA_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); d = ctx->B2G[h]; if (d != 0) { COUNT(tctx->stat_d0++); uint32_t j = pos; uint32_t first = pos - (ctx->m - B2G_CUDA_Q + 1); do { j = j - 1; if (d >= (uint32_t)(1 << (ctx->m - 1))) { if (j > first) pos = j; else { /* get our patterns from the hash */ h = B2G_CUDA_HASH16(u8_tolower(buf[j + ctx->m - 2]),u8_tolower(buf[j + ctx->m - 1])); if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((buflen - j) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf+j, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); SCLogDebug("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); goto skip_loop; } } } B2gCudaHashItem *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->nxt) { COUNT(tctx->stat_d0_hashloop++); B2gCudaPattern *p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if ((buflen - j) < p->len) { continue; } if (memcmp_lowercase(p->ci, buf+j, p->len) == 0) { #ifdef PRINTMATCH printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); #endif COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (buflen - j < p->len) continue; if (memcmp(p->cs, buf+j, p->len) == 0) { #ifdef PRINTMATCH printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); #endif COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } skip_loop: SCLogDebug("skipped"); //SCLogDebug("output at pos %" PRIu32 ": ", j); prt(buf + (j), ctx->m); printf("\n"); ; } } if (j == 0) { break; } h = B2G_CUDA_HASH16(u8_tolower(buf[j - 1]),u8_tolower(buf[j])); d = (d << 1) & ctx->B2G[h]; } while (d != 0); } COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (ctx->m - B2G_Q + 1)); pos = pos + ctx->m - B2G_CUDA_Q + 1; SCLogDebug("pos %"PRIu32"", pos); } SCLogDebug("matches %"PRIu32"", matches); return matches; } uint32_t B2gCudaSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; #ifdef B2G_CUDA_COUNTERS B2gCudaThreadCtx *tctx = (B2gCudaThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = 0, matches = 0; B2G_CUDA_TYPE d; uint32_t j; COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (buflen - ctx->m)) { j = ctx->m - 1; d = ~0; do { uint16_t h = B2G_CUDA_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); d = ((d << 1) & ctx->B2G[h]); j = j - 1; } while (d != 0 && j != 0); /* (partial) match, move on to verification */ if (d != 0) { COUNT(tctx->stat_d0++); //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); /* get our patterns from the hash */ uint16_t h = B2G_CUDA_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((buflen - pos) < ctx->pminlen[h]) { goto skip_loop; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf+pos, ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); goto skip_loop; } } } B2gCudaHashItem *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->nxt) { COUNT(tctx->stat_d0_hashloop++); B2gCudaPattern *p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (buflen - pos < p->len) continue; if (memcmp_lowercase(p->ci, buf+pos, p->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (buflen - pos < p->len) continue; if (memcmp(p->cs, buf+pos, p->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } skip_loop: //pos = pos + ctx->s0; pos = pos + 1; } else { COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (j + 1)); pos = pos + j + 1; } } //printf("Total matches %" PRIu32 "\n", matches); return matches; } #ifdef B2G_CUDA_SEARCH2 uint32_t B2gCudaSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; B2gCudaPattern *p; B2gCudaHashItem *thi, *hi; if (buflen < 2) return 0; //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint8_t h8 = u8_tolower(*buf); hi = &ctx->hash1[h8]; if (hi->flags & 0x01) { for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } else { if (*buf == p->cs[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } } } /* save one conversion by reusing h8 */ uint16_t h16 = B2G_HASH16(h8, u8_tolower(*(buf+1))); hi = ctx->hash2[h16]; for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); // for (em = p->em; em; em = em->next) { if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) cnt++; // } } } else { if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); // for (em = p->em; em; em = em->next) { if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) cnt++; // } } } } buf += 1; } //printf("B2gSearch2: after 2byte cnt %" PRIu32 "\n", cnt); if (ctx->pat_x_cnt > 0) { /* Pass bufmin on because buf no longer points to the * start of the buffer. */ cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); //printf("B2gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); } return cnt; } #endif uint32_t B2gCudaSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { SCEnter(); B2gCudaCtx *ctx = (B2gCudaCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; B2gCudaPattern *p; B2gCudaHashItem *thi, *hi; if (buflen == 0) SCReturnUInt(0); //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint8_t h = u8_tolower(*buf); hi = &ctx->hash1[h]; if (hi->flags & 0x01) { for (thi = hi; thi != NULL; thi = thi->nxt) { p = ctx->parray[thi->idx]; if (p->len != 1) continue; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if (u8_tolower(*buf) == p->ci[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } else { if (*buf == p->cs[0]) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } } } } buf += 1; } //printf("B2gSearch1: after 1byte cnt %" PRIu32 "\n", cnt); #ifdef B2G_CUDA_SEARCH2 if (ctx->pat_2_cnt) { /* Pass bufmin on because buf no longer points to the * start of the buffer. */ cnt += ctx->MBSearch2(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); //printf("B2gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); } else #endif if (ctx->pat_x_cnt) { cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); } SCReturnUInt(cnt); } /*********************Cuda_Specific_Mgmt_Code_Starts_Here**********************/ /* * \brief This data holds all resources needed by a cuda stream such as * device pointers, host pointers, CUmodule and Kernel function. These * are only valid within the context of the associated B2gCudaMpmThreadCtxData. */ typedef struct B2gCudaMpmStreamData_ { /* Stream used for asynchronous memcopy in the Cuda MPM dispatcher. * This is != NULL if the memory is allocated page-locked, i.e. profile->page_locked * is set. Only streams != NULL are used for async. processing. */ CUstream cuda_stream; /* Flag that indicates if there is some asynchronous operation in progress */ uint8_t cuda_async; /* The CUmodule for this stream and corresponding handle. We need to load the * cuda module for every stream to avoid rebinding the kernel configuration * with every kernel call. */ int b2g_cuda_cumodule_handle; CUmodule b2g_cuda_cumodule; /* the search kernel */ CUfunction b2g_cuda_search_kernel; /* the cuda_search_kernel argument offsets */ uint8_t b2g_cuda_search_kernel_arg0_offset; uint8_t b2g_cuda_search_kernel_arg1_offset; uint8_t b2g_cuda_search_kernel_arg2_offset; uint8_t b2g_cuda_search_kernel_arg3_offset; uint8_t b2g_cuda_search_kernel_arg4_offset; uint8_t b2g_cuda_search_kernel_arg5_offset; uint8_t b2g_cuda_search_kernel_arg_total; /* the results buffer to hold the match offsets for the packets */ uint16_t *results_buffer; /* gpu buffer corresponding to the above buffer */ CUdeviceptr cuda_results_buffer; /* gpu buffer corresponding to SCCudaPBPacketsBuffer->packets_buffer */ CUdeviceptr cuda_packets_buffer; /* gpu buffer corresponding to SCCudaPBPacketsBuffer->packets_offset_buffer */ CUdeviceptr cuda_packets_offset_buffer; /* gpu buffer corresponding to SCCudaPBPacketsBuffer->packets_payload_offset_buffer */ CUdeviceptr cuda_packets_payload_offset_buffer; /* gpu buffer corresponding to the global symbol g_u8_lowercasetable * XXX Remove this. Store it as a constant buffer inside the kernel*/ CUdeviceptr cuda_g_u8_lowercasetable; } B2gCudaMpmStreamData; /* * \brief Cuda specific data for the MPM's thread context. */ typedef struct B2gCudaMpmThreadCtxData_ { int b2g_cuda_module_handle; CUcontext b2g_cuda_context; /* Data of the cuda streams of this context */ B2gCudaMpmStreamData *stream_data; uint8_t no_of_streams; /* Data store for packet buffers that are currently processed */ Tmq *tmq_streamq; } B2gCudaMpmThreadCtxData; /* * \brief Initialize data for the cuda streams. * * \param tctx The thread context data of the Cuda MPM. * \param profile The cuda profile used by the MPM. * * \retval 0 on succes, -1 on failure. */ static int B2gCudaMpmStreamDataInit(B2gCudaMpmThreadCtxData *tctx, MpmCudaConf *profile) { SCCudaHlModuleData *module_data = NULL; B2gCudaMpmStreamData *sd = NULL; uint8_t i = 0; module_data = SCCudaHlGetModuleData(tctx->b2g_cuda_module_handle); if (module_data == NULL) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR,"No Cuda module data"); goto error; } SCLogDebug("Initializing data for %"PRIu16" cuda streams", tctx->no_of_streams); for (i = 0; i < tctx->no_of_streams; ++i) { sd = &tctx->stream_data[i]; /* Init cuda stream */ if (profile->page_locked) { if (SCCudaStreamCreate(&sd->cuda_stream, 0) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error creating Cuda stream."); exit(EXIT_FAILURE); } } else { SCLogDebug("Disabled asynchronous cuda processing"); sd->cuda_stream = NULL; } /* Load the CUmodule */ sd->b2g_cuda_cumodule_handle = SCCudaHlGetCudaModule(&sd->b2g_cuda_cumodule, "util-mpm-b2g-cuda-kernel", module_data->handle); if (sd->b2g_cuda_cumodule_handle == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error getting a cuda module"); goto error; } /* Get kernel from module */ if (SCCudaModuleGetFunction(&sd->b2g_cuda_search_kernel, sd->b2g_cuda_cumodule, B2G_CUDA_SEARCHFUNC_NAME) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error getting a cuda function"); goto error; } /* Configure kernel execution */ if (SCCudaFuncSetBlockShape(sd->b2g_cuda_search_kernel, 32, 1, 1) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error setting function block shape"); goto error; } #define ALIGN_UP(offset, alignment) do { \ (offset) = ((offset) + (alignment) - 1) & ~((alignment) - 1); \ } while (0) int offset = 0; ALIGN_UP(offset, __alignof(void *)); sd->b2g_cuda_search_kernel_arg0_offset = offset; offset += sizeof(void *); ALIGN_UP(offset, __alignof(void *)); sd->b2g_cuda_search_kernel_arg1_offset = offset; offset += sizeof(void *); ALIGN_UP(offset, __alignof(void *)); sd->b2g_cuda_search_kernel_arg2_offset = offset; offset += sizeof(void *); ALIGN_UP(offset, __alignof(void *)); sd->b2g_cuda_search_kernel_arg3_offset = offset; offset += sizeof(void *); ALIGN_UP(offset, __alignof(uint16_t)); sd->b2g_cuda_search_kernel_arg4_offset = offset; offset += sizeof(void *); ALIGN_UP(offset, __alignof(void *)); sd->b2g_cuda_search_kernel_arg5_offset = offset; offset += sizeof(void *); tctx->stream_data[i].b2g_cuda_search_kernel_arg_total = offset; /* buffer to hold the b2g cuda mpm match results for 4000 packets. The * extra 2 bytes(the extra + 1 ) is to hold the no of * matches for the payload. The remaining profile->packet_size_limit * positions in the buffer is to hold the match offsets */ if (profile->page_locked) { if (SCCudaMemHostAlloc((void**)&sd->results_buffer, sizeof(uint16_t) * (profile->packet_size_limit + 1) * profile->packet_buffer_limit, CU_MEMHOSTALLOC_PORTABLE) == -1){ SCLogError(SC_ERR_CUDA_ERROR, "Error allocating page-locked memory\n"); exit(EXIT_FAILURE); } } else { sd->results_buffer = SCMalloc(sizeof(uint16_t) * (profile->packet_size_limit + 1) * profile->packet_buffer_limit); if (sd->results_buffer == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } } if (SCCudaHlGetCudaDevicePtr(&sd->cuda_results_buffer, "MPM_B2G_RESULTS", sizeof(uint16_t) * (profile->packet_size_limit + 1) * profile->packet_buffer_limit, NULL, module_data->handle, sd->b2g_cuda_cumodule_handle) == -1) { goto error; } if (SCCudaHlGetCudaDevicePtr(&sd->cuda_g_u8_lowercasetable, "G_U8_LOWERCASETABLE", 256 * sizeof(char), g_u8_lowercasetable, module_data->handle, sd->b2g_cuda_cumodule_handle) == -1) { goto error; } if (SCCudaHlGetCudaDevicePtr(&sd->cuda_packets_buffer, "MPM_B2G_PACKETS_BUFFER", profile->packet_buffer_limit * (profile->packet_size_limit + sizeof(SCCudaPBPacketDataForGPUNonPayload)), NULL, module_data->handle, sd->b2g_cuda_cumodule_handle) == -1) { goto error; } if (SCCudaHlGetCudaDevicePtr(&sd->cuda_packets_offset_buffer, "MPM_B2G_PACKETS_BUFFER_OFFSETS", sizeof(uint32_t) * profile->packet_buffer_limit, NULL, module_data->handle, sd->b2g_cuda_cumodule_handle) == -1) { goto error; } if (SCCudaHlGetCudaDevicePtr(&sd->cuda_packets_payload_offset_buffer, "MPM_B2G_PACKETS_PAYLOAD_BUFFER_OFFSETS", sizeof(uint32_t) * profile->packet_buffer_limit, NULL, module_data->handle, sd->b2g_cuda_cumodule_handle) == -1) { goto error; } if (SCCudaParamSetv(sd->b2g_cuda_search_kernel, sd->b2g_cuda_search_kernel_arg0_offset, (void *)&sd->cuda_results_buffer, sizeof(void *)) == -1) { goto error; } if (SCCudaParamSetv(sd->b2g_cuda_search_kernel, sd->b2g_cuda_search_kernel_arg1_offset, (void *)&sd->cuda_packets_buffer, sizeof(void *)) == -1) { goto error; } if (SCCudaParamSetv(sd->b2g_cuda_search_kernel, sd->b2g_cuda_search_kernel_arg2_offset, (void *)&sd->cuda_packets_offset_buffer, sizeof(void *)) == -1) { goto error; } if (SCCudaParamSetv(sd->b2g_cuda_search_kernel, sd->b2g_cuda_search_kernel_arg3_offset, (void *)&sd->cuda_packets_payload_offset_buffer, sizeof(void *)) == -1) { goto error; } if (SCCudaParamSetv(sd->b2g_cuda_search_kernel, sd->b2g_cuda_search_kernel_arg5_offset, (void *)&sd->cuda_g_u8_lowercasetable, sizeof(void *)) == -1) { goto error; } if (SCCudaParamSetSize(sd->b2g_cuda_search_kernel, sd->b2g_cuda_search_kernel_arg_total) == -1) { goto error; } } return 0; error: return -1; } /* * \brief DeInitialize data for the cuda streams. * * \param tctx The thread context data of the Cuda MPM. * \param profile The cuda profile used by the MPM. * * \retval 0 on succes, -1 on failure */ static int B2gCudaMpmStreamDataDeInit(B2gCudaMpmThreadCtxData *tctx, MpmCudaConf *profile) { B2gCudaMpmStreamData *sd = NULL; uint8_t i = 0; if (tctx == NULL || profile == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments cannot be NULL"); goto error; } SCLogDebug("DeInitializing data for %"PRIu16" cuda streams", tctx->no_of_streams); for (i = 0; i < tctx->no_of_streams; ++i) { sd = &tctx->stream_data[i]; if (sd->cuda_stream != NULL) { if (SCCudaStreamDestroy(sd->cuda_stream) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating Cuda stream "); goto error; } } if (profile->page_locked) { if (SCCudaMemFreeHost(sd->results_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "results_buffer\n"); goto error; } } else { SCFree(sd->results_buffer); } SCCudaHlFreeCudaDevicePtr("MPM_B2G_RESULTS", tctx->b2g_cuda_module_handle, sd->b2g_cuda_cumodule_handle); SCCudaHlFreeCudaDevicePtr("MPM_B2G_PACKETS_BUFFER", tctx->b2g_cuda_module_handle, sd->b2g_cuda_cumodule_handle); SCCudaHlFreeCudaDevicePtr("MPM_B2G_PACKETS_BUFFER_OFFSETS", tctx->b2g_cuda_module_handle, sd->b2g_cuda_cumodule_handle); SCCudaHlFreeCudaDevicePtr("MPM_B2G_PACKETS_PAYLOAD_BUFFER_OFFSETS", tctx->b2g_cuda_module_handle, sd->b2g_cuda_cumodule_handle); SCCudaHlFreeCudaDevicePtr("G_U8_LOWERCASETABLE", tctx->b2g_cuda_module_handle, sd->b2g_cuda_cumodule_handle); } SCFree(tctx->stream_data); return 0; error: return -1; } /** * \brief The Cuda MPM B2G module's thread init function. * * \param tv Pointer to the ThreadVars which has invoked this function. * \param initdata Pointer to some user sent data. * \param data Pointer to a pointer which can be used to send data to the * dispatcher thread. * * \retval TM_ECODE_OK Always. */ TmEcode B2gCudaMpmDispThreadInit(ThreadVars *tv, void *initdata, void **data) { MpmCudaConf *profile = NULL; SCCudaHlModuleData *module_data = (SCCudaHlModuleData *)initdata; if (PatternMatchDefaultMatcher() != MPM_B2G_CUDA) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "b2g cuda mpm sees mpm that is " "not b2g_cuda"); exit(EXIT_FAILURE); } if (SCCudaCtxPushCurrent(module_data->cuda_context) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error pushing cuda context"); } B2gCudaMpmThreadCtxData *tctx = SCMalloc(sizeof(B2gCudaMpmThreadCtxData)); if (unlikely(tctx == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(tctx, 0, sizeof(B2gCudaMpmThreadCtxData)); tctx->b2g_cuda_module_handle = module_data->handle; /* Check configuration if streams and async operations can be used. * If (CC == 1.0 || page_locked is disabled) then one stream is used, * else more streams are used. When using the stream for async processing * please check if memory has been allocated page-locked. */ profile = SCCudaHlGetProfile("mpm"); SCCudaDevices *devices = SCCudaGetDeviceList(); if (devices == NULL) { SCLogError(SC_ERR_CUDA_ERROR, "CUDA environment not initialized. " "Please initialized the CUDA environment by calling " "SCCudaInitCudaEnvironment() before making any calls " "to the CUDA API."); goto error; } if (profile->device_id >= devices->count) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Cuda device does not exist."); goto error; } tctx->no_of_streams = profile->cuda_streams; if (!devices->devices[profile->device_id]->attr_gpu_overlap) { SCLogInfo("Cuda device does not support gpu overlap. Falling back to 1 stream."); tctx->no_of_streams = 1; } if (!profile->page_locked) { SCLogInfo("In order to use asynchronous operations you need to enable " "page-locked memory in suricata.yaml."); tctx->no_of_streams = 1; } /* Initialize resources for the streams */ tctx->stream_data = SCMalloc(tctx->no_of_streams * sizeof(B2gCudaMpmStreamData)); if (tctx->stream_data == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory."); exit(EXIT_FAILURE); } memset(tctx->stream_data, 0, tctx->no_of_streams * sizeof(B2gCudaMpmStreamData)); if (SCCudaHlGetCudaContext(&tctx->b2g_cuda_context, "mpm", module_data->handle) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error getting a cuda context"); goto error; } /* Initialize stream data */ if (B2gCudaMpmStreamDataInit(tctx, profile) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error initializing Cuda device data."); goto error; } /* Setup queue to hold packet buffers for stream processing */ char *streamq_name = "b2g_cuda_mpm_streamq"; tctx->tmq_streamq = TmqGetQueueByName(streamq_name); if (tctx->tmq_streamq == NULL) { tctx->tmq_streamq = TmqCreateQueue(streamq_name); if (tctx->tmq_streamq == NULL) { goto error; } } tctx->tmq_streamq->q_type = 1; tctx->tmq_streamq->reader_cnt++; tctx->tmq_streamq->writer_cnt++; *data = tctx; return TM_ECODE_OK; error: return TM_ECODE_FAILED; } /** * \brief The Cuda MPM B2G module's thread de-init function. * * \param tv Pointer to the ThreadVars which has invoked this function. * \param data Pointer to the slot data if anything had been attached in * the thread init function. * * \retval TM_ECODE_OK Always. */ TmEcode B2gCudaMpmDispThreadDeInit(ThreadVars *tv, void *data) { B2gCudaMpmThreadCtxData *tctx = data; MpmCudaConf *profile = NULL; if (tctx == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments. data NULL\n"); return TM_ECODE_OK; } if (PatternMatchDefaultMatcher() != MPM_B2G_CUDA) return TM_ECODE_OK; CUcontext dummy_context; SCCudaHlModuleData *module_data = SCCudaHlGetModuleData(tctx->b2g_cuda_module_handle); if (module_data == NULL) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "How did we even fail to get a " "module_data if we are having a module_handle"); goto error; } if (SCCudaHlGetCudaContext(&dummy_context, "mpm", tctx->b2g_cuda_module_handle) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error getting a cuda context for the " "module %s", module_data->name); goto error; } SCCudaCtxPushCurrent(dummy_context); profile = SCCudaHlGetProfile("mpm"); if (B2gCudaMpmStreamDataDeInit(tctx, profile) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error deallocating Cuda device data."); goto error; } SCFree(tctx); if (SCCudaCtxPopCurrent(NULL) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error popping cuda context"); } return TM_ECODE_OK; error: return TM_ECODE_FAILED; } /* * \brief Process a packet buffer on the GPU. * * \param pb Pointer to the packet buffer. * \param tctx Pointer to the thread context which contains the Cuda context, kernel module, * streams, CPU+GPU memory etc. * \param s ID of the stream to be used. * * \retval 0 on succes, -1 on failure */ static int B2gCudaMpmProcessBuffer(SCCudaPBPacketsBuffer *pb, B2gCudaMpmThreadCtxData *tctx, uint16_t s) { B2gCudaMpmStreamData *sd = NULL; if (pb == NULL || tctx == NULL || s >= tctx->no_of_streams) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Either pb == NULL || tctx == NULL" "or the CUstream does not exist"); goto error; } SCLogDebug("Process packet buffer %p in stream %"PRIu16, pb, s); sd = &tctx->stream_data[s]; if (sd->cuda_stream != NULL) { SCLogDebug("B2g Cuda: Asynchronous processing enabled."); sd->cuda_async = 1; } /* H->D */ if (sd->cuda_async) { if (SCCudaMemcpyHtoDAsync(sd->cuda_packets_buffer, pb->packets_buffer, pb->packets_buffer_len, sd->cuda_stream) == -1) { goto error; } if (SCCudaMemcpyHtoDAsync(sd->cuda_packets_offset_buffer, pb->packets_offset_buffer, sizeof(uint32_t) * pb->nop_in_buffer, sd->cuda_stream) == -1) { goto error; } if (SCCudaMemcpyHtoDAsync(sd->cuda_packets_payload_offset_buffer, pb->packets_payload_offset_buffer, sizeof(uint32_t) * pb->nop_in_buffer, sd->cuda_stream) == -1) { goto error; } } else { if (SCCudaMemcpyHtoD(sd->cuda_packets_buffer, pb->packets_buffer, pb->packets_buffer_len) == -1) { goto error; } if (SCCudaMemcpyHtoD(sd->cuda_packets_offset_buffer, pb->packets_offset_buffer, sizeof(uint32_t) * pb->nop_in_buffer) == -1) { goto error; } if (SCCudaMemcpyHtoD(sd->cuda_packets_payload_offset_buffer, pb->packets_payload_offset_buffer, sizeof(uint32_t) * pb->nop_in_buffer) == -1) { goto error; } } if (SCCudaParamSeti(sd->b2g_cuda_search_kernel, sd->b2g_cuda_search_kernel_arg4_offset, pb->nop_in_buffer) == -1) { goto error; } /* Kernel: * the no of threads per block has already been set to 32 * \todo if we are very sure we are allocating a multiple of block_size * buffer_threshold, then we can remove this + 1 here below */ int no_of_cuda_blocks = (pb->nop_in_buffer / 32) + 1; if (sd->cuda_async) { if (SCCudaLaunchGridAsync(sd->b2g_cuda_search_kernel, no_of_cuda_blocks, 1, sd->cuda_stream) == -1) { goto error; } } else { if (SCCudaLaunchGrid(sd->b2g_cuda_search_kernel, no_of_cuda_blocks, 1) == -1) { goto error; } } /* D->H */ if (sd->cuda_async) { if (SCCudaMemcpyDtoHAsync(sd->results_buffer, sd->cuda_results_buffer, sizeof(uint16_t) * (pb->nop_in_buffer + pb->packets_total_payload_len), sd->cuda_stream) == -1) { goto error; } } else { if (SCCudaMemcpyDtoH(sd->results_buffer, sd->cuda_results_buffer, sizeof(uint16_t) * (pb->nop_in_buffer + pb->packets_total_payload_len)) == -1) { goto error; } } return 0; error: SCCudaCtxSynchronize(); sd->cuda_async = 0; return -1; } /** * \brief The dispatcher function for the cuda mpm. Takes a packet, feeds * it to the gpu and informs the calling client when it has the * results ready. * * \param tv We don't need this. * \param incoming_buffer Pointer to the Packet which contains all the relevant data, * like the bufffer, buflen, the contexts. * \param data Pointer to the slot data if anything had been attached in * the thread init function. * \param buffer_dq Pointer to a data queue that can contain additional packet buffers * that should be processed in other CUstreams (if enabled). The dispatcher * function will dequeue all buffers that have been processed. The queue will * not be changed if CUstreams are disabled. * \param post_pq We don't need this. * * \retval TM_ECODE_OK Always. */ TmEcode B2gCudaMpmDispatcher(ThreadVars *tv, Packet *incoming_buffer, void *data, PacketQueue *buffer_dq, PacketQueue *post_pq) { SCCudaPBPacketsBuffer *pb = (SCCudaPBPacketsBuffer *)incoming_buffer; B2gCudaMpmThreadCtxData *tctx = data; SCDQDataQueue *in_dq = (SCDQDataQueue *)buffer_dq; SCDQDataQueue *out_dq = &data_queues[tctx->tmq_streamq->id]; SCDQGenericQData *q_ptr = NULL; SCCudaPBPacketsBuffer *pb_in_queue = NULL; uint8_t curr_stream = 0; uint32_t i = 0; SCLogDebug("Running the B2g CUDA mpm dispatcher"); if (pb == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument. pb is NULL!!"); return TM_ECODE_OK; } /* Start processing the incoming_buffer */ if (B2gCudaMpmProcessBuffer(pb, tctx, curr_stream) == -1) { goto error; } /* Check if there are additional buffers in in_dq */ while (in_dq != NULL && ++curr_stream < tctx->no_of_streams) { SCMutexLock(&in_dq->mutex_q); pb_in_queue = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(in_dq); SCMutexUnlock(&in_dq->mutex_q); if (pb_in_queue == NULL) { break; } /* Add buffer to out_dq and start processing */ SCDQDataEnqueue(out_dq, (SCDQGenericQData *)pb_in_queue); if (B2gCudaMpmProcessBuffer(pb_in_queue, tctx, curr_stream) == -1) { goto error; } } /* Sync first packet buffer */ curr_stream = 0; if (tctx->stream_data[curr_stream].cuda_async) { SCLogDebug("Synchronize PB %p in Cuda stream %"PRIu16, pb, curr_stream); if (SCCudaStreamSynchronize(tctx->stream_data[curr_stream].cuda_stream) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Failed to synchronize Cuda stream"); goto error; } tctx->stream_data[curr_stream].cuda_async = 0; } i = 0; for (i = 0; i < pb->nop_in_buffer; i++) { memcpy(pb->packets_address_buffer[i]->mpm_offsets, (tctx->stream_data[curr_stream].results_buffer + i + pb->packets_payload_offset_buffer[i]), (pb->packets_address_buffer[i]->payload_len + 1) * sizeof(uint16_t)); SCMutexLock(&pb->packets_address_buffer[i]->cuda_mutex); pb->packets_address_buffer[i]->cuda_done = 1; SCMutexUnlock(&pb->packets_address_buffer[i]->cuda_mutex); SCCondSignal(&pb->packets_address_buffer[i]->cuda_cond); } /* Sync all other buffers in out_dq (if any) */ q_ptr = out_dq->bot; while (q_ptr != NULL && ++curr_stream < tctx->no_of_streams) { pb_in_queue = (SCCudaPBPacketsBuffer *)q_ptr; if (tctx->stream_data[curr_stream].cuda_async) { SCLogDebug("Synchronize PB %p in Cuda stream %"PRIu16, pb_in_queue, curr_stream); if (SCCudaStreamSynchronize(tctx->stream_data[curr_stream].cuda_stream) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Failed to synchronize Cuda stream"); goto error; } tctx->stream_data[curr_stream].cuda_async = 0; } i = 0; for (i = 0; i < pb_in_queue->nop_in_buffer; i++) { memcpy(pb_in_queue->packets_address_buffer[i]->mpm_offsets, (tctx->stream_data[curr_stream].results_buffer + i + pb_in_queue->packets_payload_offset_buffer[i]), (pb_in_queue->packets_address_buffer[i]->payload_len + 1) * sizeof(uint16_t)); SCMutexLock(&pb_in_queue->packets_address_buffer[i]->cuda_mutex); pb_in_queue->packets_address_buffer[i]->cuda_done = 1; SCMutexUnlock(&pb_in_queue->packets_address_buffer[i]->cuda_mutex); SCCondSignal(&pb_in_queue->packets_address_buffer[i]->cuda_cond); } q_ptr = q_ptr->prev; } SCLogDebug("B2g Cuda mpm dispatcher returning"); return TM_ECODE_OK; error: if (SCCudaCtxSynchronize() == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Failed to synchronize context."); } curr_stream = 0; tctx->stream_data[curr_stream].cuda_async = 0; for (i = 0; i < pb->nop_in_buffer; i++) { SCMutexLock(&pb->packets_address_buffer[i]->cuda_mutex); pb->packets_address_buffer[i]->cuda_done = 1; SCMutexUnlock(&pb->packets_address_buffer[i]->cuda_mutex); SCCondSignal(&pb->packets_address_buffer[i]->cuda_cond); } q_ptr = out_dq->bot; while (q_ptr != NULL && ++curr_stream < tctx->no_of_streams) { pb_in_queue = (SCCudaPBPacketsBuffer *)q_ptr; tctx->stream_data[curr_stream].cuda_async = 0; for (i = 0; i < pb_in_queue->nop_in_buffer; i++) { SCMutexLock(&pb_in_queue->packets_address_buffer[i]->cuda_mutex); pb_in_queue->packets_address_buffer[i]->cuda_done = 1; SCMutexUnlock(&pb_in_queue->packets_address_buffer[i]->cuda_mutex); SCCondSignal(&pb_in_queue->packets_address_buffer[i]->cuda_cond); } q_ptr = q_ptr->prev; } SCLogError(SC_ERR_B2G_CUDA_ERROR, "B2g Cuda mpm dispatcher returning with error"); return TM_ECODE_OK; } /** * \brief The post processing of cuda mpm b2g results for a packet * is done here. Will be used by the detection thread. We basically * obtain the match offsets from the cuda mpm search and carry out * further matches on those offsets. Also if the results are not * read for a packet, we wait on the conditional, which will then * be signalled by the cuda mpm dispatcher thread, once the results * for the packet are ready. * * \param p Pointer to the packet whose mpm cuda results are * to be further processed. * \param mpm_ctx Pointer to the mpm context for this packet. * \param mpm_thread_ctx Pointer to the mpm thread context. * \param pmq Pointer to the patter matcher queue. * * \retval matches Holds the no of matches. */ int B2gCudaResultsPostProcessing(Packet *p, MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq) { B2gCudaCtx *ctx = mpm_ctx->ctx; while (p->cuda_done == 0) { SCMutexLock(&p->cuda_mutex); if (p->cuda_done == 1) { SCMutexUnlock(&p->cuda_mutex); break; } else { SCCondWait(&p->cuda_cond, &p->cuda_mutex); SCMutexUnlock(&p->cuda_mutex); } } /* reset this flag for the packet */ p->cuda_done = 0; uint16_t *no_of_matches = p->mpm_offsets; uint16_t *host_offsets = p->mpm_offsets + 1; int i = 0, h = 0; uint8_t *buf = p->payload; uint16_t buflen = p->payload_len; int matches = 0; for (i = 0; i < no_of_matches[0]; i++) { h = B2G_CUDA_HASH16(u8_tolower(buf[host_offsets[i] + ctx->m - 2]), u8_tolower(buf[host_offsets[i] + ctx->m - 1])); if (ctx->bloom[h] != NULL) { COUNT(tctx->stat_pminlen_calls++); COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); if ((buflen - host_offsets[i]) < ctx->pminlen[h]) { continue; } else { COUNT(tctx->stat_bloom_calls++); if (BloomFilterTest(ctx->bloom[h], buf + host_offsets[i], ctx->pminlen[h]) == 0) { COUNT(tctx->stat_bloom_hits++); continue; } } } B2gCudaHashItem *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->nxt) { COUNT(tctx->stat_d0_hashloop++); B2gCudaPattern *p = ctx->parray[thi->idx]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { if ((buflen - host_offsets[i]) < p->len) { continue; } if (memcmp_lowercase(p->ci, buf + host_offsets[i], p->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (buflen - host_offsets[i] < p->len) continue; if (memcmp(p->cs, buf + host_offsets[i], p->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); } else { COUNT(tctx->stat_loop_no_match++); } } } } return matches; } /** * \brief Registers the Cuda B2G MPM Module. */ void TmModuleCudaMpmB2gRegister(void) { tmm_modules[TMM_CUDA_MPM_B2G].name = "Cuda_Mpm_B2g"; tmm_modules[TMM_CUDA_MPM_B2G].ThreadInit = B2gCudaMpmDispThreadInit; tmm_modules[TMM_CUDA_MPM_B2G].Func = B2gCudaMpmDispatcher; tmm_modules[TMM_CUDA_MPM_B2G].ThreadExitPrintStats = NULL; tmm_modules[TMM_CUDA_MPM_B2G].ThreadDeinit = B2gCudaMpmDispThreadDeInit; tmm_modules[TMM_CUDA_MPM_B2G].RegisterTests = NULL; } /***************************Code_Specific_To_Mpm_B2g***************************/ void *CudaMpmB2gThreadsSlot1(void *td) { ThreadVars *tv = (ThreadVars *)td; TmSlot *s = (TmSlot *)tv->tm_slots; SCCudaPBPacketsBuffer *data = NULL; B2gCudaMpmThreadCtxData *tctx = NULL; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ SCSetThreadName(tv->name); if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); SCLogDebug("%s starting", tv->name); if (s->SlotThreadInit != NULL) { void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); } SC_ATOMIC_SET(s->slot_data, slot_data); } memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); tctx = (B2gCudaMpmThreadCtxData *)SC_ATOMIC_GET(s->slot_data); TmThreadsSetFlag(tv, THV_INIT_DONE); while(run) { TmThreadTestThreadUnPaused(tv); /* input data */ data = (SCCudaPBPacketsBuffer *)TmqhInputSimpleOnQ(&data_queues[tv->inq->id]); if (data == NULL) { //printf("%s: TmThreadsSlot1: p == NULL\n", tv->name); } else { /* We pass the current packet buffer (1) to the dispatcher function. The data queue * is checked by the dispatcher thread if there is another packet buffer (2) ready. * If the MPM is configured to use multiple CUstreams, buffer (1) and buffer (2) are * processed in parallel using multiple streams; In this case * data_queues[tctx->tmq_streamq->id] will contain the results of packet buffer (2). */ TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); r = SlotFunc(tv, (Packet *)data, (void *)tctx, (PacketQueue *)&data_queues[tv->inq->id], NULL); /* handle error */ /* output the packet buffer (1) */ TmqhOutputSimpleOnQ(&data_queues[tv->outq->id], (SCDQGenericQData *)data); /* output additional packet buffers (2) */ while (data != NULL) { data = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(&data_queues[tctx->tmq_streamq->id]); if (data == NULL) { break; } TmqhOutputSimpleOnQ(&data_queues[tv->outq->id], (SCDQGenericQData *)data); } } if (TmThreadsCheckFlag(tv, THV_KILL)) { run = 0; } } TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); if (s->SlotThreadExitPrintStats != NULL) { s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); } if (s->SlotThreadDeinit != NULL) { r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } } SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); } int B2gCudaStartDispatcherThreadRC(const char *name) { SCCudaHlModuleData *data = NULL; TmModule *tm_module = NULL; if (name == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Error invalid arguments. " "name NULL"); return -1; } if (tv_CMB2_RC != NULL) { SCLogError(SC_ERR_TM_THREADS_ERROR, "We already have this thread " "running from b2g-cuda"); return 0; } data = SCCudaHlGetModuleData(SCCudaHlGetModuleHandle(name)); if (data == NULL) { SCLogDebug("Module not registered. To avail the benefits of this " "registration facility, first register a module using " "context using SCCudaHlRegisterModule(), after which you " "can call this function"); return -1; } /* create the threads */ tv_CMB2_RC = TmThreadCreate("Cuda_Mpm_B2g_RC", "cuda_batcher_mpm_outqueue", "simple", "cuda_batcher_mpm_inqueue", "simple", "custom", CudaMpmB2gThreadsSlot1, 0); if (tv_CMB2_RC == NULL) { SCLogError(SC_ERR_TM_THREADS_ERROR, "ERROR: TmThreadsCreate failed"); exit(EXIT_FAILURE); } tv_CMB2_RC->type = TVT_PPT; tv_CMB2_RC->inq->q_type = 1; tv_CMB2_RC->outq->q_type = 1; tm_module = TmModuleGetByName("Cuda_Mpm_B2g"); if (tm_module == NULL) { SCLogError(SC_ERR_TM_MODULES_ERROR, "ERROR: TmModuleGetByName failed for Cuda_Mpm_B2g_RC"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_CMB2_RC, tm_module, data); if (TmThreadSpawn(tv_CMB2_RC) != TM_ECODE_OK) { SCLogError(SC_ERR_TM_THREADS_ERROR, "ERROR: TmThreadSpawn failed"); exit(EXIT_FAILURE); } TmThreadContinue(tv_CMB2_RC); return 0; } /** * \brief Hacks for the tests. While running the tests, we sometimes need to * kill the threads to make them pop the cuda contexts. We don't need * these under normal running. */ void B2gCudaKillDispatcherThreadRC(void) { if (tv_CMB2_RC == NULL) return; TmThreadKillThread(tv_CMB2_RC); TmThreadRemove(tv_CMB2_RC, tv_CMB2_RC->type); SCFree(tv_CMB2_RC); tv_CMB2_RC = NULL; return; } /*********************************Unittests************************************/ #ifdef UNITTESTS static int B2gCudaTest01(void) { Packet *p = NULL; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; B2gCudaCtx *ctx = NULL; int result = 0; int module_handle = SCCudaHlRegisterModule("B2G_CUDA_TEST"); SCCudaHlModuleData *module_data = SCCudaHlGetModuleData(module_handle); SCCudaPBPacketsBuffer *pb = NULL; /* get the cuda context and push it */ CUcontext dummy_context; if (SCCudaHlGetCudaContext(&dummy_context, "mpm", module_handle) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error getting a cuda context for the " "module SC_RULES_CONTENT_B2G_CUDA"); } SCCudaCtxPushCurrent(dummy_context); memset(&mpm_ctx, 0, sizeof(MpmCtx)); B2gCudaInitCtx(&mpm_ctx, module_handle); /* pop the context before we make further calls to the mpm cuda dispatcher */ SCCudaCtxPopCurrent(NULL); B2gCudaMpmThreadCtxData *tctx = NULL; B2gCudaMpmDispThreadInit(NULL, module_data, (void *)&tctx); ctx = mpm_ctx.ctx; if (tctx->b2g_cuda_context == 0) goto end; if (tctx->stream_data[0].b2g_cuda_cumodule == 0) goto end; if (tctx->stream_data[0].b2g_cuda_search_kernel == 0) goto end; if (B2gCudaAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 1, 1, 0) == -1) goto end; if (B2gCudaPreparePatterns(&mpm_ctx) == -1) goto end; B2gCudaThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); result = 1; SCCudaPBSetProfile("mpm"); pb = SCCudaPBAllocSCCudaPBPacketsBuffer(); SCCudaPBPacketDataForGPU *curr_packet = (SCCudaPBPacketDataForGPU *)pb->packets_buffer; char *string = "tone_one_one_one"; curr_packet->m = ctx->m; curr_packet->table = ctx->cuda_B2G; curr_packet->payload_len = strlen(string); memcpy(curr_packet->payload, string, strlen(string)); pb->nop_in_buffer = 1; pb->packets_buffer_len = sizeof(SCCudaPBPacketDataForGPUNonPayload) + strlen(string); pb->packets_total_payload_len = strlen(string); pb->packets_offset_buffer[0] = 0; pb->packets_payload_offset_buffer[0] = 0; p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) goto end; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); pb->packets_address_buffer[0] = p; p->payload_len = strlen(string); B2gCudaMpmDispatcher(NULL, (Packet *)pb, tctx, NULL, NULL); result &= (p->mpm_offsets[0] == 4); result &= (p->mpm_offsets[1] == 1); result &= (p->mpm_offsets[2] == 5); result &= (p->mpm_offsets[3] == 9); result &= (p->mpm_offsets[4] == 13); end: SCCudaPBDeAllocSCCudaPBPacketsBuffer(pb); B2gCudaMpmDispThreadDeInit(NULL, (void *)tctx); B2gCudaDestroyCtx(&mpm_ctx); B2gCudaThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); SCFree(p); return result; } static int B2gCudaTest02(void) { uint8_t raw_eth[] = { 0x00, 0x25, 0x00, 0x9e, 0xfa, 0xfe, 0x00, 0x02, 0xcf, 0x74, 0xfe, 0xe1, 0x08, 0x00, 0x45, 0x00, 0x01, 0xcc, 0xcb, 0x91, 0x00, 0x00, 0x34, 0x06, 0xdf, 0xa8, 0xd1, 0x55, 0xe3, 0x67, 0xc0, 0xa8, 0x64, 0x8c, 0x00, 0x50, 0xc0, 0xb7, 0xd1, 0x11, 0xed, 0x63, 0x81, 0xa9, 0x9a, 0x05, 0x80, 0x18, 0x00, 0x75, 0x0a, 0xdd, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x09, 0x8a, 0x06, 0xd0, 0x12, 0x21, 0x2a, 0x3b, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x33, 0x30, 0x32, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x30, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x67, 0x77, 0x73, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x31, 0x38, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x65, 0x71, 0x75, 0x69, 0x76, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x0a, 0x3c, 0x48, 0x31, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x31, 0x3e, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x0a, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x41, 0x3e, 0x2e, 0x0d, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0d, 0x0a }; int result = 0; const char *strings[10] = { "test_test_one", "test_two_test", "test_three_test", "test_four_test", "test_five_test", "test_six_test", "test_seven_test", "test_eight_test", "test_nine_test", "test_ten_test"}; /* don't shoot me for hardcoding the results. We will change this in * sometime, by running a separate mpm on the cpu, and then hold * the results in this temp buffer */ int results[10][2] = { {0, 5}, {0, 9}, {0, 11}, {0, 10}, {0, 10}, {0, 9}, {0, 11}, {0, 11}, {0, 10}, {0, 9} }; Packet *p[10]; SCCudaPBThreadCtx *pb_tctx = NULL; DecodeThreadVars dtv; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; SCCudaPBPacketsBuffer *pb = NULL; SCDQDataQueue *dq = NULL; char *inq_name = "cuda_batcher_mpm_inqueue"; char *outq_name = "cuda_batcher_mpm_outqueue"; Tmq *tmq_outq = NULL; Tmq *tmq_inq = NULL; uint32_t i = 0, j = 0; uint8_t no_of_pkts = 10; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); memset(p, 0, sizeof(p)); for (i = 0; i < no_of_pkts; i++) { p[i] = SCMalloc(SIZE_OF_PACKET); if (p[i] == NULL) { printf("error allocating memory\n"); exit(EXIT_FAILURE); } memset(p[i], 0, SIZE_OF_PACKET); p[i]->pkt = (uint8_t *)(p[i] + 1); DecodeEthernet(&tv, &dtv, p[i], raw_eth, sizeof(raw_eth), NULL); } de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G_CUDA; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"test\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("signature parsing failed\n"); goto end; } SigGroupBuild(de_ctx); SCCudaPBSetProfile("mpm"); SCCudaPBSetUpQueuesAndBuffers(); /* get the queues used by the batcher thread */ tmq_inq = TmqGetQueueByName(inq_name); if (tmq_inq == NULL) { printf("tmq_inq NULL\n"); goto end; } tmq_outq = TmqGetQueueByName(outq_name); if (tmq_outq == NULL) { printf("tmq_outq NULL\n"); goto end; } result = 1; /* queue state before calling the thread init function */ dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 10); SCCudaPBRunningTests(1); /* init the TM thread */ SCCudaPBThreadInit(&tv, de_ctx, (void *)&pb_tctx); SCCudaPBSetBufferPacketThreshhold(no_of_pkts); /* queue state after calling the thread init function */ dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); pb = pb_tctx->curr_pb; for (i = 0; i < no_of_pkts; i++) { p[i]->payload = (uint8_t *)strings[i]; p[i]->payload_len = strlen(strings[i]); SCCudaPBBatchPackets(NULL, p[i], pb_tctx, NULL, NULL); } dq = &data_queues[tmq_outq->id]; result &= (dq->len == 1); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 8); result &= (pb->nop_in_buffer == no_of_pkts); int module_handle = SCCudaHlRegisterModule("SC_RULES_CONTENT_B2G_CUDA"); SCCudaHlModuleData *module_data = SCCudaHlGetModuleData(module_handle); B2gCudaMpmThreadCtxData *b2g_tctx = NULL; B2gCudaMpmDispThreadInit(NULL, module_data, (void *)&b2g_tctx); if (b2g_tctx->b2g_cuda_context == 0 || b2g_tctx->stream_data[0].b2g_cuda_cumodule == 0 || b2g_tctx->stream_data[0].b2g_cuda_search_kernel == 0) { result = 0; goto end; } B2gCudaMpmDispatcher(NULL, (Packet *)pb, b2g_tctx, NULL, NULL); for (i = 0; i < no_of_pkts; i++) { for (j = 0; j < p[i]->mpm_offsets[0]; j++) result &= (results[i][j] == p[i]->mpm_offsets[j + 1]); } end: for (i = 0; i < no_of_pkts; i++) { SCFree(p[i]); } SCCudaPBCleanUpQueuesAndBuffers(); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } SCCudaPBThreadDeInit(NULL, (void *)pb_tctx); B2gCudaMpmDispThreadDeInit(NULL, (void *)b2g_tctx); return result; } static int B2gCudaTest03(void) { uint8_t raw_eth[] = { 0x00, 0x25, 0x00, 0x9e, 0xfa, 0xfe, 0x00, 0x02, 0xcf, 0x74, 0xfe, 0xe1, 0x08, 0x00, 0x45, 0x00, 0x01, 0xcc, 0xcb, 0x91, 0x00, 0x00, 0x34, 0x06, 0xdf, 0xa8, 0xd1, 0x55, 0xe3, 0x67, 0xc0, 0xa8, 0x64, 0x8c, 0x00, 0x50, 0xc0, 0xb7, 0xd1, 0x11, 0xed, 0x63, 0x81, 0xa9, 0x9a, 0x05, 0x80, 0x18, 0x00, 0x75, 0x0a, 0xdd, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x09, 0x8a, 0x06, 0xd0, 0x12, 0x21, 0x2a, 0x3b, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x33, 0x30, 0x32, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x30, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x67, 0x77, 0x73, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x31, 0x38, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x65, 0x71, 0x75, 0x69, 0x76, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x0a, 0x3c, 0x48, 0x31, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x31, 0x3e, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x0a, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x41, 0x3e, 0x2e, 0x0d, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0d, 0x0a }; int result = 0; const char *strings[10] = { "test_test_one", "test_two_test", "test_three_test", "test_four_test", "test_five_test", "test_six_test", "test_seven_test", "test_eight_test", "test_nine_test", "test_ten_test"}; /* don't shoot me for hardcoding the results. We will change this in * sometime, by having run a separate mpm on the cpu and then hold * the results in a temp buffer */ Packet *p[10]; SCCudaPBThreadCtx *pb_tctx = NULL; DecodeThreadVars dtv; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx; ThreadVars de_tv; SCCudaPBPacketsBuffer *pb = NULL; SCDQDataQueue *dq = NULL; char *inq_name = "cuda_batcher_mpm_inqueue"; char *outq_name = "cuda_batcher_mpm_outqueue"; Tmq *tmq_outq = NULL; Tmq *tmq_inq = NULL; uint32_t i = 0, j = 0; uint8_t no_of_pkts = 10; Signature *sig = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&de_tv, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); for (i = 0; i < no_of_pkts; i++) { p[i] = SCMalloc(SIZE_OF_PACKET); if (p[i] == NULL) { printf("error allocating memory\n"); exit(EXIT_FAILURE); } memset(p[i], 0, SIZE_OF_PACKET); p[i]->pkt = (uint8_t *)(p[i] + 1); DecodeEthernet(&tv, &dtv, p[i], raw_eth, sizeof(raw_eth), NULL); } de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G_CUDA; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"test\"; sid:0;)"); if (de_ctx->sig_list == NULL) { printf("signature parsing failed\n"); goto end; } sig = de_ctx->sig_list; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"one\"; sid:1;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"two\"; sid:2;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"three\"; sid:3;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"four\"; sid:4;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"five\"; sid:5;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"six\"; sid:6;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"seven\"; sid:7;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"eight\"; sid:8;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"nine\"; sid:9;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"ten\"; sid:10;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } /* build the signatures */ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&de_tv, (void *)de_ctx, (void *)&det_ctx); SCCudaPBSetProfile("mpm"); SCCudaPBSetUpQueuesAndBuffers(); /* get the queues used by the batcher thread */ tmq_inq = TmqGetQueueByName(inq_name); if (tmq_inq == NULL) { printf("tmq_inq NULL\n"); goto end; } tmq_outq = TmqGetQueueByName(outq_name); if (tmq_outq == NULL) { printf("tmq_outq NULL\n"); goto end; } result = 1; /* queue state before calling the thread init function */ dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 10); SCCudaPBRunningTests(1); /* init the TM thread */ SCCudaPBThreadInit(&tv, de_ctx, (void *)&pb_tctx); SCCudaPBSetBufferPacketThreshhold(no_of_pkts); /* queue state after calling the thread init function */ dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); pb = pb_tctx->curr_pb; for (i = 0; i < no_of_pkts; i++) { p[i]->payload = (uint8_t *)strings[i]; p[i]->payload_len = strlen(strings[i]); SCCudaPBBatchPackets(NULL, p[i], pb_tctx, NULL, NULL); } dq = &data_queues[tmq_outq->id]; result &= (dq->len == 1); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 8); result &= (pb->nop_in_buffer == no_of_pkts); int module_handle = SCCudaHlRegisterModule("SC_RULES_CONTENT_B2G_CUDA"); SCCudaHlModuleData *module_data = SCCudaHlGetModuleData(module_handle); B2gCudaMpmThreadCtxData *b2g_tctx = NULL; B2gCudaMpmDispThreadInit(NULL, module_data, (void *)&b2g_tctx); if (b2g_tctx->b2g_cuda_context == 0 || b2g_tctx->stream_data[0].b2g_cuda_cumodule == 0 || b2g_tctx->stream_data[0].b2g_cuda_search_kernel == 0) { result = 0; goto end; } B2gCudaMpmDispatcher(NULL, (Packet *)pb, b2g_tctx, NULL, NULL); for (i = 0; i < 10; i++) SigMatchSignatures(&de_tv, de_ctx, det_ctx, p[i]); for (i = 0; i < 10; i++) { if (!PacketAlertCheck(p[i], 0)) { result = 0; goto end; } for (j = 1; j <= 10; j++) { if (j == i + 1) { if (!PacketAlertCheck(p[i], j)) { result = 0; goto end; } } else { if (PacketAlertCheck(p[i], j)) { result = 0; goto end; } } } } end: for (i = 0; i < no_of_pkts; i++) { SCFree(p[i]); } SCCudaPBCleanUpQueuesAndBuffers(); if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } SCCudaPBThreadDeInit(NULL, (void *)pb_tctx); B2gCudaMpmDispThreadDeInit(NULL, (void *)b2g_tctx); return result; } static int B2gCudaTest04(void) { uint8_t raw_eth[] = { 0x00, 0x25, 0x00, 0x9e, 0xfa, 0xfe, 0x00, 0x02, 0xcf, 0x74, 0xfe, 0xe1, 0x08, 0x00, 0x45, 0x00, 0x01, 0xcc, 0xcb, 0x91, 0x00, 0x00, 0x34, 0x06, 0xdf, 0xa8, 0xd1, 0x55, 0xe3, 0x67, 0xc0, 0xa8, 0x64, 0x8c, 0x00, 0x50, 0xc0, 0xb7, 0xd1, 0x11, 0xed, 0x63, 0x81, 0xa9, 0x9a, 0x05, 0x80, 0x18, 0x00, 0x75, 0x0a, 0xdd, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x09, 0x8a, 0x06, 0xd0, 0x12, 0x21, 0x2a, 0x3b, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x33, 0x30, 0x32, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x30, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x67, 0x77, 0x73, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x31, 0x38, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x65, 0x71, 0x75, 0x69, 0x76, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x0a, 0x3c, 0x48, 0x31, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x31, 0x3e, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x0a, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x41, 0x3e, 0x2e, 0x0d, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0d, 0x0a }; int result = 0; const char *strings[10] = { "test_test_one", "test_two_test", "test_three_test", "test_four_test", "test_five_test", "test_six_test", "test_seven_test", "test_eight_test", "test_nine_test", "test_ten_test"}; /* don't shoot me for hardcoding the results. We will change this in * sometime, by having run a separate mpm on the cpu and then hold * the results in a temp buffer */ const uint16_t max_pkts_in_buffer = 5; const uint16_t no_of_pkts = max_pkts_in_buffer * 2; Packet *p[no_of_pkts]; SCCudaPBThreadCtx *pb_tctx = NULL; DecodeThreadVars dtv; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx; ThreadVars de_tv; SCCudaPBPacketsBuffer *pb = NULL; SCDQDataQueue *dq = NULL; char *inq_name = "cuda_batcher_mpm_inqueue"; char *outq_name = "cuda_batcher_mpm_outqueue"; Tmq *tmq_outq = NULL; Tmq *tmq_inq = NULL; uint32_t i = 0, j = 0; Signature *sig = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&de_tv, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); for (i = 0; i < no_of_pkts; i++) { p[i] = SCMalloc(sizeof(Packet)); if (p[i] == NULL) { printf("error allocating memory\n"); exit(EXIT_FAILURE); } memset(p[i], 0, sizeof(Packet)); p[i]->pkt = (uint8_t *)(p[i] + 1); DecodeEthernet(&tv, &dtv, p[i], raw_eth, sizeof(raw_eth), NULL); } de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G_CUDA; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"test\"; sid:0;)"); if (de_ctx->sig_list == NULL) { printf("signature parsing failed\n"); goto end; } sig = de_ctx->sig_list; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"one\"; sid:1;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"two\"; sid:2;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"three\"; sid:3;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"four\"; sid:4;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"five\"; sid:5;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"six\"; sid:6;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"seven\"; sid:7;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"eight\"; sid:8;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"nine\"; sid:9;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"ten\"; sid:10;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } /* build the signatures */ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&de_tv, (void *)de_ctx, (void *)&det_ctx); SCCudaPBSetProfile("mpm"); SCCudaPBSetUpQueuesAndBuffers(); /* get the queues used by the batcher thread */ tmq_inq = TmqGetQueueByName(inq_name); if (tmq_inq == NULL) { printf("tmq_inq NULL\n"); goto end; } tmq_outq = TmqGetQueueByName(outq_name); if (tmq_outq == NULL) { printf("tmq_outq NULL\n"); goto end; } result = 1; /* queue state before calling the thread init function */ dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 10); SCCudaPBRunningTests(1); /* init the TM thread */ SCCudaPBThreadInit(&tv, de_ctx, (void *)&pb_tctx); SCCudaPBSetBufferPacketThreshhold(max_pkts_in_buffer); /* queue state after calling the thread init function */ dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); for (i = 0; i < no_of_pkts; i++) { p[i]->payload = (uint8_t *)strings[i]; p[i]->payload_len = strlen(strings[i]); SCCudaPBBatchPackets(NULL, p[i], pb_tctx, NULL, NULL); } dq = &data_queues[tmq_outq->id]; result &= (dq->len == 2); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 7); int module_handle = SCCudaHlRegisterModule("SC_RULES_CONTENT_B2G_CUDA"); SCCudaHlModuleData *module_data = SCCudaHlGetModuleData(module_handle); B2gCudaMpmThreadCtxData *b2g_tctx = NULL; B2gCudaMpmDispThreadInit(NULL, module_data, (void *)&b2g_tctx); if (b2g_tctx->no_of_streams < 2) { printf("At least 2 cuda streams needed for this test. Skipping ..\n"); goto end; } if (b2g_tctx->b2g_cuda_context == 0 || b2g_tctx->stream_data[0].b2g_cuda_cumodule == 0 || b2g_tctx->stream_data[0].b2g_cuda_search_kernel == 0) { result = 0; goto end; } SCCudaCtxSynchronize(); /* Run the dispatcher function. */ pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(&data_queues[tmq_outq->id]); if (pb == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "PacketBuffer should not be empty"); result = 0; } result &= (pb->nop_in_buffer == max_pkts_in_buffer); B2gCudaMpmDispatcher(NULL, (Packet *)pb, b2g_tctx, (PacketQueue *)&data_queues[tmq_outq->id], NULL); TmqhOutputSimpleOnQ(&data_queues[tmq_inq->id], (SCDQGenericQData *)pb); if (data_queues[b2g_tctx->tmq_streamq->id].len != 1) { result = 0; } while ((pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(&data_queues[b2g_tctx->tmq_streamq->id])) != NULL) { TmqhOutputSimpleOnQ(&data_queues[tmq_inq->id], (SCDQGenericQData *)pb); } if (data_queues[b2g_tctx->tmq_streamq->id].len != 0) { result = 0; } for (i = 0; i < no_of_pkts; i++) SigMatchSignatures(&de_tv, de_ctx, det_ctx, p[i]); for (i = 0; i < no_of_pkts; i++) { if (!PacketAlertCheck(p[i], 0)) { result = 0; goto end; } for (j = 1; j <= 10; j++) { if (j == i + 1) { if (!PacketAlertCheck(p[i], j)) { result = 0; goto end; } } else { if (PacketAlertCheck(p[i], j)) { result = 0; goto end; } } } } end: for (i = 0; i < no_of_pkts; i++) { SCFree(p[i]); } SCCudaPBCleanUpQueuesAndBuffers(); if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } SCCudaPBThreadDeInit(NULL, (void *)pb_tctx); B2gCudaMpmDispThreadDeInit(NULL, (void *)b2g_tctx); return result; } static int B2gCudaTest05(void) { uint8_t raw_eth[] = { 0x00, 0x25, 0x00, 0x9e, 0xfa, 0xfe, 0x00, 0x02, 0xcf, 0x74, 0xfe, 0xe1, 0x08, 0x00, 0x45, 0x00, 0x01, 0xcc, 0xcb, 0x91, 0x00, 0x00, 0x34, 0x06, 0xdf, 0xa8, 0xd1, 0x55, 0xe3, 0x67, 0xc0, 0xa8, 0x64, 0x8c, 0x00, 0x50, 0xc0, 0xb7, 0xd1, 0x11, 0xed, 0x63, 0x81, 0xa9, 0x9a, 0x05, 0x80, 0x18, 0x00, 0x75, 0x0a, 0xdd, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x09, 0x8a, 0x06, 0xd0, 0x12, 0x21, 0x2a, 0x3b, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x33, 0x30, 0x32, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x30, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x67, 0x77, 0x73, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x31, 0x38, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x65, 0x71, 0x75, 0x69, 0x76, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x0a, 0x3c, 0x48, 0x31, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x31, 0x3e, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x0a, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x41, 0x3e, 0x2e, 0x0d, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0d, 0x0a }; int result = 0; const char *strings[10] = { "test_test_one", "test_two_test", "test_three_test", "test_four_test", "test_five_test", "test_six_test", "test_seven_test", "test_eight_test", "test_nine_test", "test_ten_test"}; /* don't shoot me for hardcoding the results. We will change this in * sometime, by having run a separate mpm on the cpu and then hold * the results in a temp buffer */ const uint16_t max_pkts_in_buffer = 300; const uint16_t no_of_pkts = max_pkts_in_buffer * 4; uint16_t max_runs = 2; Packet *p[no_of_pkts]; SCCudaPBThreadCtx *pb_tctx = NULL; DecodeThreadVars dtv; ThreadVars tv; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx; ThreadVars de_tv; SCCudaPBPacketsBuffer *pb = NULL; SCCudaPBPacketsBuffer *pb2 = NULL; SCDQDataQueue *dq = NULL; char *inq_name = "cuda_batcher_mpm_inqueue"; char *outq_name = "cuda_batcher_mpm_outqueue"; Tmq *tmq_outq = NULL; Tmq *tmq_inq = NULL; uint32_t i = 0, j = 0; Signature *sig = NULL; memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&de_tv, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); for (i = 0; i < no_of_pkts; i++) { p[i] = SCMalloc(sizeof(Packet)); if (p[i] == NULL) { printf("error allocating memory\n"); exit(EXIT_FAILURE); } memset(p[i], 0, sizeof(Packet)); p[i]->pkt = (uint8_t *)(p[i] + 1); DecodeEthernet(&tv, &dtv, p[i], raw_eth, sizeof(raw_eth), NULL); } de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G_CUDA; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"test\"; sid:0;)"); if (de_ctx->sig_list == NULL) { printf("signature parsing failed\n"); goto end; } sig = de_ctx->sig_list; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"one\"; sid:1;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"two\"; sid:2;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"three\"; sid:3;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"four\"; sid:4;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"five\"; sid:5;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"six\"; sid:6;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"seven\"; sid:7;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"eight\"; sid:8;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"nine\"; sid:9;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } sig = sig->next; sig->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"ten\"; sid:10;)"); if (sig->next == NULL) { printf("signature parsing failed\n"); goto end; } /* build the signatures */ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&de_tv, (void *)de_ctx, (void *)&det_ctx); SCCudaPBSetProfile("mpm"); SCCudaPBSetUpQueuesAndBuffers(); /* get the queues used by the batcher thread */ tmq_inq = TmqGetQueueByName(inq_name); if (tmq_inq == NULL) { printf("tmq_inq NULL\n"); goto end; } tmq_outq = TmqGetQueueByName(outq_name); if (tmq_outq == NULL) { printf("tmq_outq NULL\n"); goto end; } result = 1; /* queue state before calling the thread init function */ dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 10); SCCudaPBRunningTests(1); /* init the TM thread */ SCCudaPBThreadInit(&tv, de_ctx, (void *)&pb_tctx); SCCudaPBSetBufferPacketThreshhold(max_pkts_in_buffer); /* queue state after calling the thread init function */ dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); int module_handle = SCCudaHlRegisterModule("SC_RULES_CONTENT_B2G_CUDA"); SCCudaHlModuleData *module_data = SCCudaHlGetModuleData(module_handle); B2gCudaMpmThreadCtxData *b2g_tctx = NULL; B2gCudaMpmDispThreadInit(NULL, module_data, (void *)&b2g_tctx); if (b2g_tctx->no_of_streams < 2) { printf("At least 2 cuda streams needed for this test. Skipping ..\n"); goto end; } if (b2g_tctx->b2g_cuda_context == 0 || b2g_tctx->stream_data[0].b2g_cuda_cumodule == 0 || b2g_tctx->stream_data[0].b2g_cuda_search_kernel == 0) { result = 0; goto end; } uint64_t start_ = 0; uint64_t stop_ = 0; uint64_t time_nostream_ = 0; uint64_t time_stream_ = 0; SCCudaCtxSynchronize(); /* Benchmark the dispatcher function. */ int run = 0; for (run = 0; run < max_runs; ++run) { /* Fill the packet buffers */ for (i = 0; i < no_of_pkts; i++) { p[i]->payload = (uint8_t *)strings[i%10]; p[i]->payload_len = strlen(strings[i%10]); SCCudaPBBatchPackets(NULL, p[i], pb_tctx, NULL, NULL); } dq = &data_queues[tmq_outq->id]; result &= (dq->len == 4); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 5); /* Performance test with two separate calls */ pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(&data_queues[tmq_outq->id]); pb2 = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(&data_queues[tmq_outq->id]); if (pb == NULL || pb2 == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "PacketBuffer should not be empty"); result = 0; } result &= (pb->nop_in_buffer == max_pkts_in_buffer); result &= (pb2->nop_in_buffer == max_pkts_in_buffer); start_ = UtilCpuGetTicks(); B2gCudaMpmDispatcher(NULL, (Packet *)pb, b2g_tctx, (PacketQueue *)NULL, (PacketQueue *)NULL); B2gCudaMpmDispatcher(NULL, (Packet *)pb2, b2g_tctx, (PacketQueue *)NULL, (PacketQueue *)NULL); stop_ = UtilCpuGetTicks(); TmqhOutputSimpleOnQ(&data_queues[tmq_inq->id], (SCDQGenericQData *)pb); TmqhOutputSimpleOnQ(&data_queues[tmq_inq->id], (SCDQGenericQData *)pb2); time_nostream_ += stop_ - start_; /* Performance test with one call using streams */ pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(&data_queues[tmq_outq->id]); if (pb == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "PacketBuffer should not be empty"); result = 0; } result &= (pb->nop_in_buffer == max_pkts_in_buffer); result &= (pb2->nop_in_buffer == max_pkts_in_buffer); start_ = UtilCpuGetTicks(); B2gCudaMpmDispatcher(NULL, (Packet *)pb, b2g_tctx, (PacketQueue *)&data_queues[tmq_outq->id], NULL); stop_ = UtilCpuGetTicks(); TmqhOutputSimpleOnQ(&data_queues[tmq_inq->id], (SCDQGenericQData *)pb); while ((pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(&data_queues[b2g_tctx->tmq_streamq->id])) != NULL) { TmqhOutputSimpleOnQ(&data_queues[tmq_inq->id], (SCDQGenericQData *)pb); } time_stream_ += stop_ - start_; } printf("Avg CPU ticks without stream after %i runs: %"PRIu64"\n", run, time_nostream_/run); printf("Avg CPU ticks with 2 streams after %i runs: %"PRIu64"\n", run, time_stream_/run); for (i = 0; i < no_of_pkts; i++) SigMatchSignatures(&de_tv, de_ctx, det_ctx, p[i]); for (i = 0; i < no_of_pkts; i++) { if (!PacketAlertCheck(p[i], 0)) { result = 0; goto end; } for (j = 1; j <= 10; j++) { if (j == i%10 + 1) { if (!PacketAlertCheck(p[i], j)) { result = 0; goto end; } } else { if (PacketAlertCheck(p[i], j)) { result = 0; goto end; } } } } end: for (i = 0; i < no_of_pkts; i++) { SCFree(p[i]); } SCCudaPBCleanUpQueuesAndBuffers(); if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } SCCudaPBThreadDeInit(NULL, (void *)pb_tctx); B2gCudaMpmDispThreadDeInit(NULL, (void *)b2g_tctx); return result; } #endif /* UNITTESTS */ /*********************************Unittests************************************/ void B2gCudaRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("B2gCudaTest01", B2gCudaTest01, 1); UtRegisterTest("B2gCudaTest02", B2gCudaTest02, 1); UtRegisterTest("B2gCudaTest03", B2gCudaTest03, 1); UtRegisterTest("B2gCudaTest04", B2gCudaTest04, 1); UtRegisterTest("B2gCudaTest05", B2gCudaTest05, 1); #endif /* UNITTESTS */ } #endif /* __SC_CUDA_SUPPORT */ suricata-1.4.7/src/log-pcap.c0000644000000000000000000005142512253546156012702 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author William Metcalf * * Pcap packet logging module. */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "conf.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "util-unittest.h" #include "log-pcap.h" #include "decode-ipv4.h" #include "util-error.h" #include "util-debug.h" #include "util-time.h" #include "util-byte.h" #include "util-misc.h" #include "source-pcap.h" #include "output.h" #include "queue.h" #define DEFAULT_LOG_FILENAME "pcaplog" #define MODULE_NAME "PcapLog" #define MIN_LIMIT 1 * 1024 * 1024 #define DEFAULT_LIMIT 100 * 1024 * 1024 #define DEFAULT_FILE_LIMIT 0 #define LOGMODE_NORMAL 0 #define LOGMODE_SGUIL 1 #define RING_BUFFER_MODE_DISABLED 0 #define RING_BUFFER_MODE_ENABLED 1 #define TS_FORMAT_SEC 0 #define TS_FORMAT_USEC 1 #define USE_STREAM_DEPTH_DISABLED 0 #define USE_STREAM_DEPTH_ENABLED 1 TmEcode PcapLog(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode PcapLogDataInit(ThreadVars *, void *, void **); TmEcode PcapLogDataDeinit(ThreadVars *, void *); static void PcapLogFileDeInitCtx(OutputCtx *); typedef struct PcapFileName_ { char *filename; char *dirname; TAILQ_ENTRY(PcapFileName_) next; /**< Pointer to next Pcap File for tailq. */ } PcapFileName; /** * PcapLog thread vars * * Used for storing file options. */ typedef struct PcapLogData_ { uint64_t size_current; /**< file current size */ uint64_t size_limit; /**< file size limit */ struct pcap_pkthdr *h; /**< pcap header struct */ char *filename; /**< current filename */ uint32_t file_cnt; /**< count of pcap files we currently have */ uint32_t max_files; /**< maximum files to use in ring buffer mode */ uint64_t pkt_cnt; /**< total number of packets */ int prev_day; /**< last day, for finding out when */ pcap_t *pcap_dead_handle; /**< pcap_dumper_t needs a handle */ pcap_dumper_t *pcap_dumper; /**< actually writes the packets */ char *prefix; /**< filename prefix */ int mode; /**< normal or sguil */ int use_ringbuffer; /**< ring buffer mode enabled or disabled */ int timestamp_format; /**< timestamp format sec or usec */ int use_stream_depth; /**< use stream depth i.e. ignore packets that reach limit */ char dir[PATH_MAX]; /**< pcap log directory */ SCMutex plog_lock; TAILQ_HEAD(, PcapFileName_) pcap_file_list; } PcapLogData; int PcapLogOpenFileCtx(PcapLogData *); void TmModulePcapLogRegister(void) { tmm_modules[TMM_PCAPLOG].name = MODULE_NAME; tmm_modules[TMM_PCAPLOG].ThreadInit = PcapLogDataInit; tmm_modules[TMM_PCAPLOG].Func = PcapLog; tmm_modules[TMM_PCAPLOG].ThreadDeinit = PcapLogDataDeinit; tmm_modules[TMM_PCAPLOG].RegisterTests = NULL; OutputRegisterModule(MODULE_NAME, "pcap-log", PcapLogInitCtx); return; } /** * \brief Function to close pcaplog file * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param pl PcapLog thread variable. */ int PcapLogCloseFile(ThreadVars *t, PcapLogData *pl) { if (pl != NULL) { if (pl->pcap_dumper != NULL) pcap_dump_close(pl->pcap_dumper); pl->size_current = 0; pl->pcap_dumper = NULL; if (pl->pcap_dead_handle != NULL) pcap_close(pl->pcap_dead_handle); pl->pcap_dead_handle = NULL; } return 0; } static void PcapFileNameFree(PcapFileName *pf) { if (pf != NULL) { if (pf->filename != NULL) { SCFree(pf->filename); } if (pf->dirname != NULL) { SCFree(pf->dirname); } SCFree(pf); } return; } /** * \brief Function to rotate pcaplog file * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param pl PcapLog thread variable. * * \retval 0 on succces * \retval -1 on failure */ int PcapLogRotateFile(ThreadVars *t, PcapLogData *pl) { PcapFileName *pf; PcapFileName *pfnext; if (PcapLogCloseFile(t,pl) < 0) { SCLogDebug("PcapLogCloseFile failed"); return -1; } if (pl->use_ringbuffer == RING_BUFFER_MODE_ENABLED && pl->file_cnt >= pl->max_files) { pf = TAILQ_FIRST(&pl->pcap_file_list); SCLogDebug("Removing pcap file %s", pf->filename); if (remove(pf->filename) != 0) { // VJ remove can fail because file is already gone //LogWarning(SC_ERR_PCAP_FILE_DELETE_FAILED, // "failed to remove log file %s: %s", // pf->filename, strerror( errno )); } /* Remove directory if Sguil mode and no files left in sguil dir */ if (pl->mode == LOGMODE_SGUIL) { pfnext = TAILQ_NEXT(pf,next); if (strcmp(pf->dirname, pfnext->dirname) == 0) { SCLogDebug("Current entry dir %s and next entry %s " "are equal: not removing dir", pf->dirname, pfnext->dirname); } else { SCLogDebug("current entry %s and %s are " "not equal: removing dir", pf->dirname, pfnext->dirname); if (remove(pf->dirname) != 0) { SCLogWarning(SC_ERR_PCAP_FILE_DELETE_FAILED, "failed to remove sguil log %s: %s", pf->dirname, strerror( errno )); } } } TAILQ_REMOVE(&pl->pcap_file_list, pf, next); PcapFileNameFree(pf); pl->file_cnt--; } if (PcapLogOpenFileCtx(pl) < 0) { SCLogError(SC_ERR_FOPEN, "opening new pcap log file failed"); return -1; } pl->file_cnt++; return 0; } /** * \brief Pcap logging main function * * \param t threadvar * \param p packet * \param data thread module specific data * \param pq pre-packet-queue * \param postpq post-packet-queue * * \retval TM_ECODE_OK on succes * \retval TM_ECODE_FAILED on serious error */ TmEcode PcapLog (ThreadVars *t, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { size_t len; int rotate = 0; int ret = 0; PcapLogData *pl = (PcapLogData *)data; if ((p->flags & PKT_PSEUDO_STREAM_END) || ((p->flags & PKT_STREAM_NOPCAPLOG) && (pl->use_stream_depth == USE_STREAM_DEPTH_ENABLED)) || (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p))) { return TM_ECODE_OK; } SCMutexLock(&pl->plog_lock); pl->pkt_cnt++; pl->h->ts.tv_sec = p->ts.tv_sec; pl->h->ts.tv_usec = p->ts.tv_usec; pl->h->caplen = GET_PKT_LEN(p); pl->h->len = GET_PKT_LEN(p); len = sizeof(*pl->h) + GET_PKT_LEN(p); if (pl->filename == NULL) { SCLogDebug("Opening PCAP log file %s", pl->filename); ret = PcapLogOpenFileCtx(pl); if (ret < 0) { SCMutexUnlock(&pl->plog_lock); return TM_ECODE_FAILED; } } if (pl->mode == LOGMODE_SGUIL) { struct tm local_tm; struct tm *tms = (struct tm *)SCLocalTime(p->ts.tv_sec, &local_tm); if (tms->tm_mday != pl->prev_day) { rotate = 1; pl->prev_day = tms->tm_mday; } } if ((pl->size_current + len) > pl->size_limit || rotate) { if (PcapLogRotateFile(t,pl) < 0) { SCMutexUnlock(&pl->plog_lock); SCLogDebug("rotation of pcap failed"); return TM_ECODE_FAILED; } } /* XXX pcap handles, nfq, pfring, can only have one link type ipfw? we do * this here as we don't know the link type until we get our first packet */ if (pl->pcap_dead_handle == NULL) { SCLogDebug("Setting pcap-log link type to %u", p->datalink); if ((pl->pcap_dead_handle = pcap_open_dead(p->datalink, -1)) == NULL) { SCLogDebug("Error opening dead pcap handle"); SCMutexUnlock(&pl->plog_lock); return TM_ECODE_FAILED; } } /* XXX LogfileCtx setup currently doesn't allow thread vars so we open the * handle here */ if (pl->pcap_dumper == NULL) { if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle, pl->filename)) == NULL) { SCLogInfo("Error opening dump file %s", pcap_geterr(pl->pcap_dead_handle)); SCMutexUnlock(&pl->plog_lock); return TM_ECODE_FAILED; } } pcap_dump((u_char *)pl->pcap_dumper, pl->h, GET_PKT_DATA(p)); pl->size_current += len; SCLogDebug("pl->size_current %"PRIu64", pl->size_limit %"PRIu64, pl->size_current, pl->size_limit); SCMutexUnlock(&pl->plog_lock); return TM_ECODE_OK; } TmEcode PcapLogDataInit(ThreadVars *t, void *initdata, void **data) { if (initdata == NULL) { SCLogDebug("Error getting context for PcapLog. \"initdata\" argument NULL"); return TM_ECODE_FAILED; } PcapLogData *pl = ((OutputCtx *)initdata)->data; SCMutexLock(&pl->plog_lock); /** Use the Ouptut Context (file pointer and mutex) */ pl->pkt_cnt = 0; pl->pcap_dead_handle = NULL; pl->pcap_dumper = NULL; pl->file_cnt = 1; struct timeval ts; memset(&ts, 0x00, sizeof(struct timeval)); TimeGet(&ts); struct tm local_tm; struct tm *tms = (struct tm *)SCLocalTime(ts.tv_sec, &local_tm); pl->prev_day = tms->tm_mday; *data = (void *)pl; SCMutexUnlock(&pl->plog_lock); return TM_ECODE_OK; } /** * \brief Thread deinit function. * * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param data PcapLog thread data. * \retval TM_ECODE_OK on succces * \retval TM_ECODE_FAILED on failure */ TmEcode PcapLogDataDeinit(ThreadVars *t, void *data) { return TM_ECODE_OK; } /** \brief Fill in pcap logging struct from the provided ConfNode. * \param conf The configuration node for this output. * \retval output_ctx * */ OutputCtx *PcapLogInitCtx(ConfNode *conf) { PcapLogData *pl = SCMalloc(sizeof(PcapLogData)); if (unlikely(pl == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate Memory for PcapLogData"); exit(EXIT_FAILURE); } memset(pl, 0, sizeof(PcapLogData)); pl->h = SCMalloc(sizeof(*pl->h)); if (pl->h == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate Memory for pcap header struct"); exit(EXIT_FAILURE); } /* Set the defaults */ pl->mode = LOGMODE_NORMAL; pl->max_files = DEFAULT_FILE_LIMIT; pl->use_ringbuffer = RING_BUFFER_MODE_DISABLED; pl->timestamp_format = TS_FORMAT_SEC; pl->use_stream_depth = USE_STREAM_DEPTH_DISABLED; TAILQ_INIT(&pl->pcap_file_list); SCMutexInit(&pl->plog_lock, NULL); /* conf params */ const char *filename = NULL; if (conf != NULL) { /* To faciliate unit tests. */ filename = ConfNodeLookupChildValue(conf, "filename"); } if (filename == NULL) filename = DEFAULT_LOG_FILENAME; if ((pl->prefix = SCStrdup(filename)) == NULL) { exit(EXIT_FAILURE); } pl->size_limit = DEFAULT_LIMIT; if (conf != NULL) { const char *s_limit = NULL; s_limit = ConfNodeLookupChildValue(conf, "limit"); if (s_limit != NULL) { if (ParseSizeStringU64(s_limit, &pl->size_limit) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid limit: %s", s_limit); exit(EXIT_FAILURE); } if (pl->size_limit < 4096) { SCLogInfo("pcap-log \"limit\" value of %"PRIu64" assumed to be pre-1.2 " "style: setting limit to %"PRIu64"mb", pl->size_limit, pl->size_limit); uint64_t size = pl->size_limit * 1024 * 1024; pl->size_limit = size; } else if (pl->size_limit < MIN_LIMIT) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Fail to initialize pcap-log output, limit less than " "allowed minimum."); exit(EXIT_FAILURE); } } } if (conf != NULL) { const char *s_mode = NULL; s_mode = ConfNodeLookupChildValue(conf, "mode"); if (s_mode != NULL) { if (strcasecmp(s_mode, "sguil") == 0) { pl->mode = LOGMODE_SGUIL; } else if (strcasecmp(s_mode, "normal") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "log-pcap you must specify \"sguil\" or \"normal\" mode " "option to be set."); exit(EXIT_FAILURE); } } const char *s_dir = NULL; s_dir = ConfNodeLookupChildValue(conf, "dir"); if (s_dir == NULL) { s_dir = ConfNodeLookupChildValue(conf, "sguil-base-dir"); } if (s_dir == NULL) { if (pl->mode == LOGMODE_SGUIL) { SCLogError(SC_ERR_LOGPCAP_SGUIL_BASE_DIR_MISSING, "log-pcap \"sguil\" mode requires \"sguil-base-dir\" " "option to be set."); exit(EXIT_FAILURE); } else { char *log_dir = NULL; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; strlcpy(pl->dir, log_dir, sizeof(pl->dir)); SCLogInfo("Using log dir %s", pl->dir); } } else { if (PathIsAbsolute(s_dir)) { strlcpy(pl->dir, s_dir, sizeof(pl->dir)); } else { char *log_dir = NULL; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; snprintf(pl->dir, sizeof(pl->dir), "%s/%s", log_dir, s_dir); } struct stat stat_buf; if (stat(pl->dir, &stat_buf) != 0) { SCLogError(SC_ERR_LOGDIR_CONFIG, "The sguil-base-dir directory \"%s\" " "supplied doesn't exist. Shutting down the engine", pl->dir); exit(EXIT_FAILURE); } SCLogInfo("Using log dir %s", pl->dir); } } SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL ? "Sguil compatible" : "normal"); uint32_t max_file_limit = DEFAULT_FILE_LIMIT; if (conf != NULL) { const char *max_number_of_files_s = NULL; max_number_of_files_s = ConfNodeLookupChildValue(conf, "max-files"); if (max_number_of_files_s != NULL) { if (ByteExtractStringUint32(&max_file_limit, 10, 0, max_number_of_files_s) == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize " "pcap-log output, invalid number of files limit: %s", max_number_of_files_s); exit(EXIT_FAILURE); } else if (max_file_limit < 1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize pcap-log output, limit less than " "allowed minimum."); exit(EXIT_FAILURE); } else { pl->max_files = max_file_limit; pl->use_ringbuffer = RING_BUFFER_MODE_ENABLED; } } } const char *ts_format = NULL; if (conf != NULL) { /* To faciliate unit tests. */ ts_format = ConfNodeLookupChildValue(conf, "ts-format"); } if (ts_format != NULL) { if (strcasecmp(ts_format, "usec") == 0) { pl->timestamp_format = TS_FORMAT_USEC; } else if (strcasecmp(ts_format, "sec") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "log-pcap ts_format specified %s is invalid must be" " \"sec\" or \"usec\"", ts_format); exit(EXIT_FAILURE); } } const char *use_stream_depth = NULL; if (conf != NULL) { /* To faciliate unit tests. */ use_stream_depth = ConfNodeLookupChildValue(conf, "use-stream-depth"); } if (use_stream_depth != NULL) { if (ConfValIsFalse(use_stream_depth)) { pl->use_stream_depth = USE_STREAM_DEPTH_DISABLED; } else if (ConfValIsTrue(use_stream_depth)) { pl->use_stream_depth = USE_STREAM_DEPTH_ENABLED; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "log-pcap use_stream_depth specified is invalid must be"); exit(EXIT_FAILURE); } } /* create the output ctx and send it back */ OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for OutputCtx."); exit(EXIT_FAILURE); } output_ctx->data = pl; output_ctx->DeInit = PcapLogFileDeInitCtx; return output_ctx; } static void PcapLogFileDeInitCtx(OutputCtx *output_ctx) { if (output_ctx == NULL) return; PcapLogData *pl = output_ctx->data; PcapFileName *pf = NULL; TAILQ_FOREACH(pf, &pl->pcap_file_list, next) { SCLogDebug("PCAP files left at exit: %s\n", pf->filename); } return; } /** * \brief Read the config set the file pointer, open the file * * \param PcapLogData. * * \retval -1 if failure * \retval 0 if succesful */ int PcapLogOpenFileCtx(PcapLogData *pl) { char *filename = NULL; if (pl->filename != NULL) filename = pl->filename; else { filename = pl->filename = SCMalloc(PATH_MAX); if (filename == NULL) { return -1; } } /** get the time so we can have a filename with seconds since epoch */ struct timeval ts; memset(&ts, 0x00, sizeof(struct timeval)); TimeGet(&ts); /* Place to store the name of our PCAP file */ PcapFileName *pf = SCMalloc(sizeof(PcapFileName)); if (unlikely(pf == NULL)) { return -1; } memset(pf, 0, sizeof(PcapFileName)); if (pl->mode == LOGMODE_SGUIL) { struct tm local_tm; struct tm *tms = (struct tm *)SCLocalTime(ts.tv_sec, &local_tm); char dirname[32], dirfull[PATH_MAX] = ""; snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d", tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday); /* create the filename to use */ snprintf(dirfull, PATH_MAX, "%s/%s", pl->dir, dirname); /* if mkdir fails file open will fail, so deal with errors there */ #ifndef OS_WIN32 (void)mkdir(dirfull, 0700); #else (void)mkdir(dirfull); #endif if ((pf->dirname = SCStrdup(dirfull)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for " "directory name"); goto error; } if (pl->timestamp_format == TS_FORMAT_SEC) { snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, dirfull, pl->prefix, (uint32_t)ts.tv_sec); } else { snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 ".%" PRIu32, dirfull, pl->prefix, (uint32_t)ts.tv_sec, (uint32_t)ts.tv_usec); } } else { /* create the filename to use */ if (pl->timestamp_format == TS_FORMAT_SEC) { snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, pl->dir, pl->prefix, (uint32_t)ts.tv_sec); } else { snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 ".%" PRIu32, pl->dir, pl->prefix, (uint32_t)ts.tv_sec, (uint32_t)ts.tv_usec); } } if ((pf->filename = SCStrdup(pl->filename)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory. For filename"); goto error; } SCLogDebug("Opening pcap file log %s", pf->filename); TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next); return 0; error: PcapFileNameFree(pf); return -1; } suricata-1.4.7/src/detect-engine-proto.c0000644000000000000000000003337012253546156015053 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Proto part of the detection engine. * * \todo move this out of the detection plugin structure */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "app-layer-parser.h" #include "flow-util.h" #include "flow-var.h" #include "detect-engine-siggroup.h" #include "detect-engine-state.h" #include "util-cidr.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" /** * \brief Function to initialize the protocol detection and * allocate memory to the DetectProto structure. * * \retval DetectProto instance pointer if successful otherwise NULL */ DetectProto *DetectProtoInit(void) { DetectProto *dp = SCMalloc(sizeof(DetectProto)); if (unlikely(dp == NULL)) return NULL; memset(dp,0,sizeof(DetectProto)); return dp; } /** * \brief Free a DetectProto object * * \param dp Pointer to the DetectProto instance to be freed */ void DetectProtoFree(DetectProto *dp) { if (dp == NULL) return; SCFree(dp); } /** * \brief Parses a protocol sent as a string. * * \param dp Pointer to the DetectProto instance which will be updated with the * incoming protocol information. * \param str Pointer to the string containing the protocol name. * * \retval 0 Always return 0. */ int DetectProtoParse(DetectProto *dp, char *str) { int proto; if (strcasecmp(str, "tcp") == 0) { proto = IPPROTO_TCP; dp->proto[proto / 8] |= 1 << (proto % 8); SCLogDebug("TCP protocol detected"); } else if (strcasecmp(str, "tcp-pkt") == 0) { proto = IPPROTO_TCP; dp->proto[proto / 8] |= 1 << (proto % 8); SCLogDebug("TCP protocol detected, packets only"); dp->flags |= DETECT_PROTO_ONLY_PKT; } else if (strcasecmp(str, "tcp-stream") == 0) { proto = IPPROTO_TCP; dp->proto[proto / 8] |= 1 << (proto % 8); SCLogDebug("TCP protocol detected, stream only"); dp->flags |= DETECT_PROTO_ONLY_STREAM; } else if (strcasecmp(str, "udp") == 0) { proto = IPPROTO_UDP; dp->proto[proto / 8] |= 1 << (proto % 8); SCLogDebug("UDP protocol detected"); } else if (strcasecmp(str, "icmp") == 0) { proto = IPPROTO_ICMP; dp->proto[proto / 8] |= 1 << (proto % 8); proto = IPPROTO_ICMPV6; dp->proto[proto / 8] |= 1 << (proto % 8); SCLogDebug("ICMP protocol detected, sig applies both to ICMPv4 and ICMPv6"); } else if (strcasecmp(str, "sctp") == 0) { proto = IPPROTO_SCTP; dp->proto[proto / 8] |= 1 << (proto % 8); SCLogDebug("SCTP protocol detected"); } else if (strcasecmp(str,"ipv4") == 0 || strcasecmp(str,"ip4") == 0 ) { dp->flags |= DETECT_PROTO_IPV4; memset(dp->proto, 0xff, sizeof(dp->proto)); SCLogDebug("IPv4 protocol detected"); } else if (strcasecmp(str,"ipv6") == 0 || strcasecmp(str,"ip6") == 0 ) { dp->flags |= DETECT_PROTO_IPV6; memset(dp->proto, 0xff, sizeof(dp->proto)); SCLogDebug("IPv6 protocol detected"); } else if (strcasecmp(str,"ip") == 0 || strcasecmp(str,"pkthdr") == 0) { /* Proto "ip" is treated as an "any" */ dp->flags |= DETECT_PROTO_ANY; memset(dp->proto, 0xff, sizeof(dp->proto)); SCLogDebug("IP protocol detected"); } else { goto error; /** \todo are numeric protocols even valid? */ #if 0 uint8_t proto_u8; /* Used to avoid sign extension */ /* Extract out a 0-256 value with validation checks */ if (ByteExtractStringUint8(&proto_u8, 10, 0, str) == -1) { // XXX SCLogDebug("DetectProtoParse: Error in extracting byte string"); goto error; } proto = (int)proto_u8; /* Proto 0 is the same as "ip" above */ if (proto == IPPROTO_IP) { dp->flags |= DETECT_PROTO_ANY; } else { dp->proto[proto / 8] |= 1<<(proto % 8); } #endif } return 0; error: return -1; } /** \brief see if a DetectProto contains a certain proto * \param dp detect proto to inspect * \param proto protocol (such as IPPROTO_TCP) to look for * \retval 0 protocol not in the set * \retval 1 protocol is in the set */ int DetectProtoContainsProto(DetectProto *dp, int proto) { if (dp->flags & DETECT_PROTO_ANY) return 1; if (dp->proto[proto / 8] & (1<<(proto % 8))) return 1; return 0; } /* TESTS */ #ifdef UNITTESTS #include "detect-engine.h" #include "detect-parse.h" #include "detect-engine-mpm.h" /** * \brief this function is used to initialize the detection engine context and * setup the signature with passed values. */ static int DetectProtoInitTest(DetectEngineCtx **de_ctx, Signature **sig, DetectProto *dp, char *str) { char fullstr[1024]; int result = 0; *de_ctx = NULL; *sig = NULL; if (snprintf(fullstr, 1024, "alert %s any any -> any any (msg:\"DetectProto" " test\"; sid:1;)", str) >= 1024) { goto end; } *de_ctx = DetectEngineCtxInit(); if (*de_ctx == NULL) { goto end; } (*de_ctx)->flags |= DE_QUIET; (*de_ctx)->sig_list = SigInit(*de_ctx, fullstr); if ((*de_ctx)->sig_list == NULL) { goto end; } *sig = (*de_ctx)->sig_list; if (DetectProtoParse(dp, str) != 0) goto end; result = 1; end: return result; } /** * \test ProtoTestParse01 is a test to make sure that we parse the * protocol correctly, when given valid proto option. */ static int ProtoTestParse01 (void) { DetectProto dp; memset(&dp,0,sizeof(DetectProto)); int r = DetectProtoParse(&dp, "6"); if (r != 0) { return 1; } SCLogDebug("DetectProtoParse should have rejected the \"6\" string"); return 0; } /** * \test ProtoTestParse02 is a test to make sure that we parse the * protocol correctly, when given "tcp" as proto option. */ static int ProtoTestParse02 (void) { DetectProto dp; memset(&dp,0,sizeof(DetectProto)); int r = DetectProtoParse(&dp, "tcp"); if (r == 0 && dp.proto[(IPPROTO_TCP/8)] & (1<<(IPPROTO_TCP%8))) { return 1; } SCLogDebug("ProtoTestParse02: Error in parsing the \"tcp\" string"); return 0; } /** * \test ProtoTestParse03 is a test to make sure that we parse the * protocol correctly, when given "ip" as proto option. */ static int ProtoTestParse03 (void) { DetectProto dp; memset(&dp,0,sizeof(DetectProto)); int r = DetectProtoParse(&dp, "ip"); if (r == 0 && dp.flags & DETECT_PROTO_ANY) { return 1; } SCLogDebug("ProtoTestParse03: Error in parsing the \"ip\" string"); return 0; } /** * \test ProtoTestParse04 is a test to make sure that we do not parse the * protocol, when given an invalid proto option. */ static int ProtoTestParse04 (void) { DetectProto dp; memset(&dp,0,sizeof(DetectProto)); /* Check for a bad number */ int r = DetectProtoParse(&dp, "4242"); if (r == -1) { return 1; } SCLogDebug("ProtoTestParse04: it should not parsing the \"4242\" string"); return 0; } /** * \test ProtoTestParse05 is a test to make sure that we do not parse the * protocol, when given an invalid proto option. */ static int ProtoTestParse05 (void) { DetectProto dp; memset(&dp,0,sizeof(DetectProto)); /* Check for a bad string */ int r = DetectProtoParse(&dp, "tcp/udp"); if (r == -1) { return 1; } SCLogDebug("ProtoTestParse05: it should not parsing the \"tcp/udp\" string"); return 0; } /** * \test make sure that we properly parse tcp-pkt */ static int ProtoTestParse06 (void) { DetectProto dp; memset(&dp,0,sizeof(DetectProto)); /* Check for a bad string */ int r = DetectProtoParse(&dp, "tcp-pkt"); if (r == -1) { printf("parsing tcp-pkt failed: "); return 0; } if (!(dp.flags & DETECT_PROTO_ONLY_PKT)) { printf("DETECT_PROTO_ONLY_PKT flag not set: "); return 0; } return 1; } /** * \test make sure that we properly parse tcp-stream */ static int ProtoTestParse07 (void) { DetectProto dp; memset(&dp,0,sizeof(DetectProto)); /* Check for a bad string */ int r = DetectProtoParse(&dp, "tcp-stream"); if (r == -1) { printf("parsing tcp-stream failed: "); return 0; } if (!(dp.flags & DETECT_PROTO_ONLY_STREAM)) { printf("DETECT_PROTO_ONLY_STREAM flag not set: "); return 0; } return 1; } /** * \test DetectIPProtoTestSetup01 is a test for a protocol setting up in * signature. */ static int DetectProtoTestSetup01(void) { DetectProto dp; Signature *sig = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; int i; memset(&dp, 0, sizeof(dp)); result = DetectProtoInitTest(&de_ctx, &sig, &dp, "tcp"); if (result == 0) { goto end; } result = 0; /* The signature proto should be TCP */ if (!(sig->proto.proto[(IPPROTO_TCP/8)] & (1<<(IPPROTO_TCP%8)))) { printf("failed in sig matching\n"); goto cleanup; } for (i = 2; i < 256/8; i++) { if (sig->proto.proto[i] != 0) { printf("failed in sig clear\n"); goto cleanup; } } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); end: return result; } /** * \test DetectProtoTestSig01 is a test for checking the working of protocol * detection by setting up the signature and later testing its working * by matching the received packet against the sig. */ static int DetectProtoTestSig01(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; Flow f; memset(&f, 0, sizeof(Flow)); memset(&th_v, 0, sizeof(th_v)); FLOW_INITIALIZE(&f); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flags |= PKT_HAS_FLOW; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert udp any any -> any any " "(msg:\"Not tcp\"; flow:to_server; sid:1;)"); if (s == NULL) goto end; s = s->next = SigInit(de_ctx,"alert ip any any -> any any " "(msg:\"IP\"; flow:to_server; sid:2;)"); if (s == NULL) goto end; s = s->next = SigInit(de_ctx,"alert tcp any any -> any any " "(msg:\"TCP\"; flow:to_server; sid:3;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 alerted, but should not have: "); goto cleanup; } else if (PacketAlertCheck(p, 2) == 0) { printf("sid 2 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 3) == 0) { printf("sid 3 did not alert, but should have: "); goto cleanup; } result = 1; cleanup: FLOW_DESTROY(&f); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); end: return result; } /** * \test signature parsing with tcp-pkt and tcp-stream */ static int DetectProtoTestSig02(void) { Signature *s = NULL; int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp-pkt any any -> any any " "(msg:\"tcp-pkt\"; content:\"blah\"; sid:1;)"); if (s == NULL) { printf("tcp-pkt sig parsing failed: "); goto end; } s = s->next = SigInit(de_ctx,"alert tcp-stream any any -> any any " "(msg:\"tcp-stream\"; content:\"blah\"; sid:2;)"); if (s == NULL) { printf("tcp-pkt sig parsing failed: "); goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectProto */ void DetectProtoTests(void) { #ifdef UNITTESTS UtRegisterTest("ProtoTestParse01", ProtoTestParse01, 1); UtRegisterTest("ProtoTestParse02", ProtoTestParse02, 1); UtRegisterTest("ProtoTestParse03", ProtoTestParse03, 1); UtRegisterTest("ProtoTestParse04", ProtoTestParse04, 1); UtRegisterTest("ProtoTestParse05", ProtoTestParse05, 1); UtRegisterTest("ProtoTestParse06", ProtoTestParse06, 1); UtRegisterTest("ProtoTestParse07", ProtoTestParse07, 1); UtRegisterTest("DetectProtoTestSetup01", DetectProtoTestSetup01, 1); UtRegisterTest("DetectProtoTestSig01", DetectProtoTestSig01, 1); UtRegisterTest("DetectProtoTestSig02", DetectProtoTestSig02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-debug.c0000644000000000000000000015127612253546156013246 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Debug utility functions */ #include "suricata-common.h" #include "threads.h" #include "util-debug.h" #include "util-error.h" #include "util-enum.h" #include "util-debug-filters.h" #include "decode.h" #include "detect.h" #include "packet-queue.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tm-queues.h" #include "tm-threads.h" #include "util-unittest.h" #include "util-syslog.h" #include "conf.h" /* holds the string-enum mapping for the enums held in the table SCLogLevel */ SCEnumCharMap sc_log_level_map[ ] = { { "Not set", SC_LOG_NOTSET}, { "None", SC_LOG_NONE }, { "Emergency", SC_LOG_EMERGENCY }, { "Alert", SC_LOG_ALERT }, { "Critical", SC_LOG_CRITICAL }, { "Error", SC_LOG_ERROR }, { "Warning", SC_LOG_WARNING }, { "Notice", SC_LOG_NOTICE }, { "Info", SC_LOG_INFO }, { "Debug", SC_LOG_DEBUG }, { NULL, -1 } }; /* holds the string-enum mapping for the enums held in the table SCLogOPIface */ SCEnumCharMap sc_log_op_iface_map[ ] = { { "Console", SC_LOG_OP_IFACE_CONSOLE }, { "File", SC_LOG_OP_IFACE_FILE }, { "Syslog", SC_LOG_OP_IFACE_SYSLOG }, { NULL, -1 } }; #if defined (OS_WIN32) /** * \brief Used for synchronous output on WIN32 */ static SCMutex sc_log_stream_lock = NULL; #endif /* OS_WIN32 */ /** * \brief Holds the config state for the logging module */ static SCLogConfig *sc_log_config = NULL; /** * \brief Returns the full path given a file and configured log dir */ static char *SCLogGetLogFilename(char *); /** * \brief Holds the global log level. Is the same as sc_log_config->log_level */ SCLogLevel sc_log_global_log_level; /** * \brief Used to indicate whether the logging module has been init or not */ int sc_log_module_initialized = 0; /** * \brief Used to indicate whether the logging module has been cleaned or not */ int sc_log_module_cleaned = 0; /** * \brief Maps the SC logging level to the syslog logging level * * \param The SC logging level that has to be mapped to the syslog_log_level * * \retval syslog_log_level The mapped syslog_api_log_level, for the logging * module api's internal log_level */ static inline int SCLogMapLogLevelToSyslogLevel(int log_level) { int syslog_log_level = 0; switch (log_level) { case SC_LOG_EMERGENCY: syslog_log_level = LOG_EMERG; break; case SC_LOG_ALERT: syslog_log_level = LOG_ALERT; break; case SC_LOG_CRITICAL: syslog_log_level = LOG_CRIT; break; case SC_LOG_ERROR: syslog_log_level = LOG_ERR; break; case SC_LOG_WARNING: syslog_log_level = LOG_WARNING; break; case SC_LOG_NOTICE: syslog_log_level = LOG_NOTICE; break; case SC_LOG_INFO: syslog_log_level = LOG_INFO; break; case SC_LOG_DEBUG: syslog_log_level = LOG_DEBUG; break; default: syslog_log_level = LOG_EMERG; break; } return syslog_log_level; } /** * \brief Output function that logs a character string out to a file descriptor * * \param fd Pointer to the file descriptor * \param msg Pointer to the character string that should be logged */ static inline void SCLogPrintToStream(FILE *fd, char *msg) { #if defined (OS_WIN32) SCMutexLock(&sc_log_stream_lock); #endif /* OS_WIN32 */ if (fprintf(fd, "%s", msg) < 0) printf("Error writing to stream using fprintf\n"); fflush(fd); #if defined (OS_WIN32) SCMutexUnlock(&sc_log_stream_lock); #endif /* OS_WIN32 */ return; } /** * \brief Output function that logs a character string throught the syslog iface * * \param syslog_log_level Holds the syslog_log_level that the message should be * logged as * \param msg Pointer to the char string, that should be logged * * \todo syslog is thread-safe according to POSIX manual and glibc code, but we * we will have to look into non POSIX compliant boxes like freeBSD */ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) { //static struct syslog_data data = SYSLOG_DATA_INIT; //syslog_r(syslog_log_level, NULL, "%s", msg); syslog(syslog_log_level, "%s", msg); return; } /** * \brief Outputs the message sent as the argument * * \param msg Pointer to the message that has to be logged * \param log_level The log_level of the message that has to be logged */ void SCLogOutputBuffer(SCLogLevel log_level, char *msg) { char *temp = msg; int len = strlen(msg); SCLogOPIfaceCtx *op_iface_ctx = NULL; #define MAX_SUBSTRINGS 30 int ov[MAX_SUBSTRINGS]; if (sc_log_module_initialized != 1) { printf("Logging module not initialized. Call SCLogInitLogModule() " "first before using the debug API\n"); return; } /* We need to add a \n for our messages, before logging them. If the * messages have hit the 1023 length limit, strip the message to * accomodate the \n */ if (len == SC_LOG_MAX_LOG_MSG_LEN - 1) len = SC_LOG_MAX_LOG_MSG_LEN - 2; temp[len] = '\n'; temp[len + 1] = '\0'; if (sc_log_config->op_filter_regex != NULL) { if (pcre_exec(sc_log_config->op_filter_regex, sc_log_config->op_filter_regex_study, msg, strlen(msg), 0, 0, ov, MAX_SUBSTRINGS) < 0) return; } op_iface_ctx = sc_log_config->op_ifaces; while (op_iface_ctx != NULL) { if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) { op_iface_ctx = op_iface_ctx->next; continue; } switch (op_iface_ctx->iface) { case SC_LOG_OP_IFACE_CONSOLE: SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, msg); break; case SC_LOG_OP_IFACE_FILE: SCLogPrintToStream(op_iface_ctx->file_d, msg); break; case SC_LOG_OP_IFACE_SYSLOG: SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), msg); break; default: break; } op_iface_ctx = op_iface_ctx->next; } return; } /** * \brief Adds the global log_format to the outgoing buffer * * \param log_level log_level of the message that has to be logged * \param msg Buffer containing the outgoing message * \param file File_name from where the message originated * \param function Function_name from where the message originated * \param line Line_no from where the messaged originated * * \retval SC_OK on success; else an error code */ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, unsigned line, const char *function) { char *temp = *msg; const char *s = NULL; struct timeval tval; struct tm *tms = NULL; /* no of characters_written(cw) by snprintf */ int cw = 0; if (sc_log_module_initialized != 1) { #ifdef DEBUG printf("Logging module not initialized. Call SCLogInitLogModule(), " "before using the logging API\n"); #endif return SC_ERR_LOG_MODULE_NOT_INIT; } if (sc_log_fg_filters_present == 1) { if (SCLogMatchFGFilterWL(file, function, line) != 1) { return SC_ERR_LOG_FG_FILTER_MATCH; } if (SCLogMatchFGFilterBL(file, function, line) != 1) { return SC_ERR_LOG_FG_FILTER_MATCH; } } if (sc_log_fd_filters_present == 1 && SCLogMatchFDFilter(function) != 1) { return SC_ERR_LOG_FG_FILTER_MATCH; } char *temp_fmt = strdup(sc_log_config->log_format); if (unlikely(temp_fmt == NULL)) { return SC_ERR_MEM_ALLOC; } char *temp_fmt_h = temp_fmt; char *substr = temp_fmt; while ( (temp_fmt = index(temp_fmt, SC_LOG_FMT_PREFIX)) ) { if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { printf("Warning: Log message exceeded message length limit of %d\n", SC_LOG_MAX_LOG_MSG_LEN); *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; if (temp_fmt_h != NULL) SCFree(temp_fmt_h); return SC_OK; } switch(temp_fmt[1]) { case SC_LOG_FMT_TIME: temp_fmt[0] = '\0'; gettimeofday(&tval, NULL); struct tm local_tm; tms = SCLocalTime(tval.tv_sec, &local_tm); cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%d/%d/%04d -- %02d:%02d:%02d", substr, tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec); if (cw < 0) goto error; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; case SC_LOG_FMT_PID: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%u", substr, getpid()); if (cw < 0) goto error; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; case SC_LOG_FMT_TID: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%lu", substr, SCGetThreadIdLong()); if (cw < 0) goto error; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; case SC_LOG_FMT_TM: temp_fmt[0] = '\0'; ThreadVars *tv = TmThreadsGetCallingThread(); cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%s", substr, ((tv != NULL)? tv->name: "UNKNOWN TM")); if (cw < 0) goto error; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; case SC_LOG_FMT_LOG_LEVEL: temp_fmt[0] = '\0'; s = SCMapEnumValueToName(log_level, sc_log_level_map); if (s != NULL) cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%s", substr, s); else cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%s", substr, "INVALID"); if (cw < 0) goto error; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; case SC_LOG_FMT_FILE_NAME: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%s", substr, file); if (cw < 0) goto error; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; case SC_LOG_FMT_LINE: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%d", substr, line); if (cw < 0) goto error; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; case SC_LOG_FMT_FUNCTION: temp_fmt[0] = '\0'; cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%s", substr, function); if (cw < 0) goto error; temp += cw; temp_fmt++; substr = temp_fmt; substr++; break; } temp_fmt++; } if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { printf("Warning: Log message exceeded message length limit of %d\n", SC_LOG_MAX_LOG_MSG_LEN); *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; if (temp_fmt_h != NULL) SCFree(temp_fmt_h); return SC_OK; } cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s", substr); if (cw < 0) goto error; temp += cw; if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { printf("Warning: Log message exceeded message length limit of %d\n", SC_LOG_MAX_LOG_MSG_LEN); *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; if (temp_fmt_h != NULL) SCFree(temp_fmt_h); return SC_OK; } *msg = temp; SCFree(temp_fmt_h); return SC_OK; error: if (temp_fmt != NULL) SCFree(temp_fmt_h); return SC_ERR_SPRINTF; } /** * \brief Returns whether debug messages are enabled to be logged or not * * \retval 1 if debug messages are enabled to be logged * \retval 0 if debug messages are not enabled to be logged */ int SCLogDebugEnabled(void) { #ifdef DEBUG if (sc_log_global_log_level == SC_LOG_DEBUG) return 1; else return 0; #else return 0; #endif } /** * \brief Allocates an output buffer for an output interface. Used when we * want the op_interface log_format to override the global_log_format. * Currently not used. * * \retval buffer Pointer to the newly created output_buffer */ SCLogOPBuffer *SCLogAllocLogOPBuffer(void) { SCLogOPBuffer *buffer = NULL; SCLogOPIfaceCtx *op_iface_ctx = NULL; int i = 0; if ( (buffer = SCMalloc(sc_log_config->op_ifaces_cnt * sizeof(SCLogOPBuffer))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogAllocLogOPBuffer. Exiting..."); exit(EXIT_FAILURE); } op_iface_ctx = sc_log_config->op_ifaces; for (i = 0; i < sc_log_config->op_ifaces_cnt; i++, op_iface_ctx = op_iface_ctx->next) { buffer[i].log_format = op_iface_ctx->log_format; buffer[i].temp = buffer[i].msg; } return buffer; } /*----------------------The logging module initialization code--------------- */ /** * \brief Returns a new output_interface_context * * \retval iface_ctx Pointer to a newly allocated output_interface_context * \initonly */ static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx() { SCLogOPIfaceCtx *iface_ctx = NULL; if ( (iface_ctx = SCMalloc(sizeof(SCLogOPIfaceCtx))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogallocLogOPIfaceCtx. Exiting..."); exit(EXIT_FAILURE); } memset(iface_ctx, 0, sizeof(SCLogOPIfaceCtx)); return iface_ctx; } /** * \brief Initializes the file output interface * * \param file Path to the file used for logging purposes * \param log_format Pointer to the log_format for this op interface, that * overrides the global_log_format * \param log_level Override of the global_log_level by this interface * * \retval iface_ctx Pointer to the file output interface context created * \initonly */ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, const char *log_format, int log_level) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); if (iface_ctx == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogInitFileOPIface. Exiting..."); exit(EXIT_FAILURE); } if (file == NULL || log_format == NULL) { goto error; } iface_ctx->iface = SC_LOG_OP_IFACE_FILE; if ( (iface_ctx->file_d = fopen(file, "w+")) == NULL) { printf("Error opening file %s\n", file); goto error; } if ((iface_ctx->file = SCStrdup(file)) == NULL) { goto error; } if ((iface_ctx->log_format = SCStrdup(log_format)) == NULL) { goto error; } iface_ctx->log_level = log_level; return iface_ctx; error: if (iface_ctx->file != NULL) { SCFree((char *)iface_ctx->file); iface_ctx->file = NULL; } if (iface_ctx->log_format != NULL) { SCFree((char *)iface_ctx->log_format); iface_ctx->log_format = NULL; } if (iface_ctx->file_d != NULL) { fclose(iface_ctx->file_d); iface_ctx->file_d = NULL; } return NULL; } /** * \brief Initializes the console output interface and deals with possible * env var overrides. * * \param log_format Pointer to the log_format for this op interface, that * overrides the global_log_format * \param log_level Override of the global_log_level by this interface * * \retval iface_ctx Pointer to the console output interface context created * \initonly */ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, SCLogLevel log_level) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); if (iface_ctx == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogInitConsoleOPIface. Exiting..."); exit(EXIT_FAILURE); } iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE; /* console log format is overridden by envvars */ const char *tmp_log_format = log_format; const char *s = getenv(SC_LOG_ENV_LOG_FORMAT); if (s != NULL) { #if 0 printf("Overriding setting for \"console.format\" because of env " "var SC_LOG_FORMAT=\"%s\".\n", s); #endif tmp_log_format = s; } if (tmp_log_format != NULL && (iface_ctx->log_format = SCStrdup(tmp_log_format)) == NULL) { printf("Error allocating memory\n"); exit(EXIT_FAILURE); } /* console log level is overridden by envvars */ SCLogLevel tmp_log_level = log_level; s = getenv(SC_LOG_ENV_LOG_LEVEL); if (s != NULL) { SCLogLevel l = SCMapEnumNameToValue(s, sc_log_level_map); if (l > SC_LOG_NOTSET && l < SC_LOG_LEVEL_MAX) { #if 0 printf("Overriding setting for \"console.level\" because of env " "var SC_LOG_LEVEL=\"%s\".\n", s); #endif tmp_log_level = l; } } iface_ctx->log_level = tmp_log_level; return iface_ctx; } /** * \brief Initializes the syslog output interface * * \param facility The facility code for syslog * \param log_format Pointer to the log_format for this op interface, that * overrides the global_log_format * \param log_level Override of the global_log_level by this interface * * \retval iface_ctx Pointer to the syslog output interface context created */ static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility, const char *log_format, SCLogLevel log_level) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); if ( iface_ctx == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogInitSyslogOPIface. Exiting..."); exit(EXIT_FAILURE); } iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG; if (facility == -1) facility = SC_LOG_DEF_SYSLOG_FACILITY; iface_ctx->facility = facility; if (log_format != NULL && (iface_ctx->log_format = SCStrdup(log_format)) == NULL) { printf("Error allocating memory\n"); exit(EXIT_FAILURE); } iface_ctx->log_level = log_level; openlog(NULL, LOG_NDELAY, iface_ctx->facility); return iface_ctx; } /** * \brief Frees the output_interface context supplied as an argument * * \param iface_ctx Pointer to the op_interface_context to be freed */ static inline void SCLogFreeLogOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx) { SCLogOPIfaceCtx *temp = NULL; while (iface_ctx != NULL) { temp = iface_ctx; if (iface_ctx->file_d != NULL) fclose(iface_ctx->file_d); if (iface_ctx->file != NULL) SCFree((void *)iface_ctx->file); if (iface_ctx->log_format != NULL) SCFree((void *)iface_ctx->log_format); if (iface_ctx->iface == SC_LOG_OP_IFACE_SYSLOG) { closelog(); } iface_ctx = iface_ctx->next; SCFree(temp); } return; } /** * \brief Internal function used to set the logging module global_log_level * during the initialization phase * * \param sc_lid The initialization data supplied. * \param sc_lc The logging module context which has to be updated. */ static inline void SCLogSetLogLevel(SCLogInitData *sc_lid, SCLogConfig *sc_lc) { SCLogLevel log_level = SC_LOG_NOTSET; const char *s = NULL; /* envvar overrides config */ s = getenv(SC_LOG_ENV_LOG_LEVEL); if (s != NULL) { log_level = SCMapEnumNameToValue(s, sc_log_level_map); } else if (sc_lid != NULL) { log_level = sc_lid->global_log_level; } /* deal with the global_log_level to be used */ if (log_level > SC_LOG_NOTSET && log_level < SC_LOG_LEVEL_MAX) sc_lc->log_level = log_level; else { sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL; #ifndef UNITTESTS if (sc_lid != NULL) { printf("Warning: Invalid/No global_log_level assigned by user. Falling " "back on the default_log_level \"%s\"\n", SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map)); } #endif } /* we also set it to a global var, as it is easier to access it */ sc_log_global_log_level = sc_lc->log_level; return; } /** * \brief Internal function used to set the logging module global_log_format * during the initialization phase * * \param sc_lid The initialization data supplied. * \param sc_lc The logging module context which has to be updated. */ static inline void SCLogSetLogFormat(SCLogInitData *sc_lid, SCLogConfig *sc_lc) { char *format = NULL; /* envvar overrides config */ format = getenv(SC_LOG_ENV_LOG_FORMAT); if (format == NULL) { if (sc_lid != NULL) { format = sc_lid->global_log_format; } } /* deal with the global log format to be used */ if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) { format = SC_LOG_DEF_LOG_FORMAT; #ifndef UNITTESTS if (sc_lid != NULL) { printf("Warning: Invalid/No global_log_format supplied by user or format " "length exceeded limit of \"%d\" characters. Falling back on " "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN, format); } #endif } if (format != NULL && (sc_lc->log_format = SCStrdup(format)) == NULL) { printf("Error allocating memory\n"); exit(EXIT_FAILURE); } return; } /** * \brief Internal function used to set the logging module global_op_ifaces * during the initialization phase * * \param sc_lid The initialization data supplied. * \param sc_lc The logging module context which has to be updated. */ static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc) { SCLogOPIfaceCtx *op_ifaces_ctx = NULL; int op_iface = 0; const char *s = NULL; if (sc_lid != NULL && sc_lid->op_ifaces != NULL) { sc_lc->op_ifaces = sc_lid->op_ifaces; sc_lid->op_ifaces = NULL; sc_lc->op_ifaces_cnt = sc_lid->op_ifaces_cnt; } else { s = getenv(SC_LOG_ENV_LOG_OP_IFACE); if (s != NULL) { op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map); if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) { op_iface = SC_LOG_DEF_LOG_OP_IFACE; #ifndef UNITTESTS printf("Warning: Invalid output interface supplied by user. " "Falling back on default_output_interface \"%s\"\n", SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); #endif } } else { op_iface = SC_LOG_DEF_LOG_OP_IFACE; #ifndef UNITTESTS if (sc_lid != NULL) { printf("Warning: Output_interface not supplied by user. Falling " "back on default_output_interface \"%s\"\n", SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); } #endif } switch (op_iface) { case SC_LOG_OP_IFACE_CONSOLE: op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX); break; case SC_LOG_OP_IFACE_FILE: s = getenv(SC_LOG_ENV_LOG_FILE); if (s == NULL) s = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE); op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, SC_LOG_LEVEL_MAX); break; case SC_LOG_OP_IFACE_SYSLOG: s = getenv(SC_LOG_ENV_LOG_FACILITY); if (s == NULL) s = SC_LOG_DEF_SYSLOG_FACILITY_STR; op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1); break; } sc_lc->op_ifaces = op_ifaces_ctx; sc_lc->op_ifaces_cnt++; } return; } /** * \brief Internal function used to set the logging module op_filter * during the initialization phase * * \param sc_lid The initialization data supplied. * \param sc_lc The logging module context which has to be updated. */ static inline void SCLogSetOPFilter(SCLogInitData *sc_lid, SCLogConfig *sc_lc) { const char *filter = NULL; int opts = 0; const char *ep; int eo = 0; /* envvar overrides */ filter = getenv(SC_LOG_ENV_LOG_OP_FILTER); if (filter == NULL) { if (sc_lid != NULL) { filter = sc_lid->op_filter; } } if (filter != NULL && strcmp(filter, "") != 0) { sc_lc->op_filter = SCStrdup(filter); sc_lc->op_filter_regex = pcre_compile(filter, opts, &ep, &eo, NULL); if (sc_lc->op_filter_regex == NULL) { printf("pcre compile of \"%s\" failed at offset %d : %s\n", filter, eo, ep); return; } sc_lc->op_filter_regex_study = pcre_study(sc_lc->op_filter_regex, 0, &ep); if (ep != NULL) { printf("pcre study failed: %s\n", ep); return; } } return; } /** * \brief Returns a pointer to a new SCLogInitData. This is a public interface * intended to be used after the logging paramters are read from the * conf file * * \retval sc_lid Pointer to the newly created SCLogInitData * \initonly */ SCLogInitData *SCLogAllocLogInitData(void) { SCLogInitData *sc_lid = NULL; /* not using SCMalloc here because if it fails we can't log */ if ( (sc_lid = SCMalloc(sizeof(SCLogInitData))) == NULL) return NULL; memset(sc_lid, 0, sizeof(SCLogInitData)); return sc_lid; } /** * \brief Frees a SCLogInitData * * \param sc_lid Pointer to the SCLogInitData to be freed */ void SCLogFreeLogInitData(SCLogInitData *sc_lid) { if (sc_lid != NULL) { if (sc_lid->startup_message != NULL) SCFree(sc_lid->startup_message); if (sc_lid->global_log_format != NULL) SCFree(sc_lid->global_log_format); if (sc_lid->op_filter != NULL) SCFree(sc_lid->op_filter); SCLogFreeLogOPIfaceCtx(sc_lid->op_ifaces); } return; } /** * \brief Frees the logging module context */ static inline void SCLogFreeLogConfig(SCLogConfig *sc_lc) { if (sc_lc != NULL) { if (sc_lc->startup_message != NULL) SCFree(sc_lc->startup_message); if (sc_lc->log_format != NULL) SCFree(sc_lc->log_format); if (sc_lc->op_filter != NULL) SCFree(sc_lc->op_filter); SCLogFreeLogOPIfaceCtx(sc_lc->op_ifaces); SCFree(sc_lc); } return; } /** * \brief Appends an output_interface to the output_interface list sent in head * * \param iface_ctx Pointer to the output_interface that has to be added to head * \param head Pointer to the output_interface list */ void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx, SCLogInitData *sc_lid) { SCLogOPIfaceCtx *temp = NULL, *prev = NULL; SCLogOPIfaceCtx **head = &sc_lid->op_ifaces; if (iface_ctx == NULL) { #ifdef DEBUG printf("Argument(s) to SCLogAppendOPIfaceCtx() NULL\n"); #endif return; } temp = *head; while (temp != NULL) { prev = temp; temp = temp->next; } if (prev == NULL) *head = iface_ctx; else prev->next = iface_ctx; sc_lid->op_ifaces_cnt++; return; } /** * \brief Creates a new output interface based on the arguments sent. The kind * of output interface to be created is decided by the iface_name arg. * If iface_name is "file", the arg argument will hold the filename to be * used for logging purposes. If iface_name is "syslog", the arg * argument holds the facility code. If iface_name is "console", arg is * NULL. * * \param iface_name Interface name. Can be "console", "file" or "syslog" * \param log_format Override for the global_log_format * \param log_level Override for the global_log_level * \param log_level Parameter required by a particular interface. Explained in * the function description * * \retval iface_ctx Pointer to the newly created output interface */ SCLogOPIfaceCtx *SCLogInitOPIfaceCtx(const char *iface_name, const char *log_format, int log_level, const char *arg) { int iface = SCMapEnumNameToValue(iface_name, sc_log_op_iface_map); if (log_level < SC_LOG_NONE || log_level > SC_LOG_DEBUG) { #ifndef UNITTESTS printf("Warning: Supplied log_level_override for op_interface \"%s\" " "is invalid. Defaulting to not specifying an override\n", iface_name); #endif log_level = SC_LOG_NOTSET; } switch (iface) { case SC_LOG_OP_IFACE_CONSOLE: return SCLogInitConsoleOPIface(log_format, log_level); case SC_LOG_OP_IFACE_FILE: return SCLogInitFileOPIface(arg, log_format, log_level); case SC_LOG_OP_IFACE_SYSLOG: return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()), log_format, log_level); default: #ifdef DEBUG printf("Output Interface \"%s\" not supported by the logging module", iface_name); #endif return NULL; } } /** * \brief Initializes the logging module. * * \param sc_lid The initialization data for the logging module. If sc_lid is * NULL, we would stick to the default configuration for the * logging subsystem. * \initonly */ void SCLogInitLogModule(SCLogInitData *sc_lid) { /* De-initialize the logging context, if it has already init by the * environment variables at the start of the engine */ SCLogDeInitLogModule(); #if defined (OS_WIN32) if (SCMutexInit(&sc_log_stream_lock, NULL) != 0) { SCLogError(SC_ERR_MUTEX, "Failed to initialize log mutex."); exit(EXIT_FAILURE); } #endif /* OS_WIN32 */ /* sc_log_config is a global variable */ if ( (sc_log_config = SCMalloc(sizeof(SCLogConfig))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogInitLogModule. Exiting..."); exit(EXIT_FAILURE); } memset(sc_log_config, 0, sizeof(SCLogConfig)); SCLogSetLogLevel(sc_lid, sc_log_config); SCLogSetLogFormat(sc_lid, sc_log_config); SCLogSetOPIface(sc_lid, sc_log_config); SCLogSetOPFilter(sc_lid, sc_log_config); sc_log_module_initialized = 1; sc_log_module_cleaned = 0; //SCOutputPrint(sc_did->startup_message); return; } void SCLogLoadConfig(int daemon) { ConfNode *outputs; SCLogInitData *sc_lid; int have_logging = 0; outputs = ConfGetNode("logging.outputs"); if (outputs == NULL) { SCLogDebug("No logging.output configuration section found."); return; } sc_lid = SCLogAllocLogInitData(); if (sc_lid == NULL) { SCLogDebug("Could not allocate memory for log init data"); return; } /* Get default log level and format. */ char *default_log_level_s = NULL; if (ConfGet("logging.default-log-level", &default_log_level_s) == 1) { sc_lid->global_log_level = SCMapEnumNameToValue(default_log_level_s, sc_log_level_map); if (sc_lid->global_log_level == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid default log level: %s", default_log_level_s); exit(EXIT_FAILURE); } } else { SCLogWarning(SC_ERR_MISSING_CONFIG_PARAM, "No default log level set, will use info."); sc_lid->global_log_level = SC_LOG_INFO; } if (ConfGet("logging.default-log-format", &sc_lid->global_log_format) != 1) sc_lid->global_log_format = SC_LOG_DEF_LOG_FORMAT; ConfGet("logging.default-output-filter", &sc_lid->op_filter); ConfNode *seq_node, *output; TAILQ_FOREACH(seq_node, &outputs->head, next) { SCLogLevel level = sc_lid->global_log_level; SCLogOPIfaceCtx *op_iface_ctx = NULL; const char *format; const char *level_s; output = ConfNodeLookupChild(seq_node, seq_node->val); if (output == NULL) continue; /* By default an output is enabled. */ const char *enabled = ConfNodeLookupChildValue(output, "enabled"); if (enabled != NULL && ConfValIsFalse(enabled)) continue; /* if available use the log format setting for this output, * otherwise fall back to the global setting. */ format = ConfNodeLookupChildValue(output, "format"); if (format == NULL) format = sc_lid->global_log_format; level_s = ConfNodeLookupChildValue(output, "level"); if (level_s != NULL) { level = SCMapEnumNameToValue(level_s, sc_log_level_map); if (level == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid log level: %s", level_s); exit(EXIT_FAILURE); } } if (strcmp(output->name, "console") == 0) { op_iface_ctx = SCLogInitConsoleOPIface(format, level); } else if (strcmp(output->name, "file") == 0) { const char *filename = ConfNodeLookupChildValue(output, "filename"); if (filename == NULL) { SCLogError(SC_ERR_MISSING_CONFIG_PARAM, "Logging to file requires a filename"); exit(EXIT_FAILURE); } have_logging = 1; op_iface_ctx = SCLogInitFileOPIface(filename, format, level); } else if (strcmp(output->name, "syslog") == 0) { int facility = SC_LOG_DEF_SYSLOG_FACILITY; const char *facility_s = ConfNodeLookupChildValue(output, "facility"); if (facility_s != NULL) { facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap()); if (facility == -1) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid syslog " "facility: \"%s\", now using \"%s\" as syslog " "facility", facility_s, SC_LOG_DEF_SYSLOG_FACILITY_STR); facility = SC_LOG_DEF_SYSLOG_FACILITY; } } printf("Initialization syslog logging with format \"%s\".\n", format); have_logging = 1; op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level); } else { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid logging method: %s, " "ignoring", output->name); } if (op_iface_ctx != NULL) { SCLogAppendOPIfaceCtx(op_iface_ctx, sc_lid); } } if (daemon && (have_logging == 0)) { SCLogError(SC_ERR_MISSING_CONFIG_PARAM, "NO logging compatible with daemon mode selected," " suricata won't be able to log. Please update " " 'logging.outputs' in the YAML."); } SCLogInitLogModule(sc_lid); SCLogDebug("sc_log_global_log_level: %d", sc_log_global_log_level); SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format); SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter); //exit(1); /* \todo Can we free sc_lid now? */ if (sc_lid != NULL) SCFree(sc_lid); } /** * \brief Initializes the logging module if the environment variables are set. * Used at the start of the engine, for cases, where there is an error * in the yaml parsing code, and we want to enable the logging module. */ void SCLogInitLogModuleIfEnvSet(void) { SCLogConfig *sc_lc = NULL; const char *s = NULL; const char *filter = NULL; int opts = 0; const char *ep; int eo = 0; SCLogOPIfaceCtx *op_ifaces_ctx = NULL; int op_iface = 0; char *format = NULL; SCLogLevel log_level = SC_LOG_NOTSET; /* sc_log_config is a global variable */ if ( (sc_log_config = SCMalloc(sizeof(SCLogConfig))) == NULL) return; memset(sc_log_config, 0, sizeof(SCLogConfig)); sc_lc = sc_log_config; /* Check if the user has set the op_iface env var. Only if it is set, * we proceed with the initialization */ s = getenv(SC_LOG_ENV_LOG_OP_IFACE); if (s != NULL) { op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map); if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) { op_iface = SC_LOG_DEF_LOG_OP_IFACE; #ifndef UNITTESTS printf("Warning: Invalid output interface supplied by user. " "Falling back on default_output_interface \"%s\"\n", SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); #endif } } else { SCLogFreeLogConfig(sc_lc); sc_log_config = NULL; return; } switch (op_iface) { case SC_LOG_OP_IFACE_CONSOLE: op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, -1); break; case SC_LOG_OP_IFACE_FILE: s = getenv(SC_LOG_ENV_LOG_FILE); if (s == NULL) s = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE); op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, -1); break; case SC_LOG_OP_IFACE_SYSLOG: s = getenv(SC_LOG_ENV_LOG_FACILITY); if (s == NULL) s = SC_LOG_DEF_SYSLOG_FACILITY_STR; op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1); break; } sc_lc->op_ifaces = op_ifaces_ctx; /* Set the filter */ filter = getenv(SC_LOG_ENV_LOG_OP_FILTER); if (filter != NULL && strcmp(filter, "") != 0) { sc_lc->op_filter_regex = pcre_compile(filter, opts, &ep, &eo, NULL); if (sc_lc->op_filter_regex == NULL) { printf("pcre compile of \"%s\" failed at offset %d : %s\n", filter, eo, ep); return; } sc_lc->op_filter_regex_study = pcre_study(sc_lc->op_filter_regex, 0, &ep); if (ep != NULL) { printf("pcre study failed: %s\n", ep); return; } } /* Set the log_format */ format = getenv(SC_LOG_ENV_LOG_FORMAT); if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) { format = SC_LOG_DEF_LOG_FORMAT; #ifndef UNITTESTS printf("Warning: Invalid global_log_format supplied by user or format " "length exceeded limit of \"%d\" characters. Falling back on " "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN, format); #endif } if (format != NULL && (sc_lc->log_format = SCStrdup(format)) == NULL) { printf("Error allocating memory\n"); exit(EXIT_FAILURE); } /* Set the log_level */ s = getenv(SC_LOG_ENV_LOG_LEVEL); if (s != NULL) log_level = SCMapEnumNameToValue(s, sc_log_level_map); if (log_level >= 0 && log_level < SC_LOG_LEVEL_MAX) sc_lc->log_level = log_level; else { sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL; #ifndef UNITTESTS printf("Warning: Invalid global_log_level assigned by user. Falling " "back on default_log_level \"%s\"\n", SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map)); #endif } /* we also set it to a global var, as it is easier to access it */ sc_log_global_log_level = sc_lc->log_level; sc_log_module_initialized = 1; sc_log_module_cleaned = 0; return; } /** * \brief Returns a full file path given a filename uses log dir specified in * conf or DEFAULT_LOG_DIR * * \param filearg The relative filename for which we want a full path include * log directory * * \retval log_filename The fullpath of the logfile to open */ static char *SCLogGetLogFilename(char *filearg) { char *log_dir; char *log_filename; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; log_filename = SCMalloc(PATH_MAX); if (unlikely(log_filename == NULL)) return NULL; snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, filearg); return log_filename; } /** * \brief De-Initializes the logging module */ void SCLogDeInitLogModule(void) { SCLogFreeLogConfig(sc_log_config); /* reset the global logging_module variables */ sc_log_global_log_level = 0; sc_log_module_initialized = 0; sc_log_module_cleaned = 1; sc_log_config = NULL; /* de-init the FD filters */ SCLogReleaseFDFilters(); /* de-init the FG filters */ SCLogReleaseFGFilters(); #if defined (OS_WIN32) if (sc_log_stream_lock != NULL) { SCMutexDestroy(&sc_log_stream_lock); sc_log_stream_lock = NULL; } #endif /* OS_WIN32 */ return; } //------------------------------------Unit_Tests-------------------------------- /* The logging engine should be tested to the maximum extent possible, since * logging code would be used throughout the codebase, and hence we can't afford * to have a single bug here(not that you can afford to have a bug * elsewhere ;) ). Please report a bug, if you get a slightest hint of a bug * from the logging module. */ #ifdef UNITTESTS int SCLogTestInit01() { int result = 1; /* unset any environment variables set for the logging module */ unsetenv(SC_LOG_ENV_LOG_LEVEL); unsetenv(SC_LOG_ENV_LOG_OP_IFACE); unsetenv(SC_LOG_ENV_LOG_FORMAT); SCLogInitLogModule(NULL); if (sc_log_config == NULL) return 0; result &= (SC_LOG_DEF_LOG_LEVEL == sc_log_config->log_level); result &= (sc_log_config->op_ifaces != NULL && SC_LOG_DEF_LOG_OP_IFACE == sc_log_config->op_ifaces->iface); result &= (sc_log_config->log_format != NULL && strcmp(SC_LOG_DEF_LOG_FORMAT, sc_log_config->log_format) == 0); SCLogDeInitLogModule(); setenv(SC_LOG_ENV_LOG_LEVEL, "Debug", 1); setenv(SC_LOG_ENV_LOG_OP_IFACE, "Console", 1); setenv(SC_LOG_ENV_LOG_FORMAT, "%n- %l", 1); SCLogInitLogModule(NULL); result &= (SC_LOG_DEBUG == sc_log_config->log_level); result &= (sc_log_config->op_ifaces != NULL && SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface); result &= (sc_log_config->log_format != NULL && !strcmp("%n- %l", sc_log_config->log_format)); unsetenv(SC_LOG_ENV_LOG_LEVEL); unsetenv(SC_LOG_ENV_LOG_OP_IFACE); unsetenv(SC_LOG_ENV_LOG_FORMAT); SCLogDeInitLogModule(); return result; } int SCLogTestInit02() { SCLogInitData *sc_lid = NULL; SCLogOPIfaceCtx *sc_iface_ctx = NULL; int result = 1; char *logfile = SCLogGetLogFilename("boo.txt"); sc_lid = SCLogAllocLogInitData(); if (sc_lid == NULL) return 0; sc_lid->startup_message = "Test02"; sc_lid->global_log_level = SC_LOG_DEBUG; sc_lid->op_filter = "boo"; sc_iface_ctx = SCLogInitOPIfaceCtx("file", "%m - %d", SC_LOG_ALERT, logfile); SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid); sc_iface_ctx = SCLogInitOPIfaceCtx("console", NULL, SC_LOG_ERROR, NULL); SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid); SCLogInitLogModule(sc_lid); if (sc_log_config == NULL) return 0; result &= (SC_LOG_DEBUG == sc_log_config->log_level); result &= (sc_log_config->op_ifaces != NULL && SC_LOG_OP_IFACE_FILE == sc_log_config->op_ifaces->iface); result &= (sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->next != NULL && SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->next->iface); result &= (sc_log_config->log_format != NULL && strcmp(SC_LOG_DEF_LOG_FORMAT, sc_log_config->log_format) == 0); result &= (sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->log_format != NULL && strcmp("%m - %d", sc_log_config->op_ifaces->log_format) == 0); result &= (sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->next != NULL && sc_log_config->op_ifaces->next->log_format == NULL); SCLogDeInitLogModule(); sc_lid = SCLogAllocLogInitData(); if (sc_lid == NULL) return 0; sc_lid->startup_message = "Test02"; sc_lid->global_log_level = SC_LOG_DEBUG; sc_lid->op_filter = "boo"; sc_lid->global_log_format = "kaboo"; SCLogInitLogModule(sc_lid); if (sc_log_config == NULL) return 0; result &= (SC_LOG_DEBUG == sc_log_config->log_level); result &= (sc_log_config->op_ifaces != NULL && SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface); result &= (sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->next == NULL); result &= (sc_log_config->log_format != NULL && strcmp("kaboo", sc_log_config->log_format) == 0); result &= (sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->log_format == NULL); result &= (sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->next == NULL); SCLogDeInitLogModule(); return result; } int SCLogTestInit03() { int result = 1; SCLogInitLogModule(NULL); SCLogAddFGFilterBL(NULL, "bamboo", -1); SCLogAddFGFilterBL(NULL, "soo", -1); SCLogAddFGFilterBL(NULL, "dummy", -1); result &= (SCLogPrintFGFilters() == 3); SCLogAddFGFilterBL(NULL, "dummy1", -1); SCLogAddFGFilterBL(NULL, "dummy2", -1); result &= (SCLogPrintFGFilters() == 5); SCLogDeInitLogModule(); return result; } int SCLogTestInit04() { int result = 1; SCLogInitLogModule(NULL); SCLogAddFDFilter("bamboo"); SCLogAddFDFilter("soo"); SCLogAddFDFilter("foo"); SCLogAddFDFilter("roo"); result &= (SCLogPrintFDFilters() == 4); SCLogAddFDFilter("loo"); SCLogAddFDFilter("soo"); result &= (SCLogPrintFDFilters() == 5); SCLogRemoveFDFilter("bamboo"); SCLogRemoveFDFilter("soo"); SCLogRemoveFDFilter("foo"); SCLogRemoveFDFilter("noo"); result &= (SCLogPrintFDFilters() == 2); SCLogDeInitLogModule(); return result; } int SCLogTestInit05() { int result = 1; SCLogInfo("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); return result; } #endif /* UNITTESTS */ void SCLogRegisterTests() { #ifdef UNITTESTS UtRegisterTest("SCLogTestInit01", SCLogTestInit01, 1); UtRegisterTest("SCLogTestInit02", SCLogTestInit02, 1); UtRegisterTest("SCLogTestInit03", SCLogTestInit03, 1); UtRegisterTest("SCLogTestInit04", SCLogTestInit04, 1); UtRegisterTest("SCLogTestInit05", SCLogTestInit05, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/decode-pppoe.h0000644000000000000000000000514612253546156013550 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author James Riden */ #ifndef __DECODE_PPPOE_H__ #define __DECODE_PPPOE_H__ #include "decode.h" #include "threadvars.h" #define PPPOE_SESSION_HEADER_LEN 8 #define PPPOE_DISCOVERY_HEADER_MIN_LEN 6 #define PPPOE_SESSION_GET_VERSION(hdr) ((hdr)->pppoe_version_type & 0xF0) >> 4 #define PPPOE_SESSION_GET_TYPE(hdr) ((hdr)->pppoe_version_type & 0x0F) #define PPPOE_DISCOVERY_GET_VERSION(hdr) ((hdr)->pppoe_version_type & 0xF0) >> 4 #define PPPOE_DISCOVERY_GET_TYPE(hdr) ((hdr)->pppoe_version_type & 0x0F) typedef struct PPPOESessionHdr_ { uint8_t pppoe_version_type; uint8_t pppoe_code; uint16_t session_id; uint16_t pppoe_length; uint16_t protocol; } PPPOESessionHdr; typedef struct PPPOEDiscoveryTag_ { uint16_t pppoe_tag_type; uint16_t pppoe_tag_length; } PPPOEDiscoveryTag; typedef struct PPPOEDiscoveryHdr_ { uint8_t pppoe_version_type; uint8_t pppoe_code; uint16_t discovery_id; uint16_t pppoe_length; } PPPOEDiscoveryHdr; /* see RFC 2516 - discovery codes */ #define PPPOE_CODE_PADI 0x09 #define PPPOE_CODE_PADO 0x07 #define PPPOE_CODE_PADR 0x19 #define PPPOE_CODE_PADS 0x65 #define PPPOE_CODE_PADT 0xa7 /* see RFC 2516 Appendix A */ #define PPPOE_TAG_END_OF_LIST 0x0000 /* End-Of-List */ #define PPPOE_TAG_SERVICE_NAME 0x0101 /* Service-Name */ #define PPPOE_TAG_AC_NAME 0x0102 /* AC-Name */ #define PPPOE_TAG_HOST_UNIQ 0x0103 /* Host-Uniq */ #define PPPOE_TAG_AC_COOKIE 0x0104 /* AC-Cookie */ #define PPPOE_TAG_VENDOR_SPECIFIC 0x0105 /* Vendor-Specific */ #define PPPOE_TAG_RELAY_SESSION_ID 0x0110 /* Relay-Session-Id */ #define PPPOE_TAG_SERVICE_NAME_ERROR 0x0201 /* Service-Name-Error */ #define PPPOE_TAG_AC_SYS_ERROR 0x0202 /* AC-System Error */ #define PPPOE_TAG_GEN_ERROR 0x0203 /* Generic-Error */ void DecodePPPOERegisterTests(void); #endif /* __DECODE_PPPOE_H__ */ suricata-1.4.7/src/util-var.h0000644000000000000000000000212612253546156012742 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_VAR_H__ #define __UTIL_VAR_H__ typedef struct GenericVar_ { uint8_t type; struct GenericVar_ *next; uint16_t idx; } GenericVar; void GenericVarFree(GenericVar *); void GenericVarAppend(GenericVar **, GenericVar *); void GenericVarRemove(GenericVar **, GenericVar *); #endif /* __UTIL_VAR_H__ */ suricata-1.4.7/src/detect-ack.h0000644000000000000000000000210112253546156013174 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus */ #ifndef __DETECT_ACK_H__ #define __DETECT_ACK_H__ /** * \brief ack data */ typedef struct DetectAckData_ { uint32_t ack; /**< ack to match */ } DetectAckData; /** * \brief Registration function for ack: keyword */ void DetectAckRegister(void); #endif /* __DETECT_ACK_H__ */ suricata-1.4.7/src/detect-filemd5.c0000644000000000000000000002657512253546156014003 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-spm-bm.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "stream-tcp.h" #include "detect-filemd5.h" #include "queue.h" #include "util-rohash.h" #ifndef HAVE_NSS static int DetectFileMd5SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) { SCLogError(SC_ERR_NO_MD5_SUPPORT, "no MD5 calculation support built in, needed for filemd5 keyword"); return -1; } /** * \brief Registration function for keyword: filemd5 */ void DetectFileMd5Register(void) { sigmatch_table[DETECT_FILEMD5].name = "filemd5"; sigmatch_table[DETECT_FILEMD5].FileMatch = NULL; sigmatch_table[DETECT_FILEMD5].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5SetupNoSupport; sigmatch_table[DETECT_FILEMD5].Free = NULL; sigmatch_table[DETECT_FILEMD5].RegisterTests = NULL; sigmatch_table[DETECT_FILEMD5].flags = SIGMATCH_NOT_BUILT; SCLogDebug("registering filemd5 rule option"); return; } #else /* HAVE_NSS */ static int DetectFileMd5Match (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFileMd5Setup (DetectEngineCtx *, Signature *, char *); static void DetectFileMd5RegisterTests(void); static void DetectFileMd5Free(void *); /** * \brief Registration function for keyword: filemd5 */ void DetectFileMd5Register(void) { sigmatch_table[DETECT_FILEMD5].name = "filemd5"; sigmatch_table[DETECT_FILEMD5].desc = "match file MD5 against list of MD5 checksums"; sigmatch_table[DETECT_FILEMD5].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemd5"; sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileMd5Match; sigmatch_table[DETECT_FILEMD5].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5Setup; sigmatch_table[DETECT_FILEMD5].Free = DetectFileMd5Free; sigmatch_table[DETECT_FILEMD5].RegisterTests = DetectFileMd5RegisterTests; SCLogDebug("registering filemd5 rule option"); return; } static int Md5ReadString(uint8_t *md5, char *str, char *filename, int line_no) { if (strlen(str) != 32) { SCLogError(SC_ERR_INVALID_MD5, "%s:%d md5 string not 32 bytes", filename, line_no); return -1; } int i, x; for (x = 0, i = 0; i < 32; i+=2, x++) { char buf[3] = { 0, 0, 0}; buf[0] = str[i]; buf[1] = str[i+1]; long value = strtol(buf, NULL, 16); if (value >= 0 && value <= 255) md5[x] = (uint8_t)value; else { SCLogError(SC_ERR_INVALID_MD5, "%s:%d md5 byte out of range %ld", filename, line_no, value); return -1; } } return 1; } static int MD5LoadHash(ROHashTable *hash, char *string, char *filename, int line_no) { uint8_t md5[16]; if (Md5ReadString(md5, string, filename, line_no) == 1) { if (ROHashInitQueueValue(hash, &md5, (uint16_t)sizeof(md5)) != 1) return -1; } return 1; } static int MD5MatchLookupBuffer(ROHashTable *hash, uint8_t *buf, size_t buflen) { void *ptr = ROHashLookup(hash, buf, (uint16_t)buflen); if (ptr == NULL) return 0; else return 1; } /** * \brief match the specified filemd5 * * \param t thread local vars * \param det_ctx pattern matcher thread local data * \param f *LOCKED* flow * \param flags direction flags * \param file file being inspected * \param s signature being inspected * \param m sigmatch that we will cast into DetectFileMd5Data * * \retval 0 no match * \retval 1 match */ static int DetectFileMd5Match (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; DetectFileMd5Data *filemd5 = (DetectFileMd5Data *)m->ctx; if (file->txid < det_ctx->tx_id) { SCReturnInt(0); } if (file->txid > det_ctx->tx_id) { SCReturnInt(0); } if (file->state != FILE_STATE_CLOSED) { SCReturnInt(0); } if (file->flags & FILE_MD5) { if (MD5MatchLookupBuffer(filemd5->hash, file->md5, sizeof(file->md5)) == 1) { if (filemd5->negated == 0) ret = 1; else ret = 0; } else { if (filemd5->negated == 0) ret = 0; else ret = 1; } } SCReturnInt(ret); } /** * \brief Parse the filemd5 keyword * * \param idstr Pointer to the user provided option * * \retval filemd5 pointer to DetectFileMd5Data on success * \retval NULL on failure */ static DetectFileMd5Data *DetectFileMd5Parse (char *str) { DetectFileMd5Data *filemd5 = NULL; FILE *fp = NULL; char *filename = NULL; /* We have a correct filemd5 option */ filemd5 = SCMalloc(sizeof(DetectFileMd5Data)); if (unlikely(filemd5 == NULL)) goto error; memset(filemd5, 0x00, sizeof(DetectFileMd5Data)); if (strlen(str) && str[0] == '!') { filemd5->negated = 1; str++; } filemd5->hash = ROHashInit(18, 16); if (filemd5->hash == NULL) { goto error; } /* get full filename */ filename = DetectLoadCompleteSigPath(str); if (filename == NULL) { goto error; } char line[8192] = ""; fp = fopen(filename, "r"); if (fp == NULL) { SCLogError(SC_ERR_OPENING_RULE_FILE, "opening md5 file %s: %s", filename, strerror(errno)); goto error; } int line_no = 0; while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); line_no++; /* ignore comments and empty lines */ if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') continue; while (isspace(line[--len])); /* Check if we have a trailing newline, and remove it */ len = strlen(line); if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { line[len - 1] = '\0'; } /* cut off longer lines */ if (strlen(line) > 32) line[32] = 0x00; if (MD5LoadHash(filemd5->hash, line, filename, line_no) != 1) { goto error; } } fclose(fp); fp = NULL; if (ROHashInitFinalize(filemd5->hash) != 1) { goto error; } SCLogInfo("MD5 hash size %u bytes%s", ROHashMemorySize(filemd5->hash), filemd5->negated ? ", negated match" : ""); SCFree(filename); return filemd5; error: if (filemd5 != NULL) DetectFileMd5Free(filemd5); if (fp != NULL) fclose(fp); if (filename != NULL) SCFree(filename); return NULL; } /** * \brief this function is used to parse filemd5 options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param str pointer to the user provided "filemd5" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectFileMd5Data *filemd5 = NULL; SigMatch *sm = NULL; filemd5 = DetectFileMd5Parse(str); if (filemd5 == 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_FILEMD5; sm->ctx = (void *)filemd5; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } AppLayerHtpNeedFileInspection(); /** \todo remove this once we support more than http */ s->alproto = ALPROTO_HTTP; s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MD5); return 0; error: if (filemd5 != NULL) DetectFileMd5Free(filemd5); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectFileMd5Data * * \param filemd5 pointer to DetectFileMd5Data */ static void DetectFileMd5Free(void *ptr) { if (ptr != NULL) { DetectFileMd5Data *filemd5 = (DetectFileMd5Data *)ptr; if (filemd5->hash != NULL) ROHashFree(filemd5->hash); SCFree(filemd5); } } #ifdef UNITTESTS static int MD5MatchLookupString(ROHashTable *hash, char *string) { uint8_t md5[16]; if (Md5ReadString(md5, string, "file", 88) == 1) { void *ptr = ROHashLookup(hash, &md5, (uint16_t)sizeof(md5)); if (ptr == NULL) return 0; else return 1; } return 0; } static int MD5MatchTest01(void) { ROHashTable *hash = ROHashInit(4, 16); if (hash == NULL) { return 0; } if (MD5LoadHash(hash, "d80f93a93dc5f3ee945704754d6e0a36", "file", 1) != 1) return 0; if (MD5LoadHash(hash, "92a49985b384f0d993a36e4c2d45e206", "file", 2) != 1) return 0; if (MD5LoadHash(hash, "11adeaacc8c309815f7bc3e33888f281", "file", 3) != 1) return 0; if (MD5LoadHash(hash, "22e10a8fe02344ade0bea8836a1714af", "file", 4) != 1) return 0; if (MD5LoadHash(hash, "c3db2cbf02c68f073afcaee5634677bc", "file", 5) != 1) return 0; if (MD5LoadHash(hash, "7ed095da259638f42402fb9e74287a17", "file", 6) != 1) return 0; if (ROHashInitFinalize(hash) != 1) { return 0; } if (MD5MatchLookupString(hash, "d80f93a93dc5f3ee945704754d6e0a36") != 1) return 0; if (MD5MatchLookupString(hash, "92a49985b384f0d993a36e4c2d45e206") != 1) return 0; if (MD5MatchLookupString(hash, "11adeaacc8c309815f7bc3e33888f281") != 1) return 0; if (MD5MatchLookupString(hash, "22e10a8fe02344ade0bea8836a1714af") != 1) return 0; if (MD5MatchLookupString(hash, "c3db2cbf02c68f073afcaee5634677bc") != 1) return 0; if (MD5MatchLookupString(hash, "7ed095da259638f42402fb9e74287a17") != 1) return 0; /* shouldnt match */ if (MD5MatchLookupString(hash, "33333333333333333333333333333333") == 1) return 0; ROHashFree(hash); return 1; } #endif void DetectFileMd5RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("MD5MatchTest01", MD5MatchTest01, 1); #endif } #endif /* HAVE_NSS */ suricata-1.4.7/src/util-action.h0000644000000000000000000000175212253546156013433 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __ACTION_ORDER_H__ #define __ACTION_ORDER_H__ #include "suricata-common.h" int ActionInitConfig(); uint8_t ActionOrderVal(uint8_t); void UtilActionRegisterTests(void); #endif /* __ACTION_ORDER_H__ */ suricata-1.4.7/src/decode-events.c0000644000000000000000000000676212253546156013731 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "app-layer-parser.h" #include "decode-events.h" #include "flow.h" AppLayerDecoderEventsModule *decoder_events_module = NULL; void AppLayerDecoderEventsModuleRegister(uint16_t alproto, SCEnumCharMap *table) { AppLayerDecoderEventsModule *dvm = decoder_events_module; if (table == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "argument \"table\" NULL"); return; } while (dvm != NULL) { if (dvm->alproto == alproto) { SCLogInfo("Decoder event module for alproto - %"PRIu16" already " "registered", alproto); return; } dvm = dvm->next; } AppLayerDecoderEventsModule *new_dev = SCMalloc(sizeof(AppLayerDecoderEventsModule)); if (unlikely(new_dev == NULL)) return; new_dev->alproto = alproto; new_dev->table = table; new_dev->next = NULL; if (decoder_events_module != NULL) new_dev->next = decoder_events_module; decoder_events_module = new_dev; return; } uint16_t AppLayerDecoderEventsModuleGetAlproto(const char *alproto) { return AppLayerGetProtoByName(alproto); } int AppLayerDecoderEventsModuleGetEventId(uint16_t alproto, const char *event_name) { AppLayerDecoderEventsModule *dvm = decoder_events_module; while (dvm != NULL) { if (dvm->alproto == alproto) break; dvm = dvm->next; } if (dvm == NULL) { SCLogError(SC_ERR_FATAL, "decoder event module not found for " "alproto - %"PRIu16, alproto); return -1; } int event_id = SCMapEnumNameToValue(event_name, dvm->table); if (event_id == -1) { SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in " "module enum map table.", event_name); /* yes this is fatal */ return -1; } return event_id; } void AppLayerDecoderEventsModuleDeRegister(void) { AppLayerDecoderEventsModule *dvm = decoder_events_module; AppLayerDecoderEventsModule *prev_dvm; while (dvm != NULL) { prev_dvm = dvm; dvm = dvm->next; SCFree(prev_dvm); } decoder_events_module = NULL; } /************************************Unittests*********************************/ AppLayerDecoderEventsModule *decoder_events_module_backup = NULL; void AppLayerDecoderEventsModuleCreateBackup(void) { decoder_events_module_backup = decoder_events_module; decoder_events_module = NULL; return; } void AppLayerDecoderEventsModuleRestoreBackup(void) { AppLayerDecoderEventsModuleDeRegister(); decoder_events_module = decoder_events_module_backup; decoder_events_module_backup = NULL; return; } suricata-1.4.7/src/flow-var.h0000644000000000000000000000377212253546156012744 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon */ #ifndef __FLOW_VAR_H__ #define __FLOW_VAR_H__ #include "flow.h" #include "util-var.h" /** Available data types for Flowvars */ #define FLOWVAR_TYPE_STR 1 #define FLOWVAR_TYPE_INT 2 /** Struct used to hold the string data type for flowvars */ typedef struct FlowVarTypeStr { uint8_t *value; uint16_t value_len; } FlowVarTypeStr; /** Struct used to hold the integer data type for flowvars */ typedef struct FlowVarTypeInt_ { uint32_t value; } FlowVarTypeInt; /** Generic Flowvar Structure */ typedef struct FlowVar_ { uint8_t type; /* type, DETECT_FLOWVAR in this case */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ uint16_t idx; /* name idx */ uint8_t datatype; union { FlowVarTypeStr fv_str; FlowVarTypeInt fv_int; } data; } FlowVar; /** Flowvar Interface API */ void FlowVarAddStr(Flow *, uint16_t, uint8_t *, uint16_t); void FlowVarAddInt(Flow *, uint16_t, uint32_t); FlowVar *FlowVarGet(Flow *, uint16_t); void FlowVarFree(FlowVar *); void FlowVarPrint(GenericVar *); #endif /* __FLOW_VAR_H__ */ suricata-1.4.7/src/util-fix_checksum.h0000644000000000000000000000332212253546156014621 00000000000000/* * Reference: OpenBSD's pf.c. * * Copyright (c) 2001 Daniel Hartmeier * Copyright (c) 2002 - 2008 Henning Brauer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Effort sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F30602-01-2-0537. */ uint16_t FixChecksum(uint16_t sum, uint16_t old, uint16_t new); suricata-1.4.7/src/util-host-os-info.c0000644000000000000000000015141212253546156014475 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Host info utility functions */ #include "suricata-common.h" #include "util-host-os-info.h" #include "util-error.h" #include "util-debug.h" #include "util-radix-tree.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "conf.h" #include "conf-yaml-loader.h" #include "util-enum.h" #include "util-unittest.h" /** Enum map for the various OS flavours */ SCEnumCharMap sc_hinfo_os_policy_map[ ] = { { "none", OS_POLICY_NONE }, { "bsd", OS_POLICY_BSD }, { "bsd-right", OS_POLICY_BSD_RIGHT }, { "old-linux", OS_POLICY_OLD_LINUX }, { "linux", OS_POLICY_LINUX }, { "old-solaris", OS_POLICY_OLD_SOLARIS }, { "solaris", OS_POLICY_SOLARIS }, { "hpux10", OS_POLICY_HPUX10 }, { "hpux11", OS_POLICY_HPUX11 }, { "irix", OS_POLICY_IRIX }, { "macos", OS_POLICY_MACOS }, { "windows", OS_POLICY_WINDOWS }, { "vista", OS_POLICY_VISTA }, { "windows2k3", OS_POLICY_WINDOWS2K3 }, { NULL, -1 }, }; /** Radix tree that holds the host OS information */ static SCRadixTree *sc_hinfo_tree = NULL; /** * \brief Validates an IPV4 address and returns the network endian arranged * version of the IPV4 address * * \param addr Pointer to a character string containing an IPV4 address. A * valid IPV4 address is a character string containing a dotted * format of "ddd.ddd.ddd.ddd" * * \retval Pointer to an in_addr instance containing the network endian format * of the IPV4 address * \retval NULL if the IPV4 address is invalid */ static struct in_addr *SCHInfoValidateIPV4Address(const char *addr_str) { struct in_addr *addr = NULL; if ( (addr = SCMalloc(sizeof(struct in_addr))) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Fatal error encountered in SCHInfoValidateIPV4Address. Mem not allocated"); return NULL; } if (inet_pton(AF_INET, addr_str, addr) <= 0) { SCFree(addr); return NULL; } return addr; } /** * \brief Validates an IPV6 address and returns the network endian arranged * version of the IPV6 addresss * * \param addr Pointer to a character string containing an IPV6 address * * \retval Pointer to a in6_addr instance containing the network endian format * of the IPV6 address * \retval NULL if the IPV6 address is invalid */ static struct in6_addr *SCHInfoValidateIPV6Address(const char *addr_str) { struct in6_addr *addr = NULL; if ( (addr = SCMalloc(sizeof(struct in6_addr))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCHInfoValidateIPV6Address. Exiting..."); exit(EXIT_FAILURE); } if (inet_pton(AF_INET6, addr_str, addr) <= 0) { SCFree(addr); return NULL; } return addr; } /** * \brief Allocates the host_os flavour wrapped in user_data variable to be sent * along with the key to the radix tree * * \param host_os Pointer to a character string containing the host_os flavour * * \retval user_data On success, pointer to the user_data that has to be sent * along with the key, to be added to the Radix tree; NULL on * failure * \initonly */ static void *SCHInfoAllocUserDataOSPolicy(const char *host_os) { int *user_data = NULL; if ( (user_data = SCMalloc(sizeof(int))) == NULL) { SCLogError(SC_ERR_FATAL, "Error allocating memory. Exiting"); exit(EXIT_FAILURE); } /* the host os flavour that has to be sent as user data */ if ( (*user_data = SCMapEnumNameToValue(host_os, sc_hinfo_os_policy_map)) == -1) { SCLogError(SC_ERR_INVALID_ENUM_MAP, "Invalid enum map inside " "SCHInfoAddHostOSInfo()"); SCFree(user_data); return NULL; } return (void *)user_data; } /** * \brief Used to free the user data that is allocated by host_os_info API * * \param Pointer to the data that has to be freed */ static void SCHInfoFreeUserDataOSPolicy(void *data) { if (data != NULL) SCFree(data); return; } /** * \brief Culls the non-netmask portion of the ip address. * * This function can also be used for any general purpose use, to mask * the first netmask bits of the stream data sent as argument * * \param stream Pointer to the data to be masked * \param netmask The mask length(netmask) * \param bitlen The bitlen of the stream */ static void SCHInfoMaskIPNetblock(uint8_t *stream, int netmask, int bitlen) { int bytes = 0; int mask = 0; int i = 0; bytes = bitlen / 8; for (i = 0; i < bytes; i++) { mask = -1; if ( ((i + 1) * 8) > netmask) { if ( ((i + 1) * 8 - netmask) < 8) mask = -1 << ((i + 1) * 8 - netmask); else mask = 0; } stream[i] &= mask; } return; } /** * \brief Used to add the host-os-info data obtained from the conf * * \param host_os The host_os name/flavour from the conf file * \param host_os_ip_range Pointer to a char string holding the ip/ip_netblock * for the host_os specified in the first argument * \param is_ipv4 Indicates if the ip address to be considered for the * default configuration is IPV4; if not it is IPV6. * Specified using SC_HINFO_IS_IPV6 or SC_HINFO_IS_IPV4 * * \retval 0 On successfully adding the host os info to the Radix tree * \retval -1 On failure * \initonly (only specified from config, at the startup) */ int SCHInfoAddHostOSInfo(char *host_os, char *host_os_ip_range, int is_ipv4) { char *ip_str = NULL; char *ip_str_rem = NULL; struct in_addr *ipv4_addr = NULL; struct in6_addr *ipv6_addr = NULL; char *netmask_str = NULL; int netmask_value = 0; int *user_data = NULL; char recursive = FALSE; if (host_os == NULL || host_os_ip_range == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid arguments"); return -1; } /* create the radix tree that would hold all the host os info */ if (sc_hinfo_tree == NULL) sc_hinfo_tree = SCRadixCreateRadixTree(SCHInfoFreeUserDataOSPolicy, NULL); /* the host os flavour that has to be sent as user data */ if ( (user_data = SCHInfoAllocUserDataOSPolicy(host_os)) == NULL) { SCLogError(SC_ERR_INVALID_ENUM_MAP, "Invalid enum map inside"); return -1; } /* if we have a default configuration set the appropriate values for the * netblocks */ if ( (strcasecmp(host_os_ip_range, "default")) == 0) { if (is_ipv4) host_os_ip_range = "0.0.0.0/0"; else host_os_ip_range = "::/0"; } if ( (ip_str = SCStrdup(host_os_ip_range)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } /* check if we have more addresses in the host_os_ip_range */ if ((ip_str_rem = index(ip_str, ',')) != NULL) { ip_str_rem[0] = '\0'; ip_str_rem++; recursive = TRUE; } /* check if we have received a netblock */ if ( (netmask_str = index(ip_str, '/')) != NULL) { netmask_str[0] = '\0'; netmask_str++; } if (index(ip_str, ':') == NULL) { /* if we are here, we have an IPV4 address */ if ( (ipv4_addr = SCHInfoValidateIPV4Address(ip_str)) == NULL) { SCLogError(SC_ERR_INVALID_IPV4_ADDR, "Invalid IPV4 address"); return -1; } if (netmask_str == NULL) { SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, sc_hinfo_tree, (void *)user_data); } else { netmask_value = atoi(netmask_str); if (netmask_value < 0 || netmask_value > 32) { SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Invalid IPV4 Netblock"); SCFree(ipv4_addr); return -1; } SCHInfoMaskIPNetblock((uint8_t *)ipv4_addr, netmask_value, 32); SCRadixAddKeyIPV4Netblock((uint8_t *)ipv4_addr, sc_hinfo_tree, (void *)user_data, netmask_value); } } else { /* if we are here, we have an IPV6 address */ if ( (ipv6_addr = SCHInfoValidateIPV6Address(ip_str)) == NULL) { SCLogError(SC_ERR_INVALID_IPV6_ADDR, "Invalid IPV6 address inside"); return -1; } if (netmask_str == NULL) { SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, sc_hinfo_tree, (void *)user_data); } else { netmask_value = atoi(netmask_str); if (netmask_value < 0 || netmask_value > 128) { SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Invalid IPV6 Netblock"); SCFree(ipv6_addr); return -1; } SCHInfoMaskIPNetblock((uint8_t *)ipv6_addr, netmask_value, 128); SCRadixAddKeyIPV6Netblock((uint8_t *)ipv6_addr, sc_hinfo_tree, (void *)user_data, netmask_value); } } if (recursive == TRUE) { SCHInfoAddHostOSInfo(host_os, ip_str_rem, is_ipv4); } if (ip_str != NULL) SCFree(ip_str); if (ipv4_addr != NULL) SCFree(ipv4_addr); if (ipv6_addr != NULL) SCFree(ipv6_addr); return *user_data; } /** * \brief Retrieves the host os flavour, given an ipv4/ipv6 address as a string. * * \param Pointer to a string containing an IP address * * \retval The OS flavour on success; -1 on failure, or on not finding the key */ int SCHInfoGetHostOSFlavour(char *ip_addr_str) { SCRadixNode *node = NULL; struct in_addr *ipv4_addr = NULL; struct in6_addr *ipv6_addr = NULL; if (ip_addr_str == NULL || index(ip_addr_str, '/') != NULL) return -1; if (index(ip_addr_str, ':') != NULL) { if ( (ipv6_addr = SCHInfoValidateIPV6Address(ip_addr_str)) == NULL) { SCLogError(SC_ERR_INVALID_IPV4_ADDR, "Invalid IPV4 address"); return -1; } if ( (node = SCRadixFindKeyIPV6BestMatch((uint8_t *)ipv6_addr, sc_hinfo_tree)) == NULL) return -1; else return *((int *)node->prefix->user_data_result); } else { if ( (ipv4_addr = SCHInfoValidateIPV4Address(ip_addr_str)) == NULL) { SCLogError(SC_ERR_INVALID_IPV4_ADDR, "Invalid IPV4 address"); return -1; } if ( (node = SCRadixFindKeyIPV4BestMatch((uint8_t *)ipv4_addr, sc_hinfo_tree)) == NULL) return -1; else return *((int *)node->prefix->user_data_result); } } /** * \brief Retrieves the host os flavour, given an ipv4 address in the raw * address format. * * \param Pointer to a raw ipv4 address. * * \retval The OS flavour on success; -1 on failure, or on not finding the key */ int SCHInfoGetIPv4HostOSFlavour(uint8_t *ipv4_addr) { SCRadixNode *node = SCRadixFindKeyIPV4BestMatch(ipv4_addr, sc_hinfo_tree); if (node == NULL) return -1; else return *((int *)node->prefix->user_data_result); } /** * \brief Retrieves the host os flavour, given an ipv6 address in the raw * address format. * * \param Pointer to a raw ipv6 address. * * \retval The OS flavour on success; -1 on failure, or on not finding the key */ int SCHInfoGetIPv6HostOSFlavour(uint8_t *ipv6_addr) { SCRadixNode *node = SCRadixFindKeyIPV6BestMatch(ipv6_addr, sc_hinfo_tree); if (node == NULL) return -1; else return *((int *)node->prefix->user_data_result); } void SCHInfoCleanResources(void) { if (sc_hinfo_tree != NULL) { SCRadixReleaseRadixTree(sc_hinfo_tree); sc_hinfo_tree = NULL; } return; } /** * \brief Load the host os policy information from the configuration. * * \initonly (A mem alloc error should cause an exit failure) */ void SCHInfoLoadFromConfig(void) { ConfNode *root = ConfGetNode("host-os-policy"); if (root == NULL) return; ConfNode *policy; TAILQ_FOREACH(policy, &root->head, next) { ConfNode *host; TAILQ_FOREACH(host, &policy->head, next) { int is_ipv4 = 1; if (index(host->val, ':') != NULL) is_ipv4 = 0; if (SCHInfoAddHostOSInfo(policy->name, host->val, is_ipv4) == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to add host \"%s\" with policy \"%s\" to host " "info database", host->val, policy->name); exit(EXIT_FAILURE); } } } } /*------------------------------------Unit_Tests------------------------------*/ #ifdef UNITTESTS static SCRadixTree *sc_hinfo_tree_backup = NULL; static void SCHInfoCreateContextBackup(void) { sc_hinfo_tree_backup = sc_hinfo_tree; sc_hinfo_tree = NULL; return; } static void SCHInfoRestoreContextBackup(void) { sc_hinfo_tree = sc_hinfo_tree_backup; sc_hinfo_tree_backup = NULL; return; } /** * \test Check if we the IPs with the right OS flavours are added to the host OS * radix tree, and the IPS with invalid flavours returns an error(-1) */ int SCHInfoTestInvalidOSFlavour01(void) { SCHInfoCreateContextBackup(); int result = 0; if (SCHInfoAddHostOSInfo("bamboo", "192.168.1.1", SC_HINFO_IS_IPV4) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("windows", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("hpux10", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("hpux11", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("irix", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("bsd", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("bsd", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("old_linux", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("old_linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("macos", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("vista", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("windows2k3", "192.168.1.1", SC_HINFO_IS_IPV4) != SCMapEnumNameToValue("windows2k3", sc_hinfo_os_policy_map)) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check that invalid ipv4 addresses and ipv4 netblocks are rejected by * the host os info API */ int SCHInfoTestInvalidIPV4Address02(void) { SCHInfoCreateContextBackup(); int result = 1; if (SCHInfoAddHostOSInfo("linux", "192.168.1.566", SC_HINFO_IS_IPV4) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.168.1", SC_HINFO_IS_IPV4 != -1)) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.", SC_HINFO_IS_IPV4) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.168", SC_HINFO_IS_IPV4) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "", SC_HINFO_IS_IPV4) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.168.1.1/33", SC_HINFO_IS_IPV4) != -1) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check that invalid ipv4 addresses and ipv4 netblocks are rejected by * the host os info API */ int SCHInfoTestInvalidIPV6Address03(void) { SCHInfoCreateContextBackup(); int result = 1; if (SCHInfoAddHostOSInfo("linux", "2362:7322", SC_HINFO_IS_IPV6) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "19YW:", SC_HINFO_IS_IPV6) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "1235", SC_HINFO_IS_IPV6) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "1922:236115:", SC_HINFO_IS_IPV6) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "", SC_HINFO_IS_IPV6) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "1921.6311:6241:6422:7352:ABBB:DDDD:EEEE/129", SC_HINFO_IS_IPV6) != -1) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check that valid ipv4 addresses are inserted into the host os radix * tree, and the host os api retrieves the right value for the host os * flavour, on supplying as arg an ipv4 addresses that has been added to * the host os radix tree. */ int SCHInfoTestValidIPV4Address04(void) { SCHInfoCreateContextBackup(); int result = 1; if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "192.168.1.100", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux10", "192.168.2.4", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.192.1.5", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "192.168.10.20", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "111.163.151.62", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "11.1.120.210", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "19.18.110.210", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "19.18.120.110", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux11", "191.168.11.128", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "191.168.11.192", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.1") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.2") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.100") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.192.2.4") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.2.4") != SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.192.1.5") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.10.20") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.163.151.62") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("11.1.120.210") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("19.18.110.210") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("19.18.120.110") != SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("191.168.11.128") != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("191.168.11.192") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("191.168.11.224") != -1) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check that valid ipv4 addresses/netblocks are inserted into the host os * radix tree, and the host os api retrieves the right value for the host * os flavour, on supplying as arg an ipv4 addresses that has been added * to the host os radix tree. */ int SCHInfoTestValidIPV4Address05(void) { SCHInfoCreateContextBackup(); struct in_addr in; int result = 1; if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "192.168.1.100", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux10", "192.168.2.4", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.192.1.5", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "192.168.10.20", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "111.163.151.62", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux11", "111.162.208.124/20", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "111.162.240.1", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "111.162.214.100", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "111.162.208.100", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "111.162.194.112", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.1") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.2") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.100") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.192.2.4") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.2.4") != SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.192.1.5") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.10.20") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.163.151.62") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.208.0") != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.210.1") != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.214.1") != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.0.0") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.240.112") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.240.1") != SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.214.100") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (inet_pton(AF_INET, "111.162.208.100", &in) < 0) { goto end; } if (SCHInfoGetIPv4HostOSFlavour((uint8_t *)&in) != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.194.112") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.208.200") != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (inet_pton(AF_INET, "111.162.208.200", &in) < 0) { goto end; } if (SCHInfoGetIPv4HostOSFlavour((uint8_t *)&in) != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("111.162.200.201") != -1) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check that valid ipv6 addresses are inserted into the host os radix * tree, and the host os api retrieves the right value for the host os * flavour, on supplying as arg an ipv6 address that has been added to * the host os radix tree. */ int SCHInfoTestValidIPV6Address06(void) { SCHInfoCreateContextBackup(); int result = 1; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "6961:6121:2132:6241:423A:2135:2461:621D", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "DD13:613D:F312:62DD:6213:421A:6212:2652", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux10", "9891:2131:2151:6426:1342:674D:622F:2342", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "3525:2351:4223:6211:2311:2667:6242:2154", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "1511:6211:6726:7777:1212:2333:6222:7722", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "2666:6222:7222:2335:6223:7722:3425:2362", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "8762:2352:6241:7245:EE23:21AD:2312:622C", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "6422:EE1A:2621:34AD:2462:432D:642E:E13A", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "3521:7622:6241:6242:7277:1234:2352:6234", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux11", "2141:6232:6252:2223:7734:2345:6245:6222", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "5222:6432:6432:2322:6662:3423:4322:3245", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFFE") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("6422:EE1A:2621:34AD:2462:432D:642E:E13A") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("3521:7622:6241:6242:7277:1234:2352:6234") != SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("2141:6232:6252:2223:7734:2345:6245:6222") != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:3245") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != -1) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check that valid ipv6 addresses/netblocks are inserted into the host os * radix tree, and the host os api retrieves the right value for the host * os flavour, on supplying as arg an ipv6 address that has been added to * the host os radix tree. */ int SCHInfoTestValidIPV6Address07(void) { SCHInfoCreateContextBackup(); int result = 1; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "6961:6121:2132:6241:423A:2135:2461:621D", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "DD13:613D:F312:62DD:6213:421A:6212:2652", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux10", "9891:2131:2151:6426:1342:674D:622F:2342", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "3525:2351:4223:6211:2311:2667:6242:2154", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "1511:6211:6726:7777:1212:2333:6222:7722", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "2666:6222:7222:2335:6223:7722:3425:2362", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "8762:2352:6241:7245:EE23:21AD:2312:622C/68", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "8762:2352:6241:7245:EE23:21AD:2412:622C", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "8762:2352:6241:7245:EE23:21AD:FFFF:622C", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux11", "8762:2352:6241:7245:EE23:21AD:2312:62FF", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "8762:2352:6241:7245:EE23:21AD:2121:1212", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFFE") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2412:622C") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:FFFF:622C") != SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:62FF") != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1212") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1DDD") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:FFFF:2121:1DDD") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE00:0000:0000:0000") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:E000:0000:0000:0000") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check that valid ipv6 addresses/netblocks are inserted into the host os * radix tree, and the host os api retrieves the right value for the host * os flavour, on supplying as arg an ipv6 address that has been added to * the host os radix tree. */ int SCHInfoTestValidIPV6Address08(void) { SCHInfoCreateContextBackup(); struct in6_addr in6; int result = 1; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "6961:6121:2132:6241:423A:2135:2461:621D", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "DD13:613D:F312:62DD:6213:421A:6212:2652", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux10", "9891:2131:2151:6426:1342:674D:622F:2342", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "3525:2351:4223:6211:2311:2667:6242:2154", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "1511:6211:6726:7777:1212:2333:6222:7722", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "2666:6222:7222:2335:6223:7722:3425:2362", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "8762:2352:6241:7245:EE23:21AD:2312:622C/68", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "8762:2352:6241:7245:EE23:21AD:2412:622C", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "8762:2352:6241:7245:EE23:21AD:FFFF:622C", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("hpux11", "8762:2352:6241:7245:EE23:21AD:2312:62FF", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("vista", "8762:2352:6241:7245:EE23:21AD:2121:1212", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoAddHostOSInfo("irix", "default", SC_HINFO_IS_IPV6) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFF") != SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2412:622C") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:FFFF:622C") != SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:62FF") != SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1212") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1DDD") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:FFFF:2121:1DDD") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE00:0000:0000:0000") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (inet_pton(AF_INET6, "8762:2352:6241:7245:E000:0000:0000:0000", &in6) < 0) { goto end; } if (SCHInfoGetIPv6HostOSFlavour((uint8_t *)&in6) != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } if (inet_pton(AF_INET6, "AD23:2DDA:6D1D:A223:E235:0232:1241:1666", &in6) < 0) { goto end; } if (SCHInfoGetIPv6HostOSFlavour((uint8_t *)&in6) != SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check that valid ipv4 addresses are inserted into the host os radix * tree, and the host os api retrieves the right value for the host os * flavour, on supplying as arg an ipv4 addresses that has been added to * the host os radix tree. */ int SCHInfoTestValidIPV4Address09(void) { SCHInfoCreateContextBackup(); int result = 1; if (SCHInfoAddHostOSInfo("linux", "192.168.1.0", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.0") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.0") != SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("vista", "192.168.50.128/25", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.50.128") != SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoAddHostOSInfo("irix", "192.168.50.128", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.50.128") != SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.100") != SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { goto end; } struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { goto end; } SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 16); if (SCHInfoGetHostOSFlavour("192.168.1.100") != SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { goto end; } SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); if (SCHInfoGetHostOSFlavour("192.168.1.100") != -1) { goto end; } if (SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1) { goto end; } if (SCHInfoGetHostOSFlavour("192.168.1.100") == SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { goto end; } SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); if (SCHInfoGetHostOSFlavour("192.168.1.100") == SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { goto end; } SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 16); if (SCHInfoGetHostOSFlavour("192.168.1.100") != -1) { goto end; } result = 1; end: SCHInfoCleanResources(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check the loading of host info from a configuration file. */ int SCHInfoTestLoadFromConfig01(void) { char config[] = "\ %YAML 1.1\n\ ---\n\ host-os-policy:\n\ bsd: [0.0.0.0/0]\n\ windows: [10.0.0.0/8, 192.168.1.0/24]\n\ linux: [10.0.0.5/32]\n\ \n"; int result = 0; SCHInfoCreateContextBackup(); ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); SCHInfoLoadFromConfig(); if (SCHInfoGetHostOSFlavour("10.0.0.4") != OS_POLICY_WINDOWS) goto end; if (SCHInfoGetHostOSFlavour("10.0.0.5") != OS_POLICY_LINUX) goto end; if (SCHInfoGetHostOSFlavour("192.168.1.1") != OS_POLICY_WINDOWS) goto end; if (SCHInfoGetHostOSFlavour("172.168.1.1") != OS_POLICY_BSD) goto end; result = 1; end: ConfDeInit(); ConfRestoreContextBackup(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check the loading of host info from a configuration file. */ int SCHInfoTestLoadFromConfig02(void) { char config[] = "\ %YAML 1.1\n\ ---\n\ host-os-policy:\n\ one-two: [0.0.0.0/0]\n\ one-two-three:\n\ four_five:\n\ six-seven_eight: [10.0.0.0/8, 192.168.1.0/24]\n\ nine_ten_eleven: [10.0.0.5/32]\n\ \n"; int result = 0; SCHInfoCreateContextBackup(); ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ConfNode *root = ConfGetNode("host-os-policy"); if (root == NULL) goto end; int count = 0; ConfNode *policy; TAILQ_FOREACH(policy, &root->head, next) { switch (count) { case 0: if (strcmp("one-two", policy->name) != 0) goto end; break; case 1: if (strcmp("one-two-three", policy->name) != 0) goto end; break; case 2: if (strcmp("four-five", policy->name) != 0) goto end; break; case 3: if (strcmp("six-seven-eight", policy->name) != 0) goto end; break; case 4: if (strcmp("nine-ten-eleven", policy->name) != 0) goto end; break; } count++; } result = 1; end: ConfDeInit(); ConfRestoreContextBackup(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check the loading of host info from a configuration file. */ int SCHInfoTestLoadFromConfig03(void) { char config[] = "\ %YAML 1.1\n\ ---\n\ host-os-policy:\n\ bsd-right: [0.0.0.1]\n\ old-linux: [0.0.0.2]\n\ old-solaris: [0.0.0.3]\n\ windows: [0.0.0.4]\n\ vista: [0.0.0.5]\n\ \n"; int result = 1; SCHInfoCreateContextBackup(); ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ConfNode *root = ConfGetNode("host-os-policy"); if (root == NULL) goto end; ConfNode *policy; TAILQ_FOREACH(policy, &root->head, next) { if (SCMapEnumNameToValue(policy->name, sc_hinfo_os_policy_map) == -1) { printf("Invalid enum map inside\n"); goto end; } } result = 1; end: ConfDeInit(); ConfRestoreContextBackup(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check the loading of host info from a configuration file. */ int SCHInfoTestLoadFromConfig04(void) { char config[] = "\ %YAML 1.1\n\ ---\n\ host-os-policy:\n\ bsd_right: [0.0.0.1]\n\ old_linux: [0.0.0.2]\n\ old_solaris: [0.0.0.3]\n\ windows: [0.0.0.4]\n\ vista: [0.0.0.5]\n\ \n"; int result = 1; SCHInfoCreateContextBackup(); ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); ConfNode *root = ConfGetNode("host-os-policy"); if (root == NULL) goto end; ConfNode *policy; TAILQ_FOREACH(policy, &root->head, next) { if (SCMapEnumNameToValue(policy->name, sc_hinfo_os_policy_map) == -1) { printf("Invalid enum map inside\n"); goto end; } } result = 1; end: ConfDeInit(); ConfRestoreContextBackup(); SCHInfoRestoreContextBackup(); return result; } /** * \test Check the loading of host info from a configuration file. */ int SCHInfoTestLoadFromConfig05(void) { char config[] = "\ %YAML 1.1\n\ ---\n\ host-os-policy:\n\ bsd_right: [0.0.0.1]\n\ old_linux: [0.0.0.2]\n\ old-solaris: [0.0.0.3]\n\ windows: [0.0.0.4]\n\ linux: [0.0.0.5]\n\ \n"; int result = 0; SCHInfoCreateContextBackup(); ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(config, strlen(config)); SCHInfoLoadFromConfig(); if (SCHInfoGetHostOSFlavour("0.0.0.1") != OS_POLICY_BSD_RIGHT) { goto end; } if (SCHInfoGetHostOSFlavour("0.0.0.2") != OS_POLICY_OLD_LINUX) { goto end; } if (SCHInfoGetHostOSFlavour("0.0.0.3") != OS_POLICY_OLD_SOLARIS) { goto end; } if (SCHInfoGetHostOSFlavour("0.0.0.4") != OS_POLICY_WINDOWS) { goto end; } if (SCHInfoGetHostOSFlavour("0.0.0.5") != OS_POLICY_VISTA) { goto end; } if (SCHInfoGetHostOSFlavour("0.0.0.0") != -1) { goto end; } if (SCHInfoGetHostOSFlavour("0.0.0.6") != -1) { goto end; } result = 1; end: ConfDeInit(); ConfRestoreContextBackup(); SCHInfoRestoreContextBackup(); return result; } #endif /* UNITTESTS */ void SCHInfoRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCHInfoTesInvalidOSFlavour01", SCHInfoTestInvalidOSFlavour01, 1); UtRegisterTest("SCHInfoTestInvalidIPV4Address02", SCHInfoTestInvalidIPV4Address02, 1); UtRegisterTest("SCHInfoTestInvalidIPV6Address03", SCHInfoTestInvalidIPV6Address03, 1); UtRegisterTest("SCHInfoTestValidIPV4Address04", SCHInfoTestValidIPV4Address04, 1); UtRegisterTest("SCHInfoTestValidIPV4Address05", SCHInfoTestValidIPV4Address05, 1); UtRegisterTest("SCHInfoTestValidIPV6Address06", SCHInfoTestValidIPV6Address06, 1); UtRegisterTest("SCHInfoTestValidIPV6Address07", SCHInfoTestValidIPV6Address07, 1); UtRegisterTest("SCHInfoTestValidIPV6Address08", SCHInfoTestValidIPV6Address08, 1); UtRegisterTest("SCHInfoTestValidIPV4Address09", SCHInfoTestValidIPV4Address09, 1); UtRegisterTest("SCHInfoTestLoadFromConfig01", SCHInfoTestLoadFromConfig01, 1); UtRegisterTest("SCHInfoTestLoadFromConfig02", SCHInfoTestLoadFromConfig02, 1); UtRegisterTest("SCHInfoTestLoadFromConfig03", SCHInfoTestLoadFromConfig03, 1); UtRegisterTest("SCHInfoTestLoadFromConfig04", SCHInfoTestLoadFromConfig04, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-detection-filter.c0000644000000000000000000004604512253546156015711 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias * * Implements the detection_filter keyword */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "host.h" #include "detect-detection-filter.h" #include "detect-threshold.h" #include "detect-parse.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #define TRACK_DST 1 #define TRACK_SRC 2 /** *\brief Regex for parsing our detection_filter options */ #define PARSE_REGEX "^\\s*(track|count|seconds)\\s+(by_src|by_dst|\\d+)\\s*,\\s*(track|count|seconds)\\s+(by_src|by_dst|\\d+)\\s*,\\s*(track|count|seconds)\\s+(by_src|by_dst|\\d+)\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectDetectionFilterMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectDetectionFilterSetup(DetectEngineCtx *, Signature *, char *); void DetectDetectionFilterRegisterTests(void); void DetectDetectionFilterFree(void *); /** * \brief Registration function for detection_filter: keyword */ void DetectDetectionFilterRegister (void) { sigmatch_table[DETECT_DETECTION_FILTER].name = "detection_filter"; sigmatch_table[DETECT_DETECTION_FILTER].desc = "alert on every match after a threshold has been reached"; sigmatch_table[DETECT_DETECTION_FILTER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Rule-Thresholding#detection_filter"; sigmatch_table[DETECT_DETECTION_FILTER].Match = DetectDetectionFilterMatch; sigmatch_table[DETECT_DETECTION_FILTER].Setup = DetectDetectionFilterSetup; sigmatch_table[DETECT_DETECTION_FILTER].Free = DetectDetectionFilterFree; sigmatch_table[DETECT_DETECTION_FILTER].RegisterTests = DetectDetectionFilterRegisterTests; /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_DETECTION_FILTER].flags |= SIGMATCH_IPONLY_COMPAT; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) { return 1; } /** * \internal * \brief This function is used to parse detection_filter options passed via detection_filter: keyword * * \param rawstr Pointer to the user provided detection_filter options * * \retval df pointer to DetectThresholdData on success * \retval NULL on failure */ DetectThresholdData *DetectDetectionFilterParse (char *rawstr) { DetectThresholdData *df = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *str_ptr = NULL; char *args[6] = { NULL, NULL, NULL, NULL, NULL, NULL}; char *copy_str = NULL, *df_opt = NULL; int seconds_found = 0, count_found = 0, track_found = 0; int seconds_pos = 0, count_pos = 0; uint16_t pos = 0; int i = 0; copy_str = SCStrdup(rawstr); if (unlikely(copy_str == NULL)) { goto error; } for(pos = 0, df_opt = strtok(copy_str,","); pos < strlen(copy_str) && df_opt != NULL; pos++, df_opt = strtok(NULL,",")) { if(strstr(df_opt,"count")) count_found++; if(strstr(df_opt,"second")) seconds_found++; if(strstr(df_opt,"track")) track_found++; } SCFree(copy_str); copy_str = NULL; if (count_found != 1 || seconds_found != 1 || track_found != 1) goto error; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 5) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); goto error; } df = SCMalloc(sizeof(DetectThresholdData)); if (unlikely(df == NULL)) goto error; memset(df,0,sizeof(DetectThresholdData)); df->type = TYPE_DETECTION; for (i = 0; i < (ret - 1); i++) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, i + 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i] = (char *)str_ptr; if (strncasecmp(args[i],"by_dst",strlen("by_dst")) == 0) df->track = TRACK_DST; if (strncasecmp(args[i],"by_src",strlen("by_src")) == 0) df->track = TRACK_SRC; if (strncasecmp(args[i],"count",strlen("count")) == 0) count_pos = i+1; if (strncasecmp(args[i],"seconds",strlen("seconds")) == 0) seconds_pos = i+1; } if (args[count_pos] == NULL || args[seconds_pos] == NULL) { goto error; } if (ByteExtractStringUint32(&df->count, 10, strlen(args[count_pos]), args[count_pos]) <= 0) { goto error; } if (ByteExtractStringUint32(&df->seconds, 10, strlen(args[seconds_pos]), args[seconds_pos]) <= 0) { goto error; } if (df->count == 0 || df->seconds == 0) { SCLogError(SC_ERR_INVALID_VALUE, "found an invalid value"); goto error; } for (i = 0; i < 6; i++){ if (args[i] != NULL) SCFree(args[i]); } return df; error: for (i = 0; i < 6; i++){ if (args[i] != NULL) SCFree(args[i]); } if (df != NULL) SCFree(df); return NULL; } /** * \internal * \brief this function is used to add the parsed detection_filter into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param m pointer to the Current SigMatch * \param rawstr pointer to the user provided detection_filter options * * \retval 0 on Success * \retval -1 on Failure */ int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { SCEnter(); DetectThresholdData *df = NULL; SigMatch *sm = NULL; SigMatch *tmpm = NULL; /* checks if there's a previous instance of threshold */ tmpm = SigMatchGetLastSMFromLists(s, 2, DETECT_THRESHOLD, s->sm_lists_tail[DETECT_SM_LIST_MATCH]); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and \"threshold\" are not allowed in the same rule"); SCReturnInt(-1); } /* checks there's no previous instance of detection_filter */ tmpm = SigMatchGetLastSMFromLists(s, 2, DETECT_DETECTION_FILTER, s->sm_lists_tail[DETECT_SM_LIST_MATCH]); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "At most one \"detection_filter\" is allowed per rule"); SCReturnInt(-1); } df = DetectDetectionFilterParse(rawstr); if (df == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_DETECTION_FILTER; sm->ctx = (void *)df; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); return 0; error: if (df) SCFree(df); if (sm) SCFree(sm); return -1; } /** * \internal * \brief this function will free memory associated with DetectThresholdData * * \param df_ptr pointer to DetectDetectionFilterData */ void DetectDetectionFilterFree(void *df_ptr) { DetectThresholdData *df = (DetectThresholdData *)df_ptr; if (df) SCFree(df); } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-threshold.h" #include "util-time.h" #include "util-hashlist.h" /** * \test DetectDetectionFilterTestParse01 is a test for a valid detection_filter options * * \retval 1 on succces * \retval 0 on failure */ int DetectDetectionFilterTestParse01 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track by_dst,count 10,seconds 60"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); return 1; } return 0; } /** * \test DetectDetectionFilterTestParse02 is a test for a invalid detection_filter options * * \retval 1 on succces * \retval 0 on failure */ int DetectDetectionFilterTestParse02 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track both,count 10,seconds 60"); if (df && (df->track == TRACK_DST || df->track == TRACK_SRC) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); return 1; } return 0; } /** * \test DetectDetectionfilterTestParse03 is a test for a valid detection_filter options in any order * * \retval 1 on succces * \retval 0 on failure */ int DetectDetectionFilterTestParse03 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track by_dst, seconds 60, count 10"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); return 1; } return 0; } /** * \test DetectDetectionFilterTestParse04 is a test for an invalid detection_filter options in any order * * \retval 1 on succces * \retval 0 on failure */ int DetectDetectionFilterTestParse04 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 60, count 10"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); return 1; } return 0; } /** * \test DetectDetectionFilterTestParse05 is a test for a valid detection_filter options in any order * * \retval 1 on succces * \retval 0 on failure */ int DetectDetectionFilterTestParse05 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 60"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); return 1; } return 0; } /** * \test DetectDetectionFilterTestParse06 is a test for an invalid value in detection_filter * * \retval 1 on succces * \retval 0 on failure */ int DetectDetectionFilterTestParse06 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 0"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 0)) { DetectDetectionFilterFree(df); return 1; } return 0; } /** * \test DetectDetectionFilterTestSig1 is a test for checking the working of detection_filter keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. * * \retval 1 on succces * \retval 0 on failure */ static int DetectDetectionFilterTestSig1(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; HostInitConfig(HOST_QUIET); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal(NULL, 0, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"detection_filter Test\"; detection_filter: track by_dst, count 4, seconds 60; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if(alerts == 4) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test DetectDetectionFilterTestSig2 is a test for checking the working of detection_filter keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. * * \retval 1 on succces * \retval 0 on failure */ static int DetectDetectionFilterTestSig2(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal(NULL, 0, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"detection_filter Test 2\"; detection_filter: track by_dst, count 4, seconds 60; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); if (alerts == 0) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } /** * \test drops */ static int DetectDetectionFilterTestSig3(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; int alerts = 0; int drops = 0; struct timeval ts; HostInitConfig(HOST_QUIET); memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketReal(NULL, 0, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (msg:\"detection_filter Test 2\"; detection_filter: track by_dst, count 2, seconds 60; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; TimeSetIncrementTime(200); TimeGet(&p->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PACKET_TEST_ACTION(p, ACTION_DROP))?1:0); p->action = 0; if (alerts == 3 && drops == 3) result = 1; else { if (alerts != 3) printf("alerts: %d != 3: ", alerts); if (drops != 3) printf("drops: %d != 3: ", drops); } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); HostShutdown(); return result; } #endif /* UNITTESTS */ void DetectDetectionFilterRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDetectionFilterTestParse01", DetectDetectionFilterTestParse01, 1); UtRegisterTest("DetectDetectionFilterTestParse02", DetectDetectionFilterTestParse02, 0); UtRegisterTest("DetectDetectionFilterTestParse03", DetectDetectionFilterTestParse03, 1); UtRegisterTest("DetectDetectionFilterTestParse04", DetectDetectionFilterTestParse04, 0); UtRegisterTest("DetectDetectionFilterTestParse05", DetectDetectionFilterTestParse05, 1); UtRegisterTest("DetectDetectionFilterTestParse06", DetectDetectionFilterTestParse06, 0); UtRegisterTest("DetectDetectionFilterTestSig1", DetectDetectionFilterTestSig1, 1); UtRegisterTest("DetectDetectionFilterTestSig2", DetectDetectionFilterTestSig2, 1); UtRegisterTest("DetectDetectionFilterTestSig3", DetectDetectionFilterTestSig3, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/runmode-pcap-file.c0000644000000000000000000004117112253546156014504 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-pcap-file.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-affinity.h" static const char *default_mode = NULL; const char *RunModeFilePcapGetDefaultMode(void) { return default_mode; } void RunModeFilePcapRegister(void) { RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "single", "Single threaded pcap file mode", RunModeFilePcapSingle); RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "auto", "Multi threaded pcap file mode", RunModeFilePcapAuto); default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "autofp", "Multi threaded pcap file mode. Packets from " "each flow are assigned to a single detect thread, " "unlike \"pcap-file-auto\" where packets from " "the same flow can be processed by any detect " "thread", RunModeFilePcapAutoFp); return; } /** * \brief Single thread version of the Pcap file processing. */ int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) { char *file = NULL; if (ConfGet("pcap-file.file", &file) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving pcap-file from Conf"); exit(EXIT_FAILURE); } RunModeInitialize(); TimeModeSetOffline(); /* create the threads */ ThreadVars *tv = TmThreadCreatePacketHandler("PcapFile", "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); if (tv == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName("ReceivePcapFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, file); tm_module = TmModuleGetByName("DecodePcapFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName DecodePcap failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName StreamTcp failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); SetupOutputs(tv); TmThreadSetCPU(tv, DETECT_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } return 0; } /* * \brief RunModeFilePcapAuto set up the following thread packet handlers: * - Receive thread (from pcap file) * - Decode thread * - Stream thread * - Detect: If we have only 1 cpu, it will setup one Detect thread * If we have more than one, it will setup num_cpus - 1 * starting from the second cpu available. * - Outputs thread * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * * \param de_ctx Pointer to the Detection Engine. * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ int RunModeFilePcapAuto(DetectEngineCtx *de_ctx) { SCEnter(); char tname[16]; uint16_t cpu = 0; TmModule *tm_module; int cuda = 0; RunModeInitialize(); /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); char *file = NULL; if (ConfGet("pcap-file.file", &file) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving pcap-file from Conf"); exit(EXIT_FAILURE); } SCLogDebug("file %s", file); TimeModeSetOffline(); #if defined(__SC_CUDA_SUPPORT__) if (PatternMatchDefaultMatcher() == MPM_B2G_CUDA) { cuda = 1; } #endif if (cuda == 0) { /* create the threads */ ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler("ReceivePcapFile", "packetpool", "packetpool", "detect-queue1", "simple", "pktacqloop"); if (tv_receivepcap == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("ReceivePcapFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receivepcap, tm_module, file); tm_module = TmModuleGetByName("DecodePcapFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName DecodePcap failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receivepcap, tm_module, NULL); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName StreamTcp failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receivepcap, tm_module, (void *)de_ctx); TmThreadSetCPU(tv_receivepcap, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } #if defined(__SC_CUDA_SUPPORT__) } else { /* create the threads */ ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler("ReceivePcapFile", "packetpool", "packetpool", "cuda-pb", "simple", "pktacqloop"); if (tv_receivepcap == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("ReceivePcapFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receivepcap, tm_module, file); TmThreadSetCPU(tv_receivepcap, RECEIVE_CPU_SET); tm_module = TmModuleGetByName("DecodePcapFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName DecodePcap failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receivepcap, tm_module, NULL); TmThreadSetCPU(tv_receivepcap, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } ThreadVars *tv_cuda_PB = TmThreadCreate("CUDA_PB", "cuda-pb", "simple", "detect-queue1", "simple", "custom", SCCudaPBTmThreadsSlot1, 0); if (tv_cuda_PB == NULL) { printf("ERROR: TmThreadsCreate failed for CUDA_PB\n"); exit(EXIT_FAILURE); } tv_cuda_PB->type = TVT_PPT; tm_module = TmModuleGetByName("CudaPacketBatcher"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName CudaPacketBatcher failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_cuda_PB, tm_module, de_ctx); tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName StreamTcp failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_cuda_PB, tm_module, NULL); if (TmThreadSpawn(tv_cuda_PB) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } #endif } /* start with cpu 1 so that if we're creating an odd number of detect * threads we're not creating the most on CPU0. */ if (ncpus > 0) cpu = 1; /* always create at least one thread */ int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) thread_max = 1; int thread; for (thread = 0; thread < thread_max; thread++) { snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { printf("ERROR: Can not strdup thread name\n"); exit(EXIT_FAILURE); } SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name, "detect-queue1", "simple", "alert-queue1", "simple", "1slot"); if (tv_detect_ncpu == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); char *thread_group_name = SCStrdup("Detect"); if (unlikely(thread_group_name == NULL)) { printf("Error allocating memory\n"); exit(EXIT_FAILURE); } tv_detect_ncpu->thread_group_name = thread_group_name; TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } if ((cpu + 1) == ncpus) cpu = 0; else cpu++; } ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs", "alert-queue1", "simple", "packetpool", "packetpool", "varslot"); if (tv_outputs == NULL) { printf("ERROR: TmThreadCreatePacketHandler for Outputs failed\n"); exit(EXIT_FAILURE); } SetupOutputs(tv_outputs); TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } return 0; } /** * \brief RunModeFilePcapAutoFp set up the following thread packet handlers: * - Receive thread (from pcap file) * - Decode thread * - Stream thread * - Detect: If we have only 1 cpu, it will setup one Detect thread * If we have more than one, it will setup num_cpus - 1 * starting from the second cpu available. * - Outputs thread * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * * \param de_ctx Pointer to the Detection Engine * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) { SCEnter(); char tname[12]; char qname[12]; uint16_t cpu = 0; char queues[2048] = ""; RunModeInitialize(); /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); /* start with cpu 1 so that if we're creating an odd number of detect * threads we're not creating the most on CPU0. */ if (ncpus > 0) cpu = 1; /* always create at least one thread */ int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) thread_max = 1; int thread; for (thread = 0; thread < thread_max; thread++) { if (strlen(queues) > 0) strlcat(queues, ",", sizeof(queues)); snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); strlcat(queues, qname, sizeof(queues)); } SCLogDebug("queues %s", queues); char *file = NULL; if (ConfGet("pcap-file.file", &file) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving pcap-file from Conf"); exit(EXIT_FAILURE); } SCLogDebug("file %s", file); TimeModeSetOffline(); /* create the threads */ ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler("ReceivePcapFile", "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receivepcap == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } TmModule *tm_module = TmModuleGetByName("ReceivePcapFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receivepcap, tm_module, file); tm_module = TmModuleGetByName("DecodePcapFile"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName DecodePcap failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_receivepcap, tm_module, NULL); TmThreadSetCPU(tv_receivepcap, RECEIVE_CPU_SET); if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } for (thread = 0; thread < thread_max; thread++) { snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); SCLogDebug("tname %s, qname %s", tname, qname); char *thread_name = SCStrdup(tname); if (unlikely(thread_name == NULL)) { printf("ERROR: Can not strdup thread name\n"); exit(EXIT_FAILURE); } SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler(thread_name, qname, "flow", "packetpool", "packetpool", "varslot"); if (tv_detect_ncpu == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } tm_module = TmModuleGetByName("StreamTcp"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName StreamTcp failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); tm_module = TmModuleGetByName("Detect"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName Detect failed\n"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); char *thread_group_name = SCStrdup("Detect"); if (unlikely(thread_group_name == NULL)) { printf("Error allocating memory\n"); exit(EXIT_FAILURE); } tv_detect_ncpu->thread_group_name = thread_group_name; /* add outputs as well */ SetupOutputs(tv_detect_ncpu); TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); } if ((cpu + 1) == ncpus) cpu = 0; else cpu++; } return 0; } suricata-1.4.7/src/decode-icmpv6.h0000644000000000000000000002002312253546156013620 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DECODE_ICMPV6_H__ #define __DECODE_ICMPV6_H__ #include "decode-tcp.h" #include "decode-sctp.h" #include "decode-udp.h" #include "decode-ipv6.h" #define ICMPV6_HEADER_LEN 8 #define ICMPV6_HEADER_PKT_OFFSET 8 /** ICMPV6 Message Types: */ /** Error Messages: (type <128) */ #define ICMP6_DST_UNREACH 1 #define ICMP6_PACKET_TOO_BIG 2 #define ICMP6_TIME_EXCEEDED 3 #define ICMP6_PARAM_PROB 4 /** Informational Messages (type>=128) */ #define ICMP6_ECHO_REQUEST 128 #define ICMP6_ECHO_REPLY 129 #define MLD_LISTENER_QUERY 130 #define MLD_LISTENER_REPORT 131 #define MLD_LISTENER_REDUCTION 132 /** Destination Unreachable Message (type=1) Code: */ #define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ #define ICMP6_DST_UNREACH_ADMIN 1 /* communication with destination */ /* administratively prohibited */ #define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */ #define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */ #define ICMP6_DST_UNREACH_NOPORT 4 /* bad port */ #define ICMP6_DST_UNREACH_FAILEDPOLICY 5 /* Source address failed ingress/egress policy */ #define ICMP6_DST_UNREACH_REJECTROUTE 6 /* Reject route to destination */ /** Time Exceeded Message (type=3) Code: */ #define ICMP6_TIME_EXCEED_TRANSIT 0 /* Hop Limit == 0 in transit */ #define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* Reassembly time out */ /** Parameter Problem Message (type=4) Code: */ #define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */ #define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized Next Header */ #define ICMP6_PARAMPROB_OPTION 2 /* unrecognized IPv6 option */ /** macro for icmpv6 "type" access */ #define ICMPV6_GET_TYPE(p) (p)->icmpv6h->type /** macro for icmpv6 "code" access */ #define ICMPV6_GET_CODE(p) (p)->icmpv6h->code /** macro for icmpv6 "csum" access */ #define ICMPV6_GET_CSUM(p) (p)->icmpv6h->csum /** If message is informational */ /** macro for icmpv6 "id" access */ #define ICMPV6_GET_ID(p) (p)->icmpv6vars.id /** macro for icmpv6 "seq" access */ #define ICMPV6_GET_SEQ(p) (p)->icmpv6vars.seq /** If message is Error */ /** macro for icmpv6 "unused" access */ #define ICMPV6_GET_UNUSED(p) (p)->icmpv6h->icmpv6b.icmpv6e.unused /** macro for icmpv6 "error_ptr" access */ #define ICMPV6_GET_ERROR_PTR(p) (p)->icmpv6h->icmpv6b.icmpv6e.error_ptr /** macro for icmpv6 "mtu" access */ #define ICMPV6_GET_MTU(p) (p)->icmpv6h->icmpv6b.icmpv6e.mtu /** macro for icmpv6 embedded "protocol" access */ #define ICMPV6_GET_EMB_PROTO(p) (p)->icmpv6vars.emb_ip6_proto_next /** macro for icmpv6 embedded "ipv6h" header access */ #define ICMPV6_GET_EMB_IPV6(p) (p)->icmpv6vars.emb_ipv6h /** macro for icmpv6 embedded "tcph" header access */ #define ICMPV6_GET_EMB_TCP(p) (p)->icmpv6vars.emb_tcph /** macro for icmpv6 embedded "udph" header access */ #define ICMPV6_GET_EMB_UDP(p) (p)->icmpv6vars.emb_udph /** macro for icmpv6 embedded "icmpv6h" header access */ #define ICMPV6_GET_EMB_icmpv6h(p) (p)->icmpv6vars.emb_icmpv6h typedef struct ICMPV6Info_ { uint16_t id; uint16_t seq; } ICMPV6Info; /** ICMPv6 header structure */ typedef struct ICMPV6Hdr_ { uint8_t type; uint8_t code; uint16_t csum; union { ICMPV6Info icmpv6i; /** Informational message */ union { uint32_t unused; /** for types 1 and 3, should be zero */ uint32_t error_ptr; /** for type 4, pointer to the octet that originate the error */ uint32_t mtu; /** for type 2, the Maximum Transmission Unit of the next-hop link */ } icmpv6e; /** Error Message */ } icmpv6b; } ICMPV6Hdr; /** Data available from the decoded packet */ typedef struct ICMPV6Vars_ { /* checksum computed over the icmpv6 packet */ int32_t comp_csum; /* checksum of the icmpv6 packet */ uint16_t id; uint16_t seq; uint32_t mtu; uint32_t error_ptr; /** Pointers to the embedded packet headers */ IPV6Hdr *emb_ipv6h; TCPHdr *emb_tcph; UDPHdr *emb_udph; ICMPV6Hdr *emb_icmpv6h; /** IPv6 src and dst address */ uint32_t emb_ip6_src[4]; uint32_t emb_ip6_dst[4]; uint8_t emb_ip6_proto_next; /** TCP/UDP ports */ uint16_t emb_sport; uint16_t emb_dport; } ICMPV6Vars; #define CLEAR_ICMPV6_PACKET(p) do { \ (p)->icmpv6vars.comp_csum = -1; \ (p)->icmpv6vars.id = 0; \ (p)->icmpv6vars.seq = 0; \ (p)->icmpv6vars.mtu = 0; \ (p)->icmpv6vars.error_ptr = 0; \ (p)->icmpv6vars.emb_ipv6h = NULL; \ (p)->icmpv6vars.emb_tcph = NULL; \ (p)->icmpv6vars.emb_udph = NULL; \ (p)->icmpv6vars.emb_icmpv6h = NULL; \ (p)->icmpv6vars.emb_ip6_src[0] = 0; \ (p)->icmpv6vars.emb_ip6_src[1] = 0; \ (p)->icmpv6vars.emb_ip6_src[2] = 0; \ (p)->icmpv6vars.emb_ip6_src[3] = 0; \ (p)->icmpv6vars.emb_ip6_proto_next = 0; \ (p)->icmpv6vars.emb_sport = 0; \ (p)->icmpv6vars.emb_dport = 0; \ (p)->icmpv6h = NULL; \ } while(0) void DecodeICMPV6RegisterTests(void); /** -------- Inline functions --------- */ static inline uint16_t ICMPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t); /** * \brief Calculates the checksum for the ICMPV6 packet * * \param shdr Pointer to source address field from the IPV6 packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the ICMPV6 packet * \param tlen Total length of the ICMPV6 packet(header + payload) * * \retval csum Checksum for the ICMPV6 packet */ static inline uint16_t ICMPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, uint16_t tlen) { uint16_t pad = 0; uint32_t csum = shdr[0]; csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(58 + tlen); csum += pkt[0]; tlen -= 4; pkt += 2; while (tlen >= 64) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15] + pkt[16] + pkt[17] + pkt[18] + pkt[19] + pkt[20] + pkt[21] + pkt[22] + pkt[23] + pkt[24] + pkt[25] + pkt[26] + pkt[27] + pkt[28] + pkt[29] + pkt[30] + pkt[31]; tlen -= 64; pkt += 32; } while (tlen >= 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } while(tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } while(tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; } while (tlen > 1) { csum += pkt[0]; tlen -= 2; pkt += 1; } if (tlen == 1) { *(uint8_t *)(&pad) = (*(uint8_t *)pkt); csum += pad; } csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); return (uint16_t) ~csum; } #endif /* __DECODE_ICMPV6_H__ */ suricata-1.4.7/src/detect-mark.c0000644000000000000000000002066112253546156013376 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond * * Implements the mark keyword. Based on detect-gid * by Breno Silva */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "flow-var.h" #include "decode-events.h" #include "detect-mark.h" #include "detect-parse.h" #include "util-unittest.h" #include "util-debug.h" #define PARSE_REGEX "([0x]*[0-9a-f]+)/([0x]*[0-9a-f]+)" static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectMarkSetup (DetectEngineCtx *, Signature *, char *); int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m); void DetectMarkDataFree(void *ptr); /** * \brief Registration function for nfq_set_mark: keyword */ void DetectMarkRegister (void) { sigmatch_table[DETECT_MARK].name = "nfq_set_mark"; sigmatch_table[DETECT_MARK].Match = DetectMarkPacket; sigmatch_table[DETECT_MARK].Setup = DetectMarkSetup; sigmatch_table[DETECT_MARK].Free = DetectMarkDataFree; sigmatch_table[DETECT_MARK].RegisterTests = MarkRegisterTests; const char *eb; int opts = 0; int eo; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } error: return; } #ifdef NFQ /** * \internal * \brief This function is used to parse mark options passed via mark: keyword * * \param rawstr Pointer to the user provided mark options * * \retval 0 on success * \retval < 0 on failure */ static void * DetectMarkParse (char *rawstr) { int ret = 0, res = 0; #define MAX_SUBSTRINGS 30 int ov[MAX_SUBSTRINGS]; const char *str_ptr = NULL; char *ptr = NULL; char *endptr = NULL; uint32_t mark; uint32_t mask; DetectMarkData *data; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); return NULL; } res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return NULL; } ptr = (char *)str_ptr; if (ptr == NULL) return NULL; errno = 0; mark = strtoul(ptr, &endptr, 0); if (errno == ERANGE) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range"); SCFree(ptr); return NULL; } /* If there is no numeric value in the given string then strtoull(), makes endptr equals to ptr and return 0 as result */ else if (endptr == ptr && mark == 0) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "No numeric value"); SCFree(ptr); return NULL; } else if (endptr == ptr) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value"); SCFree(ptr); return NULL; } res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return NULL; } SCFree(ptr); ptr = (char *)str_ptr; if (ptr == NULL) { data = SCMalloc(sizeof(DetectMarkData)); if (unlikely(data == NULL)) { return NULL; } data->mark = mark; data->mask = 0xffff; return data; } errno = 0; mask = strtoul(ptr, &endptr, 0); if (errno == ERANGE) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range"); SCFree(ptr); return NULL; } /* If there is no numeric value in the given string then strtoull(), makes endptr equals to ptr and return 0 as result */ else if (endptr == ptr && mask == 0) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "No numeric value"); SCFree(ptr); return NULL; } else if (endptr == ptr) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value"); SCFree(ptr); return NULL; } SCLogDebug("Rule will set mark 0x%x with mask 0x%x", mark, mask); SCFree(ptr); data = SCMalloc(sizeof(DetectMarkData)); if (unlikely(data == NULL)) { return NULL; } data->mark = mark; data->mask = mask; return data; } #endif /* NFQ */ /** * \internal * \brief this function is used to add the parsed mark into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param rawstr pointer to the user provided mark options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { #ifdef NFQ DetectMarkData *data = NULL; SigMatch *sm = NULL; data = DetectMarkParse(rawstr); if (data == NULL) { return -1; } else { sm = SigMatchAlloc(); if (sm == NULL) { DetectMarkDataFree(data); return -1; } sm->type = DETECT_MARK; sm->ctx = (void *)data; /* Append it to the list of tags */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TMATCH); return 0; } #else return 0; #endif } void DetectMarkDataFree(void *ptr) { DetectMarkData *data = (DetectMarkData *)ptr; SCFree(data); } int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { #ifdef NFQ DetectMarkData *nf_data = (DetectMarkData *) m->ctx; if (nf_data->mask) { p->nfq_v.mark = (nf_data->mark & nf_data->mask) | (p->nfq_v.mark & ~(nf_data->mask)); p->flags |= PKT_MARK_MODIFIED; } #endif return 1; } /* * ONLY TESTS BELOW THIS COMMENT */ #if defined UNITTESTS && defined NFQ /** * \test MarkTestParse01 is a test for a valid mark value * * \retval 1 on succces * \retval 0 on failure */ static int MarkTestParse01 (void) { DetectMarkData *data; data = DetectMarkParse("1/1"); if (data == NULL) { return 0; } DetectMarkDataFree(data); return 1; } /** * \test MarkTestParse02 is a test for an invalid mark value * * \retval 1 on succces * \retval 0 on failure */ static int MarkTestParse02 (void) { DetectMarkData *data; data = DetectMarkParse("4"); if (data == NULL) { return 0; } DetectMarkDataFree(data); return 1; } /** * \test MarkTestParse03 is a test for a valid mark value * * \retval 1 on succces * \retval 0 on failure */ static int MarkTestParse03 (void) { DetectMarkData *data; data = DetectMarkParse("0x10/0xff"); if (data == NULL) { return 0; } DetectMarkDataFree(data); return 1; } /** * \test MarkTestParse04 is a test for a invalid mark value * * \retval 1 on succces * \retval 0 on failure */ static int MarkTestParse04 (void) { DetectMarkData *data; data = DetectMarkParse("0x1g/0xff"); if (data == NULL) { return 0; } DetectMarkDataFree(data); return 1; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for Mark */ void MarkRegisterTests(void) { #if defined UNITTESTS && defined NFQ UtRegisterTest("MarkTestParse01", MarkTestParse01, 1); UtRegisterTest("MarkTestParse02", MarkTestParse02, 0); UtRegisterTest("MarkTestParse03", MarkTestParse03, 1); UtRegisterTest("MarkTestParse04", MarkTestParse04, 0); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-engine-hsmd.h0000644000000000000000000000243412253546156014645 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HSMD_H__ #define __DETECT_ENGINE_HSMD_H__ #include "app-layer-htp.h" int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *, Flow *f, HtpState *, uint8_t); int DetectEngineInspectHttpStatMsg(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int tx_id); void DetectEngineHttpStatMsgRegisterTests(void); #endif /* __DETECT_ENGINE_HSMD_H__ */ suricata-1.4.7/src/util-fmemopen.h0000644000000000000000000000260312253546156013760 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * Based on FMem.c of Alexandre Flori (2008/10/17 AF) */ #ifndef __FMEMOPEN_H__ #define __FMEMOPEN_H__ #include #include #include /* Include this file only for OSX / BSD compilations */ #ifdef OS_DARWIN #define USE_FMEM_WRAPPER 1 #endif #ifdef OS_FREEBSD #define USE_FMEM_WRAPPER 1 #endif #ifdef __OpenBSD__ #define USE_FMEM_WRAPPER 1 #endif #ifdef OS_WIN32 #define USE_FMEM_WRAPPER 1 #endif #ifdef USE_FMEM_WRAPPER FILE *SCFmemopen(void *, size_t, const char *); #else /* Else use the normal fmemopen */ #define SCFmemopen fmemopen #endif #endif /* __FMEMOPEN_H__ */ suricata-1.4.7/src/detect-engine-hcd.c0000644000000000000000000013603312253546156014446 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP cookie match * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-hcd.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { htp_tx_t *tx = NULL; uint32_t cnt = 0; int idx; /* we need to lock because the buffers are not actually true buffers * but are ones that point to a buffer given by libhtp */ FLOWLOCK_RDLOCK(f); if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL) continue; htp_header_t *h = NULL; if (flags & STREAM_TOSERVER) { h = (htp_header_t *)table_getc(tx->request_headers, "Cookie"); if (h == NULL) { SCLogDebug("HTTP cookie header not present in this request"); continue; } } else { h = (htp_header_t *)table_getc(tx->response_headers, "Set-Cookie"); if (h == NULL) { SCLogDebug("HTTP Set-Cookie header not present in this request"); continue; } } cnt += HttpCookiePatternSearch(det_ctx, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), flags); } end: FLOWLOCK_UNLOCK(f); return cnt; } /** * \brief Do the http_cookie content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpCookie(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL) return 0; htp_header_t *h = NULL; if (flags & STREAM_TOSERVER) { h = (htp_header_t *)table_getc(tx->request_headers, "Cookie"); if (h == NULL) { SCLogDebug("HTTP cookie header not present in this request"); return 0; } } else { h = (htp_header_t *)table_getc(tx->response_headers, "Set-Cookie"); if (h == NULL) { SCLogDebug("HTTP Set-Cookie header not present in this request"); return 0; } } det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCDMATCH], f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest01(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CONNECT\"; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest02(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; depth:4; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest03(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"ECT\"; depth:4; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest04(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"ECT\"; depth:4; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest05(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"CON\"; depth:4; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"ECT\"; offset:3; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest07(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"CO\"; offset:3; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest08(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:!\"ECT\"; offset:3; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest09(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CON\"; offset:3; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest10(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_cookie; " "content:\"EC\"; within:4; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_cookie; " "content:!\"EC\"; within:3; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_cookie; " "content:\"EC\"; within:3; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_cookie; " "content:!\"EC\"; within:4; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest14(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_cookie; " "content:\"EC\"; distance:2; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest15(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_cookie; " "content:!\"EC\"; distance:3; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest16(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_cookie; " "content:\"EC\"; distance:3; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_cookie content matches against a http request * which holds the content. */ static int DetectEngineHttpCookieTest17(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" "Cookie: CONNECT\r\n" "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " "content:\"CO\"; http_cookie; " "content:!\"EC\"; distance:2; http_cookie; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpCookieRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpCookieTest01", DetectEngineHttpCookieTest01, 1); UtRegisterTest("DetectEngineHttpCookieTest02", DetectEngineHttpCookieTest02, 1); UtRegisterTest("DetectEngineHttpCookieTest03", DetectEngineHttpCookieTest03, 1); UtRegisterTest("DetectEngineHttpCookieTest04", DetectEngineHttpCookieTest04, 1); UtRegisterTest("DetectEngineHttpCookieTest05", DetectEngineHttpCookieTest05, 1); UtRegisterTest("DetectEngineHttpCookieTest06", DetectEngineHttpCookieTest06, 1); UtRegisterTest("DetectEngineHttpCookieTest07", DetectEngineHttpCookieTest07, 1); UtRegisterTest("DetectEngineHttpCookieTest08", DetectEngineHttpCookieTest08, 1); UtRegisterTest("DetectEngineHttpCookieTest09", DetectEngineHttpCookieTest09, 1); UtRegisterTest("DetectEngineHttpCookieTest10", DetectEngineHttpCookieTest10, 1); UtRegisterTest("DetectEngineHttpCookieTest11", DetectEngineHttpCookieTest11, 1); UtRegisterTest("DetectEngineHttpCookieTest12", DetectEngineHttpCookieTest12, 1); UtRegisterTest("DetectEngineHttpCookieTest13", DetectEngineHttpCookieTest13, 1); UtRegisterTest("DetectEngineHttpCookieTest14", DetectEngineHttpCookieTest14, 1); UtRegisterTest("DetectEngineHttpCookieTest15", DetectEngineHttpCookieTest15, 1); UtRegisterTest("DetectEngineHttpCookieTest16", DetectEngineHttpCookieTest16, 1); UtRegisterTest("DetectEngineHttpCookieTest17", DetectEngineHttpCookieTest17, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-filesize.c0000644000000000000000000003465612253546156014267 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the filesize keyword */ #include "suricata-common.h" #include "app-layer-protos.h" #include "app-layer-htp.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-filesize.h" #include "util-debug.h" #include "util-byte.h" #include "flow-util.h" #include "stream-tcp.h" /** * \brief Regex for parsing our filesize */ #define PARSE_REGEX "^(?:\\s*)(<|>)?(?:\\s*)([0-9]{1,23})(?:\\s*)(?:(<>)(?:\\s*)([0-9]{1,23}))?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m); static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilesizeFree (void *); static void DetectFilesizeRegisterTests (void); /** * \brief Registration function for filesize: keyword */ void DetectFilesizeRegister(void) { sigmatch_table[DETECT_FILESIZE].name = "filesize"; sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred"; sigmatch_table[DETECT_FILESIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesize"; sigmatch_table[DETECT_FILESIZE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch; sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup; sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree; sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests; sigmatch_table[DETECT_FILESIZE].flags |= SIGMATCH_PAYLOAD; /** XXX necessary? */ const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogDebug("pcre study failed: %s", eb); goto error; } return; error: if (parse_regex != NULL) SCFree(parse_regex); if (parse_regex_study != NULL) SCFree(parse_regex_study); return; } /** * \brief This function is used to match filesize rule option. * * \param t thread local vars * \param det_ctx pattern matcher thread local data * \param f *LOCKED* flow * \param flags direction flags * \param file file being inspected * \param s signature being inspected * \param m sigmatch that we will cast into DetectFilesizeData * * \retval 0 no match * \retval 1 match */ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) { SCEnter(); DetectFilesizeData *fsd = m->ctx; int ret = 0; SCLogDebug("file size %"PRIu64", check %"PRIu64, file->size, fsd->size1); if (file->state == FILE_STATE_CLOSED) { switch (fsd->mode) { case DETECT_FILESIZE_EQ: if (file->size == fsd->size1) ret = 1; break; case DETECT_FILESIZE_LT: if (file->size < fsd->size1) ret = 1; break; case DETECT_FILESIZE_GT: if (file->size > fsd->size1) ret = 1; break; case DETECT_FILESIZE_RA: if (file->size > fsd->size1 && file->size < fsd->size2) ret = 1; break; } /* truncated, error: only see if what we have meets the GT condition */ } else if (file->state > FILE_STATE_CLOSED) { if (fsd->mode == DETECT_FILESIZE_GT && file->size > fsd->size1) ret = 1; } SCReturnInt(ret); } /** * \brief parse filesize options * * \param str pointer to the user provided filesize * * \retval fsd pointer to DetectFilesizeData on success * \retval NULL on failure */ static DetectFilesizeData *DetectFilesizeParse (char *str) { DetectFilesizeData *fsd = NULL; char *arg1 = NULL; char *arg2 = NULL; char *arg3 = NULL; char *arg4 = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3 || ret > 5) { SCLogError(SC_ERR_PCRE_PARSE, "filesize option pcre parse error: \"%s\"", str); goto error; } const char *str_ptr; SCLogDebug("ret %d", ret); res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg1 = (char *) str_ptr; SCLogDebug("Arg1 \"%s\"", arg1); res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg2 = (char *) str_ptr; SCLogDebug("Arg2 \"%s\"", arg2); if (ret > 3) { res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg3 = (char *) str_ptr; SCLogDebug("Arg3 \"%s\"", arg3); if (ret > 4) { res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 4, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg4 = (char *) str_ptr; SCLogDebug("Arg4 \"%s\"", arg4); } } fsd = SCMalloc(sizeof (DetectFilesizeData)); if (unlikely(fsd == NULL)) goto error; memset(fsd, 0, sizeof(DetectFilesizeData)); if (arg1[0] == '<') fsd->mode = DETECT_FILESIZE_LT; else if (arg1[0] == '>') fsd->mode = DETECT_FILESIZE_GT; else fsd->mode = DETECT_FILESIZE_EQ; if (arg3 != NULL && strcmp("<>", arg3) == 0) { if (strlen(arg1) != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Range specified but mode also set"); goto error; } fsd->mode = DETECT_FILESIZE_RA; } /** set the first value */ if (ByteExtractStringUint64(&fsd->size1,10,strlen(arg2),arg2) <= 0){ SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size :\"%s\"",arg2); goto error; } /** set the second value if specified */ if (arg4 != NULL && strlen(arg4) > 0) { if (fsd->mode != DETECT_FILESIZE_RA) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Multiple filesize values specified" " but mode is not range"); goto error; } if(ByteExtractStringUint64(&fsd->size2,10,strlen(arg4),arg4) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size :\"%s\"",arg4); goto error; } if (fsd->size2 <= fsd->size1){ SCLogError(SC_ERR_INVALID_ARGUMENT,"filesize2:%"PRIu64" <= filesize:" "%"PRIu64"",fsd->size2,fsd->size1); goto error; } } pcre_free_substring(arg1); pcre_free_substring(arg2); if (arg3 != NULL) pcre_free_substring(arg3); if (arg4 != NULL) pcre_free_substring(arg4); return fsd; error: if (fsd) SCFree(fsd); if (arg1 != NULL) SCFree(arg1); if (arg2 != NULL) SCFree(arg2); if (arg3 != NULL) SCFree(arg3); if (arg4 != NULL) SCFree(arg4); return NULL; } /** * \brief this function is used to parse filesize data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param str pointer to the user provided options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); DetectFilesizeData *fsd = NULL; SigMatch *sm = NULL; fsd = DetectFilesizeParse(str); if (fsd == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FILESIZE; sm->ctx = (void *)fsd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } AppLayerHtpNeedFileInspection(); /** \todo remove this once we support more than http */ s->alproto = ALPROTO_HTTP; s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE); SCReturnInt(0); error: if (fsd != NULL) DetectFilesizeFree(fsd); if (sm != NULL) SCFree(sm); SCReturnInt(-1); } /** * \brief this function will free memory associated with DetectFilesizeData * * \param ptr pointer to DetectFilesizeData */ static void DetectFilesizeFree(void *ptr) { DetectFilesizeData *fsd = (DetectFilesizeData *)ptr; SCFree(fsd); } #ifdef UNITTESTS #include "stream.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "app-layer-parser.h" /** \test Test the Filesize keyword setup */ static int DetectFilesizeParseTest01(void) { int ret = 0; DetectFilesizeData *fsd = NULL; fsd = DetectFilesizeParse("10"); if (fsd != NULL) { if (fsd->size1 == 10 && fsd->mode == DETECT_FILESIZE_EQ) ret = 1; DetectFilesizeFree(fsd); } return ret; } /** \test Test the Filesize keyword setup */ static int DetectFilesizeParseTest02(void) { int ret = 0; DetectFilesizeData *fsd = NULL; fsd = DetectFilesizeParse(" < 10 "); if (fsd != NULL) { if (fsd->size1 == 10 && fsd->mode == DETECT_FILESIZE_LT) ret = 1; DetectFilesizeFree(fsd); } return ret; } /** \test Test the Filesize keyword setup */ static int DetectFilesizeParseTest03(void) { int ret = 0; DetectFilesizeData *fsd = NULL; fsd = DetectFilesizeParse(" > 10 "); if (fsd != NULL) { if (fsd->size1 == 10 && fsd->mode == DETECT_FILESIZE_GT) ret = 1; DetectFilesizeFree(fsd); } return ret; } /** \test Test the Filesize keyword setup */ static int DetectFilesizeParseTest04(void) { int ret = 0; DetectFilesizeData *fsd = NULL; fsd = DetectFilesizeParse(" 5 <> 10 "); if (fsd != NULL) { if (fsd->size1 == 5 && fsd->size2 == 10 && fsd->mode == DETECT_FILESIZE_RA) ret = 1; DetectFilesizeFree(fsd); } return ret; } /** \test Test the Filesize keyword setup */ static int DetectFilesizeParseTest05(void) { int ret = 0; DetectFilesizeData *fsd = NULL; fsd = DetectFilesizeParse("5<>10"); if (fsd != NULL) { if (fsd->size1 == 5 && fsd->size2 == 10 && fsd->mode == DETECT_FILESIZE_RA) ret = 1; DetectFilesizeFree(fsd); } return ret; } /** * \brief this function is used to initialize the detection engine context and * setup the signature with passed values. * */ static int DetectFilesizeInitTest(DetectEngineCtx **de_ctx, Signature **sig, DetectFilesizeData **fsd, char *str) { char fullstr[1024]; int result = 0; *de_ctx = NULL; *sig = NULL; if (snprintf(fullstr, 1024, "alert http any any -> any any (msg:\"Filesize " "test\"; filesize:%s; sid:1;)", str) >= 1024) { goto end; } *de_ctx = DetectEngineCtxInit(); if (*de_ctx == NULL) { goto end; } (*de_ctx)->flags |= DE_QUIET; (*de_ctx)->sig_list = SigInit(*de_ctx, fullstr); if ((*de_ctx)->sig_list == NULL) { goto end; } *sig = (*de_ctx)->sig_list; *fsd = DetectFilesizeParse(str); result = 1; end: return result; } /** * \test DetectFilesizeSetpTest01 is a test for setting up an valid filesize values * with valid "<>" operator and include spaces arround the given values. * In the test the values are setup with initializing the detection engine * context and setting up the signature itself. */ static int DetectFilesizeSetpTest01(void) { DetectFilesizeData *fsd = NULL; uint8_t res = 0; Signature *sig = NULL; DetectEngineCtx *de_ctx = NULL; res = DetectFilesizeInitTest(&de_ctx, &sig, &fsd, "1 <> 2 "); if (res == 0) { goto end; } if(fsd == NULL) goto cleanup; if (fsd != NULL) { if (fsd->size1 == 1 && fsd->size2 == 2 && fsd->mode == DETECT_FILESIZE_RA) res = 1; } cleanup: if (fsd) SCFree(fsd); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); end: return res; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectFilesize */ void DetectFilesizeRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01, 1); UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02, 1); UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03, 1); UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04, 1); UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05, 1); UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-http-raw-uri.c0000644000000000000000000006767712253546156015031 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "util-debug.h" #include "util-unittest.h" #include "util-spm.h" #include "util-print.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-raw-uri.h" #include "stream-tcp.h" static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, char *); static void DetectHttpRawUriRegisterTests(void); /** * \brief Registration function for keyword http_raw_uri. */ void DetectHttpRawUriRegister(void) { sigmatch_table[DETECT_AL_HTTP_RAW_URI].name = "http_raw_uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].desc = "content modifier to match on HTTP uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_uri-and-http_raw_uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Match = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].RegisterTests = DetectHttpRawUriRegisterTests; sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_PAYLOAD; return; } /** * \brief Sets up the http_raw_uri modifier keyword. * * \param de_ctx Pointer to the Detection Engine Context. * \param s Pointer to the Signature to which the current keyword belongs. * \param arg Should hold an empty string always. * * \retval 0 On success. * \retval -1 On failure. */ static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_raw_uri shouldn't be " "supplied with an argument"); goto error; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_raw_uri\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_raw_uri\" keyword"); goto error; } cd = (DetectContentData *)sm->ctx; /* http_raw_uri should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_raw_uri rule can not " "be used with the rawbytes rule keyword"); goto error; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "rawuricontent seen with a " "distance or within without a previous http_raw_uri " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HRUDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hrudmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HRUDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]); /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } /******************************** UNITESTS **********************************/ #ifdef UNITTESTS #include "stream-tcp-reassemble.h" /** * \test Checks if a http_raw_uri is registered in a Signature, if content is not * specified in the signature. */ int DetectHttpRawUriTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_uri\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_raw_uri is registered in a Signature, if some parameter * is specified with http_raw_uri in the signature. */ int DetectHttpRawUriTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_uri\"; content:\"one\"; " "http_raw_uri:wrong; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_raw_uri is registered in a Signature. */ int DetectHttpRawUriTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_uri\"; " "content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; " "content:\"three\"; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; } while (sm != NULL) { if (sm->type == DETECT_CONTENT) { result = 1; } else { printf("expected DETECT_CONTENT for http_raw_uri(%d), got %d: ", DETECT_CONTENT, sm->type); goto end; } sm = sm->next; } end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_raw_uri is registered in a Signature, when rawbytes is * also specified in the signature. */ int DetectHttpRawUriTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_uri\"; " "content:\"one\"; rawbytes; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_raw_uri is successfully converted to a rawuricontent. * */ int DetectHttpRawUriTest05(void) { DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; int result = 0; if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_raw_uri\"; " "content:\"we are testing http_raw_uri keyword\"; http_raw_uri; " "sid:1;)"); if (s == NULL) { printf("sig failed to parse\n"); goto end; } if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) goto end; if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH]->type != DETECT_CONTENT) { printf("wrong type\n"); goto end; } char *str = "we are testing http_raw_uri keyword"; int uricomp = memcmp((const char *) ((DetectContentData*)s->sm_lists[DETECT_SM_LIST_HRUDMATCH]->ctx)->content, str, strlen(str) - 1); int urilen = ((DetectContentData*)s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx)->content_len; if (uricomp != 0 || urilen != strlen("we are testing http_raw_uri keyword")) { printf("sig failed to parse, content not setup properly\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); return result; } int DetectHttpRawUriTest06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (cd->id == ud->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest07(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (cd->id == ud->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest08(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; " "content:\"one\"; " "content:\"one\"; http_raw_uri; content:\"one\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (cd->id != 0 || ud->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest09(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"one\"; " "content:\"one\"; " "content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (cd->id != 1 || ud->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest10(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"one\"; " "content:\"one\"; http_raw_uri; " "content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (cd->id != 1 || ud1->id != 0 || ud2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest11(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"one\"; " "content:\"one\"; http_raw_uri; " "content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; if (cd->id != 2 || ud1->id != 0 || ud2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; distance:0; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || memcmp(ud2->content, "two", ud1->content_len) != 0) { /* inside body */ goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest13(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; within:5; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || memcmp(ud2->content, "two", ud1->content_len) != 0) { /* inside the body */ goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("de_ctx->sig_list != NULL\n"); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; distance:0; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || memcmp(ud2->content, "two", ud1->content_len) != 0) { /* inside body */ goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpRawUriTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; within:5; http_raw_uri; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); goto end; } DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || memcmp(ud2->content, "two", ud1->content_len) != 0) { /* inside body */ goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } #endif /* UNITTESTS */ /** * \brief Register the UNITTESTS for the http_uri keyword */ static void DetectHttpRawUriRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectHttpRawUriTest01", DetectHttpRawUriTest01, 1); UtRegisterTest("DetectHttpRawUriTest02", DetectHttpRawUriTest02, 1); UtRegisterTest("DetectHttpRawUriTest03", DetectHttpRawUriTest03, 1); UtRegisterTest("DetectHttpRawUriTest04", DetectHttpRawUriTest04, 1); UtRegisterTest("DetectHttpRawUriTest05", DetectHttpRawUriTest05, 1); UtRegisterTest("DetectHttpRawUriTest06", DetectHttpRawUriTest06, 1); UtRegisterTest("DetectHttpRawUriTest07", DetectHttpRawUriTest07, 1); UtRegisterTest("DetectHttpRawUriTest08", DetectHttpRawUriTest08, 1); UtRegisterTest("DetectHttpRawUriTest09", DetectHttpRawUriTest09, 1); UtRegisterTest("DetectHttpRawUriTest10", DetectHttpRawUriTest10, 1); UtRegisterTest("DetectHttpRawUriTest11", DetectHttpRawUriTest11, 1); UtRegisterTest("DetectHttpRawUriTest12", DetectHttpRawUriTest12, 1); UtRegisterTest("DetectHttpRawUriTest13", DetectHttpRawUriTest13, 1); UtRegisterTest("DetectHttpRawUriTest14", DetectHttpRawUriTest14, 1); UtRegisterTest("DetectHttpRawUriTest15", DetectHttpRawUriTest15, 1); UtRegisterTest("DetectHttpRawUriTest16", DetectHttpRawUriTest16, 1); UtRegisterTest("DetectHttpRawUriTest17", DetectHttpRawUriTest17, 1); UtRegisterTest("DetectHttpRawUriTest18", DetectHttpRawUriTest18, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-ipproto.h0000644000000000000000000000302212253546156014135 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus */ #ifndef __DETECT_IPPROTO_H__ #define __DETECT_IPPROTO_H__ /** IPProto Operators */ #define DETECT_IPPROTO_OP_EQ '=' /**< "equals" operator (default) */ #define DETECT_IPPROTO_OP_NOT '!' /**< "not" operator */ #define DETECT_IPPROTO_OP_LT '<' /**< "less than" operator */ #define DETECT_IPPROTO_OP_GT '>' /**< "greater than" operator */ /** ip_proto data */ typedef struct DetectIPProtoData_ { uint8_t op; /**< Operator used to compare */ uint8_t proto; /**< Protocol used to compare */ } DetectIPProtoData; /* prototypes */ /** * \brief Registration function for ip_proto keyword. */ void DetectIPProtoRegister (void); void DetectIPProtoRemoveAllSMs(Signature *); #endif /* __DETECT_IPPROTO_H__ */ suricata-1.4.7/src/detect-reference.c0000644000000000000000000002426312253546156014404 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva * \author Anoop Saldanha * * Implements the reference keyword support */ #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "decode.h" #include "flow-var.h" #include "decode-events.h" #include "stream-tcp.h" #include "util-reference-config.h" #include "detect-reference.h" #include "util-unittest.h" #include "util-byte.h" #include "util-debug.h" #define PARSE_REGEX "^\\s*([A-Za-z0-9]+)\\s*,\"?\\s*\"?\\s*([a-zA-Z0-9\\-_\\.\\/\\?\\=]+)\"?\\s*\"?" static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectReferenceSetup(DetectEngineCtx *, Signature *s, char *str); /** * \brief Registration function for the reference: keyword */ void DetectReferenceRegister(void) { sigmatch_table[DETECT_REFERENCE].name = "reference"; sigmatch_table[DETECT_REFERENCE].desc = "direct to places where information about the rule can be found"; sigmatch_table[DETECT_REFERENCE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Reference"; sigmatch_table[DETECT_REFERENCE].Match = NULL; sigmatch_table[DETECT_REFERENCE].Setup = DetectReferenceSetup; sigmatch_table[DETECT_REFERENCE].Free = NULL; sigmatch_table[DETECT_REFERENCE].RegisterTests = ReferenceRegisterTests; const char *eb; int opts = 0; int eo; opts |= PCRE_CASELESS; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } error: return; } /** * \brief Free a Reference object */ void DetectReferenceFree(DetectReference *ref) { SCEnter(); if (ref->reference != NULL) { SCFree(ref->reference); } SCFree(ref); SCReturn; } /** * \internal * \brief This function is used to parse reference options passed via reference: keyword * * \param rawstr Pointer to the user provided reference options. * * \retval ref Pointer to signature reference on success. * \retval NULL On failure. */ static DetectReference *DetectReferenceParse(char *rawstr, DetectEngineCtx *de_ctx) { SCEnter(); DetectReference *ref = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; const char *key = NULL; const char *content = NULL; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unable to parse \"reference\" " "keyword argument - \"%s\". Invalid argument.", rawstr); goto error; } ref = SCMalloc(sizeof(DetectReference)); if (unlikely(ref == NULL)) { goto error; } memset(ref, 0, sizeof(DetectReference)); res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &key); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &content); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (key == NULL || content == NULL) goto error; SCRConfReference *lookup_ref_conf = SCRConfGetReference(key, de_ctx); if (lookup_ref_conf != NULL) { ref->key = lookup_ref_conf->url; } else { SCLogError(SC_ERR_REFERENCE_UNKNOWN, "unknown reference key \"%s\". " "Supported keys are defined in reference.config file. Please " "have a look at the conf param \"reference-config-file\"", key); goto error; } /* make a copy so we can free pcre's substring */ ref->reference = SCStrdup((char *)content); if (ref->reference == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "strdup failed: %s", strerror(errno)); goto error; } /* free the substrings */ pcre_free_substring(key); pcre_free_substring(content); SCReturnPtr(ref, "Reference"); error: if (key != NULL) pcre_free_substring(key); if (content != NULL) pcre_free_substring(content); if (ref != NULL) DetectReferenceFree(ref); SCReturnPtr(NULL, "Reference"); } /** * \internal * \brief Used to add the parsed reference into the current signature. * * \param de_ctx Pointer to the Detection Engine Context. * \param s Pointer to the Current Signature. * \param m Pointer to the Current SigMatch. * \param rawstr Pointer to the user provided reference options. * * \retval 0 On Success. * \retval -1 On Failure. */ static int DetectReferenceSetup(DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { SCEnter(); DetectReference *ref = NULL; DetectReference *sig_refs = NULL; ref = DetectReferenceParse(rawstr, de_ctx); if (ref == NULL) goto error; SCLogDebug("ref %s %s", ref->key, ref->reference); if (s->references == NULL) { s->references = ref; } else { sig_refs = s->references; while (sig_refs->next != NULL) { sig_refs = sig_refs->next; } sig_refs->next = ref; ref->next = NULL; } SCReturnInt(0); error: SCReturnInt(-1); } /***************************************Unittests******************************/ #ifdef UNITTESTS /** * \test one valid reference. * * \retval 1 on succces. * \retval 0 on failure. */ static int DetectReferenceParseTest01(void) { int result = 0; Signature *s = NULL; DetectReference *ref = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto cleanup; } de_ctx->flags |= DE_QUIET; SCRConfGenerateValidDummyReferenceConfigFD01(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"One reference\"; reference:one,001-2010; sid:2;)"); if (s == NULL) { goto cleanup; } if (s->references == NULL) { goto cleanup; } ref = s->references; if (strcmp(ref->key, "http://www.one.com") != 0 || strcmp(ref->reference, "001-2010") != 0) { goto cleanup; } result = 1; cleanup: if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } return result; } /** * \test for two valid references. * * \retval 1 on succces. * \retval 0 on failure. */ static int DetectReferenceParseTest02(void) { int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto cleanup; } de_ctx->flags |= DE_QUIET; SCRConfGenerateValidDummyReferenceConfigFD01(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"Two references\"; " "reference:one,openinfosecdoundation.txt; " "reference:two,001-2010; sid:2;)"); if (s == NULL) { printf("sig parse failed: "); goto cleanup; } if (s->references == NULL || s->references->next == NULL) { printf("no ref or not enough refs: "); goto cleanup; } if (strcmp(s->references->key, "http://www.one.com") != 0 || strcmp(s->references->reference, "openinfosecdoundation.txt") != 0) { printf("first ref failed: "); goto cleanup; } if (strcmp(s->references->next->key, "http://www.two.com") != 0 || strcmp(s->references->next->reference, "001-2010") != 0) { printf("second ref failed: "); goto cleanup; } result = 1; cleanup: if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } return result; } /** * \test parsing: invalid reference. * * \retval 1 on succces. * \retval 0 on failure. */ static int DetectReferenceParseTest03(void) { int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto cleanup; } de_ctx->flags |= DE_QUIET; SCRConfGenerateValidDummyReferenceConfigFD01(); SCRConfLoadReferenceConfigFile(de_ctx); SCRConfDeleteDummyReferenceConfigFD(); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"invalid ref\"; " "reference:unknownkey,001-2010; sid:2;)"); if (s != NULL) { printf("sig parsed even though it's invalid: "); goto cleanup; } result = 1; cleanup: if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } return result; } #endif /* UNITTESTS */ void ReferenceRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectReferenceParseTest01", DetectReferenceParseTest01, 1); UtRegisterTest("DetectReferenceParseTest02", DetectReferenceParseTest02, 1); UtRegisterTest("DetectReferenceParseTest03", DetectReferenceParseTest03, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/detect-app-layer-event.h0000644000000000000000000000204112253546156015452 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_APP_LAYER_EVENT_H__ #define __DETECT_APP_LAYER_EVENT_H__ typedef struct DetectAppLayerEventData_ { uint16_t alproto; int event_id; } DetectAppLayerEventData; void DetectAppLayerEventRegister(void); #endif /* __DETECT_APP_LAYER_EVENT_H__ */ suricata-1.4.7/src/decode-icmpv4.h0000644000000000000000000002412012253546156013620 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DECODE_ICMPV4_H__ #define __DECODE_ICMPV4_H__ #include "decode.h" #include "decode-tcp.h" #include "decode-sctp.h" #include "decode-udp.h" #define ICMPV4_HEADER_LEN 8 #ifndef ICMP_ECHOREPLY #define ICMP_ECHOREPLY 0 /* Echo Reply */ #endif #ifndef ICMP_DEST_UNREACH #define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ #endif #ifndef ICMP_SOURCE_QUENCH #define ICMP_SOURCE_QUENCH 4 /* Source Quench */ #endif #ifndef ICMP_REDIRECT #define ICMP_REDIRECT 5 /* Redirect (change route) */ #endif #ifndef ICMP_ECHO #define ICMP_ECHO 8 /* Echo Request */ #endif #ifndef ICMP_TIME_EXCEEDED #define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ #endif #ifndef ICMP_PARAMETERPROB #define ICMP_PARAMETERPROB 12 /* Parameter Problem */ #endif #ifndef ICMP_TIMESTAMP #define ICMP_TIMESTAMP 13 /* Timestamp Request */ #endif #ifndef ICMP_TIMESTAMPREPLY #define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ #endif #ifndef ICMP_INFO_REQUEST #define ICMP_INFO_REQUEST 15 /* Information Request */ #endif #ifndef ICMP_INFO_REPLY #define ICMP_INFO_REPLY 16 /* Information Reply */ #endif #ifndef ICMP_ADDRESS #define ICMP_ADDRESS 17 /* Address Mask Request */ #endif #ifndef ICMP_ADDRESSREPLY #define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ #endif #ifndef NR_ICMP_TYPES #define NR_ICMP_TYPES 18 #endif /* Codes for UNREACH. */ #ifndef ICMP_NET_UNREACH #define ICMP_NET_UNREACH 0 /* Network Unreachable */ #endif #ifndef ICMP_HOST_UNREACH #define ICMP_HOST_UNREACH 1 /* Host Unreachable */ #endif #ifndef ICMP_PROT_UNREACH #define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ #endif #ifndef ICMP_PORT_UNREACH #define ICMP_PORT_UNREACH 3 /* Port Unreachable */ #endif #ifndef ICMP_FRAG_NEEDED #define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ #endif #ifndef ICMP_SR_FAILED #define ICMP_SR_FAILED 5 /* Source Route failed */ #endif #ifndef ICMP_NET_UNKNOWN #define ICMP_NET_UNKNOWN 6 #endif #ifndef ICMP_HOST_UNKNOWN #define ICMP_HOST_UNKNOWN 7 #endif #ifndef ICMP_HOST_ISOLATED #define ICMP_HOST_ISOLATED 8 #endif #ifndef ICMP_NET_ANO #define ICMP_NET_ANO 9 #endif #ifndef ICMP_HOST_ANO #define ICMP_HOST_ANO 10 #endif #ifndef ICMP_NET_UNR_TOS #define ICMP_NET_UNR_TOS 11 #endif #ifndef ICMP_HOST_UNR_TOS #define ICMP_HOST_UNR_TOS 12 #endif #ifndef ICMP_PKT_FILTERED #define ICMP_PKT_FILTERED 13 /* Packet filtered */ #endif #ifndef ICMP_PREC_VIOLATION #define ICMP_PREC_VIOLATION 14 /* Precedence violation */ #endif #ifndef ICMP_PREC_CUTOFF #define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ #endif #ifndef NR_ICMP_UNREACH #define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */ #endif /* Codes for REDIRECT. */ #ifndef ICMP_REDIR_NET #define ICMP_REDIR_NET 0 /* Redirect Net */ #endif #ifndef ICMP_REDIR_HOST #define ICMP_REDIR_HOST 1 /* Redirect Host */ #endif #ifndef ICMP_REDIR_NETTOS #define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ #endif #ifndef ICMP_REDIR_HOSTTOS #define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ #endif /* Codes for TIME_EXCEEDED. */ #ifndef ICMP_EXC_TTL #define ICMP_EXC_TTL 0 /* TTL count exceeded */ #endif #ifndef ICMP_EXC_FRAGTIME #define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ #endif /** marco for icmpv4 type access */ #define ICMPV4_GET_TYPE(p) (p)->icmpv4h->type /** marco for icmpv4 code access */ #define ICMPV4_GET_CODE(p) (p)->icmpv4h->code /* ICMPv4 header structure */ typedef struct ICMPV4Hdr_ { uint8_t type; uint8_t code; uint16_t checksum; } ICMPV4Hdr; /* ICMPv4 header structure */ typedef struct ICMPV4ExtHdr_ { uint8_t type; uint8_t code; uint16_t checksum; uint16_t id; uint16_t seq; } ICMPV4ExtHdr; /* ICMPv4 vars */ typedef struct ICMPV4Vars_ { /* checksum computed over the icmpv4 packet */ int32_t comp_csum; uint16_t id; uint16_t seq; uint32_t mtu; uint32_t error_ptr; /** Pointers to the embedded packet headers */ IPV4Hdr *emb_ipv4h; TCPHdr *emb_tcph; UDPHdr *emb_udph; ICMPV4Hdr *emb_icmpv4h; /** IPv4 src and dst address */ struct in_addr emb_ip4_src; struct in_addr emb_ip4_dst; uint8_t emb_ip4_hlen; uint8_t emb_ip4_proto; /** TCP/UDP ports */ uint16_t emb_sport; uint16_t emb_dport; } ICMPV4Vars; #define CLEAR_ICMPV4_PACKET(p) do { \ (p)->icmpv4vars.comp_csum = -1; \ (p)->icmpv4vars.id = 0; \ (p)->icmpv4vars.seq = 0; \ (p)->icmpv4vars.mtu = 0; \ (p)->icmpv4vars.error_ptr = 0; \ (p)->icmpv4vars.emb_ipv4h = NULL; \ (p)->icmpv4vars.emb_tcph = NULL; \ (p)->icmpv4vars.emb_udph = NULL; \ (p)->icmpv4vars.emb_icmpv4h = NULL; \ (p)->icmpv4vars.emb_ip4_src.s_addr = 0; \ (p)->icmpv4vars.emb_ip4_dst.s_addr = 0; \ (p)->icmpv4vars.emb_sport = 0; \ (p)->icmpv4vars.emb_ip4_proto = 0; \ (p)->icmpv4vars.emb_sport = 0; \ (p)->icmpv4vars.emb_dport = 0; \ (p)->icmpv4h = NULL; \ } while(0) #define ICMPV4_HEADER_PKT_OFFSET 8 /** macro for icmpv4 "type" access */ #define ICMPV4_GET_TYPE(p) (p)->icmpv4h->type /** macro for icmpv4 "code" access */ #define ICMPV4_GET_CODE(p) (p)->icmpv4h->code /** macro for icmpv4 "csum" access */ #define ICMPV4_GET_CSUM(p) (p)->icmpv4h->csum /* If message is informational */ /** macro for icmpv4 "id" access */ #define ICMPV4_GET_ID(p) ((p)->icmpv4vars.id) /** macro for icmpv4 "seq" access */ #define ICMPV4_GET_SEQ(p) ((p)->icmpv4vars.seq) /* If message is Error */ /** macro for icmpv4 "unused" access */ #define ICMPV4_GET_UNUSED(p) (p)->icmpv4h->icmpv4b.icmpv4e.unused /** macro for icmpv4 "error_ptr" access */ #define ICMPV4_GET_ERROR_PTR(p) (p)->icmpv4h->icmpv4b.icmpv4e.error_ptr /** macro for icmpv4 "mtu" access */ #define ICMPV4_GET_MTU(p) (p)->icmpv4h->icmpv4b.icmpv4e.mtu /** macro for icmpv4 embedded "protocol" access */ #define ICMPV4_GET_EMB_PROTO(p) (p)->icmpv4vars.emb_ip4_proto /** macro for icmpv4 embedded "ipv4h" header access */ #define ICMPV4_GET_EMB_IPV4(p) (p)->icmpv4vars.emb_ipv4h /** macro for icmpv4 embedded "tcph" header access */ #define ICMPV4_GET_EMB_TCP(p) (p)->icmpv4vars.emb_tcph /** macro for icmpv4 embedded "udph" header access */ #define ICMPV4_GET_EMB_UDP(p) (p)->icmpv4vars.emb_udph /** macro for icmpv4 embedded "icmpv4h" header access */ #define ICMPV4_GET_EMB_ICMPV4H(p) (p)->icmpv4vars.emb_icmpv4h /** macro for checking if a ICMP DEST UNREACH packet is valid for use * in other parts of the engine, such as the flow engine. * * \warning use only _after_ the decoder has processed the packet */ #define ICMPV4_DEST_UNREACH_IS_VALID(p) (((p)->icmpv4h != NULL) && \ (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH) && \ (ICMPV4_GET_EMB_IPV4((p)) != NULL) && \ ((ICMPV4_GET_EMB_TCP((p)) != NULL) || \ (ICMPV4_GET_EMB_UDP((p)) != NULL))) /** * marco for checking if a ICMP packet is an error message or an * query message. * * \todo This check is used in the flow engine and needs to be as * cheap as possible. Consider setting a bitflag at the decoder * stage so we can to a bit check instead of the more expensive * check below. */ #define ICMPV4_IS_ERROR_MSG(p) (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH || \ ICMPV4_GET_TYPE((p)) == ICMP_SOURCE_QUENCH || \ ICMPV4_GET_TYPE((p)) == ICMP_REDIRECT || \ ICMPV4_GET_TYPE((p)) == ICMP_TIME_EXCEEDED || \ ICMPV4_GET_TYPE((p)) == ICMP_PARAMETERPROB) typedef struct ICMPV4Cache_ { } ICMPV4Cache; void DecodeICMPV4RegisterTests(void); /** ------ Inline functions ------ */ static inline uint16_t ICMPV4CalculateChecksum(uint16_t *, uint16_t); /** * \brief Calculates the checksum for the ICMP packet * * \param pkt Pointer to the start of the ICMP packet * \param hlen Total length of the ICMP packet(header + payload) * * \retval csum Checksum for the ICMP packet */ static inline uint16_t ICMPV4CalculateChecksum(uint16_t *pkt, uint16_t tlen) { uint16_t pad = 0; uint32_t csum = pkt[0]; tlen -= 4; pkt += 2; while (tlen >= 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } while(tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } while(tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; } while (tlen > 1) { csum += pkt[0]; tlen -= 2; pkt += 1; } if (tlen == 1) { *(uint8_t *)(&pad) = (*(uint8_t *)pkt); csum += pad; } csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); return (uint16_t) ~csum; } #endif /* __DECODE_ICMPV4_H__ */ suricata-1.4.7/src/app-layer-htp.c0000644000000000000000000046022512253546156013665 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Victor Julien * \author Gurvinder Singh * \author Pablo Rincon * \author Brian Rectanus * * This file provides a HTTP protocol support for the engine using HTP library. */ #include "suricata.h" #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "util-radix-tree.h" #include "util-file.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-htp.h" #include "app-layer-htp-body.h" #include "app-layer-htp-file.h" #include "util-spm.h" #include "util-debug.h" #include "util-time.h" #include "util-misc.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "flow-util.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "detect-parse.h" #include "conf.h" #include "util-memcmp.h" #ifndef HAVE_HTP_SET_PATH_DECODE_U_ENCODING void htp_config_set_path_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding); #endif //#define PRINT /** Fast lookup tree (radix) for the various HTP configurations */ static SCRadixTree *cfgtree; /** List of HTP configurations. */ static HTPCfgRec cfglist; #ifdef DEBUG static SCMutex htp_state_mem_lock = PTHREAD_MUTEX_INITIALIZER; static uint64_t htp_state_memuse = 0; static uint64_t htp_state_memcnt = 0; #endif SCEnumCharMap http_decoder_event_table[ ] = { { "UNKNOWN_ERROR", HTTP_DECODER_EVENT_UNKNOWN_ERROR}, { "GZIP_DECOMPRESSION_FAILED", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED}, { "REQUEST_FIELD_MISSING_COLON", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON}, { "RESPONSE_FIELD_MISSING_COLON", HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON}, { "INVALID_REQUEST_CHUNK_LEN", HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN}, { "INVALID_RESPONSE_CHUNK_LEN", HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN}, { "INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST}, { "INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE}, { "INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST}, { "INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE}, { "100_CONTINUE_ALREADY_SEEN", HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN}, { "UNABLE_TO_MATCH_RESPONSE_TO_REQUEST", HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST}, { "INVALID_SERVER_PORT_IN_REQUEST", HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST}, { "INVALID_AUTHORITY_PORT", HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT}, { "REQUEST_HEADER_INVALID", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID}, { "RESPONSE_HEADER_INVALID", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID}, { "MISSING_HOST_HEADER", HTTP_DECODER_EVENT_MISSING_HOST_HEADER}, { "HOST_HEADER_AMBIGUOUS", HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS}, { "INVALID_REQUEST_FIELD_FOLDING", HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING}, { "INVALID_RESPONSE_FIELD_FOLDING", HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING}, { "REQUEST_FIELD_TOO_LONG", HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG}, { "RESPONSE_FIELD_TOO_LONG", HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG}, { "REQUEST_SERVER_PORT_TCP_PORT_MISMATCH", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, /* suricata warnings/errors */ { "MULTIPART_GENERIC_ERROR", HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR}, { "MULTIPART_NO_FILEDATA", HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA}, { "MULTIPART_INVALID_HEADER", HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER}, { NULL, -1 }, }; #ifdef DEBUG /** * \internal * * \brief Lookup the HTP personality string from the numeric personality. * * \todo This needs to be a libhtp function. */ static const char *HTPLookupPersonalityString(int p) { #define CASE_HTP_PERSONALITY_STRING(p) \ case HTP_SERVER_ ## p: return #p switch (p) { CASE_HTP_PERSONALITY_STRING(MINIMAL); CASE_HTP_PERSONALITY_STRING(GENERIC); CASE_HTP_PERSONALITY_STRING(IDS); CASE_HTP_PERSONALITY_STRING(IIS_4_0); CASE_HTP_PERSONALITY_STRING(IIS_5_0); CASE_HTP_PERSONALITY_STRING(IIS_5_1); CASE_HTP_PERSONALITY_STRING(IIS_6_0); CASE_HTP_PERSONALITY_STRING(IIS_7_0); CASE_HTP_PERSONALITY_STRING(IIS_7_5); CASE_HTP_PERSONALITY_STRING(TOMCAT_6_0); CASE_HTP_PERSONALITY_STRING(APACHE); CASE_HTP_PERSONALITY_STRING(APACHE_2_2); } return NULL; } #endif /* DEBUG */ /** * \internal * * \brief Lookup the numeric HTP personality from a string. * * \todo This needs to be a libhtp function. */ static int HTPLookupPersonality(const char *str) { #define IF_HTP_PERSONALITY_NUM(p) \ if (strcasecmp(#p, str) == 0) return HTP_SERVER_ ## p IF_HTP_PERSONALITY_NUM(MINIMAL); IF_HTP_PERSONALITY_NUM(GENERIC); IF_HTP_PERSONALITY_NUM(IDS); IF_HTP_PERSONALITY_NUM(IIS_4_0); IF_HTP_PERSONALITY_NUM(IIS_5_0); IF_HTP_PERSONALITY_NUM(IIS_5_1); IF_HTP_PERSONALITY_NUM(IIS_6_0); IF_HTP_PERSONALITY_NUM(IIS_7_0); IF_HTP_PERSONALITY_NUM(IIS_7_5); IF_HTP_PERSONALITY_NUM(TOMCAT_6_0); IF_HTP_PERSONALITY_NUM(APACHE); IF_HTP_PERSONALITY_NUM(APACHE_2_2); return -1; } /** \brief Function to allocates the HTTP state memory and also creates the HTTP * connection parser to be used by the HTP library */ static void *HTPStateAlloc(void) { SCEnter(); HtpState *s = SCMalloc(sizeof(HtpState)); if (unlikely(s == NULL)) goto error; memset(s, 0x00, sizeof(HtpState)); #ifdef DEBUG SCMutexLock(&htp_state_mem_lock); htp_state_memcnt++; htp_state_memuse += sizeof(HtpState); SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); SCMutexUnlock(&htp_state_mem_lock); #endif SCReturnPtr((void *)s, "void"); error: if (s != NULL) { SCFree(s); } SCReturnPtr(NULL, "void"); } /** \brief Function to frees the HTTP state memory and also frees the HTTP * connection parser memory which was used by the HTP library */ void HTPStateFree(void *state) { SCEnter(); HtpState *s = (HtpState *)state; if (s == NULL) { SCReturn; } /* Unset the body inspection */ s->flags &=~ HTP_FLAG_NEW_BODY_SET; /* free the connection parser memory used by HTP library */ if (s->connp != NULL) { SCLogDebug("freeing HTP state"); size_t i; /* free the list of body chunks */ if (s->connp->conn != NULL) { for (i = 0; i < list_size(s->connp->conn->transactions); i++) { htp_tx_t *tx = (htp_tx_t *)list_get(s->connp->conn->transactions, i); if (tx != NULL) { HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); if (htud != NULL) { HtpBodyFree(&htud->request_body); HtpBodyFree(&htud->response_body); SCFree(htud); htp_tx_set_user_data(tx, NULL); } } } } htp_connp_destroy_all(s->connp); } FileContainerFree(s->files_ts); FileContainerFree(s->files_tc); SCFree(s); #ifdef DEBUG SCMutexLock(&htp_state_mem_lock); htp_state_memcnt--; htp_state_memuse -= sizeof(HtpState); SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); SCMutexUnlock(&htp_state_mem_lock); #endif SCReturn; } /** * \brief Update the transaction id based on the http state */ void HTPStateUpdateTransactionId(void *state, uint16_t *id) { SCEnter(); HtpState *s = (HtpState *)state; SCLogDebug("original id %"PRIu16", s->transaction_cnt %"PRIu16, *id, (s->transaction_cnt)); if ((s->transaction_cnt) > (*id)) { SCLogDebug("original id %"PRIu16", updating with s->transaction_cnt %"PRIu16, *id, (s->transaction_cnt)); (*id) = (s->transaction_cnt); SCLogDebug("updated id %"PRIu16, *id); } SCReturn; } /** * \brief HTP transaction cleanup callback * * \warning We cannot actually free the transactions here. It seems that * HTP only accepts freeing of transactions in the response callback. */ void HTPStateTransactionFree(void *state, uint16_t id) { SCEnter(); HtpState *s = (HtpState *)state; s->transaction_done = id; SCLogDebug("state %p, id %"PRIu16, s, id); /* we can't remove the actual transactions here */ SCReturn; } /** * \brief Sets a flag that informs the HTP app layer that some module in the * engine needs the http request body data. * \initonly */ void AppLayerHtpEnableRequestBodyCallback(void) { SCEnter(); SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_BODY); SCReturn; } /** * \brief Sets a flag that informs the HTP app layer that some module in the * engine needs the http request body data. * \initonly */ void AppLayerHtpEnableResponseBodyCallback(void) { SCEnter(); SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_RESPONSE_BODY); SCReturn; } /** * \brief Sets a flag that informs the HTP app layer that some module in the * engine needs the http request multi part header. * * \initonly */ void AppLayerHtpNeedMultipartHeader(void) { SCEnter(); AppLayerHtpEnableRequestBodyCallback(); SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_MULTIPART); SCReturn; } /** * \brief Sets a flag that informs the HTP app layer that some module in the * engine needs the http request file. * * \initonly */ void AppLayerHtpNeedFileInspection(void) { SCEnter(); AppLayerHtpNeedMultipartHeader(); AppLayerHtpEnableRequestBodyCallback(); AppLayerHtpEnableResponseBodyCallback(); SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_FILE); SCReturn; } struct { char *msg; int de; } htp_errors[] = { { "GZip decompressor: inflateInit2 failed", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED}, { "Request field invalid: colon missing", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON}, { "Response field invalid: colon missing", HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON}, { "Request chunk encoding: Invalid chunk length", HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN}, { "Response chunk encoding: Invalid chunk length", HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN}, { "Invalid T-E value in request", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST}, { "Invalid T-E value in response", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE}, { "Invalid C-L field in request", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST}, { "Invalid C-L field in response", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE}, { "Already seen 100-Continue", HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN}, { "Unable to match response to request", HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST}, { "Invalid server port information in request", HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST}, { "Invalid authority port", HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT}, { "Request field over", HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG}, { "Response field over", HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG}, }; struct { char *msg; int de; } htp_warnings[] = { { "GZip decompressor:", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED}, { "Request field invalid", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID}, { "Response field invalid", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID}, { "Request header name is not a token", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID}, { "Response header name is not a token", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID}, { "Host information in request headers required by HTTP/1.1", HTTP_DECODER_EVENT_MISSING_HOST_HEADER}, { "Host information ambiguous", HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS}, { "Invalid request field folding", HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING}, { "Invalid response field folding", HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING}, { "Request server port number differs from the actual TCP port", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, }; #define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0])) #define HTP_WARNING_MAX (sizeof(htp_warnings) / sizeof(htp_warnings[0])) /** * \internal * * \brief Get the warning id for the warning msg. * * \param msg warning message * * \retval id the id or 0 in case of not found */ static int HTPHandleWarningGetId(const char *msg) { SCLogDebug("received warning \"%s\"", msg); size_t idx; for (idx = 0; idx < HTP_WARNING_MAX; idx++) { if (strncmp(htp_warnings[idx].msg, msg, strlen(htp_warnings[idx].msg)) == 0) { return htp_warnings[idx].de; } } return 0; } /** * \internal * * \brief Get the error id for the error msg. * * \param msg error message * * \retval id the id or 0 in case of not found */ static int HTPHandleErrorGetId(const char *msg) { SCLogDebug("received error \"%s\"", msg); size_t idx; for (idx = 0; idx < HTP_ERROR_MAX; idx++) { if (strncmp(htp_errors[idx].msg, msg, strlen(htp_errors[idx].msg)) == 0) { return htp_errors[idx].de; } } return 0; } /** * \internal * * \brief Check state for errors, warnings and add any as events * * \param s state */ static void HTPHandleError(HtpState *s) { if (s == NULL || s->connp == NULL || s->connp->conn == NULL || s->connp->conn->messages == NULL) { return; } size_t size = list_size(s->connp->conn->messages); size_t msg; for (msg = 0; msg < size; msg++) { htp_log_t *log = list_get(s->connp->conn->messages, msg); if (log == NULL) continue; SCLogDebug("message %s", log->msg); int id = HTPHandleErrorGetId(log->msg); if (id > 0) { AppLayerDecoderEventsSetEvent(s->f, id); } else { id = HTPHandleWarningGetId(log->msg); if (id > 0) { AppLayerDecoderEventsSetEvent(s->f, id); } else { AppLayerDecoderEventsSetEvent(s->f, HTTP_DECODER_EVENT_UNKNOWN_ERROR); } } } } /** * \internal * * \brief Check state for warnings and add any as events * * \param s state */ static void HTPHandleWarning(HtpState *s) { if (s == NULL || s->connp == NULL || s->connp->conn == NULL || s->connp->conn->messages == NULL) { return; } size_t size = list_size(s->connp->conn->messages); size_t msg; for (msg = 0; msg < size; msg++) { htp_log_t *log = list_get(s->connp->conn->messages, msg); if (log == NULL) continue; int id = HTPHandleWarningGetId(log->msg); if (id > 0) { AppLayerDecoderEventsSetEvent(s->f, id); } else { AppLayerDecoderEventsSetEvent(s->f, HTTP_DECODER_EVENT_UNKNOWN_ERROR); } } } /** * \brief Function to handle the reassembled data from client and feed it to * the HTP library to process it. * * \param flow Pointer to the flow the data belong to * \param htp_state Pointer the state in which the parsed value to be stored * \param pstate Application layer parser state for this session * \param input Pointer the received HTTP client data * \param input_len Length in bytes of the received data * \param output Pointer to the output (not used in this function) * * \retval On success returns 1 or on failure returns -1 */ static int HTPHandleRequestData(Flow *f, void *htp_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SCEnter(); int r = -1; int ret = 1; //PrintRawDataFp(stdout, input, input_len); HtpState *hstate = (HtpState *)htp_state; hstate->f = f; /* On the first invocation, create the connection parser structure to * be used by HTP library. This is looked up via IP in the radix * tree. Failing that, the default HTP config is used. */ if (NULL == hstate->connp ) { HTPCfgRec *htp_cfg_rec = &cfglist; htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */ SCRadixNode *cfgnode = NULL; if (FLOW_IS_IPV4(f)) { SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f)); cfgnode = SCRadixFindKeyIPV4BestMatch((uint8_t *)GET_IPV4_DST_ADDR_PTR(f), cfgtree); } else if (FLOW_IS_IPV6(f)) { SCLogDebug("Looking up HTP config for ipv6"); cfgnode = SCRadixFindKeyIPV6BestMatch((uint8_t *)GET_IPV6_DST_ADDR(f), cfgtree); } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown address family, bug!"); goto error; } if (cfgnode != NULL) { htp_cfg_rec = SC_RADIX_NODE_USERDATA(cfgnode, HTPCfgRec); if (htp_cfg_rec != NULL) { htp = htp_cfg_rec->cfg; SCLogDebug("LIBHTP using config: %p", htp); } } else { SCLogDebug("Using default HTP config: %p", htp); } if (NULL == htp) { BUG_ON(htp == NULL); /* should never happen if HTPConfigure is properly invoked */ goto error; } hstate->connp = htp_connp_create(htp); if (hstate->connp == NULL) { goto error; } htp_connp_set_user_data(hstate->connp, (void *)hstate); hstate->cfg = htp_cfg_rec; SCLogDebug("New hstate->connp %p", hstate->connp); } /* the code block above should make sure connp is never NULL here */ BUG_ON(hstate->connp == NULL); if (hstate->connp->in_status == STREAM_STATE_ERROR) { SCLogError(SC_ERR_ALPARSER, "Inbound parser is in error state, no" " need to feed data to libhtp"); SCReturnInt(-1); } else if (hstate->connp->in_status == STREAM_STATE_TUNNEL) { SCReturnInt(0); } /* Unset the body inspection (the callback should * reactivate it if necessary) */ hstate->flags &=~ HTP_FLAG_NEW_BODY_SET; /* Open the HTTP connection on receiving the first request */ if (!(hstate->flags & HTP_FLAG_STATE_OPEN)) { SCLogDebug("opening htp handle at %p", hstate->connp); htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, 0); hstate->flags |= HTP_FLAG_STATE_OPEN; } else { SCLogDebug("using existing htp handle at %p", hstate->connp); } /* pass the new data to the htp parser */ r = htp_connp_req_data(hstate->connp, 0, input, input_len); switch(r) { case STREAM_STATE_ERROR: HTPHandleError(hstate); hstate->flags |= HTP_FLAG_STATE_ERROR; hstate->flags &= ~HTP_FLAG_STATE_DATA; hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; ret = -1; break; case STREAM_STATE_DATA: case STREAM_STATE_DATA_OTHER: HTPHandleWarning(hstate); hstate->flags |= HTP_FLAG_STATE_DATA; break; default: HTPHandleWarning(hstate); hstate->flags &= ~HTP_FLAG_STATE_DATA; hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; } /* if the TCP connection is closed, then close the HTTP connection */ if ((pstate->flags & APP_LAYER_PARSER_EOF) && !(hstate->flags & HTP_FLAG_STATE_CLOSED_TS)) { hstate->connp->in_status = STREAM_STATE_CLOSED; // Call the parsers one last time, which will allow them // to process the events that depend on stream closure htp_connp_req_data(hstate->connp, 0, NULL, 0); hstate->flags |= HTP_FLAG_STATE_CLOSED_TS; SCLogDebug("stream eof encountered, closing htp handle for ts"); } SCLogDebug("hstate->connp %p", hstate->connp); SCReturnInt(ret); error: SCReturnInt(-1); } /** * \brief Function to handle the reassembled data from server and feed it to * the HTP library to process it. * * \param flow Pointer to the flow the data belong to * \param htp_state Pointer the state in which the parsed value to be stored * \param pstate Application layer parser state for this session * \param input Pointer the received HTTP server data * \param input_len Length in bytes of the received data * \param output Pointer to the output (not used in this function) * * \retval On success returns 1 or on failure returns -1 */ static int HTPHandleResponseData(Flow *f, void *htp_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SCEnter(); int r = -1; int ret = 1; HtpState *hstate = (HtpState *)htp_state; hstate->f = f; if (hstate->connp == NULL) { SCLogError(SC_ERR_ALPARSER, "HTP state has no connp"); SCReturnInt(-1); } if (hstate->connp->out_status == STREAM_STATE_ERROR) { SCLogError(SC_ERR_ALPARSER, "Outbound parser is in error state, no" " need to feed data to libhtp"); SCReturnInt(-1); } else if (hstate->connp->out_status == STREAM_STATE_TUNNEL) { SCReturnInt(0); } /* Unset the body inspection (the callback should * reactivate it if necessary) */ hstate->flags &=~ HTP_FLAG_NEW_BODY_SET; r = htp_connp_res_data(hstate->connp, 0, input, input_len); switch(r) { case STREAM_STATE_ERROR: HTPHandleError(hstate); hstate->flags = HTP_FLAG_STATE_ERROR; hstate->flags &= ~HTP_FLAG_STATE_DATA; hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; ret = -1; break; case STREAM_STATE_DATA: case STREAM_STATE_DATA_OTHER: HTPHandleWarning(hstate); hstate->flags |= HTP_FLAG_STATE_DATA; break; default: HTPHandleWarning(hstate); hstate->flags &= ~HTP_FLAG_STATE_DATA; hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; } /* if we the TCP connection is closed, then close the HTTP connection */ if ((pstate->flags & APP_LAYER_PARSER_EOF) && !(hstate->flags & HTP_FLAG_STATE_CLOSED_TC)) { hstate->connp->out_status = STREAM_STATE_CLOSED; // Call the parsers one last time, which will allow them // to process the events that depend on stream closure htp_connp_res_data(hstate->connp, 0, NULL, 0); hstate->flags |= HTP_FLAG_STATE_CLOSED_TC; } SCLogDebug("hstate->connp %p", hstate->connp); SCReturnInt(ret); } /** * \brief get the highest loggable transaction id */ int HtpTransactionGetLoggableId(Flow *f) { SCEnter(); AppLayerParserStateStore *parser_state_store = (AppLayerParserStateStore *)f->alparser; if (parser_state_store == NULL) { SCLogDebug("no state store"); goto error; } int id = 0; HtpState *http_state = f->alstate; if (http_state == NULL || http_state->connp == NULL || http_state->connp->conn == NULL) { SCLogDebug("no (void) http state"); goto error; } if (parser_state_store->id_flags & APP_LAYER_TRANSACTION_EOF) { SCLogDebug("eof, return current transaction as well"); id = (int)(list_size(http_state->connp->conn->transactions)); } else { id = (int)(parser_state_store->avail_id - 1); } SCReturnInt(id); error: SCReturnInt(-1); } #ifdef HAVE_HTP_URI_NORMALIZE_HOOK /** * \brief Normalize the query part of the URI as if it's part of the URI. * * Called twice if double decoding is enabled. * * \param c HTP connection pointer * * \retval HOOK_OK we won't fail * * This functionality requires the uri normalize hook introduced in libhtp * version 0.2.5. */ static int HTPCallbackRequestUriNormalizeQuery(htp_connp_t *c) { SCEnter(); if (c == NULL || c->in_tx == NULL || c->in_tx->parsed_uri == NULL) { SCReturnInt(HOOK_OK); } /* uri normalize the query string as well */ if (c->in_tx->parsed_uri->query != NULL) { #ifdef HAVE_HTP_DECODE_QUERY_INPLACE htp_decode_query_inplace(c->cfg, c->in_tx, c->in_tx->parsed_uri->query); #else htp_decode_path_inplace(c->cfg, c->in_tx, c->in_tx->parsed_uri->query); #endif /* HAVE_HTP_DECODE_QUERY_INPLACE */ } SCReturnInt(HOOK_OK); } /** * \brief Normalize the path part of the URI (again). Used by double decoding * option. * * \param c HTP connection pointer * * \retval HOOK_OK we won't fail * * This functionality requires the uri normalize hook introduced in libhtp * version 0.2.5. */ static int HTPCallbackRequestUriNormalizePath(htp_connp_t *c) { SCEnter(); if (c == NULL || c->in_tx == NULL || c->in_tx->parsed_uri == NULL) { SCReturnInt(HOOK_OK); } /* uri normalize the path string */ if (c->in_tx->parsed_uri->path != NULL) { htp_decode_path_inplace(c->cfg, c->in_tx, c->in_tx->parsed_uri->path); /* Handle UTF-8 in path */ if (c->cfg->path_convert_utf8) { /* Decode Unicode characters into a single-byte stream, using best-fit mapping */ htp_utf8_decode_path_inplace(c->cfg, c->in_tx, c->in_tx->parsed_uri->path); } else { /* Only validate path as a UTF-8 stream */ htp_utf8_validate_path(c->in_tx, c->in_tx->parsed_uri->path); } /* normalize after decoding */ htp_normalize_uri_path_inplace(c->in_tx->parsed_uri->path); } SCReturnInt(HOOK_OK); } #endif /* HAVE_HTP_URI_NORMALIZE_HOOK */ /** * \param name /Lowercase/ version of the variable name */ static int HTTPParseContentDispositionHeader(uint8_t *name, size_t name_len, uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen) { #ifdef PRINT printf("DATA START: \n"); PrintRawDataFp(stdout, data, len); printf("DATA END: \n"); #endif size_t x; int quote = 0; for (x = 0; x < len; x++) { if (!(isspace(data[x]))) break; } if (x >= len) return 0; uint8_t *line = data+x; size_t line_len = len-x; size_t offset = 0; #ifdef PRINT printf("LINE START: \n"); PrintRawDataFp(stdout, line, line_len); printf("LINE END: \n"); #endif for (x = 0 ; x < line_len; x++) { if (x > 0) { if (line[x - 1] != '\\' && line[x] == '\"') { quote++; } if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) { uint8_t *token = line + offset; size_t token_len = x - offset; if ((x + 1) == line_len) { token_len++; } offset = x + 1; while (offset < line_len && isspace(line[offset])) { x++; offset++; } #ifdef PRINT printf("TOKEN START: \n"); PrintRawDataFp(stdout, token, token_len); printf("TOKEN END: \n"); #endif if (token_len > name_len) { if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) { uint8_t *value = token + name_len; size_t value_len = token_len - name_len; if (value[0] == '\"') { value++; value_len--; } if (value[value_len-1] == '\"') { value_len--; } #ifdef PRINT printf("VALUE START: \n"); PrintRawDataFp(stdout, value, value_len); printf("VALUE END: \n"); #endif *retptr = value; *retlen = value_len; return 1; } } } } } return 0; } /** * \param name /Lowercase/ version of the variable name */ static int HTTPParseContentTypeHeader(uint8_t *name, size_t name_len, uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen) { SCEnter(); #ifdef PRINT printf("DATA START: \n"); PrintRawDataFp(stdout, data, len); printf("DATA END: \n"); #endif size_t x; int quote = 0; for (x = 0; x < len; x++) { if (!(isspace(data[x]))) break; } if (x >= len) { SCReturnInt(0); } uint8_t *line = data+x; size_t line_len = len-x; size_t offset = 0; #ifdef PRINT printf("LINE START: \n"); PrintRawDataFp(stdout, line, line_len); printf("LINE END: \n"); #endif for (x = 0 ; x < line_len; x++) { if (x > 0) { if (line[x - 1] != '\\' && line[x] == '\"') { quote++; } if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) { uint8_t *token = line + offset; size_t token_len = x - offset; if ((x + 1) == line_len) { token_len++; } offset = x + 1; while (offset < line_len && isspace(line[offset])) { x++; offset++; } #ifdef PRINT printf("TOKEN START: \n"); PrintRawDataFp(stdout, token, token_len); printf("TOKEN END: \n"); #endif if (token_len > name_len) { if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) { uint8_t *value = token + name_len; size_t value_len = token_len - name_len; if (value[0] == '\"') { value++; value_len--; } if (value[value_len-1] == '\"') { value_len--; } #ifdef PRINT printf("VALUE START: \n"); PrintRawDataFp(stdout, value, value_len); printf("VALUE END: \n"); #endif *retptr = value; *retlen = value_len; SCReturnInt(1); } } } } } SCReturnInt(0); } /** * \brief setup multipart parsing: extract boundary and store it * * \param d HTTP transaction * \param htud transaction userdata * * \retval 1 ok, multipart set up * \retval 0 ok, not multipart though * \retval -1 error: problem with the boundary * * If the request contains a multipart message, this function will * set the HTP_BOUNDARY_SET in the transaction. */ static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud) { htp_header_t *cl = table_getc(d->tx->request_headers, "content-length"); if (cl != NULL) htud->request_body.content_len = htp_parse_content_length(cl->value); htp_header_t *h = (htp_header_t *)table_getc(d->tx->request_headers, "Content-Type"); if (h != NULL && bstr_len(h->value) > 0) { uint8_t *boundary = NULL; size_t boundary_len = 0; int r = HTTPParseContentTypeHeader((uint8_t *)"boundary=", 9, (uint8_t *) bstr_ptr(h->value), bstr_len(h->value), &boundary, &boundary_len); if (r == 1) { #ifdef PRINT printf("BOUNDARY START: \n"); PrintRawDataFp(stdout, boundary, boundary_len); printf("BOUNDARY END: \n"); #endif if (boundary_len < HTP_BOUNDARY_MAX) { htud->boundary = SCMalloc(boundary_len); if (htud->boundary == NULL) { return -1; } htud->boundary_len = (uint8_t)boundary_len; memcpy(htud->boundary, boundary, boundary_len); htud->tsflags |= HTP_BOUNDARY_SET; } else { SCLogDebug("invalid boundary"); return -1; } } SCReturnInt(1); } SCReturnInt(0); } /** * \brief Setup boundary buffers */ static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, uint8_t **expected_boundary, uint8_t *expected_boundary_len, uint8_t **expected_boundary_end, uint8_t *expected_boundary_end_len) { uint8_t *eb = NULL; uint8_t *ebe = NULL; uint8_t eb_len = htud->boundary_len + 2; eb = (uint8_t *)SCMalloc(eb_len); if (eb == NULL) { goto error; } memset(eb, '-', eb_len); memcpy(eb + 2, htud->boundary, htud->boundary_len); uint8_t ebe_len = htud->boundary_len + 4; ebe = (uint8_t *)SCMalloc(ebe_len); if (ebe == NULL) { goto error; } memset(ebe, '-', ebe_len); memcpy(ebe + 2, htud->boundary, htud->boundary_len); *expected_boundary = eb; *expected_boundary_len = eb_len; *expected_boundary_end = ebe; *expected_boundary_end_len = ebe_len; SCReturnInt(0); error: if (eb != NULL) { SCFree(eb); } if (ebe != NULL) { SCFree(ebe); } SCReturnInt(-1); } #define C_D_HDR "content-disposition:" #define C_D_HDR_LEN 20 #define C_T_HDR "content-type:" #define C_T_HDR_LEN 13 static void HtpRequestBodyMultipartParseHeader(HtpState *hstate, uint8_t *header, uint32_t header_len, uint8_t **filename, uint16_t *filename_len, uint8_t **filetype, uint16_t *filetype_len) { uint8_t *fn = NULL; size_t fn_len = 0; uint8_t *ft = NULL; size_t ft_len = 0; #ifdef PRINT printf("HEADER START: \n"); PrintRawDataFp(stdout, header, header_len); printf("HEADER END: \n"); #endif while (header_len > 0) { uint8_t *next_line = Bs2bmSearch(header, header_len, (uint8_t *)"\r\n", 2); uint8_t *line = header; uint32_t line_len; if (next_line == NULL) { line_len = header_len; } else { line_len = next_line - header; } uint8_t *sc = (uint8_t *)memchr(line, ':', line_len); if (sc == NULL) { AppLayerDecoderEventsSetEvent(hstate->f, HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER); /* if the : we found is the final char, it means we have * no value */ } else if (line_len > 0 && sc == &line[line_len - 1]) { AppLayerDecoderEventsSetEvent(hstate->f, HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER); } else { #ifdef PRINT printf("LINE START: \n"); PrintRawDataFp(stdout, line, line_len); printf("LINE END: \n"); #endif if (line_len >= C_D_HDR_LEN && SCMemcmpLowercase(C_D_HDR, line, C_D_HDR_LEN) == 0) { uint8_t *value = line + C_D_HDR_LEN; uint32_t value_len = line_len - C_D_HDR_LEN; /* parse content-disposition */ (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9, value, value_len, &fn, &fn_len); } else if (line_len >= C_T_HDR_LEN && SCMemcmpLowercase(C_T_HDR, line, C_T_HDR_LEN) == 0) { SCLogDebug("content-type line"); uint8_t *value = line + C_T_HDR_LEN; uint32_t value_len = line_len - C_T_HDR_LEN; (void)HTTPParseContentTypeHeader(NULL, 0, value, value_len, &ft, &ft_len); } } if (next_line == NULL) { SCLogDebug("no next_line"); break; } header_len -= ((next_line + 2) - header); header = next_line + 2; } /* while (header_len > 0) */ if (fn_len > USHRT_MAX) fn_len = USHRT_MAX; if (ft_len > USHRT_MAX) ft_len = USHRT_MAX; *filename = fn; *filename_len = fn_len; *filetype = ft; *filetype_len = ft_len; } /** * \brief Create a single buffer from the HtpBodyChunks in our list * * \param htud transaction user data * \param chunks_buffers pointer to pass back the buffer to the caller * \param chunks_buffer_len pointer to pass back the buffer length to the caller */ static void HtpRequestBodyReassemble(HtpTxUserData *htud, uint8_t **chunks_buffer, uint32_t *chunks_buffer_len) { uint8_t *buf = NULL; uint32_t buf_len = 0; HtpBodyChunk *cur = htud->request_body.first; for ( ; cur != NULL; cur = cur->next) { SCLogDebug("chunk %p", cur); /* skip body chunks entirely before what we parsed already */ if (cur->stream_offset + cur->len <= htud->request_body.body_parsed) { SCLogDebug("skipping chunk"); continue; } SCLogDebug("cur->stream_offset %"PRIu64", cur->len %"PRIu32", body_parsed %"PRIu64, cur->stream_offset, cur->len, htud->request_body.body_parsed); if (cur->stream_offset < htud->request_body.body_parsed && cur->stream_offset + cur->len >= htud->request_body.body_parsed) { SCLogDebug("use part"); uint32_t toff = htud->request_body.body_parsed - cur->stream_offset; uint32_t tlen = (cur->stream_offset + cur->len) - htud->request_body.body_parsed; buf_len += tlen; if ((buf = SCRealloc(buf, buf_len)) == NULL) { buf_len = 0; break; } memcpy(buf + buf_len - tlen, cur->data + toff, tlen); } else { SCLogDebug("use entire chunk"); buf_len += cur->len; if ((buf = SCRealloc(buf, buf_len)) == NULL) { buf_len = 0; break; } memcpy(buf + buf_len - cur->len, cur->data, cur->len); } } *chunks_buffer = buf; *chunks_buffer_len = buf_len; } int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, uint8_t *chunks_buffer, uint32_t chunks_buffer_len) { int result = 0; uint8_t *expected_boundary = NULL; uint8_t *expected_boundary_end = NULL; uint8_t expected_boundary_len = 0; uint8_t expected_boundary_end_len = 0; #ifdef PRINT printf("CHUNK START: \n"); PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); printf("CHUNK END: \n"); #endif if (HtpRequestBodySetupBoundary(htud, &expected_boundary, &expected_boundary_len, &expected_boundary_end, &expected_boundary_end_len) < 0) { goto end; } /* search for the header start, header end and form end */ uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len, expected_boundary, expected_boundary_len); uint8_t *header_end = NULL; if (header_start != NULL) { header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer), (uint8_t *)"\r\n\r\n", 4); } uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len, expected_boundary_end, expected_boundary_end_len); SCLogDebug("header_start %p, header_end %p, form_end %p", header_start, header_end, form_end); /* if we're in the file storage process, deal with that now */ if (htud->tsflags & HTP_FILENAME_SET) { if (header_start != NULL || form_end != NULL || (htud->tsflags & HTP_REQ_BODY_COMPLETE)) { SCLogDebug("reached the end of the file"); uint8_t *filedata = chunks_buffer; uint32_t filedata_len = 0; uint8_t flags = 0; if (header_start < form_end || (header_start != NULL && form_end == NULL)) { filedata_len = header_start - filedata - 2; /* 0d 0a */ } else if (form_end != NULL && form_end < header_start) { filedata_len = form_end - filedata; } else if (form_end != NULL && form_end == header_start) { filedata_len = form_end - filedata - 2; /* 0d 0a */ } else if (htud->tsflags & HTP_REQ_BODY_COMPLETE) { filedata_len = chunks_buffer_len; flags = FILE_TRUNCATED; } if (filedata_len > chunks_buffer_len) { AppLayerDecoderEventsSetEvent(hstate->f, HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); goto end; } #ifdef PRINT printf("FILEDATA (final chunk) START: \n"); PrintRawDataFp(stdout, filedata, filedata_len); printf("FILEDATA (final chunk) END: \n"); #endif if (!(htud->tsflags & HTP_DONTSTORE)) { if (HTPFileClose(hstate, filedata, filedata_len, flags, STREAM_TOSERVER) == -1) { goto end; } } htud->tsflags &=~ HTP_FILENAME_SET; /* fall through */ } else { SCLogDebug("not yet at the end of the file"); if (chunks_buffer_len > expected_boundary_end_len) { uint8_t *filedata = chunks_buffer; uint32_t filedata_len = chunks_buffer_len - expected_boundary_len; #ifdef PRINT printf("FILEDATA (part) START: \n"); PrintRawDataFp(stdout, filedata, filedata_len); printf("FILEDATA (part) END: \n"); #endif if (!(htud->tsflags & HTP_DONTSTORE)) { result = HTPFileStoreChunk(hstate, filedata, filedata_len, STREAM_TOSERVER); if (result == -1) { goto end; } else if (result == -2) { /* we know for sure we're not storing the file */ htud->tsflags |= HTP_DONTSTORE; } } htud->request_body.body_parsed += filedata_len; } else { SCLogDebug("chunk too small to already process in part"); } goto end; } } while (header_start != NULL && header_end != NULL && header_end != form_end && header_start < (chunks_buffer + chunks_buffer_len) && header_end < (chunks_buffer + chunks_buffer_len) && header_start < header_end) { uint8_t *filename = NULL; uint16_t filename_len = 0; uint8_t *filetype = NULL; uint16_t filetype_len = 0; uint32_t header_len = header_end - header_start; SCLogDebug("header_len %u", header_len); uint8_t *header = header_start; /* skip empty records */ if (expected_boundary_len == header_len) { goto next; } else if ((uint32_t)(expected_boundary_len + 2) <= header_len) { header_len -= (expected_boundary_len + 2); header = header_start + (expected_boundary_len + 2); // + for 0d 0a } HtpRequestBodyMultipartParseHeader(hstate, header, header_len, &filename, &filename_len, &filetype, &filetype_len); if (filename != NULL) { uint8_t *filedata = NULL; uint32_t filedata_len = 0; SCLogDebug("we have a filename"); htud->tsflags |= HTP_FILENAME_SET; htud->tsflags &= ~HTP_DONTSTORE; SCLogDebug("header_end %p", header_end); SCLogDebug("form_end %p", form_end); /* everything until the final boundary is the file */ if (form_end != NULL) { filedata = header_end + 4; if (form_end == filedata) { AppLayerDecoderEventsSetEvent(hstate->f, HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA); goto end; } else if (form_end < filedata) { AppLayerDecoderEventsSetEvent(hstate->f, HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); goto end; } filedata_len = form_end - (header_end + 4 + 2); SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len); /* or is it? */ uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, expected_boundary, expected_boundary_len); if (header_next != NULL) { filedata_len -= (form_end - header_next); } if (filedata_len > chunks_buffer_len) { AppLayerDecoderEventsSetEvent(hstate->f, HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); goto end; } SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len); #ifdef PRINT printf("FILEDATA START: \n"); PrintRawDataFp(stdout, filedata, filedata_len); printf("FILEDATA END: \n"); #endif result = HTPFileOpen(hstate, filename, filename_len, filedata, filedata_len, hstate->transaction_cnt, STREAM_TOSERVER); if (result == -1) { goto end; } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } else { if (HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER) == -1) { goto end; } } htud->request_body.body_parsed += (header_end - chunks_buffer); htud->tsflags &= ~HTP_FILENAME_SET; } else { SCLogDebug("chunk doesn't contain form end"); filedata = header_end + 4; filedata_len = chunks_buffer_len - (filedata - chunks_buffer); SCLogDebug("filedata_len %u (chunks_buffer_len %u)", filedata_len, chunks_buffer_len); if (filedata_len > chunks_buffer_len) { AppLayerDecoderEventsSetEvent(hstate->f, HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); goto end; } #ifdef PRINT printf("FILEDATA START: \n"); PrintRawDataFp(stdout, filedata, filedata_len); printf("FILEDATA END: \n"); #endif /* form doesn't end in this chunk, but part might. Lets * see if have another coming up */ uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, expected_boundary, expected_boundary_len); SCLogDebug("header_next %p", header_next); if (header_next == NULL) { /* no, but we'll handle the file data when we see the * form_end */ SCLogDebug("more file data to come"); uint32_t offset = (header_end + 4) - chunks_buffer; SCLogDebug("offset %u", offset); htud->request_body.body_parsed += offset; result = HTPFileOpen(hstate, filename, filename_len, NULL, 0, hstate->transaction_cnt, STREAM_TOSERVER); if (result == -1) { goto end; } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } } else if (header_next - filedata > 2) { filedata_len = header_next - filedata - 2; SCLogDebug("filedata_len %u", filedata_len); result = HTPFileOpen(hstate, filename, filename_len, filedata, filedata_len, hstate->transaction_cnt, STREAM_TOSERVER); if (result == -1) { goto end; } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } else { if (HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER) == -1) { goto end; } } htud->tsflags &= ~HTP_FILENAME_SET; htud->request_body.body_parsed += (header_end - chunks_buffer); } } } next: SCLogDebug("header_start %p, header_end %p, form_end %p", header_start, header_end, form_end); /* Search next boundary entry after the start of body */ uint32_t cursizeread = header_end - chunks_buffer; header_start = Bs2bmSearch(header_end + 4, chunks_buffer_len - (cursizeread + 4), expected_boundary, expected_boundary_len); if (header_start != NULL) { header_end = Bs2bmSearch(header_end + 4, chunks_buffer_len - (cursizeread + 4), (uint8_t *) "\r\n\r\n", 4); } } end: if (expected_boundary != NULL) { SCFree(expected_boundary); } if (expected_boundary_end != NULL) { SCFree(expected_boundary_end); } SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed); return 0; } /** \brief setup things for put request * \todo really needed? */ int HtpRequestBodySetupPUT(htp_tx_data_t *d, HtpTxUserData *htud) { // if (d->tx->parsed_uri == NULL || d->tx->parsed_uri->path == NULL) { // return -1; // } /* filename is d->tx->parsed_uri->path */ return 0; } /** \internal * \brief Handle POST, no multipart body data */ static int HtpRequestBodyHandlePOST(HtpState *hstate, HtpTxUserData *htud, htp_tx_t *tx, uint8_t *data, uint32_t data_len) { int result = 0; /* see if we need to open the file */ if (!(htud->tsflags & HTP_FILENAME_SET)) { uint8_t *filename = NULL; size_t filename_len = 0; /* get the name */ if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) { filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path); filename_len = bstr_len(tx->parsed_uri->path); } if (filename != NULL) { result = HTPFileOpen(hstate, filename, (uint32_t)filename_len, data, data_len, hstate->transaction_cnt, STREAM_TOSERVER); if (result == -1) { goto end; } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } else { htud->tsflags |= HTP_FILENAME_SET; htud->tsflags &= ~HTP_DONTSTORE; } } } else { /* otherwise, just store the data */ if (!(htud->tsflags & HTP_DONTSTORE)) { result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOSERVER); if (result == -1) { goto end; } else if (result == -2) { /* we know for sure we're not storing the file */ htud->tsflags |= HTP_DONTSTORE; } } } return 0; end: return -1; } /** \internal * \brief Handle PUT body data */ static int HtpRequestBodyHandlePUT(HtpState *hstate, HtpTxUserData *htud, htp_tx_t *tx, uint8_t *data, uint32_t data_len) { int result = 0; /* see if we need to open the file */ if (!(htud->tsflags & HTP_FILENAME_SET)) { uint8_t *filename = NULL; size_t filename_len = 0; /* get the name */ if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) { filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path); filename_len = bstr_len(tx->parsed_uri->path); } if (filename != NULL) { result = HTPFileOpen(hstate, filename, (uint32_t)filename_len, data, data_len, hstate->transaction_cnt, STREAM_TOSERVER); if (result == -1) { goto end; } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } else { htud->tsflags |= HTP_FILENAME_SET; htud->tsflags &= ~HTP_DONTSTORE; } } } else { /* otherwise, just store the data */ if (!(htud->tsflags & HTP_DONTSTORE)) { result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOSERVER); if (result == -1) { goto end; } else if (result == -2) { /* we know for sure we're not storing the file */ htud->tsflags |= HTP_DONTSTORE; } } } return 0; end: return -1; } int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, htp_tx_t *tx, uint8_t *data, uint32_t data_len) { SCEnter(); int result = 0; /* see if we need to open the file */ if (!(htud->tcflags & HTP_FILENAME_SET)) { SCLogDebug("setting up file name"); uint8_t *filename = NULL; size_t filename_len = 0; /* try Content-Disposition header first */ htp_header_t *h = (htp_header_t *)table_getc(tx->response_headers, "Content-Disposition"); if (h != NULL && bstr_len(h->value) > 0) { /* parse content-disposition */ (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9, (uint8_t *) bstr_ptr(h->value), bstr_len(h->value), &filename, &filename_len); } /* fall back to name from the uri */ if (filename == NULL) { /* get the name */ if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) { filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path); filename_len = bstr_len(tx->parsed_uri->path); } } if (filename != NULL) { result = HTPFileOpen(hstate, filename, (uint32_t)filename_len, data, data_len, hstate->transaction_cnt, STREAM_TOCLIENT); SCLogDebug("result %d", result); if (result == -1) { goto end; } else if (result == -2) { htud->tcflags |= HTP_DONTSTORE; } else { htud->tcflags |= HTP_FILENAME_SET; htud->tcflags &= ~HTP_DONTSTORE; } } } else { /* otherwise, just store the data */ if (!(htud->tcflags & HTP_DONTSTORE)) { result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOCLIENT); SCLogDebug("result %d", result); if (result == -1) { goto end; } else if (result == -2) { /* we know for sure we're not storing the file */ htud->tcflags |= HTP_DONTSTORE; } } } return 0; end: return -1; } /** * \brief Function callback to append chunks for Requests * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib) * \retval int HOOK_OK if all goes well */ int HTPCallbackRequestBodyData(htp_tx_data_t *d) { SCEnter(); if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_REQUEST_BODY)) SCReturnInt(HOOK_OK); #ifdef PRINT printf("HTPBODY START: \n"); PrintRawDataFp(stdout, (uint8_t *)d->data, d->len); printf("HTPBODY END: \n"); #endif HtpState *hstate = (HtpState *)d->tx->connp->user_data; if (hstate == NULL) { SCReturnInt(HOOK_ERROR); } SCLogDebug("New request body data available at %p -> %p -> %p, bodylen " "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(d->tx); if (htud == NULL) { htud = SCMalloc(sizeof(HtpTxUserData)); if (unlikely(htud == NULL)) { SCReturnInt(HOOK_OK); } memset(htud, 0, sizeof(HtpTxUserData)); htud->operation = HTP_BODY_REQUEST; if (d->tx->request_method_number == M_POST) { SCLogDebug("POST"); int r = HtpRequestBodySetupMultipart(d, htud); if (r == 1) { htud->request_body_type = HTP_BODY_REQUEST_MULTIPART; } else if (r == 0) { htud->request_body_type = HTP_BODY_REQUEST_POST; SCLogDebug("not multipart"); } } else if (d->tx->request_method_number == M_PUT) { if (HtpRequestBodySetupPUT(d, htud) == 0) { htud->request_body_type = HTP_BODY_REQUEST_PUT; } } /* Set the user data for handling body chunks on this transaction */ htp_tx_set_user_data(d->tx, htud); } SCLogDebug("htud->request_body.content_len_so_far %"PRIu64, htud->request_body.content_len_so_far); SCLogDebug("hstate->cfg->request_body_limit %u", hstate->cfg->request_body_limit); /* within limits, add the body chunk to the state. */ if (hstate->cfg->request_body_limit == 0 || htud->request_body.content_len_so_far < hstate->cfg->request_body_limit) { uint32_t len = (uint32_t)d->len; if (hstate->cfg->request_body_limit > 0 && (htud->request_body.content_len_so_far + len) > hstate->cfg->request_body_limit) { len = hstate->cfg->request_body_limit - htud->request_body.content_len_so_far; BUG_ON(len > (uint32_t)d->len); } SCLogDebug("len %u", len); int r = HtpBodyAppendChunk(htud, &htud->request_body, (uint8_t *)d->data, len); if (r < 0) { htud->tsflags |= HTP_REQ_BODY_COMPLETE; } else if (hstate->cfg->request_body_limit > 0 && htud->request_body.content_len_so_far >= hstate->cfg->request_body_limit) { htud->tsflags |= HTP_REQ_BODY_COMPLETE; } else if (htud->request_body.content_len_so_far == htud->request_body.content_len) { htud->tsflags |= HTP_REQ_BODY_COMPLETE; } uint8_t *chunks_buffer = NULL; uint32_t chunks_buffer_len = 0; if (htud->request_body_type == HTP_BODY_REQUEST_MULTIPART) { /* multi-part body handling starts here */ if (!(htud->tsflags & HTP_BOUNDARY_SET)) { goto end; } HtpRequestBodyReassemble(htud, &chunks_buffer, &chunks_buffer_len); if (chunks_buffer == NULL) { goto end; } #ifdef PRINT printf("REASSCHUNK START: \n"); PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); printf("REASSCHUNK END: \n"); #endif HtpRequestBodyHandleMultipart(hstate, htud, chunks_buffer, chunks_buffer_len); if (chunks_buffer != NULL) { SCFree(chunks_buffer); } } else if (htud->request_body_type == HTP_BODY_REQUEST_POST) { HtpRequestBodyHandlePOST(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } else if (htud->request_body_type == HTP_BODY_REQUEST_PUT) { HtpRequestBodyHandlePUT(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } } end: /* see if we can get rid of htp body chunks */ HtpBodyPrune(&htud->request_body); /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; SCReturnInt(HOOK_OK); } /** * \brief Function callback to append chunks for Responses * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib) * \retval int HOOK_OK if all goes well */ int HTPCallbackResponseBodyData(htp_tx_data_t *d) { SCEnter(); if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_RESPONSE_BODY)) SCReturnInt(HOOK_OK); HtpState *hstate = (HtpState *)d->tx->connp->user_data; if (hstate == NULL) { SCReturnInt(HOOK_ERROR); } SCLogDebug("New response body data available at %p -> %p -> %p, bodylen " "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(d->tx); if (htud == NULL) { htud = SCMalloc(sizeof(HtpTxUserData)); if (unlikely(htud == NULL)) { SCReturnInt(HOOK_OK); } memset(htud, 0, sizeof(HtpTxUserData)); htud->operation = HTP_BODY_RESPONSE; htp_header_t *cl = table_getc(d->tx->response_headers, "content-length"); if (cl != NULL) htud->response_body.content_len = htp_parse_content_length(cl->value); /* Set the user data for handling body chunks on this transaction */ htp_tx_set_user_data(d->tx, htud); } SCLogDebug("htud->response_body.content_len_so_far %"PRIu64, htud->response_body.content_len_so_far); SCLogDebug("hstate->cfg->response_body_limit %u", hstate->cfg->response_body_limit); /* within limits, add the body chunk to the state. */ if (hstate->cfg->response_body_limit == 0 || htud->response_body.content_len_so_far < hstate->cfg->response_body_limit) { uint32_t len = (uint32_t)d->len; if (hstate->cfg->response_body_limit > 0 && (htud->response_body.content_len_so_far + len) > hstate->cfg->response_body_limit) { len = hstate->cfg->response_body_limit - htud->response_body.content_len_so_far; BUG_ON(len > (uint32_t)d->len); } SCLogDebug("len %u", len); int r = HtpBodyAppendChunk(htud, &htud->response_body, (uint8_t *)d->data, len); if (r < 0) { htud->tcflags |= HTP_RES_BODY_COMPLETE; } else if (hstate->cfg->response_body_limit > 0 && htud->response_body.content_len_so_far >= hstate->cfg->response_body_limit) { htud->tcflags |= HTP_RES_BODY_COMPLETE; } else if (htud->response_body.content_len_so_far == htud->response_body.content_len) { htud->tcflags |= HTP_RES_BODY_COMPLETE; } HtpResponseBodyHandle(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } /* see if we can get rid of htp body chunks */ HtpBodyPrune(&htud->response_body); /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; SCReturnInt(HOOK_OK); } /** * \brief Print the stats of the HTTP requests */ void HTPAtExitPrintStats(void) { #ifdef DEBUG SCEnter(); SCMutexLock(&htp_state_mem_lock); SCLogDebug("http_state_memcnt %"PRIu64", http_state_memuse %"PRIu64"", htp_state_memcnt, htp_state_memuse); SCMutexUnlock(&htp_state_mem_lock); SCReturn; #endif } /** \brief Clears the HTTP server configuration memory used by HTP library */ void HTPFreeConfig(void) { SCEnter(); HTPCfgRec *nextrec = cfglist.next; SCRadixReleaseRadixTree(cfgtree); htp_config_destroy(cfglist.cfg); while (nextrec != NULL) { HTPCfgRec *htprec = nextrec; nextrec = nextrec->next; htp_config_destroy(htprec->cfg); SCFree(htprec); } SCReturn; } /** * \brief callback for request to store the recent incoming request in to the recent_in_tx for the given htp state * \param connp pointer to the current connection parser which has the htp * state in it as user data */ static int HTPCallbackRequest(htp_connp_t *connp) { SCEnter(); HtpState *hstate = (HtpState *)connp->user_data; if (hstate == NULL) { SCReturnInt(HOOK_ERROR); } SCLogDebug("transaction_cnt %"PRIu16", list_size %"PRIuMAX, hstate->transaction_cnt, (uintmax_t)list_size(hstate->connp->conn->transactions)); SCLogDebug("HTTP request completed"); if (connp->in_tx != NULL) { HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(connp->in_tx); if (htud != NULL) { if (htud->tsflags & HTP_FILENAME_SET) { SCLogDebug("closing file that was being stored"); (void)HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER); htud->tsflags &= ~HTP_FILENAME_SET; } } } /* request done, do raw reassembly now to inspect state and stream * at the same time. */ AppLayerTriggerRawStreamReassembly(hstate->f); SCReturnInt(HOOK_OK); } /** * \brief callback for response to remove the recent received requests from the recent_in_tx for the given htp state * \param connp pointer to the current connection parser which has the htp * state in it as user data */ static int HTPCallbackResponse(htp_connp_t *connp) { SCEnter(); HtpState *hstate = (HtpState *)connp->user_data; if (hstate == NULL) { SCReturnInt(HOOK_ERROR); } /* we have one whole transaction now */ hstate->transaction_cnt++; /* Unset the body inspection (if any) */ hstate->flags &=~ HTP_FLAG_NEW_BODY_SET; if (connp->out_tx != NULL) { HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(connp->out_tx); if (htud != NULL) { if (htud->tcflags & HTP_FILENAME_SET) { SCLogDebug("closing file that was being stored"); (void)HTPFileClose(hstate, NULL, 0, 0, STREAM_TOCLIENT); htud->tcflags &= ~HTP_FILENAME_SET; } } } /* remove obsolete transactions */ size_t idx; for (idx = 0; idx < hstate->transaction_done; idx++) { SCLogDebug("idx %"PRIuMAX, (uintmax_t)idx); htp_tx_t *tx = list_get(hstate->connp->conn->transactions, idx); if (tx == NULL) continue; /* This will remove obsolete body chunks */ HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); if (htud != NULL) { HtpBodyFree(&htud->request_body); HtpBodyFree(&htud->response_body); SCFree(htud); htp_tx_set_user_data(tx, NULL); } htp_tx_destroy(tx); } /* response done, do raw reassembly now to inspect state and stream * at the same time. */ AppLayerTriggerRawStreamReassembly(hstate->f); SCReturnInt(HOOK_OK); } static void HTPConfigSetDefaults(HTPCfgRec *cfg_prec) { cfg_prec->request_body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT; cfg_prec->response_body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT; cfg_prec->request_inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE; cfg_prec->request_inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW; cfg_prec->response_inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE; cfg_prec->response_inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW; htp_config_register_request(cfg_prec->cfg, HTPCallbackRequest); htp_config_register_response(cfg_prec->cfg, HTPCallbackResponse); #ifdef HAVE_HTP_URI_NORMALIZE_HOOK htp_config_register_request_uri_normalize(cfg_prec->cfg, HTPCallbackRequestUriNormalizeQuery); #endif htp_config_set_generate_request_uri_normalized(cfg_prec->cfg, 1); htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData); htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData); return; } static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, SCRadixTree *tree) { if (cfg_prec == NULL || s == NULL || tree == NULL) return; ConfNode *p = NULL; /* Default Parameters */ TAILQ_FOREACH(p, &s->head, next) { if (strcasecmp("address", p->name) == 0) { ConfNode *pval; /* Addresses */ TAILQ_FOREACH(pval, &p->head, next) { SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name, pval->val); /* IPV6 or IPV4? */ if (strchr(pval->val, ':') != NULL) { SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p", s->name, pval->val, cfg_prec->cfg); if (SCRadixAddKeyIPV6String(pval->val, tree, cfg_prec) == NULL) { SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP failed to " "add ipv6 server %s, ignoring", pval->val); } } else { SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p", s->name, pval->val, cfg_prec->cfg); if (SCRadixAddKeyIPV4String(pval->val, tree, cfg_prec) == NULL) { SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP failed " "to add ipv4 server %s, ignoring", pval->val); } } /* else - if (strchr(pval->val, ':') != NULL) */ } /* TAILQ_FOREACH(pval, &p->head, next) */ } else if (strcasecmp("personality", p->name) == 0) { /* Personalities */ int personality = HTPLookupPersonality(p->val); SCLogDebug("LIBHTP default: %s = %s", p->name, p->val); SCLogDebug("LIBHTP default: %s = %s", p->name, p->val); if (personality >= 0) { SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val, personality); if (htp_config_set_server_personality(cfg_prec->cfg, personality) == HTP_ERROR){ SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP Failed adding " "personality \"%s\", ignoring", p->val); } else { SCLogDebug("LIBHTP personality set to %s", HTPLookupPersonalityString(personality)); } /* The IDS personality by default converts the path (and due to * our query string callback also the query string) to lowercase. * Signatures do not expect this, so override it. */ htp_config_set_path_case_insensitive(cfg_prec->cfg, 0); #ifdef HAVE_HTP_DECODE_QUERY_INPLACE htp_config_set_query_case_insensitive(cfg_prec->cfg, 0); #endif } else { SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Unknown personality " "\"%s\", ignoring", p->val); continue; } } else if (strcasecmp("request-body-limit", p->name) == 0 || strcasecmp("request_body_limit", p->name) == 0) { if (ParseSizeStringU32(p->val, &cfg_prec->request_body_limit) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-limit " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("response-body-limit", p->name) == 0) { if (ParseSizeStringU32(p->val, &cfg_prec->response_body_limit) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-limit " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) { if (ParseSizeStringU32(p->val, &cfg_prec->request_inspect_min_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-minimal-inspect-size " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("request-body-inspect-window", p->name) == 0) { if (ParseSizeStringU32(p->val, &cfg_prec->request_inspect_window) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-inspect-window " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) { if (ParseSizeStringU32(p->val, &cfg_prec->response_inspect_min_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-minimal-inspect-size " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("response-body-inspect-window", p->name) == 0) { if (ParseSizeStringU32(p->val, &cfg_prec->response_inspect_window) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-inspect-window " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("double-decode-path", p->name) == 0) { if (ConfValIsTrue(p->val)) { #ifdef HAVE_HTP_URI_NORMALIZE_HOOK htp_config_register_request_uri_normalize(cfg_prec->cfg, HTPCallbackRequestUriNormalizePath); #else SCLogWarning(SC_WARN_OUTDATED_LIBHTP, "\"double-decode-path\" " "option requires at least libhtp version 0.2.5"); #endif } /* if */ } else if (strcasecmp("double-decode-query", p->name) == 0) { if (ConfValIsTrue(p->val)) { #ifdef HAVE_HTP_URI_NORMALIZE_HOOK htp_config_register_request_uri_normalize(cfg_prec->cfg, HTPCallbackRequestUriNormalizeQuery); #else SCLogWarning(SC_WARN_OUTDATED_LIBHTP, "\"double-decode-query\" " "option requires at least libhtp version 0.2.5"); #endif } /* if */ } else if (strcasecmp("path-backslash-separators", p->name) == 0) { if (ConfValIsTrue(p->val)) htp_config_set_path_backslash_separators(cfg_prec->cfg, 1); else htp_config_set_path_backslash_separators(cfg_prec->cfg, 0); } else if (strcasecmp("path-compress-separators", p->name) == 0) { if (ConfValIsTrue(p->val)) htp_config_set_path_compress_separators(cfg_prec->cfg, 1); else htp_config_set_path_compress_separators(cfg_prec->cfg, 0); } else if (strcasecmp("path-control-char-handling", p->name) == 0) { if (strcasecmp(p->val, "none") == 0) { htp_config_set_path_control_char_handling(cfg_prec->cfg, NONE); } else if (strcasecmp(p->val, "status_400") == 0) { htp_config_set_path_control_char_handling(cfg_prec->cfg, STATUS_400); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry " "for libhtp param path-control-char-handling"); } } else if (strcasecmp("path-convert-utf8", p->name) == 0) { if (ConfValIsTrue(p->val)) htp_config_set_path_convert_utf8(cfg_prec->cfg, 1); else htp_config_set_path_convert_utf8(cfg_prec->cfg, 0); } else if (strcasecmp("path-decode-separators", p->name) == 0) { if (ConfValIsTrue(p->val)) htp_config_set_path_decode_separators(cfg_prec->cfg, 1); else htp_config_set_path_decode_separators(cfg_prec->cfg, 0); } else if (strcasecmp("path-decode-u-encoding", p->name) == 0) { if (ConfValIsTrue(p->val)) htp_config_set_path_decode_u_encoding(cfg_prec->cfg, 1); else htp_config_set_path_decode_u_encoding(cfg_prec->cfg, 0); } else if (strcasecmp("path-invalid-encoding-handling", p->name) == 0) { if (strcasecmp(p->val, "preserve_percent") == 0) { htp_config_set_path_invalid_encoding_handling(cfg_prec->cfg, URL_DECODER_PRESERVE_PERCENT); } else if (strcasecmp(p->val, "remove_percent") == 0) { htp_config_set_path_invalid_encoding_handling(cfg_prec->cfg, URL_DECODER_REMOVE_PERCENT); } else if (strcasecmp(p->val, "decode_invalid") == 0) { htp_config_set_path_invalid_encoding_handling(cfg_prec->cfg, URL_DECODER_DECODE_INVALID); } else if (strcasecmp(p->val, "status_400") == 0) { htp_config_set_path_invalid_encoding_handling(cfg_prec->cfg, STATUS_400); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry " "for libhtp param path-invalid-encoding-handling"); } } else if (strcasecmp("path-invalid-utf8-handling", p->name) == 0) { if (strcasecmp(p->val, "none") == 0) { htp_config_set_path_invalid_utf8_handling(cfg_prec->cfg, NONE); } else if (strcasecmp(p->val, "status_400") == 0) { htp_config_set_path_invalid_utf8_handling(cfg_prec->cfg, STATUS_400); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry " "for libhtp param path-invalid-utf8-handling"); } } else if (strcasecmp("path-nul-encoded-handling", p->name) == 0) { if (strcasecmp(p->val, "terminate") == 0) { htp_config_set_path_nul_encoded_handling(cfg_prec->cfg, TERMINATE); } else if (strcasecmp(p->val, "status_400") == 0) { htp_config_set_path_nul_encoded_handling(cfg_prec->cfg, STATUS_400); } else if (strcasecmp(p->val, "status_404") == 0) { htp_config_set_path_nul_encoded_handling(cfg_prec->cfg, STATUS_404); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry " "for libhtp param path-nul-encoded-handling"); } } else if (strcasecmp("path-nul-raw-handling", p->name) == 0) { if (strcasecmp(p->val, "terminate") == 0) { htp_config_set_path_nul_raw_handling(cfg_prec->cfg, TERMINATE); } else if (strcasecmp(p->val, "status_400") == 0) { htp_config_set_path_nul_raw_handling(cfg_prec->cfg, STATUS_400); } else if (strcasecmp(p->val, "status_404") == 0) { htp_config_set_path_nul_raw_handling(cfg_prec->cfg, STATUS_404); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry " "for libhtp param path-nul-raw-handling"); } } else if (strcasecmp("path-replacement-char", p->name) == 0) { if (strlen(p->val) == 1) { htp_config_set_path_replacement_char(cfg_prec->cfg, p->val[0]); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry " "for libhtp param set-path-replacement-char"); } } else if (strcasecmp("path-unicode-mapping", p->name) == 0) { if (strcasecmp(p->val, "bestfit") == 0) { htp_config_set_path_unicode_mapping(cfg_prec->cfg, BESTFIT); } else if (strcasecmp(p->val, "status_400") == 0) { htp_config_set_path_unicode_mapping(cfg_prec->cfg, STATUS_400); } else if (strcasecmp(p->val, "status_404") == 0) { htp_config_set_path_unicode_mapping(cfg_prec->cfg, STATUS_404); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry " "for libhtp param set-path-unicode-mapping"); } } else { SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Ignoring unknown " "default config: %s", p->name); } } /* TAILQ_FOREACH(p, &default_config->head, next) */ return; } void HTPConfigure(void) { SCEnter(); cfglist.next = NULL; cfgtree = SCRadixCreateRadixTree(NULL, NULL); if (NULL == cfgtree) exit(EXIT_FAILURE); /* Default Config */ cfglist.cfg = htp_config_create(); if (NULL == cfglist.cfg) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP default config"); exit(EXIT_FAILURE); } SCLogDebug("LIBHTP default config: %p", cfglist.cfg); HTPConfigSetDefaults(&cfglist); HTPConfigParseParameters(&cfglist, ConfGetNode("libhtp.default-config"), cfgtree); /* Read server config and create a parser for each IP in radix tree */ ConfNode *server_config = ConfGetNode("libhtp.server-config"); SCLogDebug("LIBHTP Configuring %p", server_config); if (server_config == NULL) SCReturn; ConfNode *si; /* Server Nodes */ TAILQ_FOREACH(si, &server_config->head, next) { /* Need the named node, not the index */ ConfNode *s = TAILQ_FIRST(&si->head); if (NULL == s) { SCLogDebug("LIBHTP s NULL"); continue; } SCLogDebug("LIBHTP server %s", s->name); HTPCfgRec *nextrec = cfglist.next; HTPCfgRec *htprec = cfglist.next = SCMalloc(sizeof(HTPCfgRec)); if (NULL == htprec) exit(EXIT_FAILURE); cfglist.next->next = nextrec; cfglist.next->cfg = htp_config_create(); if (NULL == cfglist.next->cfg) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP server config"); exit(EXIT_FAILURE); } HTPConfigSetDefaults(htprec); HTPConfigParseParameters(htprec, s, cfgtree); } SCReturn; } void AppLayerHtpPrintStats(void) { #ifdef DEBUG SCMutexLock(&htp_state_mem_lock); SCLogInfo("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); SCMutexUnlock(&htp_state_mem_lock); #endif } /** \internal * \brief get files callback * \param state state ptr * \param direction flow direction * \retval files files ptr */ static FileContainer *HTPStateGetFiles(void *state, uint8_t direction) { if (state == NULL) return NULL; HtpState *http_state = (HtpState *)state; if (direction & STREAM_TOCLIENT) { SCReturnPtr(http_state->files_tc, "FileContainer"); } else { SCReturnPtr(http_state->files_ts, "FileContainer"); } } static void HTPStateTruncate(void *state, uint8_t flags) { FileContainer *fc = HTPStateGetFiles(state, flags); if (fc != NULL) { FileTruncateAllOpenFiles(fc); } } /** * \brief Register the HTTP protocol and state handling functions to APP layer * of the engine. */ void RegisterHTPParsers(void) { SCEnter(); char *proto_name = "http"; /** HTTP */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "GET|20|", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "GET|09|", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "PUT|20|", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "PUT|09|", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "POST|20|", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "POST|09|", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "HEAD|20|", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "HEAD|09|", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "TRACE|20|", 6, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "TRACE|09|", 6, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS|20|", 8, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS|09|", 8, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "CONNECT|20|", 8, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_HTTP, "CONNECT|09|", 8, 0, STREAM_TOSERVER); AppLayerRegisterStateFuncs(ALPROTO_HTTP, HTPStateAlloc, HTPStateFree); AppLayerRegisterTransactionIdFuncs(ALPROTO_HTTP, HTPStateUpdateTransactionId, HTPStateTransactionFree); AppLayerRegisterGetFilesFunc(ALPROTO_HTTP, HTPStateGetFiles); AppLayerDecoderEventsModuleRegister(ALPROTO_HTTP, http_decoder_event_table); AppLayerRegisterTruncateFunc(ALPROTO_HTTP, HTPStateTruncate); AppLayerRegisterProto(proto_name, ALPROTO_HTTP, STREAM_TOSERVER, HTPHandleRequestData); AppLayerRegisterProto(proto_name, ALPROTO_HTTP, STREAM_TOCLIENT, HTPHandleResponseData); SC_ATOMIC_INIT(htp_config_flags); HTPConfigure(); SCReturn; } #ifdef UNITTESTS static HTPCfgRec cfglist_backup; void HtpConfigCreateBackup(void) { cfglist_backup.cfg = cfglist.cfg; cfglist_backup.next = cfglist.next; cfglist_backup.request_body_limit = cfglist.request_body_limit; return; } void HtpConfigRestoreBackup(void) { cfglist.cfg = cfglist_backup.cfg; cfglist.next = cfglist_backup.next; cfglist.request_body_limit = cfglist_backup.request_body_limit; return; } /** \test Test case where chunks are sent in smaller chunks and check the * response of the parser from HTP library. */ int HTPParserTest01(void) { int result = 1; Flow *f = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" " Data is c0oL!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); table_iterator_next(tx->request_headers, (void **) & h); if (strcmp(bstr_tocstr(h->value), "Victor/1.0") || tx->request_method_number != M_POST || tx->request_protocol_number != HTTP_1_0) { printf("expected header value: Victor/1.0 and got %s: and expected" " method: POST and got %s, expected protocol number HTTP/1.0" " and got: %s \n", bstr_tocstr(h->value), bstr_tocstr(tx->request_method), bstr_tocstr(tx->request_protocol)); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test See how it deals with an incomplete request. */ int HTPParserTest02(void) { int result = 1; Flow *f = NULL; uint8_t httpbuf1[] = "POST"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); table_iterator_next(tx->request_headers, (void **) & h); if ((tx->request_method) != NULL || h != NULL) { printf("expected method NULL, got %s \n", bstr_tocstr(tx->request_method)); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } /** \test Test case where method is invalid and data is sent in smaller chunks * and check the response of the parser from HTP library. */ int HTPParserTest03(void) { int result = 1; Flow *f = NULL; uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); table_iterator_next(tx->request_headers, (void **) & h); if (tx->request_method_number != M_UNKNOWN || h != NULL || tx->request_protocol_number != HTTP_1_0) { printf("expected method M_UNKNOWN and got %s: , expected protocol " "HTTP/1.0 and got %s \n", bstr_tocstr(tx->request_method), bstr_tocstr(tx->request_protocol)); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test Test case where invalid data is sent and check the response of the * parser from HTP library. */ int HTPParserTest04(void) { int result = 1; Flow *f = NULL; HtpState *htp_state = NULL; uint8_t httpbuf1[] = "World!\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| STREAM_EOF, httpbuf1, httplen1); if (r != 0) { goto end; } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); table_iterator_next(tx->request_headers, (void **) & h); if (tx->request_method_number != M_UNKNOWN || h != NULL || tx->request_protocol_number != PROTOCOL_UNKNOWN) { printf("expected method M_UNKNOWN and got %s: , expected protocol " "NULL and got %s \n", bstr_tocstr(tx->request_method), bstr_tocstr(tx->request_protocol)); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test Test both sides of a http stream mixed up to see if the HTP parser * properly parsed them and also keeps them separated. */ int HTPParserTest05(void) { int result = 1; Flow *f = NULL; HtpState *http_state = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "Post D"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "ata is c0oL!"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "post R"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint8_t httpbuf6[] = "esults are tha bomb!"; uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ TcpSession ssn; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); table_iterator_next(tx->request_headers, (void **) & h); if (tx->request_method_number != M_POST || h == NULL || tx->request_protocol_number != HTTP_1_0) { printf("expected method M_POST and got %s: , expected protocol " "HTTP/1.0 and got %s \n", bstr_tocstr(tx->request_method), bstr_tocstr(tx->request_protocol)); result = 0; goto end; } if (tx->response_status_number != 200) { printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " "HTTP/1.0 and got %s \n", tx->response_status_number, bstr_tocstr(tx->response_message), bstr_tocstr(tx->response_protocol)); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } /** \test Test proper chunked encoded response body */ int HTPParserTest06(void) { int result = 1; Flow *f = NULL; uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 " "GMT\r\n" "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 " "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 " "FrontPage/5.0.2.2510\r\n" "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: " "chunked\r\n" "Content-Type: text/html\r\n\r\n" "1408\r\n" "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu" "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN" "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N" "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk" "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l" "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN" "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt" "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz" "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw" "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps" "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw" "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9" "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N" "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu" "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3" "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo" "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv" "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh" "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5" "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx" "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y" "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv" "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv" "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n" "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt" "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N" "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w" "aHA=0\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); table_iterator_next(tx->request_headers, (void **) & h); if (tx->request_method_number != M_GET || h == NULL || tx->request_protocol_number != HTTP_1_1) { printf("expected method M_GET and got %s: , expected protocol " "HTTP/1.1 and got %s \n", bstr_tocstr(tx->request_method), bstr_tocstr(tx->request_protocol)); result = 0; goto end; } if (tx->response_status_number != 200 || h == NULL || tx->request_protocol_number != HTTP_1_1) { printf("expected response 200 OK and got %"PRId32" %s: , expected proto" "col HTTP/1.1 and got %s \n", tx->response_status_number, bstr_tocstr(tx->response_message), bstr_tocstr(tx->response_protocol)); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } /** \test */ int HTPParserTest07(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } uint8_t ref[] = "/awstats.pl?/migratemigrate = |"; size_t reflen = sizeof(ref) - 1; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref, reflen); printf("\": "); goto end; } } result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } #include "conf-yaml-loader.h" /** \test Abort */ int HTPParserTest08(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint8_t flags = 0; flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); result = 0; goto end; } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { //printf("uri %s\n", bstr_tocstr(tx->request_uri_normalized)); PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized)); } result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); UTHFreeFlow(f); return result; } /** \test Abort */ int HTPParserTest09(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: Apache_2_2\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint8_t flags = 0; flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); result = 0; goto end; } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { //printf("uri %s\n", bstr_tocstr(tx->request_uri_normalized)); PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_len(tx->request_uri_normalized)); } result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); UTHFreeFlow(f); return result; } /** \test Host:www.google.com <- missing space between name:value (rfc violation) */ int HTPParserTest10(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); table_iterator_next(tx->request_headers, (void **) & h); if (h == NULL) { goto end; } char *name = bstr_tocstr(h->name); if (name == NULL) { goto end; } if (strcmp(name, "Host") != 0) { printf("header name not \"Host\", instead \"%s\": ", name); free(name); goto end; } free(name); char *value = bstr_tocstr(h->value); if (value == NULL) { goto end; } if (strcmp(value, "www.google.com") != 0) { printf("header value not \"www.google.com\", instead \"%s\": ", value); free(value); goto end; } free(value); result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test double encoding in path */ static int HTPParserTest11(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { if (4 != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be 2, is %"PRIuMAX, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (bstr_ptr(tx->request_uri_normalized)[0] != '/' || bstr_ptr(tx->request_uri_normalized)[1] != '%' || bstr_ptr(tx->request_uri_normalized)[2] != '0' || bstr_ptr(tx->request_uri_normalized)[3] != '0') { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\": "); goto end; } } result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test double encoding in query */ static int HTPParserTest12(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { if (7 != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be 5, is %"PRIuMAX, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (bstr_ptr(tx->request_uri_normalized)[0] != '/' || bstr_ptr(tx->request_uri_normalized)[1] != '?' || bstr_ptr(tx->request_uri_normalized)[2] != 'a' || bstr_ptr(tx->request_uri_normalized)[3] != '=' || bstr_ptr(tx->request_uri_normalized)[4] != '%' || bstr_ptr(tx->request_uri_normalized)[5] != '0' || bstr_ptr(tx->request_uri_normalized)[6] != '0') { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\": "); goto end; } } result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation) */ int HTPParserTest13(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); goto end; } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); htp_header_t *h = NULL; table_iterator_reset(tx->request_headers); table_iterator_next(tx->request_headers, (void **) & h); if (h == NULL) { goto end; } char *name = bstr_tocstr(h->name); if (name == NULL) { goto end; } if (strcmp(name, "Host") != 0) { printf("header name not \"Host\", instead \"%s\": ", name); free(name); goto end; } free(name); char *value = bstr_tocstr(h->value); if (value == NULL) { goto end; } if (strcmp(value, "www.google.com\rName: Value") != 0) { printf("header value not \"www.google.com\", instead \""); PrintRawUriFp(stdout, (uint8_t *)value, strlen(value)); printf("\": "); free(value); goto end; } free(value); result = 1; end: StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test Test basic config */ int HTPParserConfigTest01(void) { int ret = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ \n\ server-config:\n\ \n\ - apache-tomcat:\n\ address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ personality: Tomcat_6_0\n\ \n\ - iis7:\n\ address: \n\ - 192.168.0.0/24\n\ - 192.168.10.0/24\n\ personality: IIS_7_0\n\ "; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(input, strlen(input)); ConfNode *outputs; outputs = ConfGetNode("libhtp.default-config.personality"); if (outputs == NULL) { goto end; } outputs = ConfGetNode("libhtp.server-config"); if (outputs == NULL) { goto end; } ConfNode *node = TAILQ_FIRST(&outputs->head); if (node == NULL) { goto end; } if (strcmp(node->name, "0") != 0) { goto end; } node = TAILQ_FIRST(&node->head); if (node == NULL) { goto end; } if (strcmp(node->name, "apache-tomcat") != 0) { goto end; } int i = 0; ConfNode *n; ConfNode *node2 = ConfNodeLookupChild(node, "personality"); if (node2 == NULL) { goto end; } if (strcmp(node2->val, "Tomcat_6_0") != 0) { goto end; } node = ConfNodeLookupChild(node, "address"); if (node == NULL) { goto end; } TAILQ_FOREACH(n, &node->head, next) { if (n == NULL) { goto end; } switch(i) { case 0: if (strcmp(n->name, "0") != 0) { goto end; } if (strcmp(n->val, "192.168.1.0/24") != 0) { goto end; } break; case 1: if (strcmp(n->name, "1") != 0) { goto end; } if (strcmp(n->val, "127.0.0.0/8") != 0) { goto end; } break; case 2: if (strcmp(n->name, "2") != 0) { goto end; } if (strcmp(n->val, "::1") != 0) { goto end; } break; default: goto end; } i++; } outputs = ConfGetNode("libhtp.server-config"); if (outputs == NULL) { goto end; } node = TAILQ_FIRST(&outputs->head); node = TAILQ_NEXT(node, next); if (node == NULL) { goto end; } if (strcmp(node->name, "1") != 0) { goto end; } node = TAILQ_FIRST(&node->head); if (node == NULL) { goto end; } if (strcmp(node->name, "iis7") != 0) { goto end; } node2 = ConfNodeLookupChild(node, "personality"); if (node2 == NULL) { goto end; } if (strcmp(node2->val, "IIS_7_0") != 0) { goto end; } node = ConfNodeLookupChild(node, "address"); if (node == NULL) { goto end; } i = 0; TAILQ_FOREACH(n, &node->head, next) { if (n == NULL) { goto end; } switch(i) { case 0: if (strcmp(n->name, "0") != 0) { goto end; } if (strcmp(n->val, "192.168.0.0/24") != 0) { goto end; } break; case 1: if (strcmp(n->name, "1") != 0) { goto end; } if (strcmp(n->val, "192.168.10.0/24") != 0) { goto end; } break; default: goto end; } i++; } ret = 1; end: ConfDeInit(); ConfRestoreContextBackup(); return ret; } /** \test Test config builds radix correctly */ int HTPParserConfigTest02(void) { int ret = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ \n\ server-config:\n\ \n\ - apache-tomcat:\n\ address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ personality: Tomcat_6_0\n\ \n\ - iis7:\n\ address: \n\ - 192.168.0.0/24\n\ - 192.168.10.0/24\n\ personality: IIS_7_0\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); if (cfglist.cfg == NULL) { printf("No default config created.\n"); goto end; } if (cfgtree == NULL) { printf("No config tree created.\n"); goto end; } SCRadixNode *cfgnode = NULL; htp_cfg_t *htp = cfglist.cfg; uint8_t buf[128]; const char *addr; addr = "192.168.10.42"; if (inet_pton(AF_INET, addr, buf) == 1) { cfgnode = SCRadixFindKeyIPV4BestMatch(buf, cfgtree); if (cfgnode != NULL) { HTPCfgRec *htp_cfg_rec = SC_RADIX_NODE_USERDATA(cfgnode, HTPCfgRec); if (htp_cfg_rec != NULL) { htp = htp_cfg_rec->cfg; SCLogDebug("LIBHTP using config: %p", htp); } } if (htp == NULL) { printf("Could not get config for: %s\n", addr); goto end; } } else { printf("Failed to parse address: %s\n", addr); goto end; } addr = "::1"; if (inet_pton(AF_INET6, addr, buf) == 1) { cfgnode = SCRadixFindKeyIPV6BestMatch(buf, cfgtree); if (cfgnode != NULL) { HTPCfgRec *htp_cfg_rec = SC_RADIX_NODE_USERDATA(cfgnode, HTPCfgRec); if (htp_cfg_rec != NULL) { htp = htp_cfg_rec->cfg; SCLogDebug("LIBHTP using config: %p", htp); } } if (htp == NULL) { printf("Could not get config for: %s\n", addr); goto end; } } else { printf("Failed to parse address: %s\n", addr); goto end; } ret = 1; end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); return ret; } /** \test Test traffic is handled by the correct htp config */ int HTPParserConfigTest03(void) { int result = 1; Flow *f = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" " Data is c0oL!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ \n\ server-config:\n\ \n\ - apache-tomcat:\n\ address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ personality: Tomcat_6_0\n\ \n\ - iis7:\n\ address: \n\ - 192.168.0.0/24\n\ - 192.168.10.0/24\n\ personality: IIS_7_0\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); char *addr = "192.168.10.42"; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; SCRadixNode *cfgnode = NULL; htp_cfg_t *htp = cfglist.cfg; cfgnode = SCRadixFindKeyIPV4BestMatch((uint8_t *)f->dst.addr_data32, cfgtree); if (cfgnode != NULL) { HTPCfgRec *htp_cfg_rec = SC_RADIX_NODE_USERDATA(cfgnode, HTPCfgRec); if (htp_cfg_rec != NULL) { htp = htp_cfg_rec->cfg; SCLogDebug("LIBHTP using config: %p", htp); } } if (htp == NULL) { printf("Could not get config for: %s\n", addr); goto end; } StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } /* Check that the HTP state config matches the correct one */ if (htp_state->connp->cfg != htp) { printf("wrong HTP config (%p instead of %p - default=%p): ", htp_state->connp->cfg, htp, cfglist.cfg); result = 0; goto end; } end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } int HTPParserConfigTest04(void) { int result = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ path-control-char-handling: status_400\n\ path-convert-utf8: yes\n\ path-invalid-encoding-handling: remove_percent\n\ \n\ server-config:\n\ \n\ - apache-tomcat:\n\ personality: Tomcat_6_0\n\ path-invalid-utf8-handling: none\n\ path-nul-encoded-handling: status_404\n\ path-nul-raw-handling: status_400\n\ \n\ - iis7:\n\ personality: IIS_7_0\n\ path-replacement-char: o\n\ path-unicode-mapping: status_400\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); HTPCfgRec *cfg_rec = &cfglist; if (cfg_rec->cfg->path_control_char_handling != STATUS_400 || cfg_rec->cfg->path_convert_utf8 != 1 || cfg_rec->cfg->path_invalid_encoding_handling != URL_DECODER_REMOVE_PERCENT) { printf("failed 1\n"); goto end; } cfg_rec = cfg_rec->next; if (cfg_rec->cfg->path_replacement_char != 'o' || cfg_rec->cfg->path_unicode_mapping != STATUS_400) { printf("failed 2\n"); goto end; } cfg_rec = cfg_rec->next; if (cfg_rec->cfg->path_invalid_utf8_handling != NONE || cfg_rec->cfg->path_nul_encoded_handling != STATUS_404 || cfg_rec->cfg->path_nul_raw_handling != STATUS_400) { printf("failed 3\n"); goto end; } result = 1; end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); return result; } /** \test Test %2f decoding in profile Apache_2_2 * * %2f in path is left untouched * %2f in query string is normalized to %2F * %252f in query string is decoded/normalized to %2F */ static int HTPParserDecodingTest01(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: Apache_2_2\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); char *addr = "4.3.2.1"; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } uint8_t ref1[] = "/abc%2fdef"; size_t reflen = sizeof(ref1) - 1; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref1, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref1, reflen); printf("\": "); goto end; } } uint8_t ref2[] = "/abc/def?ghi%2Fjkl"; reflen = sizeof(ref2) - 1; tx = list_get(htp_state->connp->conn->transactions, 1); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref2, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref2, reflen); printf("\": "); goto end; } } uint8_t ref3[] = "/abc/def?ghi%2Fjkl"; reflen = sizeof(ref2) - 1; tx = list_get(htp_state->connp->conn->transactions, 2); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref3, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref3, reflen); printf("\": "); goto end; } } result = 1; end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test Test %2f decoding in profile IDS * * %2f in path decoded to / * %2f in query string is decoded to / * %252f in query string is decoded to %2F */ static int HTPParserDecodingTest02(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ double-decode-path: no\n\ double-decode-query: no\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); char *addr = "4.3.2.1"; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } uint8_t ref1[] = "/abc/def"; size_t reflen = sizeof(ref1) - 1; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref1, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref1, reflen); printf("\": "); goto end; } } uint8_t ref2[] = "/abc/def?ghi/jkl"; reflen = sizeof(ref2) - 1; tx = list_get(htp_state->connp->conn->transactions, 1); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref2, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref2, reflen); printf("\": "); goto end; } } uint8_t ref3[] = "/abc/def?ghi%2Fjkl"; reflen = sizeof(ref3) - 1; tx = list_get(htp_state->connp->conn->transactions, 2); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX" (3): ", (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref3, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref3, reflen); printf("\": "); goto end; } } result = 1; end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test Test %2f decoding in profile IDS with double-decode-* options * * %252f in path decoded to / * %252f in query string is decoded to / */ static int HTPParserDecodingTest03(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ double-decode-path: yes\n\ double-decode-query: yes\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); char *addr = "4.3.2.1"; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } uint8_t ref1[] = "/abc/def"; size_t reflen = sizeof(ref1) - 1; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref1, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref1, reflen); printf("\": "); goto end; } } uint8_t ref2[] = "/abc/def?ghi/jkl"; reflen = sizeof(ref2) - 1; tx = list_get(htp_state->connp->conn->transactions, 1); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref2, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref2, reflen); printf("\": "); goto end; } } result = 1; end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test Test http:// in query profile IDS */ static int HTPParserDecodingTest04(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ double-decode-path: yes\n\ double-decode-query: yes\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); char *addr = "4.3.2.1"; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } uint8_t ref1[] = "/abc/def?a=http://www.abc.com/"; size_t reflen = sizeof(ref1) - 1; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref1, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref1, reflen); printf("\": "); goto end; } } result = 1; end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test Test \ char in query profile IDS. Bug 739 */ static int HTPParserDecodingTest05(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /index?id=\\\" HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; HtpState *htp_state = NULL; int r = 0; char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ double-decode-path: yes\n\ double-decode-query: yes\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); char *addr = "4.3.2.1"; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); uint32_t u; for (u = 0; u < httplen1; u++) { uint8_t flags = 0; if (u == 0) flags = STREAM_TOSERVER|STREAM_START; else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; goto end; } } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); result = 0; goto end; } uint8_t ref1[] = "/index?id=\\\""; size_t reflen = sizeof(ref1) - 1; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); if (tx != NULL && tx->request_uri_normalized != NULL) { if (reflen != bstr_size(tx->request_uri_normalized)) { printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, (uintmax_t)reflen, (uintmax_t)bstr_size(tx->request_uri_normalized)); goto end; } if (memcmp(bstr_ptr(tx->request_uri_normalized), ref1, bstr_size(tx->request_uri_normalized)) != 0) { printf("normalized uri \""); PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); printf("\" != \""); PrintRawUriFp(stdout, ref1, reflen); printf("\": "); goto end; } } result = 1; end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); UTHFreeFlow(f); return result; } /** \test BG box crash -- chunks are messed up. Observed for real. */ static int HTPBodyReassemblyTest01(void) { int result = 0; HtpTxUserData htud; memset(&htud, 0x00, sizeof(htud)); HtpState hstate; memset(&hstate, 0x00, sizeof(hstate)); Flow flow; memset(&flow, 0x00, sizeof(flow)); AppLayerParserStateStore parser; memset(&parser, 0x00, sizeof(parser)); hstate.f = &flow; flow.alparser = &parser; uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; uint8_t chunk2[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; int r = HtpBodyAppendChunk(&htud, &htud.request_body, (uint8_t *)chunk1, sizeof(chunk1)-1); BUG_ON(r != 0); r = HtpBodyAppendChunk(&htud, &htud.request_body, (uint8_t *)chunk2, sizeof(chunk2)-1); BUG_ON(r != 0); uint8_t *chunks_buffer = NULL; uint32_t chunks_buffer_len = 0; HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len); if (chunks_buffer == NULL) { goto end; } #ifdef PRINT printf("REASSCHUNK START: \n"); PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); printf("REASSCHUNK END: \n"); #endif HtpRequestBodyHandleMultipart(&hstate, &htud, chunks_buffer, chunks_buffer_len); if (htud.request_body.content_len_so_far != 669) { printf("htud.request_body.content_len_so_far %"PRIu64": ", htud.request_body.content_len_so_far); goto end; } if (hstate.files_ts != NULL) goto end; result = 1; end: return result; } /** \test BG crash */ static int HTPSegvTest01(void) { int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ double-decode-path: no\n\ double-decode-query: no\n\ request-body-limit: 0\n\ response-body-limit: 0\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); TcpSession ssn; HtpState *http_state = NULL; memset(&ssn, 0, sizeof(ssn)); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SCLogDebug("\n>>>> processing chunk 1 again <<<<\n"); r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } AppLayerDecoderEvents *decoder_events = AppLayerGetDecoderEventsForFlow(f); if (decoder_events != NULL) { printf("app events: "); goto end; } result = 1; end: HTPFreeConfig(); ConfDeInit(); ConfRestoreContextBackup(); HtpConfigRestoreBackup(); StreamTcpFreeConfig(TRUE); if (http_state != NULL) HTPStateFree(http_state); UTHFreeFlow(f); return result; } #endif /* UNITTESTS */ /** * \brief Register the Unit tests for the HTTP protocol */ void HTPParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("HTPParserTest01", HTPParserTest01, 1); UtRegisterTest("HTPParserTest02", HTPParserTest02, 1); UtRegisterTest("HTPParserTest03", HTPParserTest03, 1); UtRegisterTest("HTPParserTest04", HTPParserTest04, 1); UtRegisterTest("HTPParserTest05", HTPParserTest05, 1); UtRegisterTest("HTPParserTest06", HTPParserTest06, 1); UtRegisterTest("HTPParserTest07", HTPParserTest07, 1); UtRegisterTest("HTPParserTest08", HTPParserTest08, 1); UtRegisterTest("HTPParserTest09", HTPParserTest09, 1); UtRegisterTest("HTPParserTest10", HTPParserTest10, 1); UtRegisterTest("HTPParserTest11", HTPParserTest11, 1); UtRegisterTest("HTPParserTest12", HTPParserTest12, 1); UtRegisterTest("HTPParserTest13", HTPParserTest13, 1); UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01, 1); UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02, 1); UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03, 1); UtRegisterTest("HTPParserConfigTest04", HTPParserConfigTest04, 1); UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01, 1); UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02, 1); UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03, 1); UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04, 1); UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05, 1); UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01, 1); UtRegisterTest("HTPSegvTest01", HTPSegvTest01, 1); HTPFileParserRegisterTests(); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/detect-engine-siggroup.h0000644000000000000000000000774412253546156015562 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_SIGGROUP_H__ #define __DETECT_ENGINE_SIGGROUP_H__ void DetectSigGroupPrintMemory(void); int SigGroupHeadAppendSig(DetectEngineCtx *, SigGroupHead **, Signature *); int SigGroupHeadClearSigs(SigGroupHead *); int SigGroupHeadCopySigs(DetectEngineCtx *, SigGroupHead *, SigGroupHead **); int SigGroupHeadLoadContent(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadLoadUricontent(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadLoadStreamContent(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadClearContent(SigGroupHead *); int SigGroupHeadClearUricontent(SigGroupHead *); int SigGroupHeadClearStreamContent(SigGroupHead *); void SigGroupHeadFree(SigGroupHead *); void SigGroupHeadFreeMpmArrays(DetectEngineCtx *); SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadMpmHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadMpmUriHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadMpmStreamHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadDPortHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadSPortHashLookup(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadMpmHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadMpmUriHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadMpmStreamHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadDPortHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadSPortHashAdd(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadHashFree(DetectEngineCtx *); void SigGroupHeadMpmHashFree(DetectEngineCtx *); void SigGroupHeadMpmUriHashFree(DetectEngineCtx *); void SigGroupHeadMpmStreamHashFree(DetectEngineCtx *); void SigGroupHeadDPortHashFree(DetectEngineCtx *); void SigGroupHeadSPortHashFree(DetectEngineCtx *); int SigGroupHeadHashInit(DetectEngineCtx *); int SigGroupHeadMpmHashInit(DetectEngineCtx *); int SigGroupHeadMpmUriHashInit(DetectEngineCtx *); int SigGroupHeadDPortHashInit(DetectEngineCtx *); int SigGroupHeadSPortHashInit(DetectEngineCtx *); int SigGroupHeadHashRemove(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadSPortHashRemove(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid); void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx); int SigGroupHeadBuildMatchArray (DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx); void SigGroupHeadFreeSigArrays(DetectEngineCtx *de_ctx); int SigGroupHeadContainsSigId (DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid); void SigGroupHeadRegisterTests(void); void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh); void SigGroupHeadStore(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadBuildHeadArray(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilestoreCount(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *, SigGroupHead *); #endif /* __DETECT_ENGINE_SIGGROUP_H__ */ suricata-1.4.7/src/conf.c0000644000000000000000000007010112253546156012115 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited - Jason Ish * * This file provides a basic configuration system for the IDPS * engine. * * NOTE: Setting values should only be done from one thread during * engine initialization. Multiple threads should be able access read * configuration data. Allowing run time changes to the configuration * will require some locks. * * \todo Consider having the in-memory configuration database a direct * reflection of the configuration file and moving command line * parameters to a primary lookup table? * * \todo Get rid of allow override and go with a simpler first set, * stays approach? */ #include "suricata-common.h" #include "conf.h" #include "util-unittest.h" #include "util-debug.h" #include "util-path.h" static ConfNode *root = NULL; static ConfNode *root_backup = NULL; /** * \brief Initialize the configuration system. */ void ConfInit(void) { if (root != NULL) { SCLogDebug("already initialized"); return; } root = ConfNodeNew(); if (root == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "ERROR: Failed to allocate memory for root configuration node, " "aborting."); exit(EXIT_FAILURE); } SCLogDebug("configuration module initialized"); } /** * \brief Allocate a new configuration node. * * \retval An allocated configuration node on success, NULL on failure. */ ConfNode * ConfNodeNew(void) { ConfNode *new; new = SCCalloc(1, sizeof(*new)); if (unlikely(new == NULL)) { return NULL; } /* By default we allow an override. */ new->allow_override = 1; TAILQ_INIT(&new->head); return new; } /** * \brief Free a ConfNode and all of its children. * * \param node The configuration node to SCFree. */ void ConfNodeFree(ConfNode *node) { ConfNode *tmp; while ((tmp = TAILQ_FIRST(&node->head))) { TAILQ_REMOVE(&node->head, tmp, next); ConfNodeFree(tmp); } if (node->name != NULL) SCFree(node->name); if (node->val != NULL) SCFree(node->val); SCFree(node); } /** * \brief Get a ConfNode by name. * * \param key The full name of the configuration node to lookup. * * \retval A pointer to ConfNode is found or NULL if the configuration * node does not exist. */ ConfNode * ConfGetNode(char *key) { ConfNode *node = root; #if !defined(__WIN32) && !defined(_WIN32) char *saveptr = NULL; #endif /* __WIN32 */ char *token; /* Need to dup the key for tokenization... */ char *tokstr = SCStrdup(key); if (unlikely(tokstr == NULL)) { return NULL; } #if defined(__WIN32) || defined(_WIN32) token = strtok(tokstr, "."); #else token = strtok_r(tokstr, ".", &saveptr); #endif /* __WIN32 */ for (;;) { node = ConfNodeLookupChild(node, token); if (node == NULL) break; #if defined(__WIN32) || defined(_WIN32) token = strtok(NULL, "."); #else token = strtok_r(NULL, ".", &saveptr); #endif /* __WIN32 */ if (token == NULL) break; } SCFree(tokstr); return node; } /** * \brief Get the root configuration node. */ ConfNode * ConfGetRootNode(void) { return root; } /** * \brief Set a configuration value. * * \param name The name of the configuration parameter to set. * \param val The value of the configuration parameter. * \param allow_override Can a subsequent set override this value. * * \retval 1 if the value was set otherwise 0. */ int ConfSet(char *name, char *val, int allow_override) { ConfNode *parent = root; ConfNode *node; char *token; #if !defined(__WIN32) && !defined(_WIN32) char *saveptr = NULL; #endif /* __WIN32 */ /* First check if the node already exists. */ node = ConfGetNode(name); if (node != NULL) { if (!node->allow_override) { return 0; } else { if (node->val != NULL) SCFree(node->val); node->val = SCStrdup(val); node->allow_override = allow_override; return 1; } } else { char *tokstr = SCStrdup(name); if (unlikely(tokstr == NULL)) { return 0; } #if defined(__WIN32) || defined(_WIN32) token = strtok(tokstr, "."); #else token = strtok_r(tokstr, ".", &saveptr); #endif /* __WIN32 */ node = ConfNodeLookupChild(parent, token); for (;;) { if (node == NULL) { node = ConfNodeNew(); node->name = SCStrdup(token); node->parent = parent; TAILQ_INSERT_TAIL(&parent->head, node, next); parent = node; } else { parent = node; } #if defined(__WIN32) || defined(_WIN32) token = strtok(NULL, "."); #else token = strtok_r(NULL, ".", &saveptr); #endif /* __WIN32 */ if (token == NULL) { if (!node->allow_override) break; if (node->val != NULL) SCFree(node->val); node->val = SCStrdup(val); node->allow_override = allow_override; break; } else { node = ConfNodeLookupChild(parent, token); } } SCFree(tokstr); } SCLogDebug("configuration parameter '%s' set", name); return 1; } /** * \brief Retrieve the value of a configuration node. * * This function will return the value for a configuration node based * on the full name of the node. It is possible that the value * returned could be NULL, this could happen if the requested node * does exist but is not a node that contains a value, but contains * children ConfNodes instead. * * \param name Name of configuration parameter to get. * \param vptr Pointer that will be set to the configuration value parameter. * Note that this is just a reference to the actual value, not a copy. * * \retval 1 will be returned if the name is found, otherwise 0 will * be returned. */ int ConfGet(char *name, char **vptr) { ConfNode *node = ConfGetNode(name); if (node == NULL) { SCLogDebug("failed to lookup configuration parameter '%s'", name); return 0; } else { *vptr = node->val; return 1; } } int ConfGetChildValue(ConfNode *base, char *name, char **vptr) { ConfNode *node = ConfNodeLookupChild(base, name); if (node == NULL) { SCLogDebug("failed to lookup configuration parameter '%s'", name); return 0; } else { *vptr = node->val; return 1; } } int ConfGetChildValueWithDefault(ConfNode *base, ConfNode *dflt, char *name, char **vptr) { int ret = ConfGetChildValue(base, name, vptr); /* Get 'default' value */ if (ret == 0 && dflt) { return ConfGetChildValue(dflt, name, vptr); } return ret; } /** * \brief Retrieve a configuration value as an integer. * * \param name Name of configuration parameter to get. * \param val Pointer to an intmax_t that will be set the * configuration value. * * \retval 1 will be returned if the name is found and was properly * converted to an interger, otherwise 0 will be returned. */ int ConfGetInt(char *name, intmax_t *val) { char *strval; intmax_t tmpint; char *endptr; if (ConfGet(name, &strval) == 0) return 0; errno = 0; tmpint = strtoimax(strval, &endptr, 0); if (strval[0] == '\0' || *endptr != '\0') return 0; if (errno == ERANGE && (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) return 0; *val = tmpint; return 1; } int ConfGetChildValueInt(ConfNode *base, char *name, intmax_t *val) { char *strval; intmax_t tmpint; char *endptr; if (ConfGetChildValue(base, name, &strval) == 0) return 0; errno = 0; tmpint = strtoimax(strval, &endptr, 0); if (strval[0] == '\0' || *endptr != '\0') return 0; if (errno == ERANGE && (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) return 0; *val = tmpint; return 1; } int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, intmax_t *val) { int ret = ConfGetChildValueInt(base, name, val); /* Get 'default' value */ if (ret == 0 && dflt) { return ConfGetChildValueInt(dflt, name, val); } return ret; } /** * \brief Retrieve a configuration value as an boolen. * * \param name Name of configuration parameter to get. * \param val Pointer to an int that will be set to 1 for true, or 0 * for false. * * \retval 1 will be returned if the name is found and was properly * converted to a boolean, otherwise 0 will be returned. */ int ConfGetBool(char *name, int *val) { char *strval; *val = 0; if (ConfGet(name, &strval) != 1) return 0; *val = ConfValIsTrue(strval); return 1; } int ConfGetChildValueBool(ConfNode *base, char *name, int *val) { char *strval; *val = 0; if (ConfGetChildValue(base, name, &strval) == 0) return 0; *val = ConfValIsTrue(strval); return 1; } int ConfGetChildValueBoolWithDefault(ConfNode *base, ConfNode *dflt, char *name, int *val) { int ret = ConfGetChildValueBool(base, name, val); /* Get 'default' value */ if (ret == 0 && dflt) { return ConfGetChildValueBool(dflt, name, val); } return ret; } /** * \brief Check if a value is true. * * The value is considered true if it is a string with the value of 1, * yes, true or on. The test is not case sensitive, any other value * is false. * * \param val The string to test for a true value. * * \retval 1 If the value is true, 0 if not. */ int ConfValIsTrue(const char *val) { char *trues[] = {"1", "yes", "true", "on"}; size_t u; for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) { if (strcasecmp(val, trues[u]) == 0) { return 1; } } return 0; } /** * \brief Check if a value is false. * * The value is considered false if it is a string with the value of 0, * no, false or off. The test is not case sensitive, any other value * is not false. * * \param val The string to test for a false value. * * \retval 1 If the value is false, 0 if not. */ int ConfValIsFalse(const char *val) { char *falses[] = {"0", "no", "false", "off"}; size_t u; for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) { if (strcasecmp(val, falses[u]) == 0) { return 1; } } return 0; } /** * \brief Retrieve a configuration value as a double * * \param name Name of configuration parameter to get. * \param val Pointer to an double that will be set the * configuration value. * * \retval 1 will be returned if the name is found and was properly * converted to a double, otherwise 0 will be returned. */ int ConfGetDouble(char *name, double *val) { char *strval; double tmpdo; char *endptr; if (ConfGet(name, &strval) == 0) return 0; errno = 0; tmpdo = strtod(strval, &endptr); if (strval[0] == '\0' || *endptr != '\0') return 0; if (errno == ERANGE) return 0; *val = tmpdo; return 1; } /** * \brief Retrieve a configuration value as a float * * \param name Name of configuration parameter to get. * \param val Pointer to an float that will be set the * configuration value. * * \retval 1 will be returned if the name is found and was properly * converted to a double, otherwise 0 will be returned. */ int ConfGetFloat(char *name, float *val) { char *strval; double tmpfl; char *endptr; if (ConfGet(name, &strval) == 0) return 0; errno = 0; tmpfl = strtof(strval, &endptr); if (strval[0] == '\0' || *endptr != '\0') return 0; if (errno == ERANGE) return 0; *val = tmpfl; return 1; } /** * \brief Remove (and SCFree) the provided configuration node. */ void ConfNodeRemove(ConfNode *node) { if (node->parent != NULL) TAILQ_REMOVE(&node->parent->head, node, next); ConfNodeFree(node); } /** * \brief Remove a configuration parameter from the configuration db. * * \param name The name of the configuration parameter to remove. * * \retval Returns 1 if the parameter was removed, otherwise 0 is returned * most likely indicating the parameter was not set. */ int ConfRemove(char *name) { ConfNode *node; node = ConfGetNode(name); if (node == NULL) return 0; else { ConfNodeRemove(node); return 1; } } /** * \brief Creates a backup of the conf_hash hash_table used by the conf API. */ void ConfCreateContextBackup(void) { root_backup = root; root = NULL; return; } /** * \brief Restores the backup of the hash_table present in backup_conf_hash * back to conf_hash. */ void ConfRestoreContextBackup(void) { root = root_backup; root_backup = NULL; return; } /** * \brief De-initializes the configuration system. */ void ConfDeInit(void) { if (root != NULL) { ConfNodeFree(root); root = NULL; } SCLogDebug("configuration module de-initialized"); } static char * ConfPrintNameArray(char **name_arr, int level) { static char name[128*128]; int i; name[0] = '\0'; for (i = 0; i <= level; i++) { strlcat(name, name_arr[i], sizeof(name)); if (i < level) strlcat(name, ".", sizeof(name)); } return name; } /** * \brief Dump a configuration node and all its children. */ void ConfNodeDump(ConfNode *node, const char *prefix) { ConfNode *child; static char *name[128]; static int level = -1; level++; TAILQ_FOREACH(child, &node->head, next) { name[level] = SCStrdup(child->name); if (prefix == NULL) { printf("%s = %s\n", ConfPrintNameArray(name, level), child->val); } else { printf("%s.%s = %s\n", prefix, ConfPrintNameArray(name, level), child->val); } ConfNodeDump(child, prefix); SCFree(name[level]); } level--; } /** * \brief Dump configuration to stdout. */ void ConfDump(void) { ConfNodeDump(root, NULL); } /** * \brief Lookup a child configuration node by name. * * Given a ConfNode this function will lookup an immediate child * ConfNode by name and return the child ConfNode. * * \param node The parent configuration node. * \param name The name of the child node to lookup. * * \retval A pointer the child ConfNode if found otherwise NULL. */ ConfNode * ConfNodeLookupChild(ConfNode *node, const char *name) { ConfNode *child; TAILQ_FOREACH(child, &node->head, next) { if (strcmp(child->name, name) == 0) return child; } return NULL; } /** * \brief Lookup the value of a child configuration node by name. * * Given a parent ConfNode this function will return the value of a * child configuration node by name returning a reference to that * value. * * \param node The parent configuration node. * \param name The name of the child node to lookup. * * \retval A pointer the child ConfNodes value if found otherwise NULL. */ const char * ConfNodeLookupChildValue(ConfNode *node, const char *name) { ConfNode *child; child = ConfNodeLookupChild(node, name); if (child != NULL) return child->val; return NULL; } /** * \brief Lookup for a key value under a specific node * * \return the ConfNode matching or NULL */ ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *value) { ConfNode *child; TAILQ_FOREACH(child, &base->head, next) { if (!strncmp(child->val, key, strlen(child->val))) { ConfNode *subchild; TAILQ_FOREACH(subchild, &child->head, next) { if ((!strcmp(subchild->name, key)) && (!strcmp(subchild->val, value))) { return child; } } } } return NULL; } /** * \brief Test if a configuration node has a true value. * * \param node The parent configuration node. * \param name The name of the child node to test. * * \retval 1 if the child node has a true value, otherwise 0 is * returned, even if the child node does not exist. */ int ConfNodeChildValueIsTrue(ConfNode *node, const char *key) { const char *val; val = ConfNodeLookupChildValue(node, key); return val != NULL ? ConfValIsTrue(val) : 0; } /** * \brief Create the path for an include entry * \param file The name of the file * \retval str Pointer to the string path + sig_file */ char *ConfLoadCompleteIncludePath(char *file) { char *defaultpath = NULL; char *path = NULL; /* Path not specified */ if (PathIsRelative(file)) { if (ConfGet("include-path", &defaultpath) == 1) { SCLogDebug("Default path: %s", defaultpath); size_t path_len = sizeof(char) * (strlen(defaultpath) + strlen(file) + 2); path = SCMalloc(path_len); if (unlikely(path == NULL)) return NULL; strlcpy(path, defaultpath, path_len); if (path[strlen(path) - 1] != '/') strlcat(path, "/", path_len); strlcat(path, file, path_len); } else { path = SCStrdup(file); if (unlikely(path == NULL)) return NULL; } } else { path = SCStrdup(file); if (unlikely(path == NULL)) return NULL; } return path; } #ifdef UNITTESTS /** * Lookup a non-existant value. */ static int ConfTestGetNonExistant(void) { char name[] = "non-existant-value"; char *value; return !ConfGet(name, &value); } /** * Set then lookup a value. */ static int ConfTestSetAndGet(void) { char name[] = "some-name"; char value[] = "some-value"; char *value0; if (ConfSet(name, value, 1) != 1) return 0; if (ConfGet(name, &value0) != 1) return 0; if (strcmp(value, value0) != 0) return 0; /* Cleanup. */ ConfRemove(name); return 1; } /** * Test that overriding a value is allowed provided allow_override is * true and that the config parameter gets the new value. */ static int ConfTestOverrideValue1(void) { char name[] = "some-name"; char value0[] = "some-value"; char value1[] = "new-value"; char *val; int rc; if (ConfSet(name, value0, 1) != 1) return 0; if (ConfSet(name, value1, 1) != 1) return 0; if (ConfGet(name, &val) != 1) return 0; rc = !strcmp(val, value1); /* Cleanup. */ ConfRemove(name); return rc; } /** * Test that overriding a value is not allowed provided that * allow_override is false and make sure the value was not overrided. */ static int ConfTestOverrideValue2(void) { char name[] = "some-name"; char value0[] = "some-value"; char value1[] = "new-value"; char *val; int rc; if (ConfSet(name, value0, 0) != 1) return 0; if (ConfSet(name, value1, 1) != 0) return 0; if (ConfGet(name, &val) != 1) return 0; rc = !strcmp(val, value0); /* Cleanup. */ ConfRemove(name); return rc; } /** * Test retrieving an integer value from the configuration db. */ static int ConfTestGetInt(void) { char name[] = "some-int.x"; intmax_t val; if (ConfSet(name, "0", 1) != 1) return 0; if (ConfGetInt(name, &val) != 1) return 0; if (val != 0) return 0; if (ConfSet(name, "-1", 1) != 1) return 0; if (ConfGetInt(name, &val) != 1) return 0; if (val != -1) return 0; if (ConfSet(name, "0xffff", 1) != 1) return 0; if (ConfGetInt(name, &val) != 1) return 0; if (val != 0xffff) return 0; if (ConfSet(name, "not-an-int", 1) != 1) return 0; if (ConfGetInt(name, &val) != 0) return 0; return 1; } /** * Test retrieving a boolean value from the configuration db. */ static int ConfTestGetBool(void) { char name[] = "some-bool"; char *trues[] = { "1", "on", "ON", "yes", "YeS", "true", "TRUE", }; char *falses[] = { "0", "something", "off", "OFF", "false", "FalSE", "no", "NO", }; int val; size_t u; for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) { if (ConfSet(name, trues[u], 1) != 1) return 0; if (ConfGetBool(name, &val) != 1) return 0; if (val != 1) return 0; } for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) { if (ConfSet(name, falses[u], 1) != 1) return 0; if (ConfGetBool(name, &val) != 1) return 0; if (val != 0) return 0; } return 1; } static int ConfNodeLookupChildTest(void) { char *test_vals[] = { "one", "two", "three" }; size_t u; ConfNode *parent = ConfNodeNew(); ConfNode *child; for (u = 0; u < sizeof(test_vals)/sizeof(test_vals[0]); u++) { child = ConfNodeNew(); child->name = SCStrdup(test_vals[u]); child->val = SCStrdup(test_vals[u]); TAILQ_INSERT_TAIL(&parent->head, child, next); } child = ConfNodeLookupChild(parent, "one"); if (child == NULL) return 0; if (strcmp(child->name, "one") != 0) return 0; if (strcmp(child->val, "one") != 0) return 0; child = ConfNodeLookupChild(parent, "two"); if (child == NULL) return 0; if (strcmp(child->name, "two") != 0) return 0; if (strcmp(child->val, "two") != 0) return 0; child = ConfNodeLookupChild(parent, "three"); if (child == NULL) return 0; if (strcmp(child->name, "three") != 0) return 0; if (strcmp(child->val, "three") != 0) return 0; child = ConfNodeLookupChild(parent, "four"); if (child != NULL) return 0; ConfNodeFree(parent); return 1; } static int ConfNodeLookupChildValueTest(void) { char *test_vals[] = { "one", "two", "three" }; size_t u; ConfNode *parent = ConfNodeNew(); ConfNode *child; const char *value; for (u = 0; u < sizeof(test_vals)/sizeof(test_vals[0]); u++) { child = ConfNodeNew(); child->name = SCStrdup(test_vals[u]); child->val = SCStrdup(test_vals[u]); TAILQ_INSERT_TAIL(&parent->head, child, next); } value = (char *)ConfNodeLookupChildValue(parent, "one"); if (value == NULL) return 0; if (strcmp(value, "one") != 0) return 0; value = (char *)ConfNodeLookupChildValue(parent, "two"); if (value == NULL) return 0; if (strcmp(value, "two") != 0) return 0; value = (char *)ConfNodeLookupChildValue(parent, "three"); if (value == NULL) return 0; if (strcmp(value, "three") != 0) return 0; value = (char *)ConfNodeLookupChildValue(parent, "four"); if (value != NULL) return 0; ConfNodeFree(parent); return 1; } static int ConfGetChildValueWithDefaultTest(void) { char *val; int ret = 1; ConfCreateContextBackup(); ConfInit(); ConfSet("af-packet.0.interface", "eth0", 1); ConfSet("af-packet.1.interface", "default", 1); ConfSet("af-packet.1.cluster-type", "cluster_cpu", 1); ConfNode *root = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); ConfGetChildValueWithDefault(root, dflt, "cluster-type", &val); if (strcmp(val, "cluster_cpu")) { ConfDeInit(); ConfRestoreContextBackup(); return 0; } ConfSet("af-packet.0.cluster-type", "cluster_flow", 1); ConfGetChildValueWithDefault(root, dflt, "cluster-type", &val); if (strcmp(val, "cluster_flow")) { ret = 0; } ConfDeInit(); ConfRestoreContextBackup(); return ret; } static int ConfGetChildValueIntWithDefaultTest(void) { intmax_t val; ConfCreateContextBackup(); ConfInit(); ConfSet("af-packet.0.interface", "eth0", 1); ConfSet("af-packet.1.interface", "default", 1); ConfSet("af-packet.1.threads", "2", 1); ConfNode *root = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); ConfGetChildValueIntWithDefault(root, dflt, "threads", &val); if (val != 2) { ConfDeInit(); ConfRestoreContextBackup(); return 0; } ConfSet("af-packet.0.threads", "1", 1); ConfGetChildValueIntWithDefault(root, dflt, "threads", &val); ConfDeInit(); ConfRestoreContextBackup(); if (val != 1) { return 0; } return 1; } static int ConfGetChildValueBoolWithDefaultTest(void) { int val; ConfCreateContextBackup(); ConfInit(); ConfSet("af-packet.0.interface", "eth0", 1); ConfSet("af-packet.1.interface", "default", 1); ConfSet("af-packet.1.use-mmap", "yes", 1); ConfNode *root = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); ConfGetChildValueBoolWithDefault(root, dflt, "use-mmap", &val); if (val == 0) { ConfDeInit(); ConfRestoreContextBackup(); return 0; } ConfSet("af-packet.0.use-mmap", "no", 1); ConfGetChildValueBoolWithDefault(root, dflt, "use-mmap", &val); ConfDeInit(); ConfRestoreContextBackup(); if (val) { return 0; } return 1; } /** * Test the removal of a configuration node. */ static int ConfNodeRemoveTest(void) { ConfCreateContextBackup(); ConfInit(); if (ConfSet("some.nested.parameter", "blah", 1) != 1) return 0; ConfNode *node = ConfGetNode("some.nested.parameter"); if (node == NULL) return 0; ConfNodeRemove(node); node = ConfGetNode("some.nested.parameter"); if (node != NULL) return 0; ConfDeInit(); ConfRestoreContextBackup(); return 1; } static int ConfSetTest(void) { ConfCreateContextBackup(); ConfInit(); /* Set some value with 2 levels. */ if (ConfSet("one.two", "three", 1) != 1) return 0; ConfNode *n = ConfGetNode("one.two"); if (n == NULL) return 0; /* Set another 2 level parameter with the same first level, this * used to trigger a bug that caused the second level of the name * to become a first level node. */ if (ConfSet("one.three", "four", 1) != 1) return 0; n = ConfGetNode("one.three"); if (n == NULL) return 0; /* A top level node of "three" should not exist. */ n = ConfGetNode("three"); if (n != NULL) return 0; ConfDeInit(); ConfRestoreContextBackup(); return 1; } void ConfRegisterTests(void) { UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant, 1); UtRegisterTest("ConfSetTest", ConfSetTest, 1); UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet, 1); UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1, 1); UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2, 1); UtRegisterTest("ConfTestGetInt", ConfTestGetInt, 1); UtRegisterTest("ConfTestGetBool", ConfTestGetBool, 1); UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest, 1); UtRegisterTest("ConfNodeLookupChildValueTest", ConfNodeLookupChildValueTest, 1); UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest, 1); UtRegisterTest("ConfGetChildValueWithDefaultTest", ConfGetChildValueWithDefaultTest, 1); UtRegisterTest("ConfGetChildValueIntWithDefaultTest", ConfGetChildValueIntWithDefaultTest, 1); UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", ConfGetChildValueBoolWithDefaultTest, 1); } #endif /* UNITTESTS */ suricata-1.4.7/src/detect-itype.h0000644000000000000000000000236312253546156013602 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias */ #ifndef __DETECT_ITYPE_H__ #define __DETECT_ITYPE_H__ #define DETECT_ITYPE_EQ 0 /**< "equal" operator */ #define DETECT_ITYPE_LT 1 /**< "less than" operator */ #define DETECT_ITYPE_GT 2 /**< "greater than" operator */ #define DETECT_ITYPE_RN 3 /**< "range" operator */ typedef struct DetectITypeData_ { uint8_t type1; uint8_t type2; uint8_t mode; } DetectITypeData; /* prototypes */ void DetectITypeRegister(void); #endif /* __DETECT_ITYPE_H__ */ suricata-1.4.7/src/util-mpm-ac-bs.c0000644000000000000000000026034412253546156013731 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * First iteration of aho-corasick MPM from - * * Efficient String Matching: An Aid to Bibliographic Search * Alfred V. Aho and Margaret J. Corasick * * - Uses the delta table for calculating transitions, instead of having * separate goto and failure transitions. * - If we cross 2 ** 16 states, we use 4 bytes in the transition table * to hold each state, otherwise we use 2 bytes. * - This version of the MPM is heavy on memory, but it performs well. * If you can fit the ruleset with this mpm on your box without hitting * swap, this is the MPM to go for. * * \todo - Do a proper analyis of our existing MPMs and suggest a good one based * on the pattern distribution and the expected traffic(say http). * - Tried out loop unrolling without any perf increase. Need to dig deeper. * - Irrespective of whether we cross 2 ** 16 states or not,shift to using * uint32_t for state type, so that we can integrate it's status as a * final state or not in the topmost byte. We are already doing it if * state_count is > 2 ** 16. * - Test case-senstive patterns if they have any ascii chars. If they * don't treat them as nocase. * - Carry out other optimizations we are working on. hashes, compression. */ #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "util-mpm-ac-bs.h" #include "conf.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-memcmp.h" void SCACBSInitCtx(MpmCtx *, int); void SCACBSInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void SCACBSDestroyCtx(MpmCtx *); void SCACBSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACBSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int SCACBSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int SCACBSPreparePatterns(MpmCtx *mpm_ctx); uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); void SCACBSPrintInfo(MpmCtx *mpm_ctx); void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACBSRegisterTests(void); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_BS_FAIL (-1) /* size of the hash table used to speed up pattern insertions initially */ #define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 /** * \brief Helper structure used by AC during state table creation */ typedef struct StateQueue_ { int32_t store[STATE_QUEUE_CONTAINER_SIZE]; int top; int bot; } StateQueue; /** * \brief Register the aho-corasick mpm. */ void MpmACBSRegister(void) { mpm_table[MPM_AC_BS].name = "ac-bs"; /* don't need this. isn't that awesome? no more chopping and blah blah */ mpm_table[MPM_AC_BS].max_pattern_length = 0; mpm_table[MPM_AC_BS].InitCtx = SCACBSInitCtx; mpm_table[MPM_AC_BS].InitThreadCtx = SCACBSInitThreadCtx; mpm_table[MPM_AC_BS].DestroyCtx = SCACBSDestroyCtx; mpm_table[MPM_AC_BS].DestroyThreadCtx = SCACBSDestroyThreadCtx; mpm_table[MPM_AC_BS].AddPattern = SCACBSAddPatternCS; mpm_table[MPM_AC_BS].AddPatternNocase = SCACBSAddPatternCI; mpm_table[MPM_AC_BS].Prepare = SCACBSPreparePatterns; mpm_table[MPM_AC_BS].Search = SCACBSSearch; mpm_table[MPM_AC_BS].Cleanup = NULL; mpm_table[MPM_AC_BS].PrintCtx = SCACBSPrintInfo; mpm_table[MPM_AC_BS].PrintThreadCtx = SCACBSPrintSearchStats; mpm_table[MPM_AC_BS].RegisterUnittests = SCACBSRegisterTests; return; } /** * \internal * \brief Initialize the AC context with user specified conf parameters. We * aren't retrieving anything for AC conf now, but we will certainly * need it, when we customize AC. */ static void SCACBSGetConfig() { //ConfNode *ac_conf; //const char *hash_val = NULL; //ConfNode *pm = ConfGetNode("pattern-matcher"); return; } /** * \internal * \brief Compares 2 patterns. We use it for the hashing process during the * the initial pattern insertion time, to cull duplicate sigs. * * \param p Pointer to the first pattern(SCACBSPattern). * \param pat Pointer to the second pattern(raw pattern array). * \param patlen Pattern length. * \param flags Flags. We don't need this. * * \retval hash A 32 bit unsigned hash. */ static inline int SCACBSCmpPattern(SCACBSPattern *p, uint8_t *pat, uint16_t patlen, char flags) { if (p->len != patlen) return 0; if (p->flags != flags) return 0; if (memcmp(p->cs, pat, patlen) != 0) return 0; return 1; } /** * \internal * \brief Creates a hash of the pattern. We use it for the hashing process * during the initial pattern insertion time, to cull duplicate sigs. * * \param pat Pointer to the pattern. * \param patlen Pattern length. * * \retval hash A 32 bit unsigned hash. */ static inline uint32_t SCACBSInitHashRaw(uint8_t *pat, uint16_t patlen) { uint32_t hash = patlen * pat[0]; if (patlen > 1) hash += pat[1]; return (hash % INIT_HASH_SIZE); } /** * \internal * \brief Looks up a pattern. We use it for the hashing process during the * the initial pattern insertion time, to cull duplicate sigs. * * \param ctx Pointer to the AC ctx. * \param pat Pointer to the pattern. * \param patlen Pattern length. * \param flags Flags. We don't need this. * * \retval hash A 32 bit unsigned hash. */ static inline SCACBSPattern *SCACBSInitHashLookup(SCACBSCtx *ctx, uint8_t *pat, uint16_t patlen, char flags, uint32_t pid) { uint32_t hash = SCACBSInitHashRaw(pat, patlen); if (ctx->init_hash == NULL || ctx->init_hash[hash] == NULL) { return NULL; } SCACBSPattern *t = ctx->init_hash[hash]; for ( ; t != NULL; t = t->next) { //if (SCACBSCmpPattern(t, pat, patlen, flags) == 1) if (t->flags == flags && t->id == pid) return t; } return NULL; } /** * \internal * \brief Allocs a new pattern instance. * * \param mpm_ctx Pointer to the mpm context. * * \retval p Pointer to the newly created pattern. */ static inline SCACBSPattern *SCACBSAllocPattern(MpmCtx *mpm_ctx) { SCACBSPattern *p = SCMalloc(sizeof(SCACBSPattern)); if (unlikely(p == NULL)) { exit(EXIT_FAILURE); } memset(p, 0, sizeof(SCACBSPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(SCACBSPattern); return p; } /** * \internal * \brief Used to free SCACBSPattern instances. * * \param mpm_ctx Pointer to the mpm context. * \param p Pointer to the SCACBSPattern instance to be freed. */ static inline void SCACBSFreePattern(MpmCtx *mpm_ctx, SCACBSPattern *p) { if (p != NULL && p->cs != NULL && p->cs != p->ci) { SCFree(p->cs); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL && p->ci != NULL) { SCFree(p->ci); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL && p->original_pat != NULL) { SCFree(p->original_pat); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } if (p != NULL) { SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(SCACBSPattern); } return; } /** * \internal * \brief Does a memcpy of the input string to lowercase. * * \param d Pointer to the target area for memcpy. * \param s Pointer to the src string for memcpy. * \param len len of the string sent in s. */ static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) d[i] = u8_tolower(s[i]); return; } static inline uint32_t SCACBSInitHash(SCACBSPattern *p) { uint32_t hash = p->len * p->original_pat[0]; if (p->len > 1) hash += p->original_pat[1]; return (hash % INIT_HASH_SIZE); } static inline int SCACBSInitHashAdd(SCACBSCtx *ctx, SCACBSPattern *p) { uint32_t hash = SCACBSInitHash(p); if (ctx->init_hash == NULL) { return 0; } if (ctx->init_hash[hash] == NULL) { ctx->init_hash[hash] = p; return 0; } SCACBSPattern *tt = NULL; SCACBSPattern *t = ctx->init_hash[hash]; /* get the list tail */ do { tt = t; t = t->next; } while (t != NULL); tt->next = p; return 0; } /** * \internal * \brief Add a pattern to the mpm-ac context. * * \param mpm_ctx Mpm context. * \param pat Pointer to the pattern. * \param patlen Length of the pattern. * \param pid Pattern id * \param sid Signature id (internal id). * \param flags Pattern's MPM_PATTERN_* flags. * * \retval 0 On success. * \retval -1 On failure. */ static int SCACBSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, ctx, patlen, pid); if (patlen == 0) { SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); return 0; } /* check if we have already inserted this pattern */ SCACBSPattern *p = SCACBSInitHashLookup(ctx, pat, patlen, flags, pid); if (p == NULL) { SCLogDebug("Allocing new pattern"); /* p will never be NULL */ p = SCACBSAllocPattern(mpm_ctx); p->len = patlen; p->flags = flags; p->id = pid; p->original_pat = SCMalloc(patlen); if (p->original_pat == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->original_pat, pat, patlen); p->ci = SCMalloc(patlen); if (p->ci == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy_tolower(p->ci, pat, patlen); /* setup the case sensitive part of the pattern */ if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* nocase means no difference between cs and ci */ p->cs = p->ci; } else { if (memcmp(p->ci, pat, p->len) == 0) { /* no diff between cs and ci: pat is lowercase */ p->cs = p->ci; } else { p->cs = SCMalloc(patlen); if (p->cs == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->cs, pat, patlen); } } /* put in the pattern hash */ SCACBSInitHashAdd(ctx, p); //if (mpm_ctx->pattern_cnt == 65535) { // SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " // "insert anymore. Exiting"); // exit(EXIT_FAILURE); //} mpm_ctx->pattern_cnt++; if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) { mpm_ctx->minlen = patlen; } else { if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } /* we need the max pat id */ if (pid > ctx->max_pat_id) ctx->max_pat_id = pid; } return 0; error: SCACBSFreePattern(mpm_ctx, p); return -1; } /** * \internal * \brief Initialize a new state in the goto and output tables. * * \param mpm_ctx Pointer to the mpm context. * * \retval The state id, of the newly created state. */ static inline int SCACBSInitNewState(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int ascii_code = 0; int size = 0; /* reallocate space in the goto table to include a new state */ size = (ctx->state_count + 1) * ctx->single_state_size; ctx->goto_table = SCRealloc(ctx->goto_table, size); if (ctx->goto_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } /* set all transitions for the newly assigned state as FAIL transitions */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_BS_FAIL; } /* reallocate space in the output table for the new state */ size = (ctx->state_count + 1) * sizeof(SCACBSOutputTable); ctx->output_table = SCRealloc(ctx->output_table, size); if (ctx->output_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->output_table + ctx->state_count, 0, sizeof(SCACBSOutputTable)); /* \todo using it temporarily now during dev, since I have restricted * state var in SCACBSCtx->state_table to uint16_t. */ //if (ctx->state_count > 65536) { // printf("state count exceeded\n"); // exit(EXIT_FAILURE); //} return ctx->state_count++; } /** * \internal * \brief Adds a pid to the output table for a state. * * \param state The state to whose output table we should add the pid. * \param pid The pattern id to add. * \param mpm_ctx Pointer to the mpm context. */ static void SCACBSSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; SCACBSOutputTable *output_state = &ctx->output_table[state]; uint32_t i = 0; for (i = 0; i < output_state->no_of_entries; i++) { if (output_state->pids[i] == pid) return; } output_state->no_of_entries++; output_state->pids = SCRealloc(output_state->pids, output_state->no_of_entries * sizeof(uint32_t)); if (output_state->pids == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } output_state->pids[output_state->no_of_entries - 1] = pid; return; } /** * \brief Helper function used by SCACBSCreateGotoTable. Adds a pattern to the * goto table. * * \param pattern Pointer to the pattern. * \param pattern_len Pattern length. * \param pid The pattern id, that corresponds to this pattern. We * need it to updated the output table for this pattern. * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int32_t state = 0; int32_t newstate = 0; int i = 0; int p = 0; /* walk down the trie till we have a match for the pattern prefix */ state = 0; for (i = 0; i < pattern_len; i++) { if (ctx->goto_table[state][pattern[i]] != SC_AC_BS_FAIL) { state = ctx->goto_table[state][pattern[i]]; } else { break; } } /* add the non-matching pattern suffix to the trie, from the last state * we left off */ for (p = i; p < pattern_len; p++) { newstate = SCACBSInitNewState(mpm_ctx); ctx->goto_table[state][pattern[p]] = newstate; state = newstate; } /* add this pattern id, to the output table of the last state, where the * pattern ends in the trie */ SCACBSSetOutputState(state, pid, mpm_ctx); return; } /** * \internal * \brief Create the goto table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSCreateGotoTable(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; uint32_t i = 0; /* add each pattern to create the goto table */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { SCACBSEnter(ctx->parray[i]->ci, ctx->parray[i]->len, ctx->parray[i]->id, mpm_ctx); } int ascii_code = 0; for (ascii_code = 0; ascii_code < 256; ascii_code++) { if (ctx->goto_table[0][ascii_code] == SC_AC_BS_FAIL) { ctx->goto_table[0][ascii_code] = 0; } } return; } static inline int SCACBSStateQueueIsEmpty(StateQueue *q) { if (q->top == q->bot) return 1; else return 0; } static inline void SCACBSEnqueue(StateQueue *q, int32_t state) { int i = 0; /*if we already have this */ for (i = q->bot; i < q->top; i++) { if (q->store[i] == state) return; } q->store[q->top++] = state; if (q->top == STATE_QUEUE_CONTAINER_SIZE) q->top = 0; if (q->top == q->bot) { SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " "Fatal Error. Exiting. Please file a bug report on this"); exit(EXIT_FAILURE); } return; } static inline int32_t SCACBSDequeue(StateQueue *q) { if (q->bot == STATE_QUEUE_CONTAINER_SIZE) q->bot = 0; if (q->bot == q->top) { SCLogCritical(SC_ERR_AHO_CORASICK, "StateQueue behaving weirdly. " "Fatal Error. Exiting. Please file a bug report on this"); exit(EXIT_FAILURE); } return q->store[q->bot++]; } /* #define SCACBSStateQueueIsEmpty(q) (((q)->top == (q)->bot) ? 1 : 0) #define SCACBSEnqueue(q, state) do { \ int i = 0; \ \ for (i = (q)->bot; i < (q)->top; i++) { \ if ((q)->store[i] == state) \ return; \ } \ \ (q)->store[(q)->top++] = state; \ \ if ((q)->top == STATE_QUEUE_CONTAINER_SIZE) \ (q)->top = 0; \ \ if ((q)->top == (q)->bot) { \ SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " \ "Fatal Error. Exiting. Please file a bug report on this"); \ exit(EXIT_FAILURE); \ } \ } while (0) #define SCACBSDequeue(q) ( (((q)->bot == STATE_QUEUE_CONTAINER_SIZE)? ((q)->bot = 0): 0), \ (((q)->bot == (q)->top) ? \ (printf("StateQueue behaving " \ "weirdly. Fatal Error. Exiting. Please " \ "file a bug report on this"), \ exit(EXIT_FAILURE)) : 0), \ (q)->store[(q)->bot++]) \ */ /** * \internal * \brief Club the output data from 2 states and store it in the 1st state. * dst_state_data = {dst_state_data} UNION {src_state_data} * * \param dst_state First state(also the destination) for the union operation. * \param src_state Second state for the union operation. * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSClubOutputStates(int32_t dst_state, int32_t src_state, MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; uint32_t i = 0; uint32_t j = 0; SCACBSOutputTable *output_dst_state = &ctx->output_table[dst_state]; SCACBSOutputTable *output_src_state = &ctx->output_table[src_state]; for (i = 0; i < output_src_state->no_of_entries; i++) { for (j = 0; j < output_dst_state->no_of_entries; j++) { if (output_src_state->pids[i] == output_dst_state->pids[j]) { break; } } if (j == output_dst_state->no_of_entries) { output_dst_state->no_of_entries++; output_dst_state->pids = SCRealloc(output_dst_state->pids, (output_dst_state->no_of_entries * sizeof(uint32_t)) ); if (output_dst_state->pids == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } output_dst_state->pids[output_dst_state->no_of_entries - 1] = output_src_state->pids[i]; } } return; } /** * \internal * \brief Create the failure table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSCreateFailureTable(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int ascii_code = 0; int32_t state = 0; int32_t r_state = 0; StateQueue q; memset(&q, 0, sizeof(StateQueue)); /* allot space for the failure table. A failure entry in the table for * every state(SCACBSCtx->state_count) */ ctx->failure_table = SCMalloc(ctx->state_count * sizeof(int32_t)); if (ctx->failure_table == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->failure_table, 0, ctx->state_count * sizeof(int32_t)); /* add the failure transitions for the 0th state, and add every non-fail * transition from the 0th state to the queue for further processing * of failure states */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[0][ascii_code]; if (temp_state != 0) { SCACBSEnqueue(&q, temp_state); ctx->failure_table[temp_state] = 0; } } while (!SCACBSStateQueueIsEmpty(&q)) { /* pick up every state from the queue and add failure transitions */ r_state = SCACBSDequeue(&q); for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[r_state][ascii_code]; if (temp_state == SC_AC_BS_FAIL) continue; SCACBSEnqueue(&q, temp_state); state = ctx->failure_table[r_state]; while(ctx->goto_table[state][ascii_code] == SC_AC_BS_FAIL) state = ctx->failure_table[state]; ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code]; SCACBSClubOutputStates(temp_state, ctx->failure_table[temp_state], mpm_ctx); } } return; } /** * \internal * \brief Create the delta table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSCreateDeltaTable(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int ascii_code = 0; int32_t r_state = 0; if (ctx->state_count < 32767) { ctx->state_table_u16 = SCMalloc(ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U16) * 256); if (ctx->state_table_u16 == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->state_table_u16, 0, ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U16) * 256); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U16) * 256); StateQueue q; memset(&q, 0, sizeof(StateQueue)); for (ascii_code = 0; ascii_code < 256; ascii_code++) { SC_AC_BS_STATE_TYPE_U16 temp_state = ctx->goto_table[0][ascii_code]; ctx->state_table_u16[0][ascii_code] = temp_state; if (temp_state != 0) SCACBSEnqueue(&q, temp_state); } while (!SCACBSStateQueueIsEmpty(&q)) { r_state = SCACBSDequeue(&q); for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[r_state][ascii_code]; if (temp_state != SC_AC_BS_FAIL) { SCACBSEnqueue(&q, temp_state); ctx->state_table_u16[r_state][ascii_code] = temp_state; } else { ctx->state_table_u16[r_state][ascii_code] = ctx->state_table_u16[ctx->failure_table[r_state]][ascii_code]; } } } } else { /* create space for the state table. We could have used the existing goto * table, but since we have it set to hold 32 bit state values, we will create * a new state table here of type SC_AC_BS_STATE_TYPE(current set to uint16_t) */ ctx->state_table_u32 = SCMalloc(ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U32) * 256); if (ctx->state_table_u32 == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->state_table_u32, 0, ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U32) * 256); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U32) * 256); StateQueue q; memset(&q, 0, sizeof(StateQueue)); for (ascii_code = 0; ascii_code < 256; ascii_code++) { SC_AC_BS_STATE_TYPE_U32 temp_state = ctx->goto_table[0][ascii_code]; ctx->state_table_u32[0][ascii_code] = temp_state; if (temp_state != 0) SCACBSEnqueue(&q, temp_state); } while (!SCACBSStateQueueIsEmpty(&q)) { r_state = SCACBSDequeue(&q); for (ascii_code = 0; ascii_code < 256; ascii_code++) { int32_t temp_state = ctx->goto_table[r_state][ascii_code]; if (temp_state != SC_AC_BS_FAIL) { SCACBSEnqueue(&q, temp_state); ctx->state_table_u32[r_state][ascii_code] = temp_state; } else { ctx->state_table_u32[r_state][ascii_code] = ctx->state_table_u32[ctx->failure_table[r_state]][ascii_code]; } } } } return; } static inline void SCACBSClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int ascii_code = 0; uint32_t state = 0; uint32_t temp_state = 0; if (ctx->state_count < 32767) { for (state = 0; state < ctx->state_count; state++) { for (ascii_code = 0; ascii_code < 256; ascii_code++) { temp_state = ctx->state_table_u16[state & 0x7FFF][ascii_code]; if (ctx->output_table[temp_state & 0x7FFF].no_of_entries != 0) ctx->state_table_u16[state & 0x7FFF][ascii_code] |= (1 << 15); } } } else { for (state = 0; state < ctx->state_count; state++) { for (ascii_code = 0; ascii_code < 256; ascii_code++) { temp_state = ctx->state_table_u32[state & 0x00FFFFFF][ascii_code]; if (ctx->output_table[temp_state & 0x00FFFFFF].no_of_entries != 0) ctx->state_table_u32[state & 0x00FFFFFF][ascii_code] |= (1 << 24); } } } return; } static inline void SCACBSInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; uint32_t state = 0; uint32_t k = 0; for (state = 0; state < ctx->state_count; state++) { if (ctx->output_table[state].no_of_entries == 0) continue; for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { ctx->output_table[state].pids[k] &= 0x0000FFFF; ctx->output_table[state].pids[k] |= 1 << 16; } } } return; } #if 0 static void SCACBSPrintDeltaTable(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int i = 0, j = 0; printf("##############Delta Table##############\n"); for (i = 0; i < ctx->state_count; i++) { printf("%d: \n", i); for (j = 0; j < 256; j++) { if (SCACBSGetDelta(i, j, mpm_ctx) != 0) { printf(" %c -> %d\n", j, SCACBSGetDelta(i, j, mpm_ctx)); } } } return; } #endif static inline int SCACBSZeroTransitionPresent(SCACBSCtx *ctx, uint32_t state) { if (state == 0) return 1; if (ctx->state_count < 32767) { int ascii; for (ascii = 0; ascii < 256; ascii++) { if ((ctx->state_table_u16[0][ascii] & 0x7fff) == (state & 0x7fff)) { return 1; } } return 0; } else { int ascii; for (ascii = 0; ascii < 256; ascii++) { if ((ctx->state_table_u32[0][ascii] & 0x00FFFFFF) == (state & 0x00FFFFFF)) { return 1; } } return 0; } } /** * \internal * \brief Creates a new goto table structure(throw out all the failure * transitions), to hold the existing goto table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSCreateModDeltaTable(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; if (ctx->state_count < 32767) { int size = 0; uint32_t state; for (state = 1; state < ctx->state_count; state++) { int ascii_code; int k = 0; for (ascii_code = 0; ascii_code < 256; ascii_code++) { uint32_t temp_state = ctx->state_table_u16[state][ascii_code]; if (SCACBSZeroTransitionPresent(ctx, temp_state)) continue; k++; } size += sizeof(uint16_t) * k * 2; } /* Let us use uint16_t for all. That way we don//'t have to worry about * alignment. Technically 8 bits is all we need to store ascii codes, * but by avoiding it, we save a lot of time on handling alignment */ size += (ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U16) + 256 * sizeof(SC_AC_BS_STATE_TYPE_U16) * 1); ctx->state_table_mod = SCMalloc(size); if (ctx->state_table_mod == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->state_table_mod, 0, size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += size; /* buffer to hold pointers in the buffer, so that a state can use it * directly to access its state data */ ctx->state_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *)); if (ctx->state_table_mod_pointers == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->state_table_mod_pointers, 0, ctx->state_count * sizeof(uint8_t *)); SC_AC_BS_STATE_TYPE_U16 temp_states[256]; uint16_t *curr_loc = (uint16_t *)ctx->state_table_mod; uint16_t *no_of_entries = NULL; uint16_t *ascii_codes = NULL; state = 0; uint16_t ascii_code = 0; uint16_t k = 0; for (state = 0; state < ctx->state_count; state++) { /* store the starting location in the buffer for this state */ ctx->state_table_mod_pointers[state] = (uint8_t *)curr_loc; no_of_entries = curr_loc++; ascii_codes = curr_loc; k = 0; /* store all states that have non 0 transitions in the temp buffer */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { uint32_t temp_state = ctx->state_table_u16[state][ascii_code]; if (state != 0 && SCACBSZeroTransitionPresent(ctx, temp_state)) continue; ascii_codes[k] = ascii_code; temp_states[k] = ctx->state_table_u16[state][ascii_code]; k++; } /* if we have any non 0 transitions from our previous for search, * store the acii codes as well the corresponding states */ if (k > 0) { no_of_entries[0] = k; if (state != 0) curr_loc += k; memcpy(curr_loc, temp_states, k * sizeof(SC_AC_BS_STATE_TYPE_U16)); curr_loc += k; } } /* > 33766 */ } else { int size = 0; uint32_t state; for (state = 1; state < ctx->state_count; state++) { int ascii_code; int k = 0; for (ascii_code = 0; ascii_code < 256; ascii_code++) { uint32_t temp_state = ctx->state_table_u32[state][ascii_code]; if (SCACBSZeroTransitionPresent(ctx, temp_state)) continue; k++; } size += sizeof(uint32_t) * k * 2; } /* Let us use uint32_t for all. That way we don//'t have to worry about * alignment. Technically 8 bits is all we need to store ascii codes, * but by avoiding it, we save a lot of time on handling alignment */ size += (ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U32) + 256 * sizeof(SC_AC_BS_STATE_TYPE_U32) * 1); ctx->state_table_mod = SCMalloc(size); if (ctx->state_table_mod == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->state_table_mod, 0, size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += size; /* buffer to hold pointers in the buffer, so that a state can use it * directly to access its state data */ ctx->state_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *)); if (ctx->state_table_mod_pointers == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->state_table_mod_pointers, 0, ctx->state_count * sizeof(uint8_t *)); SC_AC_BS_STATE_TYPE_U32 temp_states[256]; uint32_t *curr_loc = (uint32_t *)ctx->state_table_mod; uint32_t *no_of_entries = NULL; uint32_t *ascii_codes = NULL; state = 0; uint32_t ascii_code = 0; uint32_t k = 0; for (state = 0; state < ctx->state_count; state++) { /* store the starting location in the buffer for this state */ ctx->state_table_mod_pointers[state] = (uint8_t *)curr_loc; no_of_entries = curr_loc++; ascii_codes = curr_loc; k = 0; /* store all states that have non 0 transitions in the temp buffer */ for (ascii_code = 0; ascii_code < 256; ascii_code++) { uint32_t temp_state = ctx->state_table_u32[state][ascii_code]; if (state != 0 && SCACBSZeroTransitionPresent(ctx, temp_state)) continue; ascii_codes[k] = ascii_code; temp_states[k] = ctx->state_table_u32[state][ascii_code]; k++; } /* if we have any non 0 transitions from our previous for search, * store the acii codes as well the corresponding states */ if (k > 0) { no_of_entries[0] = k; if (state != 0) curr_loc += k; memcpy(curr_loc, temp_states, k * sizeof(SC_AC_BS_STATE_TYPE_U32)); curr_loc += k; } } } return; } /** * \brief Process the patterns and prepare the state table. * * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSPrepareStateTable(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; /* create the 0th state in the goto table and output_table */ SCACBSInitNewState(mpm_ctx); /* create the goto table */ SCACBSCreateGotoTable(mpm_ctx); /* create the failure table */ SCACBSCreateFailureTable(mpm_ctx); /* create the final state(delta) table */ SCACBSCreateDeltaTable(mpm_ctx); /* club the output state presence with delta transition entries */ SCACBSClubOutputStatePresenceWithDeltaTable(mpm_ctx); /* create the modified table */ SCACBSCreateModDeltaTable(mpm_ctx); /* club nocase entries */ SCACBSInsertCaseSensitiveEntriesForPatterns(mpm_ctx); // int state = 0; // for (state = 0; state < ctx->state_count; state++) { // int i = 0; // for (i = 0; i < 256; i++) { // if (ctx->state_table_u16[state][i] != 0) { // printf("%d-%d-%d\n", state, i, ctx->state_table_u16[state][i] & 0x7fff) ; // } // } // } #if 0 SCACBSPrintDeltaTable(mpm_ctx); #endif /* we don't need these anymore */ SCFree(ctx->goto_table); ctx->goto_table = NULL; SCFree(ctx->failure_table); ctx->failure_table = NULL; SCFree(ctx->state_table_u16); ctx->state_table_u16 = NULL; SCFree(ctx->state_table_u32); ctx->state_table_u32 = NULL; return; } /** * \brief Process the patterns added to the mpm, and create the internal tables. * * \param mpm_ctx Pointer to the mpm context. */ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ ctx->parray = (SCACBSPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); if (ctx->parray == NULL) goto error; memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; for (i = 0; i < INIT_HASH_SIZE; i++) { SCACBSPattern *node = ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; ctx->parray[p++] = node; node = nnode; } } /* we no longer need the hash, so free it's memory */ SCFree(ctx->init_hash); ctx->init_hash = NULL; /* the memory consumed by a single state in our goto table */ ctx->single_state_size = sizeof(int32_t) * 256; /* handle no case patterns */ ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACBSPatternList)); if (ctx->pid_pat_list == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACBSPatternList)); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE) { if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 0) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 1; else if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 1) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 1; else ctx->pid_pat_list[ctx->parray[i]->id].case_state = 3; } else { //if (memcmp(ctx->parray[i]->original_pat, ctx->parray[i]->ci, // ctx->parray[i]->len) != 0) { ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, ctx->parray[i]->original_pat, ctx->parray[i]->len); ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 0) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 2; else if (ctx->pid_pat_list[ctx->parray[i]->id].case_state == 2) ctx->pid_pat_list[ctx->parray[i]->id].case_state = 2; else ctx->pid_pat_list[ctx->parray[i]->id].case_state = 3; //} } } /* prepare the state table required by AC */ SCACBSPrepareStateTable(mpm_ctx); /* free all the stored patterns. Should save us a good 100-200 mbs */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { SCACBSFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); return 0; error: return -1; } /** * \brief Init the mpm thread context. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. * \param matchsize We don't need this. */ void SCACBSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); mpm_thread_ctx->ctx = SCMalloc(sizeof(SCACBSThreadCtx)); if (mpm_thread_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_thread_ctx->ctx, 0, sizeof(SCACBSThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(SCACBSThreadCtx); return; } /** * \brief Initialize the AC context. * * \param mpm_ctx Mpm context. * \param module_handle Cuda module handle from the cuda handler API. We don't * have to worry about this here. */ void SCACBSInitCtx(MpmCtx *mpm_ctx, int module_handle) { if (mpm_ctx->ctx != NULL) return; mpm_ctx->ctx = SCMalloc(sizeof(SCACBSCtx)); if (mpm_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_ctx->ctx, 0, sizeof(SCACBSCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(SCACBSCtx); /* initialize the hash we use to speed up pattern insertions */ SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; ctx->init_hash = SCMalloc(sizeof(SCACBSPattern *) * INIT_HASH_SIZE); if (ctx->init_hash == NULL) { exit(EXIT_FAILURE); } memset(ctx->init_hash, 0, sizeof(SCACBSPattern *) * INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ SCACBSGetConfig(); SCReturn; } /** * \brief Destroy the mpm thread context. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. */ void SCACBSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { SCACBSPrintSearchStats(mpm_thread_ctx); if (mpm_thread_ctx->ctx != NULL) { SCFree(mpm_thread_ctx->ctx); mpm_thread_ctx->ctx = NULL; mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(SCACBSThreadCtx); } return; } /** * \brief Destroy the mpm context. * * \param mpm_ctx Pointer to the mpm context. */ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->init_hash != NULL) { SCFree(ctx->init_hash); ctx->init_hash = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACBSPattern *)); } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { SCACBSFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); } if (ctx->state_table_u16 != NULL) { SCFree(ctx->state_table_u16); ctx->state_table_u16 = NULL; mpm_ctx->memory_cnt++; mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U16) * 256); } else if (ctx->state_table_u32 != NULL) { SCFree(ctx->state_table_u32); ctx->state_table_u32 = NULL; mpm_ctx->memory_cnt++; mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U32) * 256); } if (ctx->output_table != NULL) { uint32_t state_count; for (state_count = 0; state_count < ctx->state_count; state_count++) { if (ctx->output_table[state_count].pids != NULL) { SCFree(ctx->output_table[state_count].pids); } } SCFree(ctx->output_table); } if (ctx->pid_pat_list != NULL) { int i; for (i = 0; i < (ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); } SCFree(ctx->pid_pat_list); } if (ctx->state_table_mod != NULL) { SCFree(ctx->state_table_mod); ctx->state_table_mod = NULL; } if (ctx->state_table_mod_pointers != NULL) { SCFree(ctx->state_table_mod_pointers); ctx->state_table_mod_pointers = NULL; } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(SCACBSCtx); return; } /** * \brief The aho corasick search function. * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. * \param pmq Pointer to the Pattern Matcher Queue to hold * search matches. * \param buf Buffer to be searched. * \param buflen Buffer length. * * \retval matches Match count. */ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int i = 0; int matches = 0; uint8_t buf_local; /* \todo tried loop unrolling with register var, with no perf increase. Need * to dig deeper */ /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACBSPatternList *pid_pat_list = ctx->pid_pat_list; if (ctx->state_count < 32767) { register SC_AC_BS_STATE_TYPE_U16 state = 0; uint16_t no_of_entries; uint16_t *ascii_codes; uint16_t **state_table_mod_pointers = (uint16_t **)ctx->state_table_mod_pointers; uint16_t *zero_state = state_table_mod_pointers[0] + 1; for (i = 0; i < buflen; i++) { if (state == 0) { state = zero_state[u8_tolower(buf[i])]; } else { no_of_entries = *(state_table_mod_pointers[state & 0x7FFF]); if (no_of_entries == 1) { ascii_codes = state_table_mod_pointers[state & 0x7FFF] + 1; buf_local = u8_tolower(buf[i]); if (buf_local == ascii_codes[0]) { state = *(ascii_codes + no_of_entries);; } else { state = zero_state[buf_local]; } } else { if (no_of_entries == 0) { state = zero_state[u8_tolower(buf[i])]; goto match_u16; } buf_local = u8_tolower(buf[i]); ascii_codes = state_table_mod_pointers[state & 0x7FFF] + 1; int low = 0; int high = no_of_entries; int mid; state = 0; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { state = ((ascii_codes + no_of_entries))[mid]; goto match_u16; } else if (ascii_codes[mid] < buf_local) { low = mid + 1; } else { high = mid - 1; } } /* while */ state = zero_state[buf_local]; } /* else - if (no_of_entires == 1) */ } match_u16: if (state & 0x8000) { uint32_t no_of_entries = ctx->output_table[state & 0x7FFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { if ((i + 1) < pid_pat_list[pids[k] & 0x0000FFFF].patlen) continue; if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { /* inside loop */ if (pid_pat_list[pids[k] & 0x0000FFFF].case_state != 3) { continue; } } if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; } matches++; } else { if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; } matches++; } //loop1: //; } } } /* for (i = 0; i < buflen; i++) */ } else { register SC_AC_BS_STATE_TYPE_U32 state = 0; uint32_t no_of_entries; uint32_t *ascii_codes; uint32_t **state_table_mod_pointers = (uint32_t **)ctx->state_table_mod_pointers; uint32_t *zero_state = state_table_mod_pointers[0] + 1; for (i = 0; i < buflen; i++) { if (state == 0) { state = zero_state[u8_tolower(buf[i])]; } else { no_of_entries = *(state_table_mod_pointers[state & 0x00FFFFFF]); if (no_of_entries == 1) { ascii_codes = state_table_mod_pointers[state & 0x00FFFFFF] + 1; buf_local = u8_tolower(buf[i]); if (buf_local == ascii_codes[0]) { state = *(ascii_codes + no_of_entries);; } else { state = zero_state[buf_local];; } } else { if (no_of_entries == 0) { state = zero_state[u8_tolower(buf[i])]; goto match_u32; } buf_local = u8_tolower(buf[i]); ascii_codes = state_table_mod_pointers[state & 0x00FFFFFF] + 1; int low = 0; int high = no_of_entries; int mid; state = 0; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { state = ((ascii_codes + no_of_entries))[mid]; goto match_u32; } else if (ascii_codes[mid] < buf_local) { low = mid + 1; } else { high = mid - 1; } } /* while */ state = zero_state[buf_local]; } /* else - if (no_of_entires == 1) */ } match_u32: if (state & 0xFF000000) { uint32_t no_of_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; uint32_t k; for (k = 0; k < no_of_entries; k++) { if (pids[k] & 0xFFFF0000) { if ((i + 1) < pid_pat_list[pids[k] & 0x0000FFFF].patlen) continue; if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { /* inside loop */ if (pid_pat_list[pids[k] & 0x0000FFFF].case_state != 3) { continue; } } if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { ; } else { pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; } matches++; } else { if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; } matches++; } //loop1: //; } } } /* for (i = 0; i < buflen; i++) */ } return matches; } /** * \brief Add a case insensitive pattern. Although we have different calls for * adding case sensitive and insensitive patterns, we make a single call * for either case. No special treatment for either case. * * \param mpm_ctx Pointer to the mpm context. * \param pat The pattern to add. * \param patnen The pattern length. * \param offset Ignored. * \param depth Ignored. * \param pid The pattern id. * \param sid Ignored. * \param flags Flags associated with this pattern. * * \retval 0 On success. * \retval -1 On failure. */ int SCACBSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return SCACBSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } /** * \brief Add a case sensitive pattern. Although we have different calls for * adding case sensitive and insensitive patterns, we make a single call * for either case. No special treatment for either case. * * \param mpm_ctx Pointer to the mpm context. * \param pat The pattern to add. * \param patnen The pattern length. * \param offset Ignored. * \param depth Ignored. * \param pid The pattern id. * \param sid Ignored. * \param flags Flags associated with this pattern. * * \retval 0 On success. * \retval -1 On failure. */ int SCACBSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return SCACBSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef SC_AC_BS_COUNTERS SCACBSThreadCtx *ctx = (SCACBSThreadCtx *)mpm_thread_ctx->ctx; printf("AC Thread Search stats (ctx %p)\n", ctx); printf("Total calls: %" PRIu32 "\n", ctx->total_calls); printf("Total matches: %" PRIu64 "\n", ctx->total_matches); #endif /* SC_AC_BS_COUNTERS */ return; } void SCACBSPrintInfo(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; printf("MPM AC Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); printf(" Sizeof:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" SCACBSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSCtx)); printf(" SCACBSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSPattern)); printf(" SCACBSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count); printf("\n"); return; } /*************************************Unittests********************************/ #ifdef UNITTESTS static int SCACBSTest01(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest02(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest03(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest04(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest05(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACBSAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); SCACBSAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); SCACBSAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghjiklmnopqrstuvwxyz"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest06(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcd"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest07(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* should match 30 times */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 29 times */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 28 times */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* 26 */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 21 */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 1 */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); PmqSetup(&pmq, 0, 6); /* total matches: 135 */ SCACBSPreparePatterns(&mpm_ctx); char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest08(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest09(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest10(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "abcdefgh" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest11(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); if (SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; if (SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) goto end; if (SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) goto end; if (SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; PmqSetup(&pmq, 0, 5); if (SCACBSPreparePatterns(&mpm_ctx) == -1) goto end; result = 1; char *buf = "he"; result &= (SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); buf = "she"; result &= (SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); buf = "his"; result &= (SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); buf = "hers"; result &= (SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); end: SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest12(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest13(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest14(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest15(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest16(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzABC"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest17(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyzAB"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest18(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest19(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); PmqFree(&pmq); return result; } static int SCACBSTest20(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest21(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest22(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest23(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); if (cnt == 0) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest24(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 1 */ SCACBSAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest25(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACBSAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); SCACBSAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); SCACBSAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); PmqSetup(&pmq, 0, 3); SCACBSPreparePatterns(&mpm_ctx); char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest26(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACBSAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); PmqSetup(&pmq, 0, 2); SCACBSPreparePatterns(&mpm_ctx); char *buf = "works"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest27(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 0 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "tone"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest28(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); /* 0 match */ SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); PmqSetup(&pmq, 0, 1); SCACBSPreparePatterns(&mpm_ctx); char *buf = "tONE"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest29(void) { int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; PatternMatcherQueue pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS, -1); SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"bcdef", 5, 0, 0, 1, 0, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"cdefg", 5, 0, 0, 3, 0, 0); SCACBSAddPatternCS(&mpm_ctx, (uint8_t *)"defgh", 5, 0, 0, 4, 0, 0); PmqSetup(&pmq, 0, 4); SCACBSPreparePatterns(&mpm_ctx); char *buf = "abcdefgh"; uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); if (cnt == 4) result = 1; else printf("3 != %" PRIu32 " ",cnt); SCACBSDestroyCtx(&mpm_ctx); SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); PmqFree(&pmq); return result; } static int SCACBSTest30(void) { uint8_t *buf = (uint8_t *)"onetwothreefourfivesixseveneightnine"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->mpm_matcher = MPM_AC_BS; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); if (de_ctx->sig_list->next == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) != 1) { printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); goto end; } if (PacketAlertCheck(p, 2) != 1) { printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void SCACBSRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCACBSTest01", SCACBSTest01, 1); UtRegisterTest("SCACBSTest02", SCACBSTest02, 1); UtRegisterTest("SCACBSTest03", SCACBSTest03, 1); UtRegisterTest("SCACBSTest04", SCACBSTest04, 1); UtRegisterTest("SCACBSTest05", SCACBSTest05, 1); UtRegisterTest("SCACBSTest06", SCACBSTest06, 1); UtRegisterTest("SCACBSTest07", SCACBSTest07, 1); UtRegisterTest("SCACBSTest08", SCACBSTest08, 1); UtRegisterTest("SCACBSTest09", SCACBSTest09, 1); UtRegisterTest("SCACBSTest10", SCACBSTest10, 1); UtRegisterTest("SCACBSTest11", SCACBSTest11, 1); UtRegisterTest("SCACBSTest12", SCACBSTest12, 1); UtRegisterTest("SCACBSTest13", SCACBSTest13, 1); UtRegisterTest("SCACBSTest14", SCACBSTest14, 1); UtRegisterTest("SCACBSTest15", SCACBSTest15, 1); UtRegisterTest("SCACBSTest16", SCACBSTest16, 1); UtRegisterTest("SCACBSTest17", SCACBSTest17, 1); UtRegisterTest("SCACBSTest18", SCACBSTest18, 1); UtRegisterTest("SCACBSTest19", SCACBSTest19, 1); UtRegisterTest("SCACBSTest20", SCACBSTest20, 1); UtRegisterTest("SCACBSTest21", SCACBSTest21, 1); UtRegisterTest("SCACBSTest22", SCACBSTest22, 1); UtRegisterTest("SCACBSTest23", SCACBSTest23, 1); UtRegisterTest("SCACBSTest24", SCACBSTest24, 1); UtRegisterTest("SCACBSTest25", SCACBSTest25, 1); UtRegisterTest("SCACBSTest26", SCACBSTest26, 1); UtRegisterTest("SCACBSTest27", SCACBSTest27, 1); UtRegisterTest("SCACBSTest28", SCACBSTest28, 1); UtRegisterTest("SCACBSTest29", SCACBSTest29, 1); UtRegisterTest("SCACBSTest30", SCACBSTest30, 1); #endif return; } suricata-1.4.7/src/stream-tcp-reassemble.c0000644000000000000000000114303112253546156015373 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * \author Victor Julien * * Reference: * Judy Novak, Steve Sturges: Target-Based TCP Stream Reassembly August, 2007 * */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "threads.h" #include "flow-util.h" #include "threadvars.h" #include "tm-threads.h" #include "util-pool.h" #include "util-unittest.h" #include "util-print.h" #include "util-host-os-info.h" #include "util-unittest-helper.h" #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp-inline.h" #include "stream-tcp-util.h" #include "stream.h" #include "util-debug.h" #include "app-layer-protos.h" #include "app-layer.h" #include "detect-engine-state.h" #include "util-profiling.h" #define PSEUDO_PACKET_PAYLOAD_SIZE 65416 /* 64 Kb minus max IP and TCP header */ #ifdef DEBUG static SCMutex segment_pool_memuse_mutex; static uint64_t segment_pool_memuse = 0; static uint64_t segment_pool_memcnt = 0; #endif /* We define several pools with prealloced segments with fixed size * payloads. We do this to prevent having to do an SCMalloc call for every * data segment we receive, which would be a large performance penalty. * The cost is in memory of course. */ #define segment_pool_num 8 static uint16_t segment_pool_pktsizes[segment_pool_num] = {4, 16, 112, 248, 512, 768, 1448, 0xffff}; //static uint16_t segment_pool_poolsizes[segment_pool_num] = {2048, 3072, 3072, // 3072, 3072, 8192, // 8192, 512}; static uint16_t segment_pool_poolsizes[segment_pool_num] = {0, 0, 0, 0, 0, 0, 0, 0}; static uint16_t segment_pool_poolsizes_prealloc[segment_pool_num] = {256, 512, 512, 512, 512, 1024, 1024, 128}; static Pool *segment_pool[segment_pool_num]; static SCMutex segment_pool_mutex[segment_pool_num]; #ifdef DEBUG static SCMutex segment_pool_cnt_mutex; static uint64_t segment_pool_cnt = 0; #endif /* index to the right pool for all packet sizes. */ static uint16_t segment_pool_idx[65536]; /* O(1) lookups of the pool */ static int check_overlap_different_data = 0; /* Memory use counter */ SC_ATOMIC_DECLARE(uint64_t, ra_memuse); /* prototypes */ static int HandleSegmentStartsBeforeListSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, TcpSegment *, Packet *); static int HandleSegmentStartsAtSameListSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, TcpSegment *, Packet *); static int HandleSegmentStartsAfterListSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, TcpSegment *, Packet *); void StreamTcpSegmentDataReplace(TcpSegment *, TcpSegment *, uint32_t, uint16_t); void StreamTcpSegmentDataCopy(TcpSegment *, TcpSegment *); TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *, uint16_t); void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t); void StreamTcpReassemblePseudoPacketCreate(TcpStream *, Packet *, PacketQueue *); static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg, uint32_t start_point, uint16_t len); void StreamTcpReassembleConfigEnableOverlapCheck(void) { check_overlap_different_data = 1; } /** * \brief Function to Increment the memory usage counter for the TCP reassembly * segments * * \param size Size of the TCP segment and its payload length memory allocated */ void StreamTcpReassembleIncrMemuse(uint64_t size) { (void) SC_ATOMIC_ADD(ra_memuse, size); return; } /** * \brief Function to Decrease the memory usage counter for the TCP reassembly * segments * * \param size Size of the TCP segment and its payload length memory allocated */ void StreamTcpReassembleDecrMemuse(uint64_t size) { (void) SC_ATOMIC_SUB(ra_memuse, size); return; } void StreamTcpReassembleMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *rtv) { uint64_t smemuse = SC_ATOMIC_GET(ra_memuse); if (tv != NULL && rtv != NULL) SCPerfCounterSetUI64(rtv->counter_tcp_reass_memuse, tv->sc_perf_pca, smemuse); return; } /** * \brief Function to Check the reassembly memory usage counter against the * allowed max memory usgae for TCP segments. * * \param size Size of the TCP segment and its payload length memory allocated * \retval 1 if in bounds * \retval 0 if not in bounds */ int StreamTcpReassembleCheckMemcap(uint32_t size) { if (stream_config.reassembly_memcap == 0 || size + SC_ATOMIC_GET(ra_memuse) <= stream_config.reassembly_memcap) return 1; return 0; } /** \brief alloc a tcp segment pool entry */ void *TcpSegmentPoolAlloc() { if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment)) == 0) { return NULL; } TcpSegment *seg = NULL; seg = SCMalloc(sizeof (TcpSegment)); if (unlikely(seg == NULL)) return NULL; return seg; } int TcpSegmentPoolInit(void *data, void *payload_len) { TcpSegment *seg = (TcpSegment *) data; memset(seg, 0, sizeof (TcpSegment)); seg->pool_size = *((uint16_t *) payload_len); seg->payload_len = seg->pool_size; seg->payload = SCMalloc(seg->payload_len); if (seg->payload == NULL) { SCFree(seg); return 0; } #ifdef DEBUG SCMutexLock(&segment_pool_memuse_mutex); segment_pool_memuse += seg->payload_len; segment_pool_memcnt++; SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); SCMutexUnlock(&segment_pool_memuse_mutex); #endif StreamTcpReassembleIncrMemuse((uint32_t)seg->pool_size + sizeof(TcpSegment)); return 1; } /** \brief clean up a tcp segment pool entry */ void TcpSegmentPoolCleanup(void *ptr) { if (ptr == NULL) return; TcpSegment *seg = (TcpSegment *) ptr; StreamTcpReassembleDecrMemuse((uint32_t)seg->pool_size + sizeof(TcpSegment)); #ifdef DEBUG SCMutexLock(&segment_pool_memuse_mutex); segment_pool_memuse -= seg->pool_size; segment_pool_memcnt--; SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); SCMutexUnlock(&segment_pool_memuse_mutex); #endif SCFree(seg->payload); return; } /** * \brief Function to return the segment back to the pool. * * \param seg Segment which will be returned back to the pool. */ void StreamTcpSegmentReturntoPool(TcpSegment *seg) { if (seg == NULL) return; seg->next = NULL; seg->prev = NULL; uint16_t idx = segment_pool_idx[seg->pool_size]; SCMutexLock(&segment_pool_mutex[idx]); PoolReturn(segment_pool[idx], (void *) seg); SCLogDebug("segment_pool[%"PRIu16"]->empty_list_size %"PRIu32"", idx,segment_pool[idx]->empty_list_size); SCMutexUnlock(&segment_pool_mutex[idx]); #ifdef DEBUG SCMutexLock(&segment_pool_cnt_mutex); segment_pool_cnt--; SCMutexUnlock(&segment_pool_cnt_mutex); #endif } /** * \brief return all segments in this stream into the pool(s) * * \param stream the stream to cleanup */ void StreamTcpReturnStreamSegments (TcpStream *stream) { TcpSegment *seg = stream->seg_list; TcpSegment *next_seg; if (seg == NULL) return; while (seg != NULL) { next_seg = seg->next; StreamTcpSegmentReturntoPool(seg); seg = next_seg; } stream->seg_list = NULL; stream->seg_list_tail = NULL; } int StreamTcpReassembleInit(char quiet) { StreamMsgQueuesInit(); /* init the memcap/use tracker */ SC_ATOMIC_INIT(ra_memuse); #ifdef DEBUG SCMutexInit(&segment_pool_memuse_mutex, NULL); #endif uint16_t u16 = 0; for (u16 = 0; u16 < segment_pool_num; u16++) { SCMutexInit(&segment_pool_mutex[u16], NULL); SCMutexLock(&segment_pool_mutex[u16]); segment_pool[u16] = PoolInit(segment_pool_poolsizes[u16], segment_pool_poolsizes_prealloc[u16], sizeof (TcpSegment), TcpSegmentPoolAlloc, TcpSegmentPoolInit, (void *) &segment_pool_pktsizes[u16], TcpSegmentPoolCleanup, NULL); SCMutexUnlock(&segment_pool_mutex[u16]); } uint16_t idx = 0; u16 = 0; while (1) { if (idx <= segment_pool_pktsizes[u16]) { segment_pool_idx[idx] = u16; if (segment_pool_pktsizes[u16] == idx) u16++; } if (idx == 0xffff) break; idx++; } #ifdef DEBUG SCMutexInit(&segment_pool_cnt_mutex, NULL); #endif return 0; } #ifdef DEBUG extern uint32_t applayererrors; extern uint32_t applayerhttperrors; static uint32_t dbg_app_layer_gap; static uint32_t dbg_app_layer_gap_candidate; #endif void StreamTcpReassembleFree(char quiet) { uint16_t u16 = 0; for (u16 = 0; u16 < segment_pool_num; u16++) { SCMutexLock(&segment_pool_mutex[u16]); if (quiet == FALSE) { PoolPrintSaturation(segment_pool[u16]); SCLogDebug("segment_pool[u16]->empty_list_size %"PRIu32", " "segment_pool[u16]->alloc_list_size %"PRIu32", alloced " "%"PRIu32"", segment_pool[u16]->empty_list_size, segment_pool[u16]->alloc_list_size, segment_pool[u16]->allocated); } PoolFree(segment_pool[u16]); SCMutexUnlock(&segment_pool_mutex[u16]); SCMutexDestroy(&segment_pool_mutex[u16]); } StreamMsgQueuesDeinit(quiet); #ifdef DEBUG SCLogDebug("segment_pool_cnt %"PRIu64"", segment_pool_cnt); SCLogDebug("segment_pool_memuse %"PRIu64"", segment_pool_memuse); SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); SCMutexDestroy(&segment_pool_memuse_mutex); SCMutexDestroy(&segment_pool_cnt_mutex); SCLogInfo("applayererrors %u", applayererrors); SCLogInfo("applayerhttperrors %u", applayerhttperrors); SCLogInfo("dbg_app_layer_gap %u", dbg_app_layer_gap); SCLogInfo("dbg_app_layer_gap_candidate %u", dbg_app_layer_gap_candidate); #endif } TcpReassemblyThreadCtx *StreamTcpReassembleInitThreadCtx(void) { SCEnter(); TcpReassemblyThreadCtx *ra_ctx = SCMalloc(sizeof(TcpReassemblyThreadCtx)); if (unlikely(ra_ctx == NULL)) return NULL; memset(ra_ctx, 0x00, sizeof(TcpReassemblyThreadCtx)); ra_ctx->stream_q = StreamMsgQueueGetNew(); AlpProtoFinalize2Thread(&ra_ctx->dp_ctx); SCReturnPtr(ra_ctx, "TcpReassemblyThreadCtx"); } void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx) { SCEnter(); if (ra_ctx->stream_q != NULL) { StreamMsg *smsg; while ((smsg = StreamMsgGetFromQueue(ra_ctx->stream_q)) != NULL) { StreamMsgReturnToPool(smsg); } StreamMsgQueueFree(ra_ctx->stream_q); } ra_ctx->stream_q = NULL; AlpProtoDeFinalize2Thread(&ra_ctx->dp_ctx); SCFree(ra_ctx); SCReturn; } void PrintList2(TcpSegment *seg) { TcpSegment *prev_seg = NULL; if (seg == NULL) return; uint32_t next_seq = seg->seq; while (seg != NULL) { if (SEQ_LT(next_seq,seg->seq)) { SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data", (seg->seq - next_seq)); } SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p", seg->seq, seg->payload_len, seg, seg->prev, seg->next); if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) { /* check for SEQ_LT cornercase where a - b is exactly 2147483648, * which makes the marco return TRUE in both directions. This is * a hack though, we're going to check next how we end up with * a segment list with seq differences that big */ if (!(SEQ_LT(seg->prev->seq,seg->seq))) { SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) ==" " TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 "" "", seg->seq, seg->prev->seq); } } if (SEQ_LT(seg->seq,next_seq)) { SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, " "seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq, next_seq); } if (prev_seg != seg->prev) { SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p", prev_seg, seg->prev); } next_seq = seg->seq + seg->payload_len; SCLogDebug("next_seq is now %"PRIu32"", next_seq); prev_seg = seg; seg = seg->next; } } void PrintList(TcpSegment *seg) { TcpSegment *prev_seg = NULL; TcpSegment *head_seg = seg; if (seg == NULL) return; uint32_t next_seq = seg->seq; while (seg != NULL) { if (SEQ_LT(next_seq,seg->seq)) { SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data", (seg->seq - next_seq)); } SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p, flags 0x%02x", seg->seq, seg->payload_len, seg, seg->prev, seg->next, seg->flags); if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) { /* check for SEQ_LT cornercase where a - b is exactly 2147483648, * which makes the marco return TRUE in both directions. This is * a hack though, we're going to check next how we end up with * a segment list with seq differences that big */ if (!(SEQ_LT(seg->prev->seq,seg->seq))) { SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) == " "TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 "", seg->seq, seg->prev->seq); PrintList2(head_seg); abort(); } } if (SEQ_LT(seg->seq,next_seq)) { SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, " "seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq, next_seq); PrintList2(head_seg); abort(); } if (prev_seg != seg->prev) { SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p", prev_seg, seg->prev); PrintList2(head_seg); abort(); } next_seq = seg->seq + seg->payload_len; SCLogDebug("next_seq is now %"PRIu32"", next_seq); prev_seg = seg; seg = seg->next; } } /** * \internal * \brief Get the active ra_base_seq, considering stream gaps * * \retval seq the active ra_base_seq */ static inline uint32_t StreamTcpReassembleGetRaBaseSeq(TcpStream *stream) { if (!(stream->flags & STREAMTCP_STREAM_FLAG_GAP)) { SCReturnUInt(stream->ra_app_base_seq); } else { SCReturnUInt(stream->ra_raw_base_seq); } } /** * \internal * \brief Function to handle the insertion newly arrived segment, * The packet is handled based on its target OS. * * \param stream The given TCP stream to which this new segment belongs * \param seg Newly arrived segment * \param p received packet * * \retval 0 success * \retval -1 error -- either we hit a memory issue (OOM/memcap) or we received * a segment before ra_base_seq. */ int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, TcpSegment *seg, Packet *p) { SCEnter(); TcpSegment *list_seg = stream->seg_list; TcpSegment *next_list_seg = NULL; #if DEBUG PrintList(stream->seg_list); #endif int ret_value = 0; char return_seg = FALSE; /* before our ra_app_base_seq we don't insert it in our list, * or ra_raw_base_seq if in stream gap state */ if (SEQ_LT((TCP_GET_SEQ(p)+p->payload_len),(StreamTcpReassembleGetRaBaseSeq(stream)+1))) { SCLogDebug("not inserting: SEQ+payload %"PRIu32", last_ack %"PRIu32", " "ra_(app|raw)_base_seq %"PRIu32, (TCP_GET_SEQ(p)+p->payload_len), stream->last_ack, StreamTcpReassembleGetRaBaseSeq(stream)+1); return_seg = TRUE; ret_value = -1; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ); goto end; } SCLogDebug("SEQ %"PRIu32", SEQ+payload %"PRIu32", last_ack %"PRIu32", " "ra_app_base_seq %"PRIu32, TCP_GET_SEQ(p), (TCP_GET_SEQ(p)+p->payload_len), stream->last_ack, stream->ra_app_base_seq); if (seg == NULL) { goto end; } /* fast track */ if (list_seg == NULL) { SCLogDebug("empty list, inserting seg %p seq %" PRIu32 ", " "len %" PRIu32 "", seg, seg->seq, seg->payload_len); stream->seg_list = seg; seg->prev = NULL; stream->seg_list_tail = seg; goto end; } /* insert the segment in the stream list using this fast track, if seg->seq is equal or higher than stream->seg_list_tail.*/ if (SEQ_GEQ(seg->seq, (stream->seg_list_tail->seq + stream->seg_list_tail->payload_len))) { stream->seg_list_tail->next = seg; seg->prev = stream->seg_list_tail; stream->seg_list_tail = seg; goto end; } /* If the OS policy is not set then set the OS policy for this stream */ if (stream->os_policy == 0) { StreamTcpSetOSPolicy(stream, p); } for (; list_seg != NULL; list_seg = next_list_seg) { next_list_seg = list_seg->next; SCLogDebug("seg %p, list_seg %p, list_prev %p list_seg->next %p, " "segment length %" PRIu32 "", seg, list_seg, list_seg->prev, list_seg->next, seg->payload_len); SCLogDebug("seg->seq %"PRIu32", list_seg->seq %"PRIu32"", seg->seq, list_seg->seq); /* segment starts before list */ if (SEQ_LT(seg->seq, list_seg->seq)) { /* seg is entirely before list_seg */ if (SEQ_LEQ((seg->seq + seg->payload_len), list_seg->seq)) { SCLogDebug("before list seg: seg->seq %" PRIu32 ", list_seg->seq" " %" PRIu32 ", list_seg->payload_len %" PRIu32 ", " "list_seg->prev %p", seg->seq, list_seg->seq, list_seg->payload_len, list_seg->prev); seg->next = list_seg; if (list_seg->prev == NULL) { stream->seg_list = seg; } if (list_seg->prev != NULL) { list_seg->prev->next = seg; seg->prev = list_seg->prev; } list_seg->prev = seg; goto end; /* seg overlap with next seg(s) */ } else { ret_value = HandleSegmentStartsBeforeListSegment(tv, ra_ctx, stream, list_seg, seg, p); if (ret_value == 1) { ret_value = 0; return_seg = TRUE; goto end; } else if (ret_value == -1) { SCLogDebug("HandleSegmentStartsBeforeListSegment failed"); ret_value = -1; return_seg = TRUE; goto end; } } /* seg starts at same sequence number as list_seg */ } else if (SEQ_EQ(seg->seq, list_seg->seq)) { ret_value = HandleSegmentStartsAtSameListSegment(tv, ra_ctx, stream, list_seg, seg, p); if (ret_value == 1) { ret_value = 0; return_seg = TRUE; goto end; } else if (ret_value == -1) { SCLogDebug("HandleSegmentStartsAtSameListSegment failed"); ret_value = -1; return_seg = TRUE; goto end; } /* seg starts at sequence number higher than list_seg */ } else if (SEQ_GT(seg->seq, list_seg->seq)) { if (((SEQ_GEQ(seg->seq, (list_seg->seq + list_seg->payload_len)))) && SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { SCLogDebug("starts beyond list end, ends after list end: " "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 ", " "list_seg->payload_len %" PRIu32 " (%" PRIu32 ")", seg->seq, list_seg->seq, list_seg->payload_len, list_seg->seq + list_seg->payload_len); if (list_seg->next == NULL) { list_seg->next = seg; seg->prev = list_seg; stream->seg_list_tail = seg; goto end; } } else { ret_value = HandleSegmentStartsAfterListSegment(tv, ra_ctx, stream, list_seg, seg, p); if (ret_value == 1) { ret_value = 0; return_seg = TRUE; goto end; } else if (ret_value == -1) { SCLogDebug("HandleSegmentStartsAfterListSegment failed"); ret_value = -1; return_seg = TRUE; goto end; } } } } end: if (return_seg == TRUE && seg != NULL) { StreamTcpSegmentReturntoPool(seg); } #ifdef DEBUG PrintList(stream->seg_list); #endif SCReturnInt(ret_value); } /** * \brief Function to handle the newly arrived segment, when newly arrived * starts with the sequence number lower than the original segment and * ends at different position relative to original segment. * The packet is handled based on its target OS. * * \param list_seg Original Segment in the stream * \param seg Newly arrived segment * \param prev_seg Previous segment in the stream segment list * \param p Packet * * \retval 1 success and done * \retval 0 success, but not done yet * \retval -1 error, will *only* happen on memory errors */ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p) { SCEnter(); uint16_t overlap = 0; uint16_t packet_length = 0; uint32_t overlap_point = 0; char end_before = FALSE; char end_after = FALSE; char end_same = FALSE; char return_after = FALSE; uint8_t os_policy = stream->os_policy; #ifdef DEBUG SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 "", seg->seq, seg->payload_len); PrintList(stream->seg_list); #endif if (SEQ_GT((seg->seq + seg->payload_len), list_seg->seq) && SEQ_LT((seg->seq + seg->payload_len),(list_seg->seq + list_seg->payload_len))) { /* seg starts before list seg, ends beyond it but before list end */ end_before = TRUE; /* [aaaa[abab]bbbb] a = seg, b = list_seg, overlap is the part [abab] * We know seg->seq + seg->payload_len is bigger than list_seg->seq */ overlap = (seg->seq + seg->payload_len) - list_seg->seq; overlap_point = list_seg->seq; SCLogDebug("starts before list seg, ends before list end: seg->seq " "%" PRIu32 ", list_seg->seq %" PRIu32 ", " "list_seg->payload_len %" PRIu16 " overlap is %" PRIu32 ", " "overlap point %"PRIu32"", seg->seq, list_seg->seq, list_seg->payload_len, overlap, overlap_point); } else if (SEQ_EQ((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { /* seg fully overlaps list_seg, starts before, at end point * [aaa[ababab]] where a = seg, b = list_seg * overlap is [ababab], which is list_seg->payload_len */ overlap = list_seg->payload_len; end_same = TRUE; overlap_point = list_seg->seq; SCLogDebug("starts before list seg, ends at list end: list prev %p" "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 "," "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32 "", list_seg->prev, seg->seq, list_seg->seq, list_seg->payload_len, overlap); /* seg fully overlaps list_seg, starts before, ends after list endpoint */ } else if (SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { /* seg fully overlaps list_seg, starts before, ends after list endpoint * [aaa[ababab]aaa] where a = seg, b = list_seg * overlap is [ababab] which is list_seg->payload_len */ overlap = list_seg->payload_len; end_after = TRUE; overlap_point = list_seg->seq; SCLogDebug("starts before list seg, ends after list end: seg->seq " "%" PRIu32 ", seg->payload_len %"PRIu32" list_seg->seq " "%" PRIu32 ", list_seg->payload_len %" PRIu32 " overlap is" " %" PRIu32 "", seg->seq, seg->payload_len, list_seg->seq, list_seg->payload_len, overlap); } if (overlap > 0) { /* handle the case where we need to fill a gap before list_seg first */ if (list_seg->prev != NULL && SEQ_LT((list_seg->prev->seq + list_seg->prev->payload_len), list_seg->seq)) { SCLogDebug("GAP to fill before list segment, size %u", list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len)); uint32_t new_seq = (list_seg->prev->seq + list_seg->prev->payload_len); if (SEQ_GT(seg->seq, new_seq)) { new_seq = seg->seq; } packet_length = list_seg->seq - new_seq; if (packet_length > seg->payload_len) { packet_length = seg->payload_len; } TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); if (new_seg == NULL) { SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); SCReturnInt(-1); } new_seg->payload_len = packet_length; new_seg->seq = new_seq; SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len " "%" PRIu16"", new_seg->seq, new_seg->payload_len); new_seg->next = list_seg; new_seg->prev = list_seg->prev; list_seg->prev->next = new_seg; list_seg->prev = new_seg; /* create a new seg, copy the list_seg data over */ StreamTcpSegmentDataCopy(new_seg, seg); #ifdef DEBUG PrintList(stream->seg_list); #endif } /* Handling case when the segment starts before the first segment in * the list */ if (list_seg->prev == NULL) { if (end_after == TRUE && list_seg->next != NULL && SEQ_LT(list_seg->next->seq, (seg->seq + seg->payload_len))) { packet_length = (list_seg->seq - seg->seq) + list_seg->payload_len; } else { packet_length = seg->payload_len + (list_seg->payload_len - overlap); return_after = TRUE; } SCLogDebug("entered here packet_length %" PRIu32 ", seg->payload_len" " %" PRIu32 ", list->payload_len %" PRIu32 "", packet_length, seg->payload_len, list_seg->payload_len); TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); if (new_seg == NULL) { SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); SCReturnInt(-1); } new_seg->payload_len = packet_length; new_seg->seq = seg->seq; new_seg->next = list_seg->next; new_seg->prev = list_seg->prev; StreamTcpSegmentDataCopy(new_seg, list_seg); /* first the data before the list_seg->seq */ uint16_t replace = (uint16_t) (list_seg->seq - seg->seq); SCLogDebug("copying %"PRIu16" bytes to new_seg", replace); StreamTcpSegmentDataReplace(new_seg, seg, seg->seq, replace); /* if any, data after list_seg->seq + list_seg->payload_len */ if (SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len)) && return_after == TRUE) { replace = (uint16_t)(((seg->seq + seg->payload_len) - (list_seg->seq + list_seg->payload_len))); SCLogDebug("replacing %"PRIu16"", replace); StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq + list_seg->payload_len), replace); } /* update the stream last_seg in case of removal of list_seg */ if (stream->seg_list_tail == list_seg) stream->seg_list_tail = new_seg; StreamTcpSegmentReturntoPool(list_seg); list_seg = new_seg; if (new_seg->prev != NULL) { new_seg->prev->next = new_seg; } if (new_seg->next != NULL) { new_seg->next->prev = new_seg; } stream->seg_list = new_seg; SCLogDebug("list_seg now %p, stream->seg_list now %p", list_seg, stream->seg_list); } else if (end_before == TRUE || end_same == TRUE) { /* Handling overlapping with more than one segment and filling gap */ if (SEQ_GT(list_seg->seq, (list_seg->prev->seq + list_seg->prev->payload_len))) { SCLogDebug("list_seg->prev %p list_seg->prev->seq %"PRIu32" " "list_seg->prev->payload_len %"PRIu16"", list_seg->prev, list_seg->prev->seq, list_seg->prev->payload_len); if (SEQ_LT(list_seg->prev->seq, seg->seq)) { packet_length = list_seg->payload_len + (list_seg->seq - seg->seq); } else { packet_length = list_seg->payload_len + (list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len)); } TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); if (new_seg == NULL) { SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); SCReturnInt(-1); } new_seg->payload_len = packet_length; if (SEQ_GT((list_seg->prev->seq + list_seg->prev->payload_len), seg->seq)) { new_seg->seq = (list_seg->prev->seq + list_seg->prev->payload_len); } else { new_seg->seq = seg->seq; } SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len " "%" PRIu16"", new_seg->seq, new_seg->payload_len); new_seg->next = list_seg->next; new_seg->prev = list_seg->prev; StreamTcpSegmentDataCopy(new_seg, list_seg); uint16_t copy_len = (uint16_t) (list_seg->seq - seg->seq); SCLogDebug("copy_len %" PRIu32 " (%" PRIu32 " - %" PRIu32 ")", copy_len, list_seg->seq, seg->seq); StreamTcpSegmentDataReplace(new_seg, seg, seg->seq, copy_len); /*update the stream last_seg in case of removal of list_seg*/ if (stream->seg_list_tail == list_seg) stream->seg_list_tail = new_seg; StreamTcpSegmentReturntoPool(list_seg); list_seg = new_seg; if (new_seg->prev != NULL) { new_seg->prev->next = new_seg; } if (new_seg->next != NULL) { new_seg->next->prev = new_seg; } } } else if (end_after == TRUE) { if (list_seg->next != NULL) { if (SEQ_LEQ((seg->seq + seg->payload_len), list_seg->next->seq)) { if (SEQ_GT(seg->seq, (list_seg->prev->seq + list_seg->prev->payload_len))) { packet_length = list_seg->payload_len + (list_seg->seq - seg->seq); } else { packet_length = list_seg->payload_len + (list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len)); } packet_length += (seg->seq + seg->payload_len) - (list_seg->seq + list_seg->payload_len); TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); if (new_seg == NULL) { SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); SCReturnInt(-1); } new_seg->payload_len = packet_length; if (SEQ_GT((list_seg->prev->seq + list_seg->prev->payload_len), seg->seq)) { new_seg->seq = (list_seg->prev->seq + list_seg->prev->payload_len); } else { new_seg->seq = seg->seq; } SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len " "%" PRIu16"", new_seg->seq, new_seg->payload_len); new_seg->next = list_seg->next; new_seg->prev = list_seg->prev; /* create a new seg, copy the list_seg data over */ StreamTcpSegmentDataCopy(new_seg, list_seg); /* copy the part before list_seg */ uint16_t copy_len = list_seg->seq - new_seg->seq; StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq, copy_len); /* copy the part after list_seg */ copy_len = (seg->seq + seg->payload_len) - (list_seg->seq + list_seg->payload_len); StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq + list_seg->payload_len), copy_len); if (new_seg->prev != NULL) { new_seg->prev->next = new_seg; } if (new_seg->next != NULL) { new_seg->next->prev = new_seg; } /*update the stream last_seg in case of removal of list_seg*/ if (stream->seg_list_tail == list_seg) stream->seg_list_tail = new_seg; StreamTcpSegmentReturntoPool(list_seg); list_seg = new_seg; return_after = TRUE; } /* Handle the case, when list_seg is the end of segment list, but seg is ending after the list_seg. So we need to copy the data from newly received segment. After copying return the newly received seg to pool */ } else { if (SEQ_GT(seg->seq, (list_seg->prev->seq + list_seg->prev->payload_len))) { packet_length = list_seg->payload_len + (list_seg->seq - seg->seq); } else { packet_length = list_seg->payload_len + (list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len)); } packet_length += (seg->seq + seg->payload_len) - (list_seg->seq + list_seg->payload_len); TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); if (new_seg == NULL) { SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); SCReturnInt(-1); } new_seg->payload_len = packet_length; if (SEQ_GT((list_seg->prev->seq + list_seg->prev->payload_len), seg->seq)) { new_seg->seq = (list_seg->prev->seq + list_seg->prev->payload_len); } else { new_seg->seq = seg->seq; } SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len " "%" PRIu16"", new_seg->seq, new_seg->payload_len); new_seg->next = list_seg->next; new_seg->prev = list_seg->prev; /* create a new seg, copy the list_seg data over */ StreamTcpSegmentDataCopy(new_seg, list_seg); /* copy the part before list_seg */ uint16_t copy_len = list_seg->seq - new_seg->seq; StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq, copy_len); /* copy the part after list_seg */ copy_len = (seg->seq + seg->payload_len) - (list_seg->seq + list_seg->payload_len); StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq + list_seg->payload_len), copy_len); if (new_seg->prev != NULL) { new_seg->prev->next = new_seg; } /*update the stream last_seg in case of removal of list_seg*/ if (stream->seg_list_tail == list_seg) stream->seg_list_tail = new_seg; StreamTcpSegmentReturntoPool(list_seg); list_seg = new_seg; return_after = TRUE; } } if (check_overlap_different_data && !StreamTcpSegmentDataCompare(seg, list_seg, list_seg->seq, overlap)) { /* interesting, overlap with different data */ StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA); } if (StreamTcpInlineMode()) { if (StreamTcpInlineSegmentCompare(seg, list_seg) != 0) { StreamTcpInlineSegmentReplacePacket(p, list_seg); } } else { switch (os_policy) { case OS_POLICY_SOLARIS: case OS_POLICY_HPUX11: if (end_after == TRUE || end_same == TRUE) { StreamTcpSegmentDataReplace(list_seg, seg, overlap_point, overlap); } else { SCLogDebug("using old data in starts before list case, " "list_seg->seq %" PRIu32 " policy %" PRIu32 " " "overlap %" PRIu32 "", list_seg->seq, os_policy, overlap); } break; case OS_POLICY_VISTA: case OS_POLICY_FIRST: SCLogDebug("using old data in starts before list case, " "list_seg->seq %" PRIu32 " policy %" PRIu32 " " "overlap %" PRIu32 "", list_seg->seq, os_policy, overlap); break; case OS_POLICY_BSD: case OS_POLICY_HPUX10: case OS_POLICY_IRIX: case OS_POLICY_WINDOWS: case OS_POLICY_WINDOWS2K3: case OS_POLICY_OLD_LINUX: case OS_POLICY_LINUX: case OS_POLICY_MACOS: case OS_POLICY_LAST: default: SCLogDebug("replacing old data in starts before list seg " "list_seg->seq %" PRIu32 " policy %" PRIu32 " " "overlap %" PRIu32 "", list_seg->seq, os_policy, overlap); StreamTcpSegmentDataReplace(list_seg, seg, overlap_point, overlap); break; } } /* To return from for loop as seg is finished with current list_seg no need to check further (improve performance) */ if (end_before == TRUE || end_same == TRUE || return_after == TRUE) { SCReturnInt(1); } } SCReturnInt(0); } /** * \brief Function to handle the newly arrived segment, when newly arrived * starts with the same sequence number as the original segment and * ends at different position relative to original segment. * The packet is handled based on its target OS. * * \param list_seg Original Segment in the stream * \param seg Newly arrived segment * \param prev_seg Previous segment in the stream segment list * * \retval 1 success and done * \retval 0 success, but not done yet * \retval -1 error, will *only* happen on memory errors */ static int HandleSegmentStartsAtSameListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p) { uint16_t overlap = 0; uint16_t packet_length; char end_before = FALSE; char end_after = FALSE; char end_same = FALSE; char handle_beyond = FALSE; uint8_t os_policy = stream->os_policy; if (SEQ_LT((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { /* seg->seg == list_seg->seq and list_seg->payload_len > seg->payload_len * [[ababab]bbbb] where a = seg, b = list_seg * overlap is the [ababab] part, which equals seg->payload_len. */ overlap = seg->payload_len; end_before = TRUE; SCLogDebug("starts at list seq, ends before list end: seg->seq " "%" PRIu32 ", list_seg->seq %" PRIu32 ", " "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32, seg->seq, list_seg->seq, list_seg->payload_len, overlap); } else if (SEQ_EQ((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { /* seg starts at seq, ends at seq, retransmission. * both segments are the same, so overlap is either * seg->payload_len or list_seg->payload_len */ /* check csum, ack, other differences? */ overlap = seg->payload_len; end_same = TRUE; SCLogDebug("(retransmission) starts at list seq, ends at list end: " "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 ", " "list_seg->payload_len %" PRIu32 " overlap is %"PRIu32"", seg->seq, list_seg->seq, list_seg->payload_len, overlap); } else if (SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { /* seg starts at seq, ends beyond seq. */ /* seg->seg == list_seg->seq and seg->payload_len > list_seg->payload_len * [[ababab]aaaa] where a = seg, b = list_seg * overlap is the [ababab] part, which equals list_seg->payload_len. */ overlap = list_seg->payload_len; end_after = TRUE; SCLogDebug("starts at list seq, ends beyond list end: seg->seq " "%" PRIu32 ", list_seg->seq %" PRIu32 ", " "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32 "", seg->seq, list_seg->seq, list_seg->payload_len, overlap); } if (overlap > 0) { /*Handle the case when newly arrived segment ends after original segment and original segment is the last segment in the list or the next segment in the list starts after the end of new segment*/ if (end_after == TRUE) { char fill_gap = FALSE; if (list_seg->next != NULL) { /* first see if we have space left to fill up */ if (SEQ_LT((list_seg->seq + list_seg->payload_len), list_seg->next->seq)) { fill_gap = TRUE; } /* then see if we overlap (partly) with the next seg */ if (SEQ_GT((seg->seq + seg->payload_len), list_seg->next->seq)) { handle_beyond = TRUE; } /* Handle the case, when list_seg is the end of segment list, but seg is ending after the list_seg. So we need to copy the data from newly received segment. After copying return the newly received seg to pool */ } else { fill_gap = TRUE; } SCLogDebug("fill_gap %s, handle_beyond %s", fill_gap?"TRUE":"FALSE", handle_beyond?"TRUE":"FALSE"); if (fill_gap == TRUE) { /* if there is a gap after this list_seg we fill it now with a * new seg */ SCLogDebug("filling gap: list_seg->next->seq %"PRIu32"", list_seg->next?list_seg->next->seq:0); if (handle_beyond == TRUE) { packet_length = list_seg->next->seq - (list_seg->seq + list_seg->payload_len); } else { packet_length = seg->payload_len - list_seg->payload_len; } SCLogDebug("packet_length %"PRIu16"", packet_length); TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); if (new_seg == NULL) { SCLogDebug("egment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); return -1; } new_seg->payload_len = packet_length; new_seg->seq = list_seg->seq + list_seg->payload_len; new_seg->next = list_seg->next; if (new_seg->next != NULL) new_seg->next->prev = new_seg; new_seg->prev = list_seg; list_seg->next = new_seg; SCLogDebug("new_seg %p, new_seg->next %p, new_seg->prev %p, " "list_seg->next %p", new_seg, new_seg->next, new_seg->prev, list_seg->next); StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq, new_seg->payload_len); /*update the stream last_seg in case of removal of list_seg*/ if (stream->seg_list_tail == list_seg) stream->seg_list_tail = new_seg; } } if (check_overlap_different_data && !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) { /* interesting, overlap with different data */ StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA); } if (StreamTcpInlineMode()) { if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) { StreamTcpInlineSegmentReplacePacket(p, list_seg); } } else { switch (os_policy) { case OS_POLICY_OLD_LINUX: case OS_POLICY_SOLARIS: case OS_POLICY_HPUX11: if (end_after == TRUE || end_same == TRUE) { StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap); } else { SCLogDebug("using old data in starts at list case, " "list_seg->seq %" PRIu32 " policy %" PRIu32 " " "overlap %" PRIu32 "", list_seg->seq, os_policy, overlap); } break; case OS_POLICY_LAST: StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap); break; case OS_POLICY_LINUX: if (end_after == TRUE) { StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap); } else { SCLogDebug("using old data in starts at list case, " "list_seg->seq %" PRIu32 " policy %" PRIu32 " " "overlap %" PRIu32 "", list_seg->seq, os_policy, overlap); } break; case OS_POLICY_BSD: case OS_POLICY_HPUX10: case OS_POLICY_IRIX: case OS_POLICY_WINDOWS: case OS_POLICY_WINDOWS2K3: case OS_POLICY_VISTA: case OS_POLICY_MACOS: case OS_POLICY_FIRST: default: SCLogDebug("using old data in starts at list case, list_seg->seq" " %" PRIu32 " policy %" PRIu32 " overlap %" PRIu32 "", list_seg->seq, os_policy, overlap); break; } } /* return 1 if we're done */ if (end_before == TRUE || end_same == TRUE || handle_beyond == FALSE) { return 1; } } return 0; } /** * \internal * \brief Function to handle the newly arrived segment, when newly arrived * starts with the sequence number higher than the original segment and * ends at different position relative to original segment. * The packet is handled based on its target OS. * * \param list_seg Original Segment in the stream * \param seg Newly arrived segment * \param prev_seg Previous segment in the stream segment list * \retval 1 success and done * \retval 0 success, but not done yet * \retval -1 error, will *only* happen on memory errors */ static int HandleSegmentStartsAfterListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p) { SCEnter(); uint16_t overlap = 0; uint16_t packet_length; char end_before = FALSE; char end_after = FALSE; char end_same = FALSE; char handle_beyond = FALSE; uint8_t os_policy = stream->os_policy; if (SEQ_LT((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { /* seg starts after list, ends before list end * [bbbb[ababab]bbbb] where a = seg, b = list_seg * overlap is the part [ababab] which is seg->payload_len */ overlap = seg->payload_len; end_before = TRUE; SCLogDebug("starts beyond list seq, ends before list end: seg->seq" " %" PRIu32 ", list_seg->seq %" PRIu32 ", list_seg->payload_len " "%" PRIu32 " overlap is %" PRIu32 "", seg->seq, list_seg->seq, list_seg->payload_len, overlap); } else if (SEQ_EQ((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { /* seg starts after seq, before end, ends at seq * [bbbb[ababab]] where a = seg, b = list_seg * overlapping part is [ababab], thus seg->payload_len */ overlap = seg->payload_len; end_same = TRUE; SCLogDebug("starts beyond list seq, ends at list end: seg->seq" " %" PRIu32 ", list_seg->seq %" PRIu32 ", list_seg->payload_len " "%" PRIu32 " overlap is %" PRIu32 "", seg->seq, list_seg->seq, list_seg->payload_len, overlap); } else if (SEQ_LT(seg->seq, list_seg->seq + list_seg->payload_len) && SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq + list_seg->payload_len))) { /* seg starts after seq, before end, ends beyond seq. * * [bbb[ababab]aaa] where a = seg, b = list_seg. * overlap is the [ababab] part, which can be get using: * (list_seg->seq + list_seg->payload_len) - seg->seg */ overlap = (list_seg->seq + list_seg->payload_len) - seg->seq; end_after = TRUE; SCLogDebug("starts beyond list seq, ends after list seq end: " "seg->seq %" PRIu32 ", seg->payload_len %"PRIu16" (%"PRIu32") " "list_seg->seq %" PRIu32 ", list_seg->payload_len %" PRIu32 " " "(%"PRIu32") overlap is %" PRIu32 "", seg->seq, seg->payload_len, seg->seq + seg->payload_len, list_seg->seq, list_seg->payload_len, list_seg->seq + list_seg->payload_len, overlap); } if (overlap > 0) { /*Handle the case when newly arrived segment ends after original segment and original segment is the last segment in the list*/ if (end_after == TRUE) { char fill_gap = FALSE; if (list_seg->next != NULL) { /* first see if we have space left to fill up */ if (SEQ_LT((list_seg->seq + list_seg->payload_len), list_seg->next->seq)) { fill_gap = TRUE; } /* then see if we overlap (partly) with the next seg */ if (SEQ_GT((seg->seq + seg->payload_len), list_seg->next->seq)) { handle_beyond = TRUE; } } else { fill_gap = TRUE; } SCLogDebug("fill_gap %s, handle_beyond %s", fill_gap?"TRUE":"FALSE", handle_beyond?"TRUE":"FALSE"); if (fill_gap == TRUE) { /* if there is a gap after this list_seg we fill it now with a * new seg */ if (list_seg->next != NULL) { SCLogDebug("filling gap: list_seg->next->seq %"PRIu32"", list_seg->next?list_seg->next->seq:0); packet_length = list_seg->next->seq - (list_seg->seq + list_seg->payload_len); } else { packet_length = seg->payload_len - overlap; } if (packet_length > (seg->payload_len - overlap)) { packet_length = seg->payload_len - overlap; } SCLogDebug("packet_length %"PRIu16"", packet_length); TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); if (new_seg == NULL) { SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); SCReturnInt(-1); } new_seg->payload_len = packet_length; new_seg->seq = list_seg->seq + list_seg->payload_len; new_seg->next = list_seg->next; if (new_seg->next != NULL) new_seg->next->prev = new_seg; new_seg->prev = list_seg; list_seg->next = new_seg; SCLogDebug("new_seg %p, new_seg->next %p, new_seg->prev %p, " "list_seg->next %p new_seg->seq %"PRIu32"", new_seg, new_seg->next, new_seg->prev, list_seg->next, new_seg->seq); StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq, new_seg->payload_len); /* update the stream last_seg in case of removal of list_seg */ if (stream->seg_list_tail == list_seg) stream->seg_list_tail = new_seg; } } if (check_overlap_different_data && !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) { /* interesting, overlap with different data */ StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA); } if (StreamTcpInlineMode()) { if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) { StreamTcpInlineSegmentReplacePacket(p, list_seg); } } else { switch (os_policy) { case OS_POLICY_SOLARIS: case OS_POLICY_HPUX11: if (end_after == TRUE) { StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap); } else { SCLogDebug("using old data in starts beyond list case, " "list_seg->seq %" PRIu32 " policy %" PRIu32 " " "overlap %" PRIu32 "", list_seg->seq, os_policy, overlap); } break; case OS_POLICY_LAST: StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap); break; case OS_POLICY_BSD: case OS_POLICY_HPUX10: case OS_POLICY_IRIX: case OS_POLICY_WINDOWS: case OS_POLICY_WINDOWS2K3: case OS_POLICY_VISTA: case OS_POLICY_OLD_LINUX: case OS_POLICY_LINUX: case OS_POLICY_MACOS: case OS_POLICY_FIRST: default: /* DEFAULT POLICY */ SCLogDebug("using old data in starts beyond list case, " "list_seg->seq %" PRIu32 " policy %" PRIu32 " " "overlap %" PRIu32 "", list_seg->seq, os_policy, overlap); break; } } if (end_before == TRUE || end_same == TRUE || handle_beyond == FALSE) { SCReturnInt(1); } } SCReturnInt(0); } /** * \brief check if stream in pkt direction has depth reached * * \param p packet with *LOCKED* flow * * \retval 1 stream has depth reached * \retval 0 stream does not have depth reached */ int StreamTcpReassembleDepthReached(Packet *p) { if (p->flow != NULL && p->flow->protoctx != NULL) { TcpSession *ssn = p->flow->protoctx; TcpStream *stream; if (p->flowflags & FLOW_PKT_TOSERVER) { stream = &ssn->client; } else { stream = &ssn->server; } return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0; } return 0; } /** * \internal * \brief Function to Check the reassembly depth valuer against the * allowed max depth of the stream reassmbly for TCP streams. * * \param stream stream direction * \param seq sequence number where "size" starts * \param size size of the segment that is added * * \retval size Part of the size that fits in the depth, 0 if none */ static uint32_t StreamTcpReassembleCheckDepth(TcpStream *stream, uint32_t seq, uint32_t size) { SCEnter(); /* if the configured depth value is 0, it means there is no limit on reassembly depth. Otherwise carry on my boy ;) */ if (stream_config.reassembly_depth == 0) { SCReturnUInt(size); } /* if the final flag is set, we're not accepting anymore */ if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { SCReturnUInt(0); } /* if the ra_base_seq has moved passed the depth window we stop * checking and just reject the rest of the packets including * retransmissions. Saves us the hassle of dealing with sequence * wraps as well */ if (SEQ_GEQ((StreamTcpReassembleGetRaBaseSeq(stream)+1),(stream->isn + stream_config.reassembly_depth))) { stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED; SCReturnUInt(0); } SCLogDebug("full Depth not yet reached: %"PRIu32" <= %"PRIu32, (StreamTcpReassembleGetRaBaseSeq(stream)+1), (stream->isn + stream_config.reassembly_depth)); if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + stream_config.reassembly_depth))) { /* packet (partly?) fits the depth window */ if (SEQ_LEQ((seq + size),(stream->isn + stream_config.reassembly_depth))) { /* complete fit */ SCReturnUInt(size); } else { /* partial fit, return only what fits */ uint32_t part = (stream->isn + stream_config.reassembly_depth) - seq; #if DEBUG BUG_ON(part > size); #else if (part > size) part = size; #endif SCReturnUInt(part); } } SCReturnUInt(0); } /** * \brief Insert a packets TCP data into the stream reassembly engine. * * \retval 0 good segment, as far as we checked. * \retval -1 badness, reason to drop in inline mode * * If the retval is 0 the segment is inserted correctly, or overlap is handled, * or it wasn't added because of reassembly depth. * */ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); /* If we have reached the defined depth for either of the stream, then stop reassembling the TCP session */ uint32_t size = StreamTcpReassembleCheckDepth(stream, TCP_GET_SEQ(p), p->payload_len); SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size); if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { /* increment stream depth counter */ SCPerfCounterIncr(ra_ctx->counter_tcp_stream_depth, tv->sc_perf_pca); stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY; SCLogDebug("ssn %p: reassembly depth reached, " "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn); } if (size == 0) { SCLogDebug("ssn %p: depth reached, not reassembling", ssn); SCReturnInt(0); } #if DEBUG BUG_ON(size > p->payload_len); #else if (size > p->payload_len) size = p->payload_len; #endif TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx, size); if (seg == NULL) { SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[size]); StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); SCReturnInt(-1); } memcpy(seg->payload, p->payload, size); seg->payload_len = size; seg->seq = TCP_GET_SEQ(p); if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p) != 0) { SCLogDebug("StreamTcpReassembleInsertSegment failed"); SCReturnInt(-1); } SCReturnInt(0); } #define STREAM_SET_FLAGS(ssn, stream, p, flag) { \ flag = 0; \ if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ flag |= STREAM_START; \ } \ if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { \ flag |= STREAM_EOF; \ } \ if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ flag |= STREAM_TOCLIENT; \ } else { \ flag |= STREAM_TOSERVER; \ } \ if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { \ flag |= STREAM_DEPTH; \ } \ } #define STREAM_SET_INLINE_FLAGS(ssn, stream, p, flag) { \ flag = 0; \ if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ flag |= STREAM_START; \ } \ if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { \ flag |= STREAM_EOF; \ } \ if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ flag |= STREAM_TOSERVER; \ } else { \ flag |= STREAM_TOCLIENT; \ } \ if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { \ flag |= STREAM_DEPTH; \ } \ } static void StreamTcpSetupMsg(TcpSession *ssn, TcpStream *stream, Packet *p, StreamMsg *smsg) { SCEnter(); smsg->flags = 0; if (stream->ra_raw_base_seq == stream->isn) { SCLogDebug("setting STREAM_START"); smsg->flags = STREAM_START; } if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { SCLogDebug("setting STREAM_EOF"); smsg->flags |= STREAM_EOF; } if ((!StreamTcpInlineMode() && (p->flowflags & FLOW_PKT_TOSERVER)) || ( StreamTcpInlineMode() && (p->flowflags & FLOW_PKT_TOCLIENT))) { smsg->flags |= STREAM_TOCLIENT; SCLogDebug("stream mesage is to_client"); } else { smsg->flags |= STREAM_TOSERVER; SCLogDebug("stream mesage is to_server"); } smsg->data.data_len = 0; FlowReference(&smsg->flow, p->flow); BUG_ON(smsg->flow == NULL); SCLogDebug("smsg %p", smsg); SCReturn; } /** * \brief Check the minimum size limits for reassembly. * * \retval 0 don't reassemble yet * \retval 1 do reassemble */ static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); if (ssn->flags & STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY) { SCLogDebug("reassembling now as STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY is set"); ssn->flags &= ~STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY; SCReturnInt(1); } /* some states mean we reassemble no matter how much data we have */ if (ssn->state >= TCP_TIME_WAIT) SCReturnInt(1); if (p->flags & PKT_PSEUDO_STREAM_END) SCReturnInt(1); /* check if we have enough data to send to L7 */ if (p->flowflags & FLOW_PKT_TOCLIENT) { SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOSERVER) %"PRIu32, StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER)); if (StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER) > (stream->last_ack - stream->ra_raw_base_seq)) { SCLogDebug("toserver min chunk len not yet reached: " "last_ack %"PRIu32", ra_raw_base_seq %"PRIu32", %"PRIu32" < " "%"PRIu32"", stream->last_ack, stream->ra_raw_base_seq, (stream->last_ack - stream->ra_raw_base_seq), StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER)); SCReturnInt(0); } } else { SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOCLIENT) %"PRIu32, StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT)); if (StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT) > (stream->last_ack - stream->ra_raw_base_seq)) { SCLogDebug("toclient min chunk len not yet reached: " "last_ack %"PRIu32", ra_base_seq %"PRIu32", %"PRIu32" < " "%"PRIu32"", stream->last_ack, stream->ra_raw_base_seq, (stream->last_ack - stream->ra_raw_base_seq), StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT)); SCReturnInt(0); } } SCReturnInt(1); } /** \brief Pause the reassembling for the given stream direction for given TCP * session. * * \param ssn TCP Session to set the flag in * \param direction direction to set the flag in: 1 toserver, 0 toclient */ void StreamTcpReassemblePause (TcpSession *ssn, char direction) { direction ? (ssn->client.flags |= STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY) : (ssn->server.flags |= STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY); } /** \brief Unpause the reassembling for the given stream direction for given TCP * session. * * \param ssn TCP Session to set the flag in * \param direction direction to set the flag in: 1 toserver, 0 toclient */ void StreamTcpReassembleUnPause (TcpSession *ssn, char direction) { direction ? (ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY) : (ssn->server.flags &= ~STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY); } static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) { if (seg->prev == NULL) { stream->seg_list = seg->next; if (stream->seg_list != NULL) stream->seg_list->prev = NULL; } else { seg->prev->next = seg->next; if (seg->next != NULL) seg->next->prev = seg->prev; } if (stream->seg_list_tail == seg) stream->seg_list_tail = seg->prev; } /** * \brief see if app layer is done with a segment * * \retval 1 app layer is done with this segment * \retval 0 not done yet */ #define StreamTcpAppLayerSegmentProcessed(stream, segment) \ (( ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \ ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 )) /** * \brief Update the stream reassembly upon receiving a data segment * * Reassembly is in the same direction of the packet. * * \todo this function is too long, we need to break it up. It needs it BAD */ static int StreamTcpReassembleInlineAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); uint8_t flags = 0; SCLogDebug("pcap_cnt %"PRIu64", len %u", p->pcap_cnt, p->payload_len); SCLogDebug("stream->seg_list %p", stream->seg_list); #ifdef DEBUG PrintList(stream->seg_list); //PrintRawDataFp(stdout, p->payload, p->payload_len); #endif if (stream->seg_list == NULL) { /* send an empty EOF msg if we have no segments but TCP state * is beyond ESTABLISHED */ if (ssn->state > TCP_ESTABLISHED) { SCLogDebug("sending empty eof message"); /* send EOF to app layer */ STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, NULL, 0, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); } else { SCLogDebug("no segments in the list to reassemble"); } SCReturnInt(0); } /* check if reassembling has been paused for the moment or not */ if (stream->flags & STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY) { SCLogDebug("reassembling has been paused for this stream, so no" " reassembling at the moment"); SCReturnInt(0); } if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) { SCReturnInt(0); } /* stream->ra_app_base_seq remains at stream->isn until protocol is * detected. */ uint32_t ra_base_seq = stream->ra_app_base_seq; uint8_t data[4096]; uint32_t data_len = 0; uint16_t payload_offset = 0; uint16_t payload_len = 0; uint32_t next_seq = ra_base_seq + 1; uint32_t data_sent = 0; SCLogDebug("ra_base_seq %u", ra_base_seq); /* loop through the segments and fill one or more msgs */ TcpSegment *seg = stream->seg_list; SCLogDebug("pre-loop seg %p", seg); for (; seg != NULL;) { SCLogDebug("seg %p", seg); if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) { if (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) { SCLogDebug("removing seg %p seq %"PRIu32 " len %"PRIu16"", seg, seg->seq, seg->payload_len); TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; } else { break; } /* if app layer protocol has been detected, then remove all the segments * which has been previously processed and reassembled */ } else if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) && (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && StreamTcpAppLayerSegmentProcessed(stream, seg)) { SCLogDebug("segment(%p) of length %"PRIu16" has been processed," " so return it to pool", seg, seg->payload_len); TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; } /* If packets are fully before ra_base_seq, skip them. We do this * because we've reassembled up to the ra_base_seq point already, * so we won't do anything with segments before it anyway. */ SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" " len %"PRIu16", combined %"PRIu32" and stream->last_ack " "%"PRIu32"", ra_base_seq, seg, seg->seq, seg->payload_len, seg->seq+seg->payload_len, stream->last_ack); /* we've run into a sequence gap */ if (SEQ_GT(seg->seq, next_seq)) { /* first, pass on data before the gap */ if (data_len > 0) { SCLogDebug("pre GAP data"); STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); /* process what we have so far */ AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, data, data_len, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_sent += data_len; data_len = 0; } /* don't conclude it's a gap straight away. If ra_base_seq is lower * than last_ack - the window, we consider it a gap. */ if (SEQ_GT((stream->last_ack - stream->window), ra_base_seq)) { /* see what the length of the gap is, gap length is seg->seq - * (ra_base_seq +1) */ #ifdef DEBUG uint32_t gap_len = seg->seq - next_seq; SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", next_seq, seg->seq, stream->last_ack, gap_len); #endif /* We have missed the packet and end host has ack'd it, so * IDS should advance it's ra_base_seq and should not consider this * packet any longer, even if it is retransmitted, as end host will * drop it anyway */ ra_base_seq = seg->seq - 1; /* send gap signal */ STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, NULL, 0, flags|STREAM_GAP); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_len = 0; /* set a GAP flag and make sure not bothering this stream anymore */ SCLogDebug("set STREAMTCP_STREAM_FLAG_GAP flag"); stream->flags |= STREAMTCP_STREAM_FLAG_GAP; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); #ifdef DEBUG dbg_app_layer_gap++; #endif break; } else { SCLogDebug("possible GAP, but waiting to see if out of order " "packets might solve that"); #ifdef DEBUG dbg_app_layer_gap_candidate++; #endif break; } } /* if the segment ends beyond ra_base_seq we need to consider it */ if (SEQ_GT((seg->seq + seg->payload_len), (ra_base_seq + 1))) { SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " "ra_base_seq %" PRIu32 "", seg->seq, seg->payload_len, ra_base_seq); /* handle segments partly before ra_base_seq */ if (SEQ_GT(ra_base_seq, seg->seq)) { payload_offset = ra_base_seq - seg->seq - 1; payload_len = seg->payload_len - payload_offset; if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); BUG_ON((payload_len + payload_offset) > seg->payload_len); } } else { payload_offset = 0; payload_len = seg->payload_len; } SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" " and stream->next_win is %"PRIu32"", payload_offset, payload_len, stream->next_win); if (payload_len == 0) { SCLogDebug("no payload_len, so bail out"); break; } /* copy the data into the smsg */ uint16_t copy_size = sizeof(data) - data_len; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(data)); } SCLogDebug("copy_size is %"PRIu16"", copy_size); memcpy(data + data_len, seg->payload + payload_offset, copy_size); data_len += copy_size; ra_base_seq += copy_size; SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, ra_base_seq, data_len); /* queue the smsg if it's full */ if (data_len == sizeof(data)) { /* process what we have so far */ STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, data, data_len, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_sent += data_len; data_len = 0; } /* if the payload len is bigger than what we copied, we handle the * rest of the payload next... */ if (copy_size < payload_len) { SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, payload_len); payload_offset += copy_size; payload_len -= copy_size; SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " "%"PRIu16" and stream->last_ack is %"PRIu32"", payload_offset, seg->payload_len, stream->last_ack); if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); } /* we need a while loop here as the packets theoretically can be * 64k */ char segment_done = FALSE; while (segment_done == FALSE) { SCLogDebug("new msg at offset %" PRIu32 ", payload_len " "%" PRIu32 "", payload_offset, payload_len); data_len = 0; copy_size = sizeof(data) - data_len; if (copy_size > (seg->payload_len - payload_offset)) { copy_size = (seg->payload_len - payload_offset); } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(data)); } SCLogDebug("copy payload_offset %" PRIu32 ", data_len " "%" PRIu32 ", copy_size %" PRIu32 "", payload_offset, data_len, copy_size); memcpy(data + data_len, seg->payload + payload_offset, copy_size); data_len += copy_size; ra_base_seq += copy_size; SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); SCLogDebug("copied payload_offset %" PRIu32 ", " "data_len %" PRIu32 ", copy_size %" PRIu32 "", payload_offset, data_len, copy_size); if (data_len == sizeof(data)) { /* process what we have so far */ STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, data, data_len, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_sent += data_len; data_len = 0; } /* see if we have segment payload left to process */ if ((copy_size + payload_offset) < seg->payload_len) { payload_offset += copy_size; payload_len -= copy_size; if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); } } else { payload_offset = 0; segment_done = TRUE; } } } } /* done with this segment, return it to the pool */ TcpSegment *next_seg = seg->next; next_seq = seg->seq + seg->payload_len; seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; seg = next_seg; } /* put the partly filled smsg in the queue to the l7 handler */ if (data_len > 0) { SCLogDebug("data_len > 0, %u", data_len); /* process what we have so far */ STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, data, data_len, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_sent += data_len; } if (data_sent == 0 && ssn->state > TCP_ESTABLISHED) { SCLogDebug("sending empty eof message"); /* send EOF to app layer */ STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, NULL, 0, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); } /* store ra_base_seq in the stream */ if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { stream->ra_app_base_seq = ra_base_seq; } SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq); SCReturnInt(0); } /** * \brief Update the stream reassembly upon receiving a data segment * * | left edge | right edge based on sliding window size * [aaa] * [aaabbb] * ... * [aaabbbcccdddeeefff] * [bbbcccdddeeefffggg] <- cut off aaa to adhere to the window size * * GAP situation: each chunk that is uninterrupted has it's own smsg * [aaabbb].[dddeeefff] * [aaa].[ccc].[eeefff] * * A flag will be set to indicate where the *NEW* payload starts. This * is to aid the detection code for alert only sigs. * * \todo this function is too long, we need to break it up. It needs it BAD */ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); SCLogDebug("start p %p, seq %"PRIu32, p, TCP_GET_SEQ(p)); /* check if reassembling has been paused for the moment or not */ if (stream->flags & STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY) { SCLogDebug("reassembling has been paused for this stream, so no" " reassembling at the moment"); SCReturnInt(0); } if (stream->seg_list == NULL) { SCReturnInt(0); } uint32_t ra_base_seq = stream->ra_raw_base_seq; StreamMsg *smsg = NULL; uint16_t smsg_offset = 0; uint16_t payload_offset = 0; uint16_t payload_len = 0; TcpSegment *seg = stream->seg_list; uint32_t next_seq = ra_base_seq + 1; int gap = 0; uint16_t chunk_size = PKT_IS_TOSERVER(p) ? stream_config.reassembly_toserver_chunk_size : stream_config.reassembly_toclient_chunk_size; /* determine the left edge and right edge */ uint32_t right_edge = TCP_GET_SEQ(p) + p->payload_len; uint32_t left_edge = right_edge - chunk_size; /* shift the window to the right if the left edge doesn't cover segments */ if (SEQ_GT(seg->seq,left_edge)) { right_edge += (seg->seq - left_edge); left_edge = seg->seq; } SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32, left_edge, right_edge); /* loop through the segments and fill one or more msgs */ for (; seg != NULL && SEQ_LT(seg->seq, right_edge); ) { SCLogDebug("seg %p", seg); /* If packets are fully before ra_base_seq, skip them. We do this * because we've reassembled up to the ra_base_seq point already, * so we won't do anything with segments before it anyway. */ SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" " len %"PRIu16", combined %"PRIu32" and right_edge " "%"PRIu32"", ra_base_seq, seg, seg->seq, seg->payload_len, seg->seq+seg->payload_len, right_edge); /* Remove the segments which are completely before the ra_base_seq */ if (SEQ_LT((seg->seq + seg->payload_len), (ra_base_seq - chunk_size))) { SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" " len %"PRIu16"", ra_base_seq, seg, seg->seq, seg->payload_len); /* only remove if app layer reassembly is ready too */ if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; /* otherwise, just flag it for removal */ } else { seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; seg = seg->next; } continue; } /* if app layer protocol has been detected, then remove all the segments * which has been previously processed and reassembled * * If the stream is in GAP state the app layer flag won't be set */ if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) && (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && StreamTcpAppLayerSegmentProcessed(stream, seg)) { SCLogDebug("segment(%p) of length %"PRIu16" has been processed," " so return it to pool", seg, seg->payload_len); TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; } /* we've run into a sequence gap, wrap up any existing smsg and * queue it so the next chunk (if any) is in a new smsg */ if (SEQ_GT(seg->seq, next_seq)) { /* pass on pre existing smsg (if any) */ if (smsg != NULL && smsg->data.data_len > 0) { StreamMsgPutInQueue(ra_ctx->stream_q, smsg); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; } gap = 1; } /* if the segment ends beyond left_edge we need to consider it */ if (SEQ_GT((seg->seq + seg->payload_len), left_edge)) { SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " "left_edge %" PRIu32 "", seg->seq, seg->payload_len, left_edge); /* handle segments partly before ra_base_seq */ if (SEQ_GT(left_edge, seg->seq)) { payload_offset = left_edge - seg->seq; if (SEQ_LT(right_edge, (seg->seq + seg->payload_len))) { payload_len = (right_edge - seg->seq) - payload_offset; } else { payload_len = seg->payload_len - payload_offset; } if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); BUG_ON((payload_len + payload_offset) > seg->payload_len); } } else { payload_offset = 0; if (SEQ_LT(right_edge, (seg->seq + seg->payload_len))) { payload_len = right_edge - seg->seq; } else { payload_len = seg->payload_len; } } SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" " and stream->last_ack is %"PRIu32"", payload_offset, payload_len, stream->last_ack); if (payload_len == 0) { SCLogDebug("no payload_len, so bail out"); break; } if (smsg == NULL) { smsg = StreamMsgGetFromPool(); if (smsg == NULL) { SCLogDebug("stream_msg_pool is empty"); return -1; } smsg_offset = 0; StreamTcpSetupMsg(ssn, stream, p, smsg); smsg->data.seq = ra_base_seq + 1; } /* copy the data into the smsg */ uint16_t copy_size = sizeof (smsg->data.data) - smsg_offset; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(smsg->data.data)); } SCLogDebug("copy_size is %"PRIu16"", copy_size); memcpy(smsg->data.data + smsg_offset, seg->payload + payload_offset, copy_size); smsg_offset += copy_size; SCLogDebug("seg total %u, seq %u off %u copy %u, ra_base_seq %u", (seg->seq + payload_offset + copy_size), seg->seq, payload_offset, copy_size, ra_base_seq); if (gap == 0 && SEQ_GT((seg->seq + payload_offset + copy_size),ra_base_seq+1)) { ra_base_seq += copy_size; } SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); smsg->data.data_len += copy_size; /* queue the smsg if it's full */ if (smsg->data.data_len == sizeof (smsg->data.data)) { StreamMsgPutInQueue(ra_ctx->stream_q, smsg); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; } /* if the payload len is bigger than what we copied, we handle the * rest of the payload next... */ if (copy_size < payload_len) { SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, payload_len); payload_offset += copy_size; payload_len -= copy_size; SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " "%"PRIu16" and stream->last_ack is %"PRIu32"", payload_offset, seg->payload_len, stream->last_ack); if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); } /* we need a while loop here as the packets theoretically can be * 64k */ char segment_done = FALSE; while (segment_done == FALSE) { SCLogDebug("new msg at offset %" PRIu32 ", payload_len " "%" PRIu32 "", payload_offset, payload_len); /* get a new message XXX we need a setup function */ smsg = StreamMsgGetFromPool(); if (smsg == NULL) { SCLogDebug("stream_msg_pool is empty"); SCReturnInt(-1); } smsg_offset = 0; StreamTcpSetupMsg(ssn, stream,p,smsg); smsg->data.seq = ra_base_seq+1; copy_size = sizeof(smsg->data.data) - smsg_offset; if (copy_size > (seg->payload_len - payload_offset)) { copy_size = (seg->payload_len - payload_offset); } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(smsg->data.data)); } SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " "%" PRIu32 ", copy_size %" PRIu32 "", payload_offset, smsg_offset, copy_size); memcpy(smsg->data.data + smsg_offset, seg->payload + payload_offset, copy_size); smsg_offset += copy_size; if (gap == 0 && SEQ_GT((seg->seq + payload_offset + copy_size),ra_base_seq+1)) { ra_base_seq += copy_size; } SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); smsg->data.data_len += copy_size; SCLogDebug("copied payload_offset %" PRIu32 ", " "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", payload_offset, smsg_offset, copy_size); if (smsg->data.data_len == sizeof (smsg->data.data)) { StreamMsgPutInQueue(ra_ctx->stream_q, smsg); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; } /* see if we have segment payload left to process */ if ((copy_size + payload_offset) < seg->payload_len) { payload_offset += copy_size; payload_len -= copy_size; if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); } } else { payload_offset = 0; segment_done = TRUE; } } } } /* done with this segment, return it to the pool */ TcpSegment *next_seg = seg->next; next_seq = seg->seq + seg->payload_len; if (SEQ_LT((seg->seq + seg->payload_len), (ra_base_seq - chunk_size))) { if (seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED) { StreamTcpRemoveSegmentFromStream(stream, seg); SCLogDebug("removing seg %p, seg->next %p", seg, seg->next); StreamTcpSegmentReturntoPool(seg); } else { seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; } } seg = next_seg; } /* put the partly filled smsg in the queue */ if (smsg != NULL) { StreamMsgPutInQueue(ra_ctx->stream_q, smsg); smsg = NULL; stream->ra_raw_base_seq = ra_base_seq; } /* see if we can clean up some segments */ left_edge = (ra_base_seq + 1) - chunk_size; SCLogDebug("left_edge %"PRIu32", ra_base_seq %"PRIu32, left_edge, ra_base_seq); /* loop through the segments to remove unneeded segments */ for (seg = stream->seg_list; seg != NULL && SEQ_LEQ((seg->seq + p->payload_len), left_edge); ) { SCLogDebug("seg %p seq %"PRIu32", len %"PRIu16", sum %"PRIu32, seg, seg->seq, seg->payload_len, seg->seq+seg->payload_len); /* only remove if app layer reassembly is ready too */ if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; } else { break; } } SCLogDebug("stream->ra_raw_base_seq %u", stream->ra_raw_base_seq); SCReturnInt(0); } /** \internal * \brief check if we can remove a segment from our segment list * * If a segment is entirely before the oldest smsg, we can discard it. Otherwise * we keep it around to be able to log it. * * \retval 1 yes * \retval 0 no */ static inline int StreamTcpReturnSegmentCheck(TcpSession *ssn, TcpStream *stream, TcpSegment *seg) { if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) { /* not (seg is entirely before first smsg, skip) */ if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->data.seq))) { SCReturnInt(0); } } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) { /* not (seg is entirely before first smsg, skip) */ if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->data.seq))) { SCReturnInt(0); } } SCReturnInt(1); } /** \brief Remove idle TcpSegments from TcpSession * * \param f flow * \param flags direction flags */ void StreamTcpPruneSession(Flow *f, uint8_t flags) { if (f == NULL || f->protoctx == NULL) return; TcpSession *ssn = f->protoctx; TcpStream *stream = NULL; if (flags & STREAM_TOSERVER) { stream = &ssn->client; } else if (flags & STREAM_TOCLIENT) { stream = &ssn->server; } else { return; } /* loop through the segments and fill one or more msgs */ TcpSegment *seg = stream->seg_list; uint32_t ra_base_seq = stream->ra_app_base_seq; for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) { SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, seg, seg->seq, seg->payload_len, (uint32_t)(seg->seq + seg->payload_len)); if (SEQ_LEQ((seg->seq + seg->payload_len), (ra_base_seq+1)) && (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && (seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) { if (StreamTcpReturnSegmentCheck(ssn, stream, seg) == 0) { seg = seg->next; break; } SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32 " len %"PRIu16"", ra_base_seq, seg, seg->seq, seg->payload_len); TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; } else if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) && (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && (seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) { if (StreamTcpReturnSegmentCheck(ssn, stream, seg) == 0) { seg = seg->next; break; } SCLogDebug("segment(%p) of length %"PRIu16" has been processed," " so return it to pool", seg, seg->payload_len); TcpSegment *next_seg = seg->next; seg = next_seg; continue; } else { /* give up */ break; } } } /** * \brief Update the stream reassembly upon receiving an ACK packet. * * Stream is in the opposite direction of the packet, as the ACK-packet * is ACK'ing the stream. * * \todo this function is too long, we need to break it up. It needs it BAD */ static int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); uint8_t flags = 0; SCLogDebug("stream->seg_list %p", stream->seg_list); #ifdef DEBUG PrintList(stream->seg_list); #endif /* if no segments are in the list or all are already processed, * and state is beyond established, we send an empty msg */ TcpSegment *seg_tail = stream->seg_list_tail; if (seg_tail == NULL || (seg_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) { /* send an empty EOF msg if we have no segments but TCP state * is beyond ESTABLISHED */ if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) { SCLogDebug("sending empty eof message"); /* send EOF to app layer */ STREAM_SET_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, NULL, 0, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); SCReturnInt(0); } } /* no segments, nothing to do */ if (stream->seg_list == NULL) { SCLogDebug("no segments in the list to reassemble"); SCReturnInt(0); } /* check if reassembling has been paused for the moment or not */ if (stream->flags & STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY) { SCLogDebug("reassembling has been paused for this stream, so no" " reassembling at the moment"); SCReturnInt(0); } if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) { SCReturnInt(0); } /* stream->ra_app_base_seq remains at stream->isn until protocol is * detected. */ uint32_t ra_base_seq = stream->ra_app_base_seq; uint8_t data[4096]; uint32_t data_len = 0; uint16_t payload_offset = 0; uint16_t payload_len = 0; uint32_t next_seq = ra_base_seq + 1; SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32, ra_base_seq, stream->last_ack, next_seq); /* loop through the segments and fill one or more msgs */ TcpSegment *seg = stream->seg_list; SCLogDebug("pre-loop seg %p", seg); for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) { SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, seg, seg->seq, seg->payload_len, (uint32_t)(seg->seq + seg->payload_len)); if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) { if (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) { SCLogDebug("removing seg %p seq %"PRIu32 " len %"PRIu16"", seg, seg->seq, seg->payload_len); TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; } else { break; } /* Remove the segments which are either completely before the * ra_base_seq and processed by both app layer and raw reassembly. */ } else if (SEQ_LEQ((seg->seq + seg->payload_len), (ra_base_seq+1)) && (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && (seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) { if (StreamTcpReturnSegmentCheck(ssn, stream, seg) == 0) { seg = seg->next; continue; } SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32 " len %"PRIu16"", ra_base_seq, seg, seg->seq, seg->payload_len); TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; } /* if app layer protocol has been detected, then remove all the segments which has been previously processed and reassembled */ if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) && (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && (seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) { if (StreamTcpReturnSegmentCheck(ssn, stream, seg) == 0) { next_seq = seg->seq + seg->payload_len; seg = seg->next; continue; } SCLogDebug("segment(%p) of length %"PRIu16" has been processed," " so return it to pool", seg, seg->payload_len); next_seq = seg->seq + seg->payload_len; TcpSegment *next_seg = seg->next; seg = next_seg; continue; } /* we've run into a sequence gap */ if (SEQ_GT(seg->seq, next_seq)) { /* first, pass on data before the gap */ if (data_len > 0) { SCLogDebug("pre GAP data"); STREAM_SET_FLAGS(ssn, stream, p, flags); /* process what we have so far */ AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, data, data_len, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_len = 0; } /* don't conclude it's a gap straight away. If ra_base_seq is lower * than last_ack - the window, we consider it a gap. */ if (SEQ_GT((stream->last_ack - stream->window), ra_base_seq) || ssn->state > TCP_ESTABLISHED) { /* see what the length of the gap is, gap length is seg->seq - * (ra_base_seq +1) */ #ifdef DEBUG uint32_t gap_len = seg->seq - next_seq; SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", next_seq, seg->seq, stream->last_ack, gap_len); #endif /* We have missed the packet and end host has ack'd it, so * IDS should advance it's ra_base_seq and should not consider this * packet any longer, even if it is retransmitted, as end host will * drop it anyway */ ra_base_seq = seg->seq - 1; /* send gap signal */ STREAM_SET_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, NULL, 0, flags|STREAM_GAP); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_len = 0; /* set a GAP flag and make sure not bothering this stream anymore */ SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); stream->flags |= STREAMTCP_STREAM_FLAG_GAP; StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); #ifdef DEBUG dbg_app_layer_gap++; #endif break; } else { SCLogDebug("possible GAP, but waiting to see if out of order " "packets might solve that"); #ifdef DEBUG dbg_app_layer_gap_candidate++; #endif break; } } int partial = FALSE; /* if the segment ends beyond ra_base_seq we need to consider it */ if (SEQ_GT((seg->seq + seg->payload_len), ra_base_seq+1)) { SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " "ra_base_seq %" PRIu32 ", last_ack %"PRIu32, seg->seq, seg->payload_len, ra_base_seq, stream->last_ack); /* handle segments partly before ra_base_seq */ if (SEQ_GT(ra_base_seq, seg->seq)) { payload_offset = (ra_base_seq + 1) - seg->seq; SCLogDebug("payload_offset %u", payload_offset); if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { if (SEQ_LT(stream->last_ack, (ra_base_seq + 1))) { payload_len = (stream->last_ack - seg->seq); SCLogDebug("payload_len %u", payload_len); } else { payload_len = (stream->last_ack - seg->seq) - payload_offset; SCLogDebug("payload_len %u", payload_len); } partial = TRUE; } else { payload_len = seg->payload_len - payload_offset; SCLogDebug("payload_len %u", payload_len); } if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); BUG_ON((payload_len + payload_offset) > seg->payload_len); } } else { payload_offset = 0; if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { payload_len = stream->last_ack - seg->seq; SCLogDebug("payload_len %u", payload_len); partial = TRUE; } else { payload_len = seg->payload_len; SCLogDebug("payload_len %u", payload_len); } } SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" " and stream->last_ack is %"PRIu32"", payload_offset, payload_len, stream->last_ack); if (payload_len == 0) { SCLogDebug("no payload_len, so bail out"); break; } /* copy the data into the smsg */ uint16_t copy_size = sizeof(data) - data_len; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(data)); } SCLogDebug("copy_size is %"PRIu16"", copy_size); memcpy(data + data_len, seg->payload + payload_offset, copy_size); data_len += copy_size; ra_base_seq += copy_size; SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, ra_base_seq, data_len); /* queue the smsg if it's full */ if (data_len == sizeof(data)) { /* process what we have so far */ STREAM_SET_FLAGS(ssn, stream, p, flags); BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, data, data_len, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_len = 0; /* if after the first data chunk we have no alproto yet, * there is no point in continueing here. */ if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { SCLogDebug("no alproto after first data chunk"); break; } } /* if the payload len is bigger than what we copied, we handle the * rest of the payload next... */ if (copy_size < payload_len) { SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, payload_len); payload_offset += copy_size; payload_len -= copy_size; SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " "%"PRIu16" and stream->last_ack is %"PRIu32"", payload_offset, seg->payload_len, stream->last_ack); if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); } /* we need a while loop here as the packets theoretically can be * 64k */ char segment_done = FALSE; while (segment_done == FALSE) { SCLogDebug("new msg at offset %" PRIu32 ", payload_len " "%" PRIu32 "", payload_offset, payload_len); data_len = 0; copy_size = sizeof(data) - data_len; if (copy_size > (seg->payload_len - payload_offset)) { copy_size = (seg->payload_len - payload_offset); } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(data)); } SCLogDebug("copy payload_offset %" PRIu32 ", data_len " "%" PRIu32 ", copy_size %" PRIu32 "", payload_offset, data_len, copy_size); memcpy(data + data_len, seg->payload + payload_offset, copy_size); data_len += copy_size; ra_base_seq += copy_size; SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); SCLogDebug("copied payload_offset %" PRIu32 ", " "data_len %" PRIu32 ", copy_size %" PRIu32 "", payload_offset, data_len, copy_size); if (data_len == sizeof(data)) { /* process what we have so far */ STREAM_SET_FLAGS(ssn, stream, p, flags); BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, data, data_len, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); data_len = 0; /* if after the first data chunk we have no alproto yet, * there is no point in continueing here. */ if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { SCLogDebug("no alproto after first data chunk"); break; } } /* see if we have segment payload left to process */ if ((copy_size + payload_offset) < seg->payload_len) { payload_offset += copy_size; payload_len -= copy_size; if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); } } else { payload_offset = 0; segment_done = TRUE; } } } } /* done with this segment, return it to the pool */ TcpSegment *next_seg = seg->next; next_seq = seg->seq + seg->payload_len; if (partial == FALSE) { SCLogDebug("fully done with segment in app layer reassembly"); seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; } else { SCLogDebug("not yet fully done with segment in app layer reassembly"); } seg = next_seg; } /* put the partly filled smsg in the queue to the l7 handler */ if (data_len > 0) { SCLogDebug("data_len > 0, %u", data_len); /* process what we have so far */ STREAM_SET_FLAGS(ssn, stream, p, flags); BUG_ON(data_len > sizeof(data)); AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, data, data_len, flags); PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p); } /* store ra_base_seq in the stream */ if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { stream->ra_app_base_seq = ra_base_seq; } SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq); SCReturnInt(0); } /** * \brief Update the stream reassembly upon receiving an ACK packet. * \todo this function is too long, we need to break it up. It needs it BAD */ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); SCLogDebug("start p %p", p); if (stream->seg_list == NULL) { /* send an empty EOF msg if we have no segments but TCP state * is beyond ESTABLISHED */ if (ssn->state > TCP_ESTABLISHED) { StreamMsg *smsg = StreamMsgGetFromPool(); if (smsg == NULL) { SCLogDebug("stream_msg_pool is empty"); SCReturnInt(-1); } StreamTcpSetupMsg(ssn, stream, p, smsg); StreamMsgPutInQueue(ra_ctx->stream_q,smsg); } else { SCLogDebug("no segments in the list to reassemble"); } SCReturnInt(0); } /* check if reassembling has been paused for the moment or not */ if (stream->flags & STREAMTCP_STREAM_FLAG_PAUSE_REASSEMBLY) { SCLogDebug("reassembling has been paused for this stream, so no" " reassembling at the moment"); SCReturnInt(0); } #if 0 if (ssn->state <= TCP_ESTABLISHED && !(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { SCLogDebug("only starting raw reassembly after app layer protocol " "detection has completed."); SCReturnInt(0); } #endif /* check if we have enough data */ if (StreamTcpReassembleRawCheckLimit(ssn,stream,p) == 0) { SCLogDebug("not yet reassembling"); SCReturnInt(0); } uint32_t ra_base_seq = stream->ra_raw_base_seq; StreamMsg *smsg = NULL; uint16_t smsg_offset = 0; uint16_t payload_offset = 0; uint16_t payload_len = 0; TcpSegment *seg = stream->seg_list; uint32_t next_seq = ra_base_seq + 1; SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32, ra_base_seq, stream->last_ack, next_seq); /* loop through the segments and fill one or more msgs */ for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) { SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, seg, seg->seq, seg->payload_len, (uint32_t)(seg->seq + seg->payload_len)); /* Remove the segments which are either completely before the ra_base_seq or if they are beyond ra_base_seq, but the segment offset from which we need to copy in to smsg is beyond the stream->last_ack. As we are copying until the stream->last_ack only */ if (SEQ_LEQ((seg->seq + seg->payload_len), ra_base_seq+1)) { if (StreamTcpReturnSegmentCheck(ssn, stream, seg) == 0) { seg = seg->next; continue; } SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" " len %"PRIu16"", ra_base_seq, seg, seg->seq, seg->payload_len); TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; } /* if app layer protocol has been detected, then remove all the segments * which has been previously processed and reassembled * * If the stream is in GAP state the app layer flag won't be set */ if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) && (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && ((seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED) || (stream->flags & STREAMTCP_STREAM_FLAG_GAP))) { if (StreamTcpReturnSegmentCheck(ssn, stream, seg) == 0) { seg = seg->next; continue; } SCLogDebug("segment(%p) of length %"PRIu16" has been processed," " so return it to pool", seg, seg->payload_len); TcpSegment *next_seg = seg->next; seg = next_seg; continue; } /* we've run into a sequence gap */ if (SEQ_GT(seg->seq, next_seq)) { /* pass on pre existing smsg (if any) */ if (smsg != NULL && smsg->data.data_len > 0) { /* if app layer protocol has not been detected till yet, then check did we have sent message to app layer already or not. If not then sent the message and set flag that first message has been sent. No more data till proto has not been detected */ StreamMsgPutInQueue(ra_ctx->stream_q, smsg); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; } /* don't conclude it's a gap straight away. If ra_base_seq is lower * than last_ack - the window, we consider it a gap. */ if (SEQ_GT((stream->last_ack - stream->window), ra_base_seq) || ssn->state > TCP_ESTABLISHED) { /* see what the length of the gap is, gap length is seg->seq - * (ra_base_seq +1) */ uint32_t gap_len = seg->seq - next_seq; SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", next_seq, seg->seq, stream->last_ack, gap_len); if (smsg == NULL) { smsg = StreamMsgGetFromPool(); if (smsg == NULL) { SCLogDebug("stream_msg_pool is empty"); return -1; } } stream->ra_raw_base_seq = ra_base_seq; StreamTcpSetupMsg(ssn, stream, p, smsg); /* We have missed the packet and end host has ack'd it, so * IDS should advance it's ra_base_seq and should not consider this * packet any longer, even if it is retransmitted, as end host will * drop it anyway */ ra_base_seq = seg->seq - 1; SCLogDebug("setting STREAM_GAP"); smsg->flags |= STREAM_GAP; smsg->gap.gap_size = gap_len; StreamMsgPutInQueue(ra_ctx->stream_q,smsg); smsg = NULL; smsg_offset = 0; } else { SCLogDebug("possible GAP, but waiting to see if out of order " "packets might solve that"); break; } } /* if the segment ends beyond ra_base_seq we need to consider it */ if (SEQ_GT((seg->seq + seg->payload_len), ra_base_seq+1)) { SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " "ra_base_seq %" PRIu32 "", seg->seq, seg->payload_len, ra_base_seq); /* handle segments partly before ra_base_seq */ if (SEQ_GT(ra_base_seq, seg->seq)) { payload_offset = ra_base_seq - seg->seq; if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { if (SEQ_LT(stream->last_ack, ra_base_seq)) { payload_len = (stream->last_ack - seg->seq); } else { payload_len = (stream->last_ack - seg->seq) - payload_offset; } } else { payload_len = seg->payload_len - payload_offset; } if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); BUG_ON((payload_len + payload_offset) > seg->payload_len); } } else { payload_offset = 0; if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { payload_len = stream->last_ack - seg->seq; } else { payload_len = seg->payload_len; } } SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" " and stream->last_ack is %"PRIu32"", payload_offset, payload_len, stream->last_ack); if (payload_len == 0) { SCLogDebug("no payload_len, so bail out"); break; } if (smsg == NULL) { smsg = StreamMsgGetFromPool(); if (smsg == NULL) { SCLogDebug("stream_msg_pool is empty"); return -1; } smsg_offset = 0; StreamTcpSetupMsg(ssn, stream, p, smsg); smsg->data.seq = ra_base_seq + 1; } /* copy the data into the smsg */ uint16_t copy_size = sizeof (smsg->data.data) - smsg_offset; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(smsg->data.data)); } SCLogDebug("copy_size is %"PRIu16"", copy_size); memcpy(smsg->data.data + smsg_offset, seg->payload + payload_offset, copy_size); smsg_offset += copy_size; ra_base_seq += copy_size; SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); smsg->data.data_len += copy_size; /* queue the smsg if it's full */ if (smsg->data.data_len == sizeof (smsg->data.data)) { StreamMsgPutInQueue(ra_ctx->stream_q, smsg); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; } /* if the payload len is bigger than what we copied, we handle the * rest of the payload next... */ if (copy_size < payload_len) { SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, payload_len); payload_offset += copy_size; payload_len -= copy_size; SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " "%"PRIu16" and stream->last_ack is %"PRIu32"", payload_offset, seg->payload_len, stream->last_ack); if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); } /* we need a while loop here as the packets theoretically can be * 64k */ char segment_done = FALSE; while (segment_done == FALSE) { SCLogDebug("new msg at offset %" PRIu32 ", payload_len " "%" PRIu32 "", payload_offset, payload_len); /* get a new message XXX we need a setup function */ smsg = StreamMsgGetFromPool(); if (smsg == NULL) { SCLogDebug("stream_msg_pool is empty"); SCReturnInt(-1); } smsg_offset = 0; StreamTcpSetupMsg(ssn, stream,p,smsg); smsg->data.seq = ra_base_seq+1; copy_size = sizeof(smsg->data.data) - smsg_offset; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { BUG_ON(copy_size > sizeof(smsg->data.data)); } SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " "%" PRIu32 ", copy_size %" PRIu32 "", payload_offset, smsg_offset, copy_size); memcpy(smsg->data.data + smsg_offset, seg->payload + payload_offset, copy_size); smsg_offset += copy_size; ra_base_seq += copy_size; SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); smsg->data.data_len += copy_size; SCLogDebug("copied payload_offset %" PRIu32 ", " "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", payload_offset, smsg_offset, copy_size); if (smsg->data.data_len == sizeof (smsg->data.data)) { StreamMsgPutInQueue(ra_ctx->stream_q, smsg); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; } /* see if we have segment payload left to process */ if (copy_size < payload_len) { payload_offset += copy_size; payload_len -= copy_size; if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); } } else { payload_offset = 0; segment_done = TRUE; } } } } /* done with this segment, return it to the pool */ TcpSegment *next_seg = seg->next; seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; next_seq = seg->seq + seg->payload_len; seg = next_seg; } /* put the partly filled smsg in the queue to the l7 handler */ if (smsg != NULL) { StreamMsgPutInQueue(ra_ctx->stream_q, smsg); smsg = NULL; stream->ra_raw_base_seq = ra_base_seq; } SCReturnInt(0); } /** \brief update app layer and raw reassembly * * \retval r 0 on success, -1 on error */ int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); SCLogDebug("stream->seg_list %p", stream->seg_list); int r = 0; if (!(StreamTcpInlineMode())) { if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0) r = -1; if (StreamTcpReassembleRaw(ra_ctx, ssn, stream, p) < 0) r = -1; } SCLogDebug("stream->seg_list %p", stream->seg_list); SCReturnInt(r); } /** \brief Handle the queue'd smsgs containing reassembled app layer data when * we're running the app layer handling as part of the stream threads. * * \param ra_ctx Reassembly thread ctx, contains the queue with stream msgs * * \todo Currently we process all msgs even if we encounter an error in one * of them. We do this to make sure the thread ctx's queue is emptied. * Maybe we should just clear & return the msgs in case of error. * * \retval 0 ok * \retval -1 error */ int StreamTcpReassembleProcessAppLayer(TcpReassemblyThreadCtx *ra_ctx) { SCEnter(); int r = 0; if (ra_ctx != NULL && ra_ctx->stream_q && ra_ctx->stream_q->len > 0) { StreamMsg *smsg = NULL; do { smsg = StreamMsgGetFromQueue(ra_ctx->stream_q); if (smsg != NULL) { SCLogDebug("smsg %p, next %p, prev %p, flow %p, q->len %u, " "smsg->data.datalen %u, direction %s%s", smsg, smsg->next, smsg->prev, smsg->flow, ra_ctx->stream_q->len, smsg->data.data_len, smsg->flags & STREAM_TOSERVER ? "toserver":"", smsg->flags & STREAM_TOCLIENT ? "toclient":""); BUG_ON(smsg->flow == NULL); //PrintRawDataFp(stderr, smsg->data.data, smsg->data.data_len); /* Handle the stream msg. No need to use locking, flow is * already locked at this point. Don't break out of the * loop if we encounter an error. */ if (AppLayerHandleTCPMsg(&ra_ctx->dp_ctx, smsg) != 0) r = -1; } } while (ra_ctx->stream_q->len > 0); } SCReturnInt(r); } int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p, PacketQueue *pq) { SCEnter(); SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"", ssn, stream, p, p->payload_len); /* we need to update the opposing stream in * StreamTcpReassembleHandleSegmentUpdateACK */ TcpStream *opposing_stream = NULL; if (stream == &ssn->client) { opposing_stream = &ssn->server; } else { opposing_stream = &ssn->client; } /* handle ack received */ if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0) { SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error"); SCReturnInt(-1); } /* If no stream reassembly/application layer protocol inspection, then simple return */ if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData"); if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) { SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error"); SCReturnInt(-1); } p->flags |= PKT_STREAM_ADD; } /* in stream inline mode even if we have no data we call the reassembly * functions to handle EOF */ if (StreamTcpInlineMode()) { int r = 0; if (StreamTcpReassembleInlineAppLayer(tv, ra_ctx, ssn, stream, p) < 0) r = -1; if (StreamTcpReassembleInlineRaw(ra_ctx, ssn, stream, p) < 0) r = -1; if (r < 0) { SCReturnInt(-1); } } StreamTcpReassembleMemuseCounter(tv, ra_ctx); SCReturnInt(0); } /** * \brief Function to replace the data from a specific point up to given length. * * \param dst_seg Destination segment to replace the data * \param src_seg Source segment of which data is to be written to destination * \param start_point Starting point to replace the data onwards * \param len Length up to which data is need to be replaced * * \todo VJ We can remove the abort()s later. * \todo VJ Why not memcpy? */ void StreamTcpSegmentDataReplace(TcpSegment *dst_seg, TcpSegment *src_seg, uint32_t start_point, uint16_t len) { uint32_t seq; uint16_t src_pos = 0; uint16_t dst_pos = 0; SCLogDebug("start_point %u", start_point); if (SEQ_GT(start_point, dst_seg->seq)) { dst_pos = start_point - dst_seg->seq; } else if (SEQ_LT(start_point, dst_seg->seq)) { dst_pos = dst_seg->seq - start_point; } if (SCLogDebugEnabled()) { BUG_ON(((len + dst_pos) - 1) > dst_seg->payload_len); } else { if (((len + dst_pos) - 1) > dst_seg->payload_len) return; } src_pos = (uint16_t)(start_point - src_seg->seq); SCLogDebug("Replacing data from dst_pos %"PRIu16"", dst_pos); for (seq = start_point; SEQ_LT(seq, (start_point + len)) && src_pos < src_seg->payload_len && dst_pos < dst_seg->payload_len; seq++, dst_pos++, src_pos++) { dst_seg->payload[dst_pos] = src_seg->payload[src_pos]; } SCLogDebug("Replaced data of size %"PRIu16" up to src_pos %"PRIu16 " dst_pos %"PRIu16, len, src_pos, dst_pos); } /** * \brief Function to compare the data from a specific point up to given length. * * \param dst_seg Destination segment to compare the data * \param src_seg Source segment of which data is to be compared to destination * \param start_point Starting point to compare the data onwards * \param len Length up to which data is need to be compared * * \retval 1 same * \retval 0 different */ static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg, uint32_t start_point, uint16_t len) { uint32_t seq; uint16_t src_pos = 0; uint16_t dst_pos = 0; SCLogDebug("start_point %u dst_seg %u src_seg %u", start_point, dst_seg->seq, src_seg->seq); if (SEQ_GT(start_point, dst_seg->seq)) { SCLogDebug("start_point %u > dst %u", start_point, dst_seg->seq); dst_pos = start_point - dst_seg->seq; } else if (SEQ_LT(start_point, dst_seg->seq)) { SCLogDebug("start_point %u < dst %u", start_point, dst_seg->seq); dst_pos = dst_seg->seq - start_point; } if (SCLogDebugEnabled()) { BUG_ON(((len + dst_pos) - 1) > dst_seg->payload_len); } else { if (((len + dst_pos) - 1) > dst_seg->payload_len) return 1; } src_pos = (uint16_t)(start_point - src_seg->seq); SCLogDebug("Comparing data from dst_pos %"PRIu16", src_pos %u", dst_pos, src_pos); for (seq = start_point; SEQ_LT(seq, (start_point + len)) && src_pos < src_seg->payload_len && dst_pos < dst_seg->payload_len; seq++, dst_pos++, src_pos++) { if (dst_seg->payload[dst_pos] != src_seg->payload[src_pos]) { SCLogDebug("data is different %02x != %02x, dst_pos %u, src_pos %u", dst_seg->payload[dst_pos], src_seg->payload[src_pos], dst_pos, src_pos); return 0; } } SCLogDebug("Compared data of size %"PRIu16" up to src_pos %"PRIu16 " dst_pos %"PRIu16, len, src_pos, dst_pos); return 1; } /** * \brief Function to copy the data from src_seg to dst_seg. * * \param dst_seg Destination segment for copying the contents * \param src_seg Source segment to copy its contents * * \todo VJ wouldn't a memcpy be more appropriate here? * * \warning Both segments need to be properly initialized. */ void StreamTcpSegmentDataCopy(TcpSegment *dst_seg, TcpSegment *src_seg) { uint32_t u; uint16_t dst_pos = 0; uint16_t src_pos = 0; uint32_t seq; if (SEQ_GT(dst_seg->seq, src_seg->seq)) { src_pos = dst_seg->seq - src_seg->seq; seq = dst_seg->seq; } else { dst_pos = src_seg->seq - dst_seg->seq; seq = src_seg->seq; } SCLogDebug("Copying data from seq %"PRIu32"", seq); for (u = seq; (SEQ_LT(u, (src_seg->seq + src_seg->payload_len)) && SEQ_LT(u, (dst_seg->seq + dst_seg->payload_len))); u++) { //SCLogDebug("u %"PRIu32, u); dst_seg->payload[dst_pos] = src_seg->payload[src_pos]; dst_pos++; src_pos++; } SCLogDebug("Copyied data of size %"PRIu16" up to dst_pos %"PRIu16"", src_pos, dst_pos); } /** * \brief Function to get the segment of required length from the pool. * * \param len Length which tells the required size of needed segment. * * \retval seg Segment from the pool or NULL */ TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, uint16_t len) { uint16_t idx = segment_pool_idx[len]; SCLogDebug("segment_pool_idx %" PRIu32 " for payload_len %" PRIu32 "", idx, len); SCMutexLock(&segment_pool_mutex[idx]); TcpSegment *seg = (TcpSegment *) PoolGet(segment_pool[idx]); SCLogDebug("segment_pool[%u]->empty_list_size %u, segment_pool[%u]->alloc_" "list_size %u, alloc %u", idx, segment_pool[idx]->empty_list_size, idx, segment_pool[idx]->alloc_list_size, segment_pool[idx]->allocated); SCMutexUnlock(&segment_pool_mutex[idx]); SCLogDebug("seg we return is %p", seg); if (seg == NULL) { SCLogDebug("segment_pool[%u]->empty_list_size %u, " "alloc %u", idx, segment_pool[idx]->empty_list_size, segment_pool[idx]->allocated); /* Increment the counter to show that we are not able to serve the segment request due to memcap limit */ SCPerfCounterIncr(ra_ctx->counter_tcp_segment_memcap, tv->sc_perf_pca); } else { seg->flags = 0; seg->next = NULL; seg->prev = NULL; } #ifdef DEBUG SCMutexLock(&segment_pool_cnt_mutex); segment_pool_cnt++; SCMutexUnlock(&segment_pool_cnt_mutex); #endif return seg; } /** * \brief Trigger RAW stream reassembly * * Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream * reassembly from the applayer, for example upon completion of a * HTTP request. * * Works by setting a flag in the TcpSession that is unset as soon * as it's checked. Since everything happens when operating under * a single lock period, no side effects are expected. * * \param ssn TcpSession */ void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn) { #ifdef DEBUG BUG_ON(ssn == NULL); #endif if (ssn != NULL) { SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn); ssn->flags |= STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY; } } #ifdef UNITTESTS /** unit tests and it's support functions below */ /** \brief The Function tests the reassembly engine working for different * OSes supported. It includes all the OS cases and send * crafted packets to test the reassembly. * * \param stream The stream which will contain the reassembled segments */ static int StreamTcpReassembleStreamTest(TcpStream *stream) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ p->tcph->th_seq = htonl(12); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/ p->tcph->th_seq = htonl(16); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/ p->tcph->th_seq = htonl(18); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x44, 1, 4); /*D*/ p->tcph->th_seq = htonl(22); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x45, 2, 4); /*EE*/ p->tcph->th_seq = htonl(25); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x46, 3, 4); /*FFF*/ p->tcph->th_seq = htonl(27); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x47, 2, 4); /*GG*/ p->tcph->th_seq = htonl(30); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x48, 2, 4); /*HH*/ p->tcph->th_seq = htonl(32); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x49, 1, 4); /*I*/ p->tcph->th_seq = htonl(34); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4a, 4, 4); /*JJJJ*/ p->tcph->th_seq = htonl(13); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 4; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4b, 3, 4); /*KKK*/ p->tcph->th_seq = htonl(18); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4c, 3, 4); /*LLL*/ p->tcph->th_seq = htonl(21); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4d, 3, 4); /*MMM*/ p->tcph->th_seq = htonl(24); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4e, 1, 4); /*N*/ p->tcph->th_seq = htonl(28); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4f, 1, 4); /*O*/ p->tcph->th_seq = htonl(31); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x50, 1, 4); /*P*/ p->tcph->th_seq = htonl(32); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x51, 2, 4); /*QQ*/ p->tcph->th_seq = htonl(34); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x30, 1, 4); /*0*/ p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpReassembleFreeThreadCtx(ra_ctx); SCFree(p); return 1; } /** \brief The Function to create the packet with given payload, which is used * to test the reassembly of the engine. * * \param payload The variable used to store the payload contents of the * current packet. * \param value The value which current payload will have for this packet * \param payload_len The length of the filed payload for current packet. * \param len Length of the payload array */ void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value, uint8_t payload_len, uint8_t len) { uint8_t i; for (i = 0; i < payload_len; i++) payload[i] = value; for (; i < len; i++) payload = NULL; } /** \brief The Function Checks the reassembled stream contents against predefined * stream contents according to OS policy used. * * \param stream_policy Predefined value of stream for different OS policies * \param stream Reassembled stream returned from the reassembly functions */ int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream) { TcpSegment *temp; uint16_t i = 0; uint8_t j; #ifdef DEBUG if (SCLogDebugEnabled()) { TcpSegment *temp1; for (temp1 = stream->seg_list; temp1 != NULL; temp1 = temp1->next) PrintRawDataFp(stdout, temp1->payload, temp1->payload_len); PrintRawDataFp(stdout, stream_policy, sp_size); } #endif for (temp = stream->seg_list; temp != NULL; temp = temp->next) { j = 0; for (; j < temp->payload_len; j++) { SCLogDebug("i %"PRIu16", len %"PRIu32", stream %"PRIx32" and temp is %"PRIx8"", i, temp->payload_len, stream_policy[i], temp->payload[j]); if (stream_policy[i] == temp->payload[j]) { i++; continue; } else return 0; } } return 1; } /** \brief The Function Checks the Stream Queue contents against predefined * stream contents and the gap lentgh. * * \param stream_contents Predefined value of stream contents * \param stream Queue which has the stream contents * * \retval On success the function returns 1, on failure 0. */ static int StreamTcpCheckQueue (uint8_t *stream_contents, StreamMsgQueue *q, uint8_t test_case) { SCEnter(); StreamMsg *msg; uint16_t i = 0; uint8_t j; uint8_t cnt = 0; if (q == NULL) { printf("q == NULL, "); SCReturnInt(0); } if (q->len == 0) { printf("q->len == 0, "); SCReturnInt(0); } msg = StreamMsgGetFromQueue(q); while(msg != NULL) { cnt++; switch (test_case) { /* Gap at start */ case 1: if (cnt == 1 && msg->gap.gap_size != 3) { printf("msg->gap.gap_size %u, msg->flags %02X, ", msg->gap.gap_size, msg->flags); SCReturnInt(0); } break; /* Gap at middle */ case 2: if (cnt == 2 && msg->gap.gap_size != 3) { SCReturnInt(0); } break; /* Gap at end */ case 3: if (cnt == 3 && msg->gap.gap_size != 3 && msg->flags & STREAM_GAP) { SCReturnInt(0); } break; } SCLogDebug("gap is %" PRIu32"", msg->gap.gap_size); j = 0; for (; j < msg->data.data_len; j++) { SCLogDebug("i is %" PRIu32 " and len is %" PRIu32 " and temp is %" PRIx32 "", i, msg->data.data_len, msg->data.data[j]); if (stream_contents[i] == msg->data.data[j]) { i++; continue; } else { SCReturnInt(0); } } if (q->len > 0) { msg = StreamMsgGetFromQueue(q); } else { SCReturnInt(1); } } SCReturnInt(1); } /* \brief The function craft packets to test the overlapping, where * new segment stats before the list segment. * * \param stream The stream which will contain the reassembled segments and * also tells the OS policy used for reassembling the segments. */ static int StreamTcpTestStartsBeforeListSegment(TcpStream *stream) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/ p->tcph->th_seq = htonl(16); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x44, 1, 4); /*D*/ p->tcph->th_seq = htonl(22); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x45, 2, 4); /*EE*/ p->tcph->th_seq = htonl(25); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/ p->tcph->th_seq = htonl(15); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4a, 4, 4); /*JJJJ*/ p->tcph->th_seq = htonl(14); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 4; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } SCLogDebug("sending segment with SEQ 21, len 3"); StreamTcpCreateTestPacket(payload, 0x4c, 3, 4); /*LLL*/ p->tcph->th_seq = htonl(21); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4d, 3, 4); /*MMM*/ p->tcph->th_seq = htonl(24); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } SCFree(p); return 1; } /* \brief The function craft packets to test the overlapping, where * new segment stats at the same seq no. as the list segment. * * \param stream The stream which will contain the reassembled segments and * also tells the OS policy used for reassembling the segments. */ static int StreamTcpTestStartsAtSameListSegment(TcpStream *stream) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/ p->tcph->th_seq = htonl(18); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x48, 2, 4); /*HH*/ p->tcph->th_seq = htonl(32); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x49, 1, 4); /*I*/ p->tcph->th_seq = htonl(34); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4b, 3, 4); /*KKK*/ p->tcph->th_seq = htonl(18); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4c, 4, 4); /*LLLL*/ p->tcph->th_seq = htonl(18); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 4; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x50, 1, 4); /*P*/ p->tcph->th_seq = htonl(32); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x51, 2, 4); /*QQ*/ p->tcph->th_seq = htonl(34); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } SCFree(p); return 1; } /* \brief The function craft packets to test the overlapping, where * new segment stats after the list segment. * * \param stream The stream which will contain the reassembled segments and * also tells the OS policy used for reassembling the segments. */ static int StreamTcpTestStartsAfterListSegment(TcpStream *stream) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; uint8_t payload[4]; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/ p->tcph->th_seq = htonl(12); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x46, 3, 4); /*FFF*/ p->tcph->th_seq = htonl(27); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 3; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x47, 2, 4); /*GG*/ p->tcph->th_seq = htonl(30); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4a, 2, 4); /*JJ*/ p->tcph->th_seq = htonl(13); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4f, 1, 4); /*O*/ p->tcph->th_seq = htonl(31); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpCreateTestPacket(payload, 0x4e, 1, 4); /*N*/ p->tcph->th_seq = htonl(28); p->tcph->th_ack = htonl(31); p->payload = payload; p->payload_len = 1; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) { SCFree(p); return 0; } SCFree(p); return 1; } /** \brief The Function to test the reassembly when new segment starts * before the list segment and BSD policy is used to reassemble * segments. */ static int StreamTcpReassembleTest01(void) { TcpStream stream; uint8_t stream_before_bsd[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_before_bsd,sizeof(stream_before_bsd), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * at the same seq no. as the list segment and BSD policy is used * to reassemble segments. */ static int StreamTcpReassembleTest02(void) { TcpStream stream; uint8_t stream_same_bsd[8] = {0x43, 0x43, 0x43, 0x4c, 0x48, 0x48, 0x49, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_same_bsd, sizeof(stream_same_bsd), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * after the list segment and BSD policy is used to reassemble * segments. */ static int StreamTcpReassembleTest03(void) { TcpStream stream; uint8_t stream_after_bsd[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46, 0x47, 0x47}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAfterListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_after_bsd, sizeof(stream_after_bsd), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly engine for all the case * before, same and after overlapping and BSD policy is used to * reassemble segments. */ static int StreamTcpReassembleTest04(void) { TcpStream stream; uint8_t stream_bsd[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x43, 0x43, 0x43, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; StreamTcpInitConfig(TRUE); if (StreamTcpReassembleStreamTest(&stream) == 0) { printf("failed in segments reassembly: "); return 0; } if (StreamTcpCheckStreamContents(stream_bsd, sizeof(stream_bsd), &stream) == 0) { printf("failed in stream matching: "); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * before the list segment and VISTA policy is used to reassemble * segments. */ static int StreamTcpReassembleTest05(void) { TcpStream stream; uint8_t stream_before_vista[10] = {0x4a, 0x41, 0x42, 0x4a, 0x4c, 0x44, 0x4c, 0x4d, 0x45, 0x45}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_VISTA; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_before_vista, sizeof(stream_before_vista), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * at the same seq no. as the list segment and VISTA policy is used * to reassemble segments. */ static int StreamTcpReassembleTest06(void) { TcpStream stream; uint8_t stream_same_vista[8] = {0x43, 0x43, 0x43, 0x4c, 0x48, 0x48, 0x49, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_VISTA; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_same_vista, sizeof(stream_same_vista), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * after the list segment and BSD policy is used to reassemble * segments. */ static int StreamTcpReassembleTest07(void) { TcpStream stream; uint8_t stream_after_vista[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46, 0x47, 0x47}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_VISTA; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAfterListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_after_vista, sizeof(stream_after_vista), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly engine for all the case * before, same and after overlapping and VISTA policy is used to * reassemble segments. */ static int StreamTcpReassembleTest08(void) { TcpStream stream; uint8_t stream_vista[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x42, 0x42, 0x43, 0x43, 0x43, 0x4c, 0x44, 0x4c, 0x4d, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_VISTA; StreamTcpInitConfig(TRUE); if (StreamTcpReassembleStreamTest(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_vista, sizeof(stream_vista), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * before the list segment and LINUX policy is used to reassemble * segments. */ static int StreamTcpReassembleTest09(void) { TcpStream stream; uint8_t stream_before_linux[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_LINUX; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_before_linux, sizeof(stream_before_linux), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * at the same seq no. as the list segment and LINUX policy is used * to reassemble segments. */ static int StreamTcpReassembleTest10(void) { TcpStream stream; uint8_t stream_same_linux[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48, 0x51, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_LINUX; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_same_linux, sizeof(stream_same_linux), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * after the list segment and LINUX policy is used to reassemble * segments. */ static int StreamTcpReassembleTest11(void) { TcpStream stream; uint8_t stream_after_linux[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46, 0x47, 0x47}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_LINUX; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAfterListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_after_linux, sizeof(stream_after_linux), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly engine for all the case * before, same and after overlapping and LINUX policy is used to * reassemble segments. */ static int StreamTcpReassembleTest12(void) { TcpStream stream; uint8_t stream_linux[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x43, 0x43, 0x43, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_LINUX; StreamTcpInitConfig(TRUE); if (StreamTcpReassembleStreamTest(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_linux, sizeof(stream_linux), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * before the list segment and OLD_LINUX policy is used to reassemble * segments. */ static int StreamTcpReassembleTest13(void) { TcpStream stream; uint8_t stream_before_old_linux[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_OLD_LINUX; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_before_old_linux, sizeof(stream_before_old_linux), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * at the same seq no. as the list segment and OLD_LINUX policy is * used to reassemble segments. */ static int StreamTcpReassembleTest14(void) { TcpStream stream; uint8_t stream_same_old_linux[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48, 0x51, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_OLD_LINUX; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_same_old_linux, sizeof(stream_same_old_linux), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * after the list segment and OLD_LINUX policy is used to reassemble * segments. */ static int StreamTcpReassembleTest15(void) { TcpStream stream; uint8_t stream_after_old_linux[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46, 0x47, 0x47}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_OLD_LINUX; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAfterListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_after_old_linux, sizeof(stream_after_old_linux), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly engine for all the case * before, same and after overlapping and OLD_LINUX policy is used to * reassemble segments. */ static int StreamTcpReassembleTest16(void) { TcpStream stream; uint8_t stream_old_linux[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_OLD_LINUX; StreamTcpInitConfig(TRUE); if (StreamTcpReassembleStreamTest(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_old_linux, sizeof(stream_old_linux), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * before the list segment and SOLARIS policy is used to reassemble * segments. */ static int StreamTcpReassembleTest17(void) { TcpStream stream; uint8_t stream_before_solaris[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_SOLARIS; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_before_solaris, sizeof(stream_before_solaris), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * at the same seq no. as the list segment and SOLARIS policy is used * to reassemble segments. */ static int StreamTcpReassembleTest18(void) { TcpStream stream; uint8_t stream_same_solaris[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48, 0x51, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_SOLARIS; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_same_solaris, sizeof(stream_same_solaris), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * after the list segment and SOLARIS policy is used to reassemble * segments. */ static int StreamTcpReassembleTest19(void) { TcpStream stream; uint8_t stream_after_solaris[8] = {0x41, 0x4a, 0x4a, 0x46, 0x46, 0x46, 0x47, 0x47}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_SOLARIS; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAfterListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); StreamTcpFreeConfig(TRUE); return 0; } if (StreamTcpCheckStreamContents(stream_after_solaris, sizeof(stream_after_solaris), &stream) == 0) { printf("failed in stream matching!!\n"); StreamTcpFreeConfig(TRUE); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly engine for all the case * before, same and after overlapping and SOLARIS policy is used to * reassemble segments. */ static int StreamTcpReassembleTest20(void) { TcpStream stream; uint8_t stream_solaris[25] = {0x30, 0x41, 0x4a, 0x4a, 0x4a, 0x42, 0x42, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_SOLARIS; StreamTcpInitConfig(TRUE); if (StreamTcpReassembleStreamTest(&stream) == 0) { printf("failed in segments reassembly!!\n"); StreamTcpFreeConfig(TRUE); return 0; } if (StreamTcpCheckStreamContents(stream_solaris, sizeof(stream_solaris), &stream) == 0) { printf("failed in stream matching!!\n"); StreamTcpFreeConfig(TRUE); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * before the list segment and LAST policy is used to reassemble * segments. */ static int StreamTcpReassembleTest21(void) { TcpStream stream; uint8_t stream_before_last[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_LAST; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_before_last, sizeof(stream_before_last), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * at the same seq no. as the list segment and LAST policy is used * to reassemble segments. */ static int StreamTcpReassembleTest22(void) { TcpStream stream; uint8_t stream_same_last[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x50, 0x48, 0x51, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_LAST; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_same_last, sizeof(stream_same_last), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly when new segment starts * after the list segment and LAST policy is used to reassemble * segments. */ static int StreamTcpReassembleTest23(void) { TcpStream stream; uint8_t stream_after_last[8] = {0x41, 0x4a, 0x4a, 0x46, 0x4e, 0x46, 0x47, 0x4f}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_LAST; StreamTcpInitConfig(TRUE); if (StreamTcpTestStartsAfterListSegment(&stream) == 0) { printf("failed in segments reassembly!!\n"); return 0; } if (StreamTcpCheckStreamContents(stream_after_last, sizeof(stream_after_last), &stream) == 0) { printf("failed in stream matching!!\n"); return 0; } StreamTcpFreeConfig(TRUE); return 1; } /** \brief The Function to test the reassembly engine for all the case * before, same and after overlapping and LAST policy is used to * reassemble segments. */ static int StreamTcpReassembleTest24(void) { int ret = 0; TcpStream stream; uint8_t stream_last[25] = {0x30, 0x41, 0x4a, 0x4a, 0x4a, 0x4a, 0x42, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x46, 0x4e, 0x46, 0x47, 0x4f, 0x50, 0x48, 0x51, 0x51}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_LAST; StreamTcpInitConfig(TRUE); if (StreamTcpReassembleStreamTest(&stream) == 0) { printf("failed in segments reassembly: "); goto end; } if (StreamTcpCheckStreamContents(stream_last, sizeof(stream_last), &stream) == 0) { printf("failed in stream matching: "); goto end; } ret = 1; end: StreamTcpFreeConfig(TRUE); return ret; } /** \brief The Function to test the missed packets handling with given payload, * which is used to test the reassembly of the engine. * * \param stream Stream which contain the packets * \param seq Sequence number of the packet * \param ack Acknowledgment number of the packet * \param payload The variable used to store the payload contents of the * current packet. * \param len The length of the payload for current packet. * \param th_flag The TCP flags * \param flowflags The packet flow direction * \param state The TCP session state * * \retval On success it returns 0 and on failure it return -1. */ static int StreamTcpTestMissedPacket (TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, uint32_t seq, uint32_t ack, uint8_t *payload, uint16_t len, uint8_t th_flags, uint8_t flowflags, uint8_t state) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return -1; Flow f; TCPHdr tcph; Port sp; Port dp; struct in_addr in; ThreadVars tv; PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&tv, 0, sizeof (ThreadVars)); sp = 200; dp = 220; FLOW_INITIALIZE(&f); if (inet_pton(AF_INET, "1.2.3.4", &in) != 1) { SCFree(p); return -1; } f.src.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.5", &in) != 1) { SCFree(p); return -1; } f.dst.addr_data32[0] = in.s_addr; f.flags |= FLOW_IPV4; f.sp = sp; f.dp = dp; f.protoctx = ssn; p->flow = &f; tcph.th_win = htons(5480); tcph.th_seq = htonl(seq); tcph.th_ack = htonl(ack); tcph.th_flags = th_flags; p->tcph = &tcph; p->flowflags = flowflags; p->payload = payload; p->payload_len = len; ssn->state = state; TcpStream *s = NULL; if (flowflags & FLOW_PKT_TOSERVER) { s = &ssn->server; } else { s = &ssn->client; } if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, ssn, s, p, &pq) == -1) { SCFree(p); return -1; } SCFree(p); return 0; } /** * \test Test the handling of packets missed by both IDS and the end host. * The packet is missed in the starting of the stream. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest25 (void) { int ret = 0; uint8_t payload[4]; uint32_t seq; uint32_t ack; TcpSession ssn; uint8_t th_flag; uint8_t flowflags; uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43}; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); memset(&ssn, 0, sizeof (TcpSession)); flowflags = FLOW_PKT_TOSERVER; th_flag = TH_ACK|TH_PUSH; ack = 20; StreamTcpInitConfig(TRUE); StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/ seq = 10; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/ seq = 12; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } ssn.server.next_seq = 14; StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ seq = 7; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) { printf("failed in stream matching: "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the handling of packets missed by both IDS and the end host. * The packet is missed in the middle of the stream. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest26 (void) { int ret = 0; uint8_t payload[4]; uint32_t seq; uint32_t ack; TcpSession ssn; uint8_t th_flag; uint8_t flowflags; uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43}; memset(&ssn, 0, sizeof (TcpSession)); flowflags = FLOW_PKT_TOSERVER; th_flag = TH_ACK|TH_PUSH; ack = 20; StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ seq = 10; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/ seq = 15; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/ seq = 13; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) { printf("failed in stream matching: "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the handling of packets missed by both IDS and the end host. * The packet is missed in the end of the stream. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest27 (void) { int ret = 0; uint8_t payload[4]; uint32_t seq; uint32_t ack; TcpSession ssn; uint8_t th_flag; uint8_t flowflags; uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43}; memset(&ssn, 0, sizeof (TcpSession)); flowflags = FLOW_PKT_TOSERVER; th_flag = TH_ACK|TH_PUSH; ack = 20; StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ seq = 10; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/ seq = 13; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/ seq = 15; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) { printf("failed in stream matching: "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the handling of packets missed by IDS, but the end host has * received it and send the acknowledgment of it. The packet is missed * in the starting of the stream. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest28 (void) { int ret = 0; uint8_t payload[4]; uint32_t seq; uint32_t ack; uint8_t th_flag; uint8_t th_flags; uint8_t flowflags; uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42}; TcpSession ssn; memset(&ssn, 0, sizeof (TcpSession)); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); StreamMsgQueue *q = ra_ctx->stream_q; StreamTcpInitConfig(TRUE); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); flowflags = FLOW_PKT_TOSERVER; th_flag = TH_ACK|TH_PUSH; th_flags = TH_ACK; ssn.server.last_ack = 22; ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 6; ssn.server.isn = 6; StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/ seq = 10; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly (1): "); goto end; } flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x00, 0, 4); seq = 20; ack = 12; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly (2): "); goto end; } /* Process stream smsgs we may have in queue */ if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (3): "); goto end; } flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ seq = 12; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly (4): "); goto end; } flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x00, 0, 4); seq = 20; ack = 15; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_TIME_WAIT) == -1) { printf("failed in segments reassembly (5): "); goto end; } if (StreamTcpCheckQueue(check_contents, q, 1) == 0) { printf("failed in stream matching (6): "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the handling of packets missed by IDS, but the end host has * received it and send the acknowledgment of it. The packet is missed * in the middle of the stream. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest29 (void) { int ret = 0; uint8_t payload[4]; uint32_t seq; uint32_t ack; uint8_t th_flag; uint8_t th_flags; uint8_t flowflags; uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42}; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); StreamMsgQueue *q = ra_ctx->stream_q; TcpSession ssn; memset(&ssn, 0, sizeof (TcpSession)); flowflags = FLOW_PKT_TOSERVER; th_flag = TH_ACK|TH_PUSH; th_flags = TH_ACK; ssn.server.last_ack = 22; ssn.server.ra_raw_base_seq = 9; ssn.server.isn = 9; StreamTcpInitConfig(TRUE); StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/ seq = 10; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x00, 0, 4); seq = 20; ack = 15; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } /* Process stream smsgs we may have in queue */ if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs\n"); goto end; } flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ seq = 15; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x00, 0, 4); seq = 20; ack = 18; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_TIME_WAIT) == -1) { printf("failed in segments reassembly: "); goto end; } if (StreamTcpCheckQueue(check_contents, q, 2) == 0) { printf("failed in stream matching: "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test the handling of packets missed by IDS, but the end host has * received it and send the acknowledgment of it. The packet is missed * at the end of the stream. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest30 (void) { int ret = 0; uint8_t payload[4]; uint32_t seq; uint32_t ack; uint8_t th_flag; uint8_t th_flags; uint8_t flowflags; uint8_t check_contents[6] = {0x41, 0x41, 0x42, 0x42, 0x42, 0x00}; TcpSession ssn; memset(&ssn, 0, sizeof (TcpSession)); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); StreamMsgQueue *q = ra_ctx->stream_q; flowflags = FLOW_PKT_TOSERVER; th_flag = TH_ACK|TH_PUSH; th_flags = TH_ACK; ssn.server.last_ack = 22; ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; StreamTcpInitConfig(TRUE); StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/ seq = 10; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x00, 0, 4); seq = 20; ack = 12; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } /* Process stream smsgs we may have in queue */ if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs\n"); goto end; } flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/ seq = 12; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x00, 0, 4); seq = 20; ack = 18; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } /* Process stream smsgs we may have in queue */ if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs\n"); goto end; } th_flag = TH_FIN|TH_ACK; seq = 18; ack = 20; flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x00, 1, 4); if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } flowflags = FLOW_PKT_TOCLIENT; StreamTcpCreateTestPacket(payload, 0x00, 0, 4); seq = 20; ack = 18; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flag, flowflags, TCP_TIME_WAIT) == -1) { printf("failed in segments reassembly: "); goto end; } if (StreamTcpCheckQueue(check_contents, q, 3) == 0) { printf("failed in stream matching: "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test to reassemble the packets using the fast track method, as most * packets arrives in order. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest31 (void) { int ret = 0; uint8_t payload[4]; uint32_t seq; uint32_t ack; uint8_t th_flag; uint8_t flowflags; uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42}; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); TcpSession ssn; memset(&ssn, 0, sizeof (TcpSession)); flowflags = FLOW_PKT_TOSERVER; th_flag = TH_ACK|TH_PUSH; ssn.server.ra_raw_base_seq = 9; ssn.server.isn = 9; StreamTcpInitConfig(TRUE); StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/ seq = 10; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){ printf("failed in segments reassembly: "); goto end; } flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/ seq = 15; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/ seq = 12; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } flowflags = FLOW_PKT_TOSERVER; StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/ seq = 16; ack = 20; if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) { printf("failed in segments reassembly: "); goto end; } if (StreamTcpCheckStreamContents(check_contents, 5, &ssn.server) == 0) { printf("failed in stream matching: "); goto end; } if (ssn.server.seg_list_tail->seq != 16) { printf("failed in fast track handling: "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); return ret; } static int StreamTcpReassembleTest32(void) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); TcpStream stream; uint8_t ret = 0; uint8_t check_contents[35] = {0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43}; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; uint8_t payload[20] = ""; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->tcph->th_seq = htonl(10); p->tcph->th_ack = htonl(31); p->payload_len = 10; StreamTcpCreateTestPacket(payload, 0x41, 10, 20); /*AA*/ p->payload = payload; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) goto end; p->tcph->th_seq = htonl(20); p->tcph->th_ack = htonl(31); p->payload_len = 10; StreamTcpCreateTestPacket(payload, 0x42, 10, 20); /*BB*/ p->payload = payload; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) goto end; p->tcph->th_seq = htonl(40); p->tcph->th_ack = htonl(31); p->payload_len = 10; StreamTcpCreateTestPacket(payload, 0x43, 10, 20); /*CC*/ p->payload = payload; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) goto end; p->tcph->th_seq = htonl(5); p->tcph->th_ack = htonl(31); p->payload_len = 20; StreamTcpCreateTestPacket(payload, 0x41, 20, 20); /*AA*/ p->payload = payload; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) goto end; if (StreamTcpCheckStreamContents(check_contents, 35, &stream) != 0) { ret = 1; } else { printf("failed in stream matching: "); } end: StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } static int StreamTcpReassembleTest33(void) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); TcpStream stream; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; uint8_t packet[1460] = ""; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; p->tcph->th_seq = htonl(10); p->tcph->th_ack = htonl(31); p->payload_len = 10; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(20); p->tcph->th_ack = htonl(31); p->payload_len = 10; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(40); p->tcph->th_ack = htonl(31); p->payload_len = 10; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(5); p->tcph->th_ack = htonl(31); p->payload_len = 30; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpFreeConfig(TRUE); SCFree(p); return 1; } static int StreamTcpReassembleTest34(void) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); TcpStream stream; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; uint8_t packet[1460] = ""; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; p->tcph->th_seq = htonl(857961230); p->tcph->th_ack = htonl(31); p->payload_len = 304; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(857961534); p->tcph->th_ack = htonl(31); p->payload_len = 1460; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(857963582); p->tcph->th_ack = htonl(31); p->payload_len = 1460; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(857960946); p->tcph->th_ack = htonl(31); p->payload_len = 1460; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpFreeConfig(TRUE); SCFree(p); return 1; } /** \test Test the bug 56 condition */ static int StreamTcpReassembleTest35(void) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); TcpStream stream; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; uint8_t packet[1460] = ""; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 10); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 10); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; p->tcph->th_seq = htonl(2257022155UL); p->tcph->th_ack = htonl(1374943142); p->payload_len = 142; stream.last_ack = 2257022285UL; stream.ra_raw_base_seq = 2257022172UL; stream.ra_app_base_seq = 2257022172UL; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(2257022285UL); p->tcph->th_ack = htonl(1374943142); p->payload_len = 34; stream.last_ack = 2257022285UL; stream.ra_raw_base_seq = 2257022172UL; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpFreeConfig(TRUE); SCFree(p); return 1; } /** \test Test the bug 57 condition */ static int StreamTcpReassembleTest36(void) { TcpSession ssn; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); TcpStream stream; memset(&stream, 0, sizeof (TcpStream)); stream.os_policy = OS_POLICY_BSD; uint8_t packet[1460] = ""; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 10); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 10); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; p->tcph->th_seq = htonl(1549588966); p->tcph->th_ack = htonl(4162241372UL); p->payload_len = 204; stream.last_ack = 1549589007; stream.ra_raw_base_seq = 1549589101; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(1549589007); p->tcph->th_ack = htonl(4162241372UL); p->payload_len = 23; stream.last_ack = 1549589007; stream.ra_raw_base_seq = 1549589101; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpFreeConfig(TRUE); SCFree(p); return 1; } /** \test Test the bug 76 condition */ static int StreamTcpReassembleTest37(void) { TcpSession ssn; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); TcpStream stream; uint8_t packet[1460] = ""; PacketQueue pq; ThreadVars tv; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 10); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 10); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&stream, 0, sizeof (TcpStream)); memset(&pq,0,sizeof(PacketQueue)); memset(&ssn, 0, sizeof (TcpSession)); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&tv, 0, sizeof (ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; p->flow = &f; tcph.th_win = 5480; tcph.th_flags = TH_PUSH | TH_ACK; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; stream.os_policy = OS_POLICY_BSD; p->tcph->th_seq = htonl(3061088537UL); p->tcph->th_ack = htonl(1729548549UL); p->payload_len = 1391; stream.last_ack = 3061091137UL; stream.ra_raw_base_seq = 3061091309UL; stream.ra_app_base_seq = 3061091309UL; /* pre base_seq, so should be rejected */ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) != -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(3061089928UL); p->tcph->th_ack = htonl(1729548549UL); p->payload_len = 1391; stream.last_ack = 3061091137UL; stream.ra_raw_base_seq = 3061091309UL; stream.ra_app_base_seq = 3061091309UL; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } p->tcph->th_seq = htonl(3061091319UL); p->tcph->th_ack = htonl(1729548549UL); p->payload_len = 1391; stream.last_ack = 3061091137UL; stream.ra_raw_base_seq = 3061091309UL; stream.ra_app_base_seq = 3061091309UL; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { SCFree(p); return 0; } StreamTcpFreeConfig(TRUE); SCFree(p); return 1; } /** * \test Test to make sure we don't send the smsg from toclient to app layer * until the app layer protocol has been detected and one smsg from * toserver side has been sent to app layer. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest38 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow f; TCPHdr tcph; Port sp; Port dp; struct in_addr in; TcpSession ssn; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&f, 0, sizeof (Flow)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ FLOW_INITIALIZE(&f); if (inet_pton(AF_INET, "1.2.3.4", &in) != 1) goto end; f.src.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.5", &in) != 1) goto end; f.dst.addr_data32[0] = in.s_addr; sp = 200; dp = 220; ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; ssn.server.last_ack = 60; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; ssn.client.isn = 9; ssn.client.last_ack = 60; f.alproto = ALPROTO_UNKNOWN; f.flags |= FLOW_IPV4; f.sp = sp; f.dp = dp; f.protoctx = &ssn; p->flow = &f; tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; ssn.state = TCP_ESTABLISHED; TcpStream *s = NULL; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue (2): "); goto end; } p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; p->payload_len = httplen1; tcph.th_seq = htonl(10); tcph.th_ack = htonl(55); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (3): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue, as we didn't" " processed any smsg from toserver side till yet (4): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(55); tcph.th_ack = htonl(53); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (5): "); goto end; } /* we should now have a smsg as the http request is complete and triggered * reassembly */ if (ra_ctx->stream_q->len != 1) { printf("there should one stream smsg in the queue (6): "); goto end; } p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; p->payload_len = httplen1; tcph.th_seq = htonl(53); tcph.th_ack = htonl(100); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (8): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = NULL; p->payload_len = 0; tcph.th_seq = htonl(100); tcph.th_ack = htonl(53); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (9): "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); return ret; } /** * \test Test to make sure that we don't return the segments until the app * layer proto has been detected and after that remove the processed * segments. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest39 (void) { SCEnter(); int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow *f = NULL; TCPHdr tcph; TcpSession ssn; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 7); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 7); uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; ssn.server.last_ack = 160; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq= 9; ssn.client.isn = 9; ssn.client.last_ack = 160; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; SCLogDebug("check client seg list %p", ssn.client.seg_list); tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; ssn.state = TCP_ESTABLISHED; TcpStream *s = NULL; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue: (2): "); goto end; } SCLogDebug("check client seg list %p", ssn.client.seg_list); p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; p->payload_len = httplen1; tcph.th_seq = htonl(10); tcph.th_ack = htonl(55); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (3): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0) { printf("there should be stream smsgs in the queue (4): "); goto end; } SCLogDebug("check client seg list %p", ssn.client.seg_list); p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(55); tcph.th_ack = htonl(53); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (5): "); goto end; } SCLogDebug("check client seg list %p", ssn.client.seg_list); /* Check if we have stream smsgs in queue */ SCLogDebug("check if we have stream smsgs in queue"); if (ra_ctx->stream_q->len == 0) { printf("there should be a stream smsgs in the queue (6): "); goto end; } SCLogDebug("check client seg list %p", ssn.client.seg_list); /* Process stream smsgs we may have in queue */ SCLogDebug("process stream smsgs we may have in queue"); if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (7): "); goto end; } SCLogDebug("check client seg list %p", ssn.client.seg_list); /* check is have the segment in the list and flagged or not */ /* if (ssn.client.seg_list == NULL || !(ssn.client.seg_list->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { printf("the list is NULL or the processed segment has not been flaged (8), seg %p, flags %02X: ", ssn.client.seg_list, ssn.client.seg_list? ssn.client.seg_list->flags:0); //abort(); goto end; } */ p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; p->payload_len = httplen1; tcph.th_seq = htonl(53); tcph.th_ack = htonl(100); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (9): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0 && !(ssn.flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { printf("there should be a stream smsgs in the queue, as we have detected" " the app layer protocol and one smsg from toserver side has " "been sent (10): "); goto end; /* Process stream smsgs we may have in queue */ } else if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (11): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(100); tcph.th_ack = htonl(96); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (12): "); goto end; } SCLogDebug("final check"); if (!(ssn.flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { printf("STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED flag should have been set (13): "); goto end; } /* check if the segment in the list is flagged or not */ if (ssn.client.seg_list == NULL) { printf("segment list should not be empty (14): "); goto end; } SCLogDebug("ssn.client.seg_list->flags %02x, seg %p", ssn.client.seg_list->flags, ssn.client.seg_list); if (!(ssn.client.seg_list->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) { printf("segment should have flags SEGMENTTCP_FLAG_APPLAYER_PROCESSED set (15): "); goto end; } if (!(ssn.client.seg_list->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { printf("segment should have flags SEGMENTTCP_FLAG_RAW_PROCESSED set (16): "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); UTHFreeFlow(f); return ret; } /** * \test Test to make sure that we sent all the segments from the initial * segments to app layer until we have detected the app layer proto. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest40 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow *f = NULL; TCPHdr tcph; TcpSession ssn; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); StreamTcpInitConfig(TRUE); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 130); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); uint8_t httpbuf1[] = "P"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "O"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "S"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ uint8_t httpbuf5[] = "T \r\n"; uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; ssn.server.last_ack = 10; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; ssn.client.isn = 9; ssn.client.last_ack = 10; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(10); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; p->payload_len = httplen1; ssn.state = TCP_ESTABLISHED; TcpStream *s = NULL; s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue, as we didn't" " processed any smsg from toserver side till yet (2): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(10); tcph.th_ack = htonl(11); s = &ssn.server; ssn.server.last_ack = 11; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (3): "); goto end; } /* Process stream smsgs we may have in queue */ if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (4): "); goto end; } p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf3; p->payload_len = httplen3; tcph.th_seq = htonl(11); tcph.th_ack = htonl(55); s = &ssn.client; ssn.client.last_ack = 55; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (5): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(55); tcph.th_ack = htonl(12); s = &ssn.server; ssn.server.last_ack = 12; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (6): "); goto end; } /* check is have the segment in the list and flagged or not */ if (ssn.client.seg_list == NULL || !(ssn.client.seg_list->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) { printf("the list is NULL or the processed segment has not been flaged (7): "); goto end; } /* Check if we have stream smsgs in queue */ #if 0 if (ra_ctx->stream_q->len == 0) { printf("there should be a stream smsgs in the queue, as we have detected" " the app layer protocol and one smsg from toserver side has " "been sent (8): "); goto end; /* Process stream smsgs we may have in queue */ } else if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (9): "); goto end; } #endif p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf4; p->payload_len = httplen4; tcph.th_seq = htonl(12); tcph.th_ack = htonl(100); s = &ssn.client; ssn.client.last_ack = 100; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (10): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(100); tcph.th_ack = htonl(13); s = &ssn.server; ssn.server.last_ack = 13; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (11): "); goto end; } /* Check if we have stream smsgs in queue */ #if 0 if (ra_ctx->stream_q->len == 0) { printf("there should be a stream smsgs in the queue, as we have detected" " the app layer protocol and one smsg from toserver side has " "been sent (12): "); goto end; /* Process stream smsgs we may have in queue */ } else if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (13): "); goto end; } #endif p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf5; p->payload_len = httplen5; tcph.th_seq = htonl(13); tcph.th_ack = htonl(145); s = &ssn.client; ssn.client.last_ack = 145; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (14): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(145); tcph.th_ack = htonl(16); s = &ssn.server; ssn.server.last_ack = 16; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (15): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0) { printf("there should be a stream smsgs in the queue, as we have detected" " the app layer protocol and one smsg from toserver side has " "been sent (16): "); goto end; /* Process stream smsgs we may have in queue */ } if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (17): "); goto end; } if (f->alproto != ALPROTO_HTTP) { printf("app layer proto has not been detected (18): "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); UTHFreeFlow(f); return ret; } /** * \test Test to make sure we don't send more than one smsg from toserver to * app layer until the app layer protocol has not been detected. After * protocol has been detected the processed segments should be returned * to pool. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest41 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow *f = NULL; TCPHdr tcph; TcpSession ssn; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: Victor/1.0" "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu" "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN" "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N" "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk" "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l" "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN" "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt" "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz" "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw" "aG9uZT"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "psb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps" "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw" "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9" "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N" "\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 100); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 500); ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; ssn.server.last_ack = 600; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; ssn.client.isn = 9; ssn.client.last_ack = 600; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; ssn.state = TCP_ESTABLISHED; TcpStream *s = NULL; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet: "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue: "); goto end; } p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; p->payload_len = httplen1; tcph.th_seq = htonl(10); tcph.th_ack = htonl(55); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet: "); goto end; } p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf3; p->payload_len = httplen3; tcph.th_seq = htonl(522); tcph.th_ack = htonl(100); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet: "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0) { printf("there should be stream smsgs in the queue: "); goto end; } if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs: "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(55); tcph.th_ack = htonl(522); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet: "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0) { printf("there should be a stream smsgs in the queue: "); goto end; /* Process stream smsgs we may have in queue */ } else if (ra_ctx->stream_q->len > 1) { printf("there should be only one stream smsgs in the queue: "); goto end; } else if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs: "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(100); tcph.th_ack = htonl(522); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet: "); goto end; } /* check if the segment in the list is flagged or not */ if (ssn.client.seg_list == NULL) { printf("segment list should not be empty: "); goto end; } /* last_ack is in the middle of this segment */ if ((ssn.client.seg_list_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) { printf("segment should not have flags SEGMENTTCP_FLAG_APPLAYER_PROCESSED set: "); goto end; } if (!(ssn.client.seg_list_tail->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { printf("segment should have flags SEGMENTTCP_FLAG_RAW_PROCESSED set: "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); UTHFreeFlow(f); return ret; } /** * \test Test to make sure that Pause/Unpause API is working. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest42 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow *f = NULL; TCPHdr tcph; TcpSession ssn; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 50); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 50); ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; ssn.server.last_ack = 60; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; ssn.client.isn = 9; ssn.client.last_ack = 60; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; ssn.state = TCP_ESTABLISHED; TcpStream *s = NULL; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue (2): "); goto end; } /* pause the reassembling */ StreamTcpReassemblePause(&ssn, 1); p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; p->payload_len = httplen1; tcph.th_seq = htonl(10); tcph.th_ack = htonl(55); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (3): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0) { printf("there should be stream smsgs in the queue (4): "); goto end; } if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs: "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(55); tcph.th_ack = htonl(53); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (5): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue, as we have" " paused the reassembling (6): "); goto end; } /* Unpause the reassembling */ StreamTcpReassembleUnPause(&ssn, 1); p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(100); tcph.th_ack = htonl(53); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (7): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0) { printf("there should be a stream smsgs in the queue, as reassembling has" " been unpaused now (8): "); goto end; /* Process stream smsgs we may have in queue */ } else if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (9): "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); UTHFreeFlow(f); return ret; } /** * \test Test to make sure that Pause/Unpause API is working. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest43 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow *f = NULL; TCPHdr tcph; TcpSession ssn; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu" "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN" "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N" "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk" "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l" "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN" "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt" "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz" "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw" "aG9uZT\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; ssn.server.last_ack = 600; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; ssn.client.isn = 9; ssn.client.last_ack = 600; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(10); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; ssn.state = TCP_ESTABLISHED; TcpStream *s = NULL; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue (2): "); goto end; } p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; p->payload_len = httplen1; tcph.th_seq = htonl(10); tcph.th_ack = htonl(55); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (3): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue, as we didn't" " processed any smsg from toserver side till yet (4): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(55); tcph.th_ack = htonl(44); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (5): "); goto end; } #if 0 /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0) { printf("there should be a stream smsgs in the queue (6): "); goto end; /* Process stream smsgs we may have in queue */ } else if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (7): "); goto end; } #endif if (!(ssn.flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { printf("app layer detected flag isn't set, it should be (8): "); goto end; } /* This packets induces a packet gap and also shows why we need to process the current segment completely, even if it results in sending more than one smsg to the app layer. If we don't send more than one smsg in this case, then the first segment of lentgh 34 bytes will be sent to app layer and protocol can not be detected in that message and moreover the segment lentgh is less than the max. signature size for protocol detection, so this will keep looping !! */ p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf3; p->payload_len = httplen3; tcph.th_seq = htonl(54); tcph.th_ack = htonl(100); s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (9): "); goto end; } /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len > 0) { printf("there shouldn't be any stream smsgs in the queue, as we didn't" " detected the app layer protocol till yet (10): "); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf2; p->payload_len = httplen2; tcph.th_seq = htonl(100); tcph.th_ack = htonl(53); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (11): "); goto end; } #if 0 /* Check if we have stream smsgs in queue */ if (ra_ctx->stream_q->len == 0) { printf("there should be a stream smsgs in the queue, as reassembling has" " been unpaused now (12): "); goto end; /* Process stream smsgs we may have in queue */ } else if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs (13): "); goto end; } #endif /* the flag should be set, as the smsg scanned size has crossed the max. signature size for app proto detection */ if (! (ssn.flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) { printf("app layer detected flag is not set, it should be (14): "); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); UTHFreeFlow(f); return ret; } /** \test Test the memcap incrementing/decrementing and memcap check */ static int StreamTcpReassembleTest44(void) { uint8_t ret = 0; StreamTcpInitConfig(TRUE); uint32_t memuse = SC_ATOMIC_GET(ra_memuse); StreamTcpReassembleIncrMemuse(500); if (SC_ATOMIC_GET(ra_memuse) != (memuse+500)) { printf("failed in incrementing the memory"); goto end; } StreamTcpReassembleDecrMemuse(500); if (SC_ATOMIC_GET(ra_memuse) != memuse) { printf("failed in decrementing the memory"); goto end; } if (StreamTcpReassembleCheckMemcap(500) != 1) { printf("failed in validating the memcap"); goto end; } if (StreamTcpReassembleCheckMemcap((memuse + stream_config.reassembly_memcap)) != 0) { printf("failed in validating the memcap"); goto end; } StreamTcpFreeConfig(TRUE); if (SC_ATOMIC_GET(ra_memuse) != 0) { printf("failed in clearing the memory"); goto end; } ret = 1; return ret; end: StreamTcpFreeConfig(TRUE); return ret; } /** * \test Test to make sure that reassembly_depth is enforced. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest45 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow *f = NULL; TCPHdr tcph; TcpSession ssn; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); ThreadVars tv; memset(&tv, 0, sizeof (ThreadVars)); uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, 9); ssn.server.isn = 9; ssn.server.last_ack = 60; STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9); ssn.client.isn = 9; ssn.client.last_ack = 60; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf1; p->payload_len = httplen1; ssn.state = TCP_ESTABLISHED; /* set the default value of reassembly depth, as there is no config file */ stream_config.reassembly_depth = httplen1 + 1; TcpStream *s = NULL; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toclient packet: "); goto end; } /* Check if we have flags set or not */ if (s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) { printf("there shouldn't be a noreassembly flag be set: "); goto end; } STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, ssn.server.isn + httplen1); p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = httplen1; s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet: "); goto end; } /* Check if we have flags set or not */ if (s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) { printf("there shouldn't be a noreassembly flag be set: "); goto end; } STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, ssn.client.isn + httplen1); p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = httplen1; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet: "); goto end; } /* Check if we have flags set or not */ if (!(s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("the noreassembly flags should be set, " "p.payload_len %"PRIu16" stream_config.reassembly_" "depth %"PRIu32": ", p->payload_len, stream_config.reassembly_depth); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); UTHFreeFlow(f); return ret; } /** * \test Test the undefined config value of reassembly depth. * the default value of 0 will be loaded and stream will be reassembled * until the session ended * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest46 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow *f = NULL; TCPHdr tcph; TcpSession ssn; ThreadVars tv; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); memset(&tv, 0, sizeof (ThreadVars)); uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, 9); ssn.server.isn = 9; ssn.server.last_ack = 60; ssn.server.next_seq = ssn.server.isn; STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9); ssn.client.isn = 9; ssn.client.last_ack = 60; ssn.client.next_seq = ssn.client.isn; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(20); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOCLIENT; p->payload = httpbuf1; p->payload_len = httplen1; ssn.state = TCP_ESTABLISHED; stream_config.reassembly_depth = 0; TcpStream *s = NULL; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toclient packet\n"); goto end; } /* Check if we have flags set or not */ if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("there shouldn't be any no reassembly flag be set \n"); goto end; } STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, ssn.server.isn + httplen1); p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = httplen1; s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet\n"); goto end; } /* Check if we have flags set or not */ if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("there shouldn't be any no reassembly flag be set \n"); goto end; } STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, ssn.client.isn + httplen1); p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = httplen1; tcph.th_seq = htonl(10 + httplen1); tcph.th_ack = htonl(20 + httplen1); s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet\n"); goto end; } /* Check if we have flags set or not */ if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { printf("the no_reassembly flags should not be set, " "p->payload_len %"PRIu16" stream_config.reassembly_" "depth %"PRIu32": ", p->payload_len, stream_config.reassembly_depth); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); UTHFreeFlow(f); return ret; } /** * \test Test to make sure we detect the sequence wrap around and continue * stream reassembly properly. * * \retval On success it returns 1 and on failure 0. */ static int StreamTcpReassembleTest47 (void) { int ret = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Flow *f = NULL; TCPHdr tcph; TcpSession ssn; ThreadVars tv; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); PacketQueue pq; memset(&pq,0,sizeof(PacketQueue)); memset(&tcph, 0, sizeof (TCPHdr)); memset(&ssn, 0, sizeof(TcpSession)); memset(&tv, 0, sizeof (ThreadVars)); /* prevent L7 from kicking in */ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 0); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 0); StreamTcpInitConfig(TRUE); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 572799781UL; ssn.server.isn = 572799781UL; ssn.server.last_ack = 572799782UL; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 4294967289UL; ssn.client.isn = 4294967289UL; ssn.client.last_ack = 21; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) goto end; f->protoctx = &ssn; p->flow = f; tcph.th_win = htons(5480); ssn.state = TCP_ESTABLISHED; TcpStream *s = NULL; uint8_t cnt = 0; for (cnt=0; cnt < httplen1; cnt++) { tcph.th_seq = htonl(ssn.client.isn + 1 + cnt); tcph.th_ack = htonl(572799782UL); tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = &httpbuf1[cnt]; p->payload_len = 1; s = &ssn.client; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver " "packet\n"); goto end; } p->flowflags = FLOW_PKT_TOCLIENT; p->payload = NULL; p->payload_len = 0; tcph.th_seq = htonl(572799782UL); tcph.th_ack = htonl(ssn.client.isn + 1 + cnt); tcph.th_flags = TH_ACK; p->tcph = &tcph; s = &ssn.server; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver " "packet\n"); goto end; } /* Process stream smsgs we may have in queue */ if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) { printf("failed in processing stream smsgs\n"); goto end; } } if (f->alproto != ALPROTO_HTTP) { printf("App layer protocol (HTTP) should have been detected\n"); goto end; } ret = 1; end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); UTHFreeFlow(f); return ret; } /** \test 3 in order segments in inline reassembly */ static int StreamTcpReassembleInlineTest01(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); uint8_t stream_payload[] = "AAAAABBBBBCCCCC"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } ssn.client.next_seq = 17; int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 1) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 15) { printf("expected data length to be 15, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload, smsg->data.data, 15) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload, 15); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test 3 in order segments, then reassemble, add one more and reassemble again. * test the sliding window reassembly. */ static int StreamTcpReassembleInlineTest02(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); uint8_t stream_payload1[] = "AAAAABBBBBCCCCC"; uint8_t stream_payload2[] = "AAAAABBBBBCCCCCDDDDD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } ssn.client.next_seq = 17; int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 1) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 15) { printf("expected data length to be 15, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 15) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload1, 15); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); goto end; } ssn.client.next_seq = 22; r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed 2: "); goto end; } if (ra_ctx->stream_q->len != 2) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 20) { printf("expected data length to be 20, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload2, smsg->data.data, 20) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 20); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test 3 in order segments, then reassemble, add one more and reassemble again. * test the sliding window reassembly with a small window size so that we * cutting off at the start (left edge) */ static int StreamTcpReassembleInlineTest03(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); stream_config.reassembly_toserver_chunk_size = 15; uint8_t stream_payload1[] = "AAAAABBBBBCCCCC"; uint8_t stream_payload2[] = "BBBBBCCCCCDDDDD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } ssn.client.next_seq = 17; int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 1) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 15) { printf("expected data length to be 15, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 15) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload1, 15); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); goto end; } ssn.client.next_seq = 22; p->tcph->th_seq = htonl(17); r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed 2: "); goto end; } if (ra_ctx->stream_q->len != 2) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 15) { printf("expected data length to be 15, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload2, smsg->data.data, 15) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 15); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test 3 in order segments, then reassemble, add one more and reassemble again. * test the sliding window reassembly with a small window size so that we * cutting off at the start (left edge) with small packet overlap. */ static int StreamTcpReassembleInlineTest04(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); stream_config.reassembly_toserver_chunk_size = 16; uint8_t stream_payload1[] = "AAAAABBBBBCCCCC"; uint8_t stream_payload2[] = "ABBBBBCCCCCDDDDD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } ssn.client.next_seq = 17; int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 1) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 15) { printf("expected data length to be 15, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 15) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload1, 15); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); goto end; } ssn.client.next_seq = 22; p->tcph->th_seq = htonl(17); r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed 2: "); goto end; } if (ra_ctx->stream_q->len != 2) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 16) { printf("expected data length to be 16, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload2, smsg->data.data, 16) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 16); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test with a GAP we should have 2 smsgs */ static int StreamTcpReassembleInlineTest05(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); uint8_t stream_payload1[] = "AAAAABBBBB"; uint8_t stream_payload2[] = "DDDDD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } ssn.client.next_seq = 12; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); goto end; } p->tcph->th_seq = htonl(17); int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 2) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top->next; if (smsg->data.data_len != 10) { printf("expected data length to be 10, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 10) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 10); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 5) { printf("expected data length to be 5, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload2, smsg->data.data, 5) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 5); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test with a GAP we should have 2 smsgs, with filling the GAP later */ static int StreamTcpReassembleInlineTest06(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); uint8_t stream_payload1[] = "AAAAABBBBB"; uint8_t stream_payload2[] = "DDDDD"; uint8_t stream_payload3[] = "AAAAABBBBBCCCCCDDDDD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } ssn.client.next_seq = 12; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); goto end; } p->tcph->th_seq = htonl(17); int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 2) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top->next; if (smsg->data.data_len != 10) { printf("expected data length to be 10, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 10) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 10); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 5) { printf("expected data length to be 5, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload2, smsg->data.data, 5) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 5); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } ssn.client.next_seq = 22; p->tcph->th_seq = htonl(12); r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 3) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 20) { printf("expected data length to be 20, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload3, smsg->data.data, 20) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload3, 20); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test with a GAP we should have 2 smsgs, with filling the GAP later, small * window */ static int StreamTcpReassembleInlineTest07(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); stream_config.reassembly_toserver_chunk_size = 16; uint8_t stream_payload1[] = "ABBBBB"; uint8_t stream_payload2[] = "DDDDD"; uint8_t stream_payload3[] = "AAAAABBBBBCCCCCD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } ssn.client.next_seq = 12; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); goto end; } p->tcph->th_seq = htonl(17); int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 2) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top->next; if (smsg->data.data_len != 6) { printf("expected data length to be 6, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 6) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload1, 6); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 5) { printf("expected data length to be 5, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload2, smsg->data.data, 5) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 5); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } ssn.client.next_seq = 22; p->tcph->th_seq = htonl(12); r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 3) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 16) { printf("expected data length to be 16, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload3, smsg->data.data, 16) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload3, 16); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test 3 in order segments, then reassemble, add one more and reassemble again. * test the sliding window reassembly with a small window size so that we * cutting off at the start (left edge). Test if the first segment is * removed from the list. */ static int StreamTcpReassembleInlineTest08(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); stream_config.reassembly_toserver_chunk_size = 15; ssn.client.flags |= STREAMTCP_STREAM_FLAG_GAP; uint8_t stream_payload1[] = "AAAAABBBBBCCCCC"; uint8_t stream_payload2[] = "BBBBBCCCCCDDDDD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } ssn.client.next_seq = 17; int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 1) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 15) { printf("expected data length to be 15, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 15) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload1, 15); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (ssn.client.ra_raw_base_seq != 16) { printf("ra_raw_base_seq %"PRIu32", expected 16: ", ssn.client.ra_raw_base_seq); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); goto end; } ssn.client.next_seq = 22; p->tcph->th_seq = htonl(17); r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed 2: "); goto end; } if (ra_ctx->stream_q->len != 2) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 15) { printf("expected data length to be 15, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload2, smsg->data.data, 15) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 15); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); goto end; } if (ssn.client.seg_list->seq != 7) { printf("expected segment 2 (seq 7) to be first in the list, got seq %"PRIu32": ", ssn.client.seg_list->seq); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test 3 in order segments, then reassemble, add one more and reassemble again. * test the sliding window reassembly with a small window size so that we * cutting off at the start (left edge). Test if the first segment is * removed from the list. */ static int StreamTcpReassembleInlineTest09(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); stream_config.reassembly_toserver_chunk_size = 20; ssn.client.flags |= STREAMTCP_STREAM_FLAG_GAP; uint8_t stream_payload1[] = "AAAAABBBBBCCCCC"; uint8_t stream_payload2[] = "DDDDD"; uint8_t stream_payload3[] = "AAAAABBBBBCCCCCDDDDD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(17); p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 3: "); goto end; } ssn.client.next_seq = 12; int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 2) { printf("expected 2 stream message2, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->bot; if (smsg->data.data_len != 10) { printf("expected data length to be 10, got %u (bot): ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 10) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload1, 10); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 5) { printf("expected data length to be 5, got %u (top): ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload2, smsg->data.data, 5) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload2, 5); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (ssn.client.ra_raw_base_seq != 11) { printf("ra_raw_base_seq %"PRIu32", expected 11: ", ssn.client.ra_raw_base_seq); goto end; } /* close the GAP and see if we properly reassemble and update ra_base_seq */ if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 4: "); goto end; } ssn.client.next_seq = 22; p->tcph->th_seq = htonl(12); r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed 2: "); goto end; } if (ra_ctx->stream_q->len != 3) { printf("expected 3 stream messages, got %u: ", ra_ctx->stream_q->len); goto end; } smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 20) { printf("expected data length to be 20, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload3, smsg->data.data, 20) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload3, 20); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); goto end; } if (ssn.client.seg_list->seq != 2) { printf("expected segment 1 (seq 2) to be first in the list, got seq %"PRIu32": ", ssn.client.seg_list->seq); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test App Layer reassembly. */ static int StreamTcpReassembleInlineTest10(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow *f = NULL; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.server, 1); f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); if (f == NULL) goto end; f->protoctx = &ssn; uint8_t stream_payload1[] = "GE"; uint8_t stream_payload2[] = "T /"; uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n"; Packet *p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(7); p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 2, stream_payload1, 2) == -1) { printf("failed to add segment 1: "); goto end; } ssn.server.next_seq = 4; int r = StreamTcpReassembleInlineAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); if (r < 0) { printf("StreamTcpReassembleInlineAppLayer failed: "); goto end; } /* ssn.server.ra_app_base_seq should be isn here. */ if (ssn.server.ra_app_base_seq != 1 || ssn.server.ra_app_base_seq != ssn.server.isn) { printf("expected ra_app_base_seq 1, got %u: ", ssn.server.ra_app_base_seq); goto end; } if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 4, stream_payload2, 3) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 7, stream_payload3, 12) == -1) { printf("failed to add segment 3: "); goto end; } ssn.server.next_seq = 19; r = StreamTcpReassembleInlineAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); if (r < 0) { printf("StreamTcpReassembleInlineAppLayer failed: "); goto end; } if (ssn.server.ra_app_base_seq != 18) { printf("expected ra_app_base_seq 18, got %u: ", ssn.server.ra_app_base_seq); goto end; } ret = 1; end: #if 0 FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); #endif UTHFreeFlow(f); return ret; } /** \test test insert with overlap */ static int StreamTcpReassembleInsertTest01(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; Flow f; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); uint8_t stream_payload1[] = "AAAAABBBBBCCCCCDDDDD"; uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { printf("couldn't get a packet: "); goto end; } p->tcph->th_seq = htonl(12); p->flow = &f; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1) { printf("failed to add segment 3: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1) { printf("failed to add segment 4: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 5: "); goto end; } ssn.client.next_seq = 21; int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); if (r < 0) { printf("StreamTcpReassembleInlineRaw failed: "); goto end; } if (ra_ctx->stream_q->len != 1) { printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); goto end; } StreamMsg *smsg = ra_ctx->stream_q->top; if (smsg->data.data_len != 20) { printf("expected data length to be 20, got %u: ", smsg->data.data_len); goto end; } if (!(memcmp(stream_payload1, smsg->data.data, 20) == 0)) { printf("data is not what we expected:\nExpected:\n"); PrintRawDataFp(stdout, stream_payload1, 20); printf("Got:\n"); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); goto end; } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); goto end; } ret = 1; end: FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test test insert with overlaps */ static int StreamTcpReassembleInsertTest02(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); int i; for (i = 2; i < 10; i++) { int len; len = i % 2; if (len == 0) len = 1; int seq; seq = i * 10; if (seq < 2) seq = 2; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1) { printf("failed to add segment 1: "); goto end; } } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1) { printf("failed to add segment 2: "); goto end; } ret = 1; end: StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } /** \test test insert with overlaps */ static int StreamTcpReassembleInsertTest03(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpSession ssn; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1) { printf("failed to add segment 2: "); goto end; } int i; for (i = 2; i < 10; i++) { int len; len = i % 2; if (len == 0) len = 1; int seq; seq = i * 10; if (seq < 2) seq = 2; if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1) { printf("failed to add segment 2: "); goto end; } } ret = 1; end: StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); return ret; } #endif /* UNITTESTS */ /** \brief The Function Register the Unit tests to test the reassembly engine * for various OS policies. */ void StreamTcpReassembleRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("StreamTcpReassembleTest01 -- BSD OS Before Reassembly Test", StreamTcpReassembleTest01, 1); UtRegisterTest("StreamTcpReassembleTest02 -- BSD OS At Same Reassembly Test", StreamTcpReassembleTest02, 1); UtRegisterTest("StreamTcpReassembleTest03 -- BSD OS After Reassembly Test", StreamTcpReassembleTest03, 1); UtRegisterTest("StreamTcpReassembleTest04 -- BSD OS Complete Reassembly Test", StreamTcpReassembleTest04, 1); UtRegisterTest("StreamTcpReassembleTest05 -- VISTA OS Before Reassembly Test", StreamTcpReassembleTest05, 1); UtRegisterTest("StreamTcpReassembleTest06 -- VISTA OS At Same Reassembly Test", StreamTcpReassembleTest06, 1); UtRegisterTest("StreamTcpReassembleTest07 -- VISTA OS After Reassembly Test", StreamTcpReassembleTest07, 1); UtRegisterTest("StreamTcpReassembleTest08 -- VISTA OS Complete Reassembly Test", StreamTcpReassembleTest08, 1); UtRegisterTest("StreamTcpReassembleTest09 -- LINUX OS Before Reassembly Test", StreamTcpReassembleTest09, 1); UtRegisterTest("StreamTcpReassembleTest10 -- LINUX OS At Same Reassembly Test", StreamTcpReassembleTest10, 1); UtRegisterTest("StreamTcpReassembleTest11 -- LINUX OS After Reassembly Test", StreamTcpReassembleTest11, 1); UtRegisterTest("StreamTcpReassembleTest12 -- LINUX OS Complete Reassembly Test", StreamTcpReassembleTest12, 1); UtRegisterTest("StreamTcpReassembleTest13 -- LINUX_OLD OS Before Reassembly Test", StreamTcpReassembleTest13, 1); UtRegisterTest("StreamTcpReassembleTest14 -- LINUX_OLD At Same Reassembly Test", StreamTcpReassembleTest14, 1); UtRegisterTest("StreamTcpReassembleTest15 -- LINUX_OLD OS After Reassembly Test", StreamTcpReassembleTest15, 1); UtRegisterTest("StreamTcpReassembleTest16 -- LINUX_OLD OS Complete Reassembly Test", StreamTcpReassembleTest16, 1); UtRegisterTest("StreamTcpReassembleTest17 -- SOLARIS OS Before Reassembly Test", StreamTcpReassembleTest17, 1); UtRegisterTest("StreamTcpReassembleTest18 -- SOLARIS At Same Reassembly Test", StreamTcpReassembleTest18, 1); UtRegisterTest("StreamTcpReassembleTest19 -- SOLARIS OS After Reassembly Test", StreamTcpReassembleTest19, 1); UtRegisterTest("StreamTcpReassembleTest20 -- SOLARIS OS Complete Reassembly Test", StreamTcpReassembleTest20, 1); UtRegisterTest("StreamTcpReassembleTest21 -- LAST OS Before Reassembly Test", StreamTcpReassembleTest21, 1); UtRegisterTest("StreamTcpReassembleTest22 -- LAST OS At Same Reassembly Test", StreamTcpReassembleTest22, 1); UtRegisterTest("StreamTcpReassembleTest23 -- LAST OS After Reassembly Test", StreamTcpReassembleTest23, 1); UtRegisterTest("StreamTcpReassembleTest24 -- LAST OS Complete Reassembly Test", StreamTcpReassembleTest24, 1); UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test", StreamTcpReassembleTest25, 1); UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test", StreamTcpReassembleTest26, 1); UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test", StreamTcpReassembleTest27, 1); UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test", StreamTcpReassembleTest28, 1); UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test", StreamTcpReassembleTest29, 1); UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test", StreamTcpReassembleTest30, 1); UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test", StreamTcpReassembleTest31, 1); UtRegisterTest("StreamTcpReassembleTest32 -- Bug test", StreamTcpReassembleTest32, 1); UtRegisterTest("StreamTcpReassembleTest33 -- Bug test", StreamTcpReassembleTest33, 1); UtRegisterTest("StreamTcpReassembleTest34 -- Bug test", StreamTcpReassembleTest34, 1); UtRegisterTest("StreamTcpReassembleTest35 -- Bug56 test", StreamTcpReassembleTest35, 1); UtRegisterTest("StreamTcpReassembleTest36 -- Bug57 test", StreamTcpReassembleTest36, 1); UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test", StreamTcpReassembleTest37, 1); UtRegisterTest("StreamTcpReassembleTest38 -- app proto test", StreamTcpReassembleTest38, 1); UtRegisterTest("StreamTcpReassembleTest39 -- app proto test", StreamTcpReassembleTest39, 1); UtRegisterTest("StreamTcpReassembleTest40 -- app proto test", StreamTcpReassembleTest40, 1); UtRegisterTest("StreamTcpReassembleTest41 -- app proto test", StreamTcpReassembleTest41, 1); UtRegisterTest("StreamTcpReassembleTest42 -- pause/unpause reassembly test", StreamTcpReassembleTest42, 1); UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", StreamTcpReassembleTest43, 1); UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44, 1); UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", StreamTcpReassembleTest45, 1); UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", StreamTcpReassembleTest46, 1); UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", StreamTcpReassembleTest47, 1); UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra", StreamTcpReassembleInlineTest01, 1); UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2", StreamTcpReassembleInlineTest02, 1); UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3", StreamTcpReassembleInlineTest03, 1); UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4", StreamTcpReassembleInlineTest04, 1); UtRegisterTest("StreamTcpReassembleInlineTest05 -- inline RAW ra 5 GAP", StreamTcpReassembleInlineTest05, 1); UtRegisterTest("StreamTcpReassembleInlineTest06 -- inline RAW ra 6 GAP", StreamTcpReassembleInlineTest06, 1); UtRegisterTest("StreamTcpReassembleInlineTest07 -- inline RAW ra 7 GAP", StreamTcpReassembleInlineTest07, 1); UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", StreamTcpReassembleInlineTest08, 1); UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup", StreamTcpReassembleInlineTest09, 1); UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", StreamTcpReassembleInlineTest10, 1); UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", StreamTcpReassembleInsertTest01, 1); UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap", StreamTcpReassembleInsertTest02, 1); UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap", StreamTcpReassembleInsertTest03, 1); StreamTcpInlineRegisterTests(); StreamTcpUtilRegisterTests(); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-mpm-b2g-cuda-kernel.cu0000644000000000000000000000744112253546156015770 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * The Cuda kernel for MPM B2G. * * \todo This is a basic version of the kernel. Modify it to support multiple * blocks of threads. Make use of shared memory/texture memory. */ #define B2G_CUDA_Q 2 #define CUDA_THREADS 4000 #define B2G_CUDA_HASHSHIFT 4 #define B2G_CUDA_TYPE unsigned int #define B2G_CUDA_HASH16(a, b) (((a) << B2G_CUDA_HASHSHIFT) | (b)) #define u8_tolower(c) g_u8_lowercasetable[(c)] typedef struct SCCudaPBPacketDataForGPU_ { /* holds the value B2gCtx->m */ unsigned int m; /* holds B2gCtx->B2g */ unsigned int table; /* holds the length of the payload */ unsigned int payload_len; /* holds the payload */ unsigned char payload; } SCCudaPBPacketDataForGPU; extern "C" __global__ void B2gCudaSearchBNDMq(unsigned short *results_buffer, unsigned char *packets_buffer, unsigned int *packets_offset_buffer, unsigned int *packets_payload_offset_buffer, unsigned int nop, unsigned char *g_u8_lowercasetable) { unsigned int tid = blockIdx.x * 32 + threadIdx.x; /* if the thread id is greater than the no of packets sent in the packets * buffer, terminate the thread */ //if (tid <= nop) if (tid >= nop) return; SCCudaPBPacketDataForGPU *packet = (SCCudaPBPacketDataForGPU *)(packets_buffer + packets_offset_buffer[tid]); unsigned int m = packet->m; unsigned char *buf = &packet->payload; unsigned int buflen = packet->payload_len; unsigned int *B2G = (unsigned int *)packet->table; unsigned int pos = m - B2G_CUDA_Q + 1; B2G_CUDA_TYPE d; unsigned short h; unsigned int first; unsigned int j = 0; unsigned short *matches_count = results_buffer + packets_payload_offset_buffer[tid] + tid; //unsigned short *matches_count = results_buffer + packets_payload_offset_buffer[1] + 1; //unsigned short *offsets = results_buffer + packets_payload_offset_buffer[1] + 1 + 1; unsigned short *offsets = matches_count + 1; // temporarily hold the results here, before we shift it to matches_count // before returning unsigned short matches = 0; while (pos <= (buflen - B2G_CUDA_Q + 1)) { h = B2G_CUDA_HASH16(u8_tolower(buf[pos - 1]), u8_tolower(buf[pos])); d = B2G[h]; if (d != 0) { j = pos; first = pos - (m - B2G_CUDA_Q + 1); do { j = j - 1; if (d >= (1 << (m - 1))) { if (j > first) { pos = j; } else { offsets[matches++] = j; } } if (j == 0) break; h = B2G_CUDA_HASH16(u8_tolower(buf[j - 1]), u8_tolower(buf[j])); d = (d << 1) & B2G[h]; } while (d != 0); } pos = pos + m - B2G_CUDA_Q + 1; } matches_count[0] = matches; return; } suricata-1.4.7/src/app-layer-dcerpc-udp.c0000644000000000000000000010441012253546156015107 00000000000000/* * Copyright (c) 2009, 2010 Open Information Security Foundation * * \author Kirby Kuehl * * \todo Updated by AS: Inspect the possibilities of sending junk start at the * start of udp session to avoid alproto detection. */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "decode.h" #include "flow-util.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "util-debug.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "util-spm.h" #include "util-unittest.h" #include "app-layer-dcerpc-udp.h" enum { DCERPC_FIELD_NONE = 0, DCERPC_PARSE_DCERPC_HEADER, DCERPC_PARSE_DCERPC_BIND, DCERPC_PARSE_DCERPC_BIND_ACK, DCERPC_PARSE_DCERPC_REQUEST, /* must be last */ DCERPC_FIELD_MAX, }; static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; uint8_t **stub_data_buffer = NULL; uint32_t *stub_data_buffer_len = NULL; uint8_t *stub_data_fresh = NULL; uint16_t stub_len = 0; /* request PDU. Retrieve the request stub buffer */ if (sstate->dcerpc.dcerpchdrudp.type == REQUEST) { stub_data_buffer = &sstate->dcerpc.dcerpcrequest.stub_data_buffer; stub_data_buffer_len = &sstate->dcerpc.dcerpcrequest.stub_data_buffer_len; stub_data_fresh = &sstate->dcerpc.dcerpcrequest.stub_data_fresh; /* response PDU. Retrieve the response stub buffer */ } else { stub_data_buffer = &sstate->dcerpc.dcerpcresponse.stub_data_buffer; stub_data_buffer_len = &sstate->dcerpc.dcerpcresponse.stub_data_buffer_len; stub_data_fresh = &sstate->dcerpc.dcerpcresponse.stub_data_fresh; } stub_len = (sstate->dcerpc.fraglenleft < input_len) ? sstate->dcerpc.fraglenleft : input_len; if (stub_len == 0) { SCReturnUInt(0); } /* if the frag is the the first frag irrespective of it being a part of * a multi frag PDU or not, it indicates the previous PDU's stub would * have been buffered and processed and we can use the buffer to hold * frags from a fresh request/response */ if (sstate->dcerpc.dcerpchdrudp.flags1 & PFC_FIRST_FRAG) { *stub_data_buffer_len = 0; } *stub_data_buffer = SCRealloc(*stub_data_buffer, *stub_data_buffer_len + stub_len); if (*stub_data_buffer == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); goto end; } memcpy(*stub_data_buffer + *stub_data_buffer_len, input, stub_len); *stub_data_fresh = 1; /* length of the buffered stub */ *stub_data_buffer_len += stub_len; sstate->dcerpc.fraglenleft -= stub_len; sstate->dcerpc.bytesprocessed += stub_len; #ifdef DEBUG if (SCLogDebugEnabled()) { int i = 0; for (i = 0; i < stub_len; i++) { SCLogDebug("0x%02x ", input[i]); } } #endif end: SCReturnUInt((uint32_t)stub_len); } /** * \brief DCERPCParseHeader parses the 16 byte DCERPC header * A fast path for normal decoding is used when there is enough bytes * present to parse the entire header. A slow path is used to parse * fragmented packets. */ static int DCERPCUDPParseHeader(Flow *f, void *dcerpcudp_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { SCEnter(); uint8_t *p = input; DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; if (input_len) { switch (sstate->bytesprocessed) { case 0: // fallthrough /* above statement to prevent coverity FPs from the switch * fall through */ if (input_len >= DCERPC_UDP_HDR_LEN) { sstate->dcerpc.dcerpchdrudp.rpc_vers = *p; if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { SCLogDebug("DCERPC UDP Header did not validate"); SCReturnInt(-1); } sstate->dcerpc.dcerpchdrudp.type = *(p + 1); sstate->dcerpc.dcerpchdrudp.flags1 = *(p + 2); sstate->dcerpc.dcerpchdrudp.flags2 = *(p + 3); sstate->dcerpc.dcerpchdrudp.drep[0] = *(p + 4); sstate->dcerpc.dcerpchdrudp.drep[1] = *(p + 5); sstate->dcerpc.dcerpchdrudp.drep[2] = *(p + 6); sstate->dcerpc.dcerpchdrudp.serial_hi = *(p + 7); sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p + 8); sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p + 9); sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p + 10); sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p + 11); sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p + 12); sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p + 13); sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p + 14); sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p + 15); sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p + 16); sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p + 17); sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p + 18); sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p + 19); sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p + 20); sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p + 21); sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p + 22); sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p + 23); sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p + 24); sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p + 25); sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p + 26); sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p + 27); sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p + 28); sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p + 29); sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p + 30); sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p + 31); sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p + 32); sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p + 33); sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p + 34); sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p + 35); sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p + 36); sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p + 37); sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p + 38); sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p + 39); sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p + 40); sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p + 41); sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p + 42); sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p + 43); sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p + 44); sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p + 45); sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p + 46); sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p + 47); sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p + 48); sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p + 49); sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p + 50); sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p + 51); sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p + 52); sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p + 53); sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p + 54); sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p + 55); if (sstate->dcerpc.dcerpchdrudp.drep[0] == 0x10) { sstate->dcerpc.dcerpchdrudp.server_boot = *(p + 56); sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 57) << 8; sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 58) << 16; sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 59) << 24; sstate->dcerpc.dcerpchdrudp.if_vers = *(p + 60); sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 61) << 8; sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 62) << 16; sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 63) << 24; sstate->dcerpc.dcerpchdrudp.seqnum = *(p + 64); sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 65) << 8; sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 66) << 16; sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 67) << 24; sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68); sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 8; sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70); sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71) << 8; sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72); sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73) << 8; sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74); sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75) << 8; sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76); sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77) << 8; } else { sstate->dcerpc.dcerpchdrudp.server_boot = *(p + 56) << 24; sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 57) << 16; sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 58) << 8; sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 59); sstate->dcerpc.dcerpchdrudp.if_vers = *(p + 60) << 24; sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 61) << 16; sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 62) << 8; sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 63); sstate->dcerpc.dcerpchdrudp.seqnum = *(p + 64) << 24; sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 65) << 16; sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 66) << 8; sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 67); sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68) << 24; sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 16; sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70) << 8; sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71); sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72) << 8; sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73); sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74) << 8; sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75); sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76) << 8; sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77); } sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; sstate->dcerpc.dcerpchdrudp.auth_proto = *(p + 78); sstate->dcerpc.dcerpchdrudp.serial_lo = *(p + 79); sstate->bytesprocessed = DCERPC_UDP_HDR_LEN; sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); if (sstate->uuid_entry == NULL) { SCReturnUInt(-1); } else { memcpy(sstate->uuid_entry->uuid, sstate->dcerpc.dcerpchdrudp.activityuuid, sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, next); #ifdef UNITTESTS if (RunmodeIsUnittests()) { printUUID("DCERPC UDP", sstate->uuid_entry); } #endif } SCReturnUInt(80); break; } else { sstate->dcerpc.dcerpchdrudp.rpc_vers = *(p++); if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { SCLogDebug("DCERPC UDP Header did not validate"); SCReturnInt(-1); } if (!(--input_len)) break; /* We fall through to the next case if we still have input. * Same applies for other cases as well */ } case 1: sstate->dcerpc.dcerpchdrudp.type = *(p++); if (!(--input_len)) break; case 2: sstate->dcerpc.dcerpchdrudp.flags1 = *(p++); if (!(--input_len)) break; case 3: sstate->dcerpc.dcerpchdrudp.flags2 = *(p++); if (!(--input_len)) break; case 4: sstate->dcerpc.dcerpchdrudp.drep[0] = *(p++); if (!(--input_len)) break; case 5: sstate->dcerpc.dcerpchdrudp.drep[1] = *(p++); if (!(--input_len)) break; case 6: sstate->dcerpc.dcerpchdrudp.drep[2] = *(p++); if (!(--input_len)) break; case 7: sstate->dcerpc.dcerpchdrudp.serial_hi = *(p++); if (!(--input_len)) break; case 8: sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p++); if (!(--input_len)) break; case 9: sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p++); if (!(--input_len)) break; case 10: sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p++); if (!(--input_len)) break; case 11: sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p++); if (!(--input_len)) break; case 12: sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p++); if (!(--input_len)) break; case 13: sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p++); if (!(--input_len)) break; case 14: sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p++); if (!(--input_len)) break; case 15: sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p++); if (!(--input_len)) break; case 16: sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p++); if (!(--input_len)) break; case 17: sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p++); if (!(--input_len)) break; case 18: sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p++); if (!(--input_len)) break; case 19: sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p++); if (!(--input_len)) break; case 20: sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p++); if (!(--input_len)) break; case 21: sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p++); if (!(--input_len)) break; case 22: sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p++); if (!(--input_len)) break; case 23: sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p++); if (!(--input_len)) break; case 24: sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p++); if (!(--input_len)) break; case 25: sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p++); if (!(--input_len)) break; case 26: sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p++); if (!(--input_len)) break; case 27: sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p++); if (!(--input_len)) break; case 28: sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p++); if (!(--input_len)) break; case 29: sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p++); if (!(--input_len)) break; case 30: sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p++); if (!(--input_len)) break; case 31: sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p++); if (!(--input_len)) break; case 32: sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p++); if (!(--input_len)) break; case 33: sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p++); if (!(--input_len)) break; case 34: sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p++); if (!(--input_len)) break; case 35: sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p++); if (!(--input_len)) break; case 36: sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p++); if (!(--input_len)) break; case 37: sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p++); if (!(--input_len)) break; case 38: sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p++); if (!(--input_len)) break; case 39: sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p++); if (!(--input_len)) break; case 40: sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p++); if (!(--input_len)) break; case 41: sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p++); if (!(--input_len)) break; case 42: sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p++); if (!(--input_len)) break; case 43: sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p++); if (!(--input_len)) break; case 44: sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p++); if (!(--input_len)) break; case 45: sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p++); if (!(--input_len)) break; case 46: sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p++); if (!(--input_len)) break; case 47: sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p++); if (!(--input_len)) break; case 48: sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p++); if (!(--input_len)) break; case 49: sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p++); if (!(--input_len)) break; case 50: sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p++); if (!(--input_len)) break; case 51: sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p++); if (!(--input_len)) break; case 52: sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p++); if (!(--input_len)) break; case 53: sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p++); if (!(--input_len)) break; case 54: sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p++); if (!(--input_len)) break; case 55: sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p++); if (!(--input_len)) break; case 56: sstate->dcerpc.dcerpchdrudp.server_boot = *(p++); if (!(--input_len)) break; case 57: sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 8; if (!(--input_len)) break; case 58: sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 16; if (!(--input_len)) break; case 59: sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 24; if (!(--input_len)) break; case 60: sstate->dcerpc.dcerpchdrudp.if_vers = *(p++); if (!(--input_len)) break; case 61: sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 8; if (!(--input_len)) break; case 62: sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 16; if (!(--input_len)) break; case 63: sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 24; if (!(--input_len)) break; case 64: sstate->dcerpc.dcerpchdrudp.seqnum = *(p++); if (!(--input_len)) break; case 65: sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 8; if (!(--input_len)) break; case 66: sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 16; if (!(--input_len)) break; case 67: sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 24; if (!(--input_len)) break; case 68: sstate->dcerpc.dcerpchdrudp.opnum = *(p++); if (!(--input_len)) break; case 69: sstate->dcerpc.dcerpchdrudp.opnum |= *(p++) << 8; if (!(--input_len)) break; case 70: sstate->dcerpc.dcerpchdrudp.ihint = *(p++); if (!(--input_len)) break; case 71: sstate->dcerpc.dcerpchdrudp.ihint |= *(p++) << 8; if (!(--input_len)) break; case 72: sstate->dcerpc.dcerpchdrudp.ahint = *(p++); if (!(--input_len)) break; case 73: sstate->dcerpc.dcerpchdrudp.ahint |= *(p++) << 8; if (!(--input_len)) break; case 74: sstate->dcerpc.dcerpchdrudp.fraglen = *(p++); if (!(--input_len)) break; case 75: sstate->dcerpc.dcerpchdrudp.fraglen |= *(p++) << 8; if (!(--input_len)) break; case 76: sstate->dcerpc.dcerpchdrudp.fragnum = *(p++); if (!(--input_len)) break; case 77: sstate->dcerpc.dcerpchdrudp.fragnum |= *(p++); if (!(--input_len)) break; case 78: sstate->dcerpc.dcerpchdrudp.auth_proto = *(p++); if (!(--input_len)) break; case 79: sstate->dcerpc.dcerpchdrudp.serial_lo = *(p++); if (sstate->dcerpc.dcerpchdrudp.drep[0] != 0x10) { sstate->dcerpc.dcerpchdrudp.server_boot = SCByteSwap32(sstate->dcerpc.dcerpchdrudp.server_boot); sstate->dcerpc.dcerpchdrudp.if_vers= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.if_vers); sstate->dcerpc.dcerpchdrudp.seqnum= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.seqnum); sstate->dcerpc.dcerpchdrudp.opnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.opnum); sstate->dcerpc.dcerpchdrudp.ihint= SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ihint); sstate->dcerpc.dcerpchdrudp.ahint = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ahint); sstate->dcerpc.dcerpchdrudp.fraglen = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fraglen); sstate->dcerpc.dcerpchdrudp.fragnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fragnum); } sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); if (sstate->uuid_entry == NULL) { SCReturnUInt(-1); } else { memcpy(sstate->uuid_entry->uuid, sstate->dcerpc.dcerpchdrudp.activityuuid, sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, next); #ifdef UNITTESTS if (RunmodeIsUnittests()) { printUUID("DCERPC UDP", sstate->uuid_entry); } #endif } --input_len; break; } } sstate->bytesprocessed += (p - input); SCReturnInt((p - input)); } static int DCERPCUDPParse(Flow *f, void *dcerpc_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { uint32_t retval = 0; uint32_t parsed = 0; int hdrretval = 0; SCEnter(); DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpc_state; while (sstate->bytesprocessed < DCERPC_UDP_HDR_LEN && input_len) { hdrretval = DCERPCUDPParseHeader(f, dcerpc_state, pstate, input, input_len, output); if (hdrretval == -1 || hdrretval > (int32_t)input_len) { sstate->bytesprocessed = 0; SCReturnInt(hdrretval); } else { parsed += hdrretval; input_len -= hdrretval; } } #if 0 printf("Done with DCERPCUDPParseHeader bytesprocessed %u/%u left %u\n", sstate->bytesprocessed, sstate->dcerpc.dcerpchdrudp.fraglen, input_len); printf("\nDCERPC Version:\t%u\n", sstate->dcerpc.dcerpchdrudp.rpc_vers); printf("DCERPC Type:\t%u\n", sstate->dcerpc.dcerpchdrudp.ptype); printf("DCERPC Flags1:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags1); printf("DCERPC Flags2:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags2); printf("DCERPC Packed Drep:\t%02x %02x %02x\n", sstate->dcerpc.dcerpchdrudp.drep[0], sstate->dcerpc.dcerpchdrudp.drep[1], sstate->dcerpc.dcerpchdrudp.drep[2]); printf("DCERPC Frag Length:\t0x%04x %u\n", sstate->dcerpc.dcerpchdrudp.fraglen, sstate->dcerpc.dcerpchdrudp.fraglen); printf("DCERPC Frag Number:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.fragnum); printf("DCERPC OpNum:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.opnum); #endif while (sstate->bytesprocessed >= DCERPC_UDP_HDR_LEN && sstate->bytesprocessed < sstate->dcerpc.dcerpchdrudp.fraglen && input_len) { retval = FragmentDataParser(f, dcerpc_state, pstate, input + parsed, input_len, output); if (retval || retval > input_len) { parsed += retval; input_len -= retval; } else if (input_len) { SCLogDebug("Error parsing DCERPC UDP Fragment Data"); parsed -= input_len; input_len = 0; sstate->bytesprocessed = 0; } } if (sstate->bytesprocessed == sstate->dcerpc.dcerpchdrudp.fraglen) { sstate->bytesprocessed = 0; } if (pstate == NULL) SCReturnInt(-1); pstate->parse_field = 0; SCReturnInt(1); } static void *DCERPCUDPStateAlloc(void) { void *s = SCMalloc(sizeof(DCERPCUDPState)); if (unlikely(s == NULL)) return NULL; memset(s, 0, sizeof(DCERPCUDPState)); return s; } static void DCERPCUDPStateFree(void *s) { DCERPCUDPState *sstate = (DCERPCUDPState *) s; DCERPCUuidEntry *item; while ((item = TAILQ_FIRST(&sstate->uuid_list))) { //printUUID("Free", item); TAILQ_REMOVE(&sstate->uuid_list, item, next); SCFree(item); } if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; sstate->dcerpc.dcerpcrequest.stub_data_buffer_len = 0; } if (sstate->dcerpc.dcerpcresponse.stub_data_buffer != NULL) { SCFree(sstate->dcerpc.dcerpcresponse.stub_data_buffer); sstate->dcerpc.dcerpcresponse.stub_data_buffer = NULL; sstate->dcerpc.dcerpcresponse.stub_data_buffer_len = 0; } if (s) { SCFree(s); s = NULL; } } void RegisterDCERPCUDPParsers(void) { char *proto_name = "dcerpcudp"; /** DCERPC */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_UDP, ALPROTO_DCERPC_UDP, "|04 00|", 2, 0, STREAM_TOSERVER); AppLayerRegisterProto(proto_name, ALPROTO_DCERPC_UDP, STREAM_TOSERVER, DCERPCUDPParse); AppLayerRegisterProto(proto_name, ALPROTO_DCERPC_UDP, STREAM_TOCLIENT, DCERPCUDPParse); AppLayerRegisterStateFuncs(ALPROTO_DCERPC_UDP, DCERPCUDPStateAlloc, DCERPCUDPStateFree); } /* UNITTESTS */ #ifdef UNITTESTS /** \test DCERPC UDP Header Parsing and UUID handling */ int DCERPCUDPParserTest01(void) { int result = 1; Flow f; uint8_t dcerpcrequest[] = { 0x04, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x3f, 0x98, 0xf0, 0x5c, 0xd9, 0x63, 0xcc, 0x46, 0xc2, 0x74, 0x51, 0x6c, 0x8a, 0x53, 0x7d, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0x70, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x24, 0x58, 0xfd, 0xcc, 0x45, 0x64, 0x49, 0xb0, 0x70, 0xdd, 0xae, 0x74, 0x2c, 0x96, 0xd2, 0x60, 0x5e, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x5e, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7c, 0x5e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x80, 0x96, 0xf1, 0xf1, 0x2a, 0x4d, 0xce, 0x11, 0xa6, 0x6a, 0x00, 0x20, 0xaf, 0x6e, 0x72, 0xf4, 0x0c, 0x00, 0x00, 0x00, 0x4d, 0x41, 0x52, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xf4, 0x0b, 0x00, 0x10, 0x09, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, 0xd8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xc8, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, 0xd8, 0x08, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x28, 0xcd, 0x00, 0x64, 0x29, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xab, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xa5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xad, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28, 0x06, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x50, 0x00, 0x00, 0x00, 0x4f, 0xb6, 0x88, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x66, 0x00, 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0x0c, 0x00, 0x58, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x98, 0x93, 0x98, 0x4f, 0xd2, 0x11, 0xa9, 0x3d, 0xbe, 0x57, 0xb2, 0x00, 0x00, 0x00, 0x32, 0x00, 0x31, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x80, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x81, 0xc5, 0x17, 0x03, 0x80, 0x0e, 0xe9, 0x4a, 0x99, 0x99, 0xf1, 0x8a, 0x50, 0x6f, 0x7a, 0x85, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xda, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x2f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x46, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x68, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, 0x68, 0x8b, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x9d, 0x13, 0x00, 0x01, 0xcc, 0xe0, 0xfd, 0x7f, 0xcc, 0xe0, 0xfd, 0x7f, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; uint32_t requestlen = sizeof(dcerpcrequest); TcpSession ssn; DCERPCUuidEntry *uuid_entry; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; FLOW_INITIALIZE(&f); StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_DCERPC_UDP, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCUDPState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers != 4) { printf("expected dcerpc version 0x04, got 0x%02x : ", dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdrudp.fraglen != 1392) { printf("expected dcerpc fraglen 0x%02x , got 0x%02x : ", 1392, dcerpc_state->dcerpc.dcerpchdrudp.fraglen); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdrudp.opnum != 4) { printf("expected dcerpc opnum 0x%02x , got 0x%02x : ", 4, dcerpc_state->dcerpc.dcerpchdrudp.opnum); result = 0; goto end; } TAILQ_FOREACH(uuid_entry, &dcerpc_state->uuid_list, next) { printUUID("REQUEST", uuid_entry); } end: StreamTcpFreeConfig(TRUE); return result; } void DCERPCUDPParserRegisterTests(void) { UtRegisterTest("DCERPCUDPParserTest01", DCERPCUDPParserTest01, 1); } #endif suricata-1.4.7/src/detect-icmp-id.h0000644000000000000000000000202212253546156013762 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias Galvan */ #ifndef __DETECT_ICMP_ID_H__ #define __DETECT_ICMP_ID_H__ typedef struct DetectIcmpIdData_ { uint16_t id; /**< id in network byte error */ } DetectIcmpIdData; /* prototypes */ void DetectIcmpIdRegister(void); #endif /* __DETECT_ICMP_ID__ */ suricata-1.4.7/src/app-layer-protos.h0000644000000000000000000000266412253546156014424 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __APP_LAYER_PROTOS_H__ #define __APP_LAYER_PROTOS_H__ enum { ALPROTO_UNKNOWN = 0, ALPROTO_HTTP, ALPROTO_FTP, ALPROTO_SMTP, ALPROTO_TLS, /* SSLv2, SSLv3 & TLSv1 */ ALPROTO_SSH, ALPROTO_IMAP, ALPROTO_MSN, ALPROTO_JABBER, ALPROTO_SMB, ALPROTO_SMB2, ALPROTO_DCERPC, ALPROTO_DCERPC_UDP, ALPROTO_IRC, /* used by the probing parser when alproto detection fails * permanently for that particular stream */ ALPROTO_FAILED, #ifdef UNITTESTS ALPROTO_TEST, #endif /* UNITESTS */ /* keep last */ ALPROTO_MAX, }; const char *TmModuleAlprotoToString(int proto); #endif /* __APP_LAYER_PROTOS_H__ */ suricata-1.4.7/src/stream-tcp.h0000644000000000000000000001532212253546156013260 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Gurvinder Singh */ #ifndef __STREAM_TCP_H__ #define __STREAM_TCP_H__ #include "stream-tcp-private.h" #define COUNTER_STREAMTCP_STREAMS 1 #include "app-layer-detect-proto.h" #include "util-mpm.h" #include "stream.h" #include "stream-tcp-reassemble.h" #define STREAM_VERBOSE FALSE /* Flag to indicate that the checksum validation for the stream engine has been enabled */ #define STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION 0x01 /*global flow data*/ typedef struct TcpStreamCnf_ { /** stream tracking * * max stream mem usage */ uint64_t memcap; uint64_t reassembly_memcap; /**< max memory usage for stream reassembly */ uint32_t max_sessions; uint32_t prealloc_sessions; int midstream; int async_oneside; uint32_t reassembly_depth; /**< Depth until when we reassemble the stream */ uint16_t reassembly_toserver_chunk_size; uint16_t reassembly_toclient_chunk_size; int check_overlap_different_data; /** reassembly -- inline mode * * sliding window size for raw stream reassembly */ uint32_t reassembly_inline_window; uint8_t flags; } TcpStreamCnf; typedef struct StreamTcpThread_ { uint64_t pkts; /** queue for pseudo packet(s) that were created in the stream * process and need further handling. Currently only used when * receiving (valid) RST packets */ PacketQueue pseudo_queue; uint16_t counter_tcp_sessions; /** sessions not picked up because memcap was reached */ uint16_t counter_tcp_ssn_memcap; /** pseudo packets processed */ uint16_t counter_tcp_pseudo; /** packets rejected because their csum is invalid */ uint16_t counter_tcp_invalid_checksum; /** TCP packets with no associated flow */ uint16_t counter_tcp_no_flow; /** sessions reused */ uint16_t counter_tcp_reused_ssn; /** sessions reused */ uint16_t counter_tcp_memuse; /** syn pkts */ uint16_t counter_tcp_syn; /** syn/ack pkts */ uint16_t counter_tcp_synack; /** rst pkts */ uint16_t counter_tcp_rst; /** tcp reassembly thread data */ TcpReassemblyThreadCtx *ra_ctx; } StreamTcpThread; TcpStreamCnf stream_config; void TmModuleStreamTcpRegister (void); void StreamTcpInitConfig (char); void StreamTcpFreeConfig(char); void StreamTcpRegisterTests (void); void StreamTcpSessionPktFree (Packet *); void StreamTcpIncrMemuse(uint64_t); void StreamTcpDecrMemuse(uint64_t); int StreamTcpCheckMemcap(uint64_t); Packet *StreamTcpPseudoSetup(Packet *, uint8_t *, uint32_t); int StreamTcpSegmentForEach(Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); void StreamTcpReassembleConfigEnableOverlapCheck(void); /** ------- Inline functions: ------ */ /** * \brief If we are on IPS mode, and got a drop action triggered from * the IP only module, or from a reassembled msg and/or from an * applayer detection, then drop the rest of the packets of the * same stream and avoid inspecting it any further * \param p pointer to the Packet to check * \retval 1 if we must drop this stream * \retval 0 if the stream still legal */ static inline int StreamTcpCheckFlowDrops(Packet *p) { extern uint8_t engine_mode; /* If we are on IPS mode, and got a drop action triggered from * the IP only module, or from a reassembled msg and/or from an * applayer detection, then drop the rest of the packets of the * same stream and avoid inspecting it any further */ if (IS_ENGINE_MODE_IPS(engine_mode) && (p->flow->flags & FLOW_ACTION_DROP)) return 1; return 0; } /** * \brief Function to flip the direction When we missed the SYN packet, * SYN/ACK is considered as sent by server, but our engine flagged the * packet as from client for the host whose packet is received first in * the session. * * \param ssn TcpSession to whom this packet belongs * \param p Packet whose flag has to be changed */ static inline void StreamTcpPacketSwitchDir(TcpSession *ssn, Packet *p) { SCLogDebug("ssn %p: switching pkt direction", ssn); if (PKT_IS_TOSERVER(p)) { p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; } else { p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; } } enum { /* stream has no segments for forced reassembly, nor for detection */ STREAM_HAS_UNPROCESSED_SEGMENTS_NONE = 0, /* stream seems to have segments that need to be forced reassembled */ STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY = 1, /* stream has no segments for forced reassembly, but only segments that * have been sent for detection, but are stuck in the detection queues */ STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION = 2, }; static inline int StreamHasUnprocessedSegments(TcpSession *ssn, int direction) { /* server tcp state */ if (direction) { if (ssn->server.seg_list != NULL && (!(ssn->server.seg_list_tail->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) || !(ssn->server.seg_list_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) ) { return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY; } else if (ssn->toclient_smsg_head != NULL) { return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION; } else { return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE; } } else { if (ssn->client.seg_list != NULL && (!(ssn->client.seg_list_tail->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) || !(ssn->client.seg_list_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) ) { return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY; } else if (ssn->toserver_smsg_head != NULL) { return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION; } else { return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE; } } } #endif /* __STREAM_TCP_H__ */ suricata-1.4.7/src/detect-file-data.h0000644000000000000000000000164612253546156014301 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_FILEDATA_H__ #define __DETECT_FILEDATA_H__ /* prototypes */ void DetectFiledataRegister (void); #endif /* __DETECT_FILEDATA_H__ */ suricata-1.4.7/src/util-enum.h0000644000000000000000000000206212253546156013115 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_ENUM_H__ #define __UTIL_ENUM_H__ typedef struct SCEnumCharMap_ { char *enum_name; int enum_value; } SCEnumCharMap; int SCMapEnumNameToValue(const char *, SCEnumCharMap *); const char * SCMapEnumValueToName(int, SCEnumCharMap *); #endif /* __UTIL_ENUM_H__ */ suricata-1.4.7/src/runmode-pcap-file.h0000644000000000000000000000213012253546156014501 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien */ #ifndef __RUNMODE_PCAP_FILE_H__ #define __RUNMODE_PCAP_FILE_H__ int RunModeFilePcapSingle(DetectEngineCtx *); int RunModeFilePcapAuto(DetectEngineCtx *); int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx); void RunModeFilePcapRegister(void); const char *RunModeFilePcapGetDefaultMode(void); #endif /* __RUNMODE_PCAP_FILE_H__ */ suricata-1.4.7/src/util-var-name.h0000644000000000000000000000206112253546156013656 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_VAR_NAME_H__ #define __UTIL_VAR_NAME_H__ int VariableNameInitHash(DetectEngineCtx *); void VariableNameFreeHash(DetectEngineCtx *); uint16_t VariableNameGetIdx(DetectEngineCtx *, char *, uint8_t); char * VariableIdxGetName(DetectEngineCtx *, uint16_t , uint8_t); #endif suricata-1.4.7/src/util-logopenfile.h0000644000000000000000000000203212253546156014451 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Mike Pomraning */ #ifndef __UTIL_LOGOPENFILE_H__ #define __UTIL_LOGOPENFILE_H__ #include "conf.h" /* ConfNode */ #include "tm-modules.h" /* LogFileCtx */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *); #endif /* __UTIL_LOGOPENFILE_H__ */ suricata-1.4.7/src/detect-urilen.c0000644000000000000000000005121612253546156013742 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * Implements the urilen keyword */ #include "suricata-common.h" #include "app-layer-protos.h" #include "app-layer-htp.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-urilen.h" #include "util-debug.h" #include "util-byte.h" #include "flow-util.h" #include "stream-tcp.h" /** * \brief Regex for parsing our urilen */ #define PARSE_REGEX "^(?:\\s*)(<|>)?(?:\\s*)([0-9]{1,5})(?:\\s*)(?:(<>)(?:\\s*)([0-9]{1,5}))?\\s*(?:,\\s*(norm|raw))?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ int DetectUrilenMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m); static int DetectUrilenSetup (DetectEngineCtx *, Signature *, char *); void DetectUrilenFree (void *); void DetectUrilenRegisterTests (void); /** * \brief Registration function for urilen: keyword */ void DetectUrilenRegister(void) { sigmatch_table[DETECT_AL_URILEN].name = "urilen"; sigmatch_table[DETECT_AL_URILEN].desc = "match on the length of the HTTP uri"; sigmatch_table[DETECT_AL_URILEN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#Urilen"; sigmatch_table[DETECT_AL_URILEN].Match = NULL; sigmatch_table[DETECT_AL_URILEN].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_URILEN].AppLayerMatch = NULL /**< We handle this at detect-engine-uri.c now */; sigmatch_table[DETECT_AL_URILEN].Setup = DetectUrilenSetup; sigmatch_table[DETECT_AL_URILEN].Free = DetectUrilenFree; sigmatch_table[DETECT_AL_URILEN].RegisterTests = DetectUrilenRegisterTests; sigmatch_table[DETECT_AL_URILEN].flags |= SIGMATCH_PAYLOAD; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogDebug("pcre study failed: %s", eb); goto error; } return; error: if (parse_regex != NULL) SCFree(parse_regex); if (parse_regex_study != NULL) SCFree(parse_regex_study); return; } /** * \brief This function is used to match urilen rule option with the HTTP * uricontent. * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectUrilenData * * \retval 0 no match * \retval 1 match */ int DetectUrilenMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; int idx = 0; DetectUrilenData *urilend = (DetectUrilenData *) m->ctx; HtpState *htp_state = (HtpState *)state; if (htp_state == NULL) { SCLogDebug("no HTP state, no need to match further"); SCReturnInt(ret); } FLOWLOCK_RDLOCK(f); htp_tx_t *tx = NULL; idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL || tx->request_uri_normalized == NULL) goto end; switch (urilend->mode) { case DETECT_URILEN_EQ: if (bstr_len(tx->request_uri_normalized) == urilend->urilen1) ret = 1; break; case DETECT_URILEN_LT: if (bstr_len(tx->request_uri_normalized) < urilend->urilen1) ret = 1; break; case DETECT_URILEN_GT: if (bstr_len(tx->request_uri_normalized) > urilend->urilen1) ret = 1; break; case DETECT_URILEN_RA: if (bstr_len(tx->request_uri_normalized) > urilend->urilen1 && bstr_len(tx->request_uri_normalized) < urilend->urilen2) ret = 1; break; } } end: FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief This function is used to parse urilen options passed via urilen: keyword * * \param urilenstr Pointer to the user provided urilen options * * \retval urilend pointer to DetectUrilenData on success * \retval NULL on failure */ DetectUrilenData *DetectUrilenParse (char *urilenstr) { DetectUrilenData *urilend = NULL; char *arg1 = NULL; char *arg2 = NULL; char *arg3 = NULL; char *arg4 = NULL; char *arg5 = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, urilenstr, strlen(urilenstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3 || ret > 6) { SCLogError(SC_ERR_PCRE_PARSE, "urilen option pcre parse error: \"%s\"", urilenstr); goto error; } const char *str_ptr; SCLogDebug("ret %d", ret); res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg1 = (char *) str_ptr; SCLogDebug("Arg1 \"%s\"", arg1); res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg2 = (char *) str_ptr; SCLogDebug("Arg2 \"%s\"", arg2); if (ret > 3) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg3 = (char *) str_ptr; SCLogDebug("Arg3 \"%s\"", arg3); if (ret > 4) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 4, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg4 = (char *) str_ptr; SCLogDebug("Arg4 \"%s\"", arg4); } if (ret > 5) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 5, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg5 = (char *) str_ptr; SCLogDebug("Arg5 \"%s\"", arg5); } } urilend = SCMalloc(sizeof (DetectUrilenData)); if (unlikely(urilend == NULL)) goto error; memset(urilend, 0, sizeof(DetectUrilenData)); if (arg1[0] == '<') urilend->mode = DETECT_URILEN_LT; else if (arg1[0] == '>') urilend->mode = DETECT_URILEN_GT; else urilend->mode = DETECT_URILEN_EQ; if (arg3 != NULL && strcmp("<>", arg3) == 0) { if (strlen(arg1) != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Range specified but mode also set"); goto error; } urilend->mode = DETECT_URILEN_RA; } /** set the first urilen value */ if (ByteExtractStringUint16(&urilend->urilen1,10,strlen(arg2),arg2) <= 0){ SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size :\"%s\"",arg2); goto error; } /** set the second urilen value if specified */ if (arg4 != NULL && strlen(arg4) > 0) { if (urilend->mode != DETECT_URILEN_RA) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Multiple urilen values specified" " but mode is not range"); goto error; } if(ByteExtractStringUint16(&urilend->urilen2,10,strlen(arg4),arg4) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size :\"%s\"",arg4); goto error; } if (urilend->urilen2 <= urilend->urilen1){ SCLogError(SC_ERR_INVALID_ARGUMENT,"urilen2:%"PRIu16" <= urilen:" "%"PRIu16"",urilend->urilen2,urilend->urilen1); goto error; } } if (arg5 != NULL) { if (strcasecmp("raw", arg5) == 0) { urilend->raw_buffer = 1; } } pcre_free_substring(arg1); pcre_free_substring(arg2); if (arg3 != NULL) pcre_free_substring(arg3); if (arg4 != NULL) pcre_free_substring(arg4); if (arg5 != NULL) pcre_free_substring(arg5); return urilend; error: if (urilend) SCFree(urilend); if (arg1 != NULL) SCFree(arg1); if (arg2 != NULL) SCFree(arg2); if (arg3 != NULL) SCFree(arg3); if (arg4 != NULL) SCFree(arg4); return NULL; } /** * \brief this function is used to parse urilen data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param urilenstr pointer to the user provided urilen options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectUrilenSetup (DetectEngineCtx *de_ctx, Signature *s, char *urilenstr) { SCEnter(); DetectUrilenData *urilend = NULL; SigMatch *sm = NULL; urilend = DetectUrilenParse(urilenstr); if (urilend == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_AL_URILEN; sm->ctx = (void *)urilend; if (urilend->raw_buffer) SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); else SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; SCReturnInt(0); error: if (urilend != NULL) DetectUrilenFree(urilend); if (sm != NULL) SCFree(sm); SCReturnInt(-1); } /** * \brief this function will free memory associated with DetectUrilenData * * \param ptr pointer to DetectUrilenData */ void DetectUrilenFree(void *ptr) { DetectUrilenData *urilend = (DetectUrilenData *)ptr; SCFree(urilend); } #ifdef UNITTESTS #include "stream.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "app-layer-parser.h" /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest01(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse("10"); if (urilend != NULL) { if (urilend->urilen1 == 10 && urilend->mode == DETECT_URILEN_EQ && !urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest02(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse(" < 10 "); if (urilend != NULL) { if (urilend->urilen1 == 10 && urilend->mode == DETECT_URILEN_LT && !urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest03(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse(" > 10 "); if (urilend != NULL) { if (urilend->urilen1 == 10 && urilend->mode == DETECT_URILEN_GT && !urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest04(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse(" 5 <> 10 "); if (urilend != NULL) { if (urilend->urilen1 == 5 && urilend->urilen2 == 10 && urilend->mode == DETECT_URILEN_RA && !urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest05(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse("5<>10,norm"); if (urilend != NULL) { if (urilend->urilen1 == 5 && urilend->urilen2 == 10 && urilend->mode == DETECT_URILEN_RA && !urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest06(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse("5<>10,raw"); if (urilend != NULL) { if (urilend->urilen1 == 5 && urilend->urilen2 == 10 && urilend->mode == DETECT_URILEN_RA && urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest07(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse(">10, norm "); if (urilend != NULL) { if (urilend->urilen1 == 10 && urilend->mode == DETECT_URILEN_GT && !urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest08(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse("<10, norm "); if (urilend != NULL) { if (urilend->urilen1 == 10 && urilend->mode == DETECT_URILEN_LT && !urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest09(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse(">10, raw "); if (urilend != NULL) { if (urilend->urilen1 == 10 && urilend->mode == DETECT_URILEN_GT && urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** \test Test the Urilen keyword setup */ static int DetectUrilenParseTest10(void) { int ret = 0; DetectUrilenData *urilend = NULL; urilend = DetectUrilenParse("<10, raw "); if (urilend != NULL) { if (urilend->urilen1 == 10 && urilend->mode == DETECT_URILEN_LT && urilend->raw_buffer) ret = 1; DetectUrilenFree(urilend); } return ret; } /** * \brief this function is used to initialize the detection engine context and * setup the signature with passed values. * */ static int DetectUrilenInitTest(DetectEngineCtx **de_ctx, Signature **sig, DetectUrilenData **urilend, char *str) { char fullstr[1024]; int result = 0; *de_ctx = NULL; *sig = NULL; if (snprintf(fullstr, 1024, "alert ip any any -> any any (msg:\"Urilen " "test\"; urilen:%s; sid:1;)", str) >= 1024) { goto end; } *de_ctx = DetectEngineCtxInit(); if (*de_ctx == NULL) { goto end; } (*de_ctx)->flags |= DE_QUIET; (*de_ctx)->sig_list = SigInit(*de_ctx, fullstr); if ((*de_ctx)->sig_list == NULL) { goto end; } *sig = (*de_ctx)->sig_list; *urilend = DetectUrilenParse(str); result = 1; end: return result; } /** * \test DetectUrilenSetpTest01 is a test for setting up an valid urilen values * with valid "<>" operator and include spaces arround the given values. * In the test the values are setup with initializing the detection engine * context and setting up the signature itself. */ static int DetectUrilenSetpTest01(void) { DetectUrilenData *urilend = NULL; uint8_t res = 0; Signature *sig = NULL; DetectEngineCtx *de_ctx = NULL; res = DetectUrilenInitTest(&de_ctx, &sig, &urilend, "1 <> 2 "); if (res == 0) { goto end; } if(urilend == NULL) goto cleanup; if (urilend != NULL) { if (urilend->urilen1 == 1 && urilend->urilen2 == 2 && urilend->mode == DETECT_URILEN_RA) res = 1; } cleanup: if (urilend) SCFree(urilend); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); end: return res; } /** \test Check a signature with gievn urilen */ static int DetectUrilenSigTest01(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST /suricata HTTP/1.0\r\n" "Host: foo.bar.tld\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing urilen\"; " "urilen: <5; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "urilen: >5; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } HtpState *htp_state = f.alstate; if (htp_state == NULL) { SCLogDebug("no http state: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ((PacketAlertCheck(p, 1))) { printf("sid 1 alerted, but should not have: \n"); goto end; } if (!PacketAlertCheck(p, 2)) { printf("sid 2 did not alerted, but should have: \n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectUrilen */ void DetectUrilenRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectUrilenParseTest01", DetectUrilenParseTest01, 1); UtRegisterTest("DetectUrilenParseTest02", DetectUrilenParseTest02, 1); UtRegisterTest("DetectUrilenParseTest03", DetectUrilenParseTest03, 1); UtRegisterTest("DetectUrilenParseTest04", DetectUrilenParseTest04, 1); UtRegisterTest("DetectUrilenParseTest05", DetectUrilenParseTest05, 1); UtRegisterTest("DetectUrilenParseTest06", DetectUrilenParseTest06, 1); UtRegisterTest("DetectUrilenParseTest07", DetectUrilenParseTest07, 1); UtRegisterTest("DetectUrilenParseTest08", DetectUrilenParseTest08, 1); UtRegisterTest("DetectUrilenParseTest09", DetectUrilenParseTest09, 1); UtRegisterTest("DetectUrilenParseTest10", DetectUrilenParseTest10, 1); UtRegisterTest("DetectUrilenSetpTest01", DetectUrilenSetpTest01, 1); UtRegisterTest("DetectUrilenSigTest01", DetectUrilenSigTest01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/tm-queues.c0000644000000000000000000000545312253546156013125 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Thread module management functions */ #include "suricata.h" #include "threads.h" #include "tm-queues.h" #include "util-debug.h" #define TMQ_MAX_QUEUES 256 static uint16_t tmq_id = 0; static Tmq tmqs[TMQ_MAX_QUEUES]; Tmq* TmqAlloc(void) { Tmq *q = SCMalloc(sizeof(Tmq)); if (unlikely(q == NULL)) goto error; memset(q, 0, sizeof(Tmq)); return q; error: return NULL; } Tmq* TmqCreateQueue(char *name) { if (tmq_id >= TMQ_MAX_QUEUES) goto error; Tmq *q = &tmqs[tmq_id]; q->name = name; q->id = tmq_id++; /* for cuda purposes */ q->q_type = 0; SCLogDebug("created queue \'%s\', %p", name, q); return q; error: return NULL; } Tmq* TmqGetQueueByName(char *name) { uint16_t i; for (i = 0; i < tmq_id; i++) { if (strcmp(tmqs[i].name, name) == 0) return &tmqs[i]; } return NULL; } void TmqDebugList(void) { uint16_t i = 0; for (i = 0; i < tmq_id; i++) { /* get a lock accessing the len */ SCMutexLock(&trans_q[tmqs[i].id].mutex_q); printf("TmqDebugList: id %" PRIu32 ", name \'%s\', len %" PRIu32 "\n", tmqs[i].id, tmqs[i].name, trans_q[tmqs[i].id].len); SCMutexUnlock(&trans_q[tmqs[i].id].mutex_q); } } void TmqResetQueues(void) { memset(&tmqs, 0x00, sizeof(tmqs)); tmq_id = 0; } /** * \brief Checks if all the queues allocated so far have at least one reader * and writer. */ void TmValidateQueueState(void) { int i = 0; char err = FALSE; for (i = 0; i < tmq_id; i++) { SCMutexLock(&trans_q[tmqs[i].id].mutex_q); if (tmqs[i].reader_cnt == 0) { printf("Error: Queue \"%s\" doesn't have a reader\n", tmqs[i].name); err = TRUE; } else if (tmqs[i].writer_cnt == 0) { printf("Error: Queue \"%s\" doesn't have a writer\n", tmqs[i].name); err = TRUE; } SCMutexUnlock(&trans_q[tmqs[i].id].mutex_q); if (err == TRUE) goto error; } return; error: exit(EXIT_FAILURE); } suricata-1.4.7/src/tmqh-simple.c0000644000000000000000000001113712253546156013434 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Simple queue handler */ #include "suricata.h" #include "packet-queue.h" #include "decode.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" Packet *TmqhInputSimple(ThreadVars *t); void TmqhOutputSimple(ThreadVars *t, Packet *p); void TmqhInputSimpleShutdownHandler(ThreadVars *); void TmqhSimpleRegister (void) { tmqh_table[TMQH_SIMPLE].name = "simple"; tmqh_table[TMQH_SIMPLE].InHandler = TmqhInputSimple; tmqh_table[TMQH_SIMPLE].InShutdownHandler = TmqhInputSimpleShutdownHandler; tmqh_table[TMQH_SIMPLE].OutHandler = TmqhOutputSimple; } Packet *TmqhInputSimple(ThreadVars *t) { PacketQueue *q = &trans_q[t->inq->id]; SCPerfSyncCountersIfSignalled(t, 0); SCMutexLock(&q->mutex_q); if (q->len == 0) { /* if we have no packets in queue, wait... */ SCCondWait(&q->cond_q, &q->mutex_q); } if (q->len > 0) { Packet *p = PacketDequeue(q); SCMutexUnlock(&q->mutex_q); return p; } else { /* return NULL if we have no pkt. Should only happen on signals. */ SCMutexUnlock(&q->mutex_q); return NULL; } } void TmqhInputSimpleShutdownHandler(ThreadVars *tv) { int i; if (tv == NULL || tv->inq == NULL) { return; } for (i = 0; i < (tv->inq->reader_cnt + tv->inq->writer_cnt); i++) SCCondSignal(&trans_q[tv->inq->id].cond_q); } void TmqhOutputSimple(ThreadVars *t, Packet *p) { SCLogDebug("Packet %p, p->root %p, alloced %s", p, p->root, p->flags & PKT_ALLOC ? "true":"false"); PacketQueue *q = &trans_q[t->outq->id]; SCMutexLock(&q->mutex_q); PacketEnqueue(q, p); SCCondSignal(&q->cond_q); SCMutexUnlock(&q->mutex_q); } /*******************************Generic-Q-Handlers*****************************/ /** * \brief Public version of TmqhInputSimple from the tmqh-simple queue * handler, except that it is a generic version that is directly * tied to a "SCDQDataQueue" instance(sent as an arg). * * Retrieves a data_instance from the queue. If the queue is empty, it * waits on the queue, till a data_instance is enqueued into the queue * by some other module. * * All references to "data_instance" means a reference to a data structure * instance that implements the template "struct SCDQGenericQData_". * * \param q The SCDQDataQueue instance to wait on. * * \retval p The returned packet from the queue. * \retval data The returned data_instance from the queue. */ SCDQGenericQData *TmqhInputSimpleOnQ(SCDQDataQueue *q) { SCMutexLock(&q->mutex_q); if (q->len == 0) { /* if we have no packets in queue, wait... */ SCCondWait(&q->cond_q, &q->mutex_q); } if (q->len > 0) { SCDQGenericQData *data = SCDQDataDequeue(q); SCMutexUnlock(&q->mutex_q); return data; } else { /* return NULL if we have no data in the queue. Should only happen * on signals. */ SCMutexUnlock(&q->mutex_q); return NULL; } } /** * \brief Public version of TmqhOutputSimple from the tmqh-simple queue * handler, except that it is a generic version that is directly * tied to a SCDQDataQueue instance(sent as an arg). * * Pumps out a data_instance into the queue. If the queue is empty, it * waits on the queue, till a data_instance is enqueued into the queue. * * All references to "data_instance" means a reference to a data structure * instance that implements the template "struct SCDQGenericQData_". * * \param q The SCDQDataQueue instance to pump the data into. * \param data The data instance to be enqueued. */ void TmqhOutputSimpleOnQ(SCDQDataQueue *q, SCDQGenericQData *data) { SCMutexLock(&q->mutex_q); SCDQDataEnqueue(q, data); SCCondSignal(&q->cond_q); SCMutexUnlock(&q->mutex_q); return; } suricata-1.4.7/src/detect-engine-address-ipv6.h0000644000000000000000000000271612253546156016224 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_ADDRESS_IPV6_H__ #define __DETECT_ENGINE_ADDRESS_IPV6_H__ int AddressIPv6Lt(Address *, Address *); int AddressIPv6Gt(Address *, Address *); int AddressIPv6Eq(Address *, Address *); int AddressIPv6Le(Address *, Address *); int AddressIPv6Ge(Address *, Address *); int DetectAddressCutNotIPv6(DetectAddress *, DetectAddress **); int DetectAddressCmpIPv6(DetectAddress *a, DetectAddress *b); int DetectAddressCutIPv6(DetectEngineCtx *, DetectAddress *, DetectAddress *, DetectAddress **); int DetectAddressJoinIPv6(DetectEngineCtx *, DetectAddress *, DetectAddress *); void DetectAddressIPv6Tests(void); #endif /* __DETECT_ENGINE_ADDRESS_IPV6_H__ */ suricata-1.4.7/src/detect-replace.h0000644000000000000000000000212012253546156014052 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #ifndef __DETECT_REPLACE_H__ #define __DETECT_REPLACE_H__ DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t *found, DetectContentData *cd); void DetectReplaceExecute(Packet *p, DetectReplaceList *replist); void DetectReplaceFree(DetectReplaceList *replist); void DetectReplaceRegister (void); #endif suricata-1.4.7/src/detect-tls.h0000644000000000000000000000400112253546156013241 00000000000000/* * Copyright (C) 2011-2012 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * \author Pierre Chifflier */ #ifndef __DETECT_TLS_H__ #define __DETECT_TLS_H__ typedef struct DetectTlsData_ { uint16_t ver; /** tls version to match */ uint32_t flags; /** flags containing match variant (Negation for example) */ char * subject; /** tls certificate subject substring to match */ char * issuerdn; /** tls certificate issuerDN substring to match */ char * fingerprint; /** tls fingerprint substring to match */ } DetectTlsData; /* prototypes */ void DetectTlsRegister (void); #endif /* __DETECT_TLS_H__ */ suricata-1.4.7/src/app-layer-ssh.h0000644000000000000000000000644412253546156013673 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __APP_LAYER_SSH_H__ #define __APP_LAYER_SSH_H__ #define SSH_FLAG_SERVER_CHANGE_CIPHER_SPEC 0x01 /**< Flag to indicate that server will now on sends encrypted msgs. */ #define SSH_FLAG_CLIENT_CHANGE_CIPHER_SPEC 0x02 /**< Flag to indicate that client will now on sends encrypted msgs. */ #define SSH_FLAG_CLIENT_VERSION_PARSED 0x01 #define SSH_FLAG_SERVER_VERSION_PARSED 0x02 /* This flags indicate that the rest of the communication * must be ciphered, so the parsing finish here */ #define SSH_FLAG_PARSER_DONE 0x04 /* MSG_CODE */ #define SSH_MSG_NEWKEYS 21 enum { SSH_FIELD_NONE = 0, SSH_FIELD_SERVER_VER_STATE_LINE, SSH_FIELD_CLIENT_VER_STATE_LINE, SSH_FIELD_SERVER_PKT_LENGTH, SSH_FIELD_CLIENT_PKT_LENGTH, SSH_FIELD_SERVER_PADDING_LENGTH, SSH_FIELD_CLIENT_PADDING_LENGTH, SSH_FIELD_SERVER_PAYLOAD, SSH_FIELD_CLIENT_PAYLOAD, /* must be last */ SSH_FIELD_MAX, }; /** From SSH-TRANSP rfc SSH Bunary packet structure: uint32 packet_length byte padding_length byte[n1] payload; n1 = packet_length - padding_length - 1 byte[n2] random padding; n2 = padding_length byte[m] mac (Message Authentication Code - MAC); m = mac_length So we are going to do a header struct to store the lenghts and msg_code (inside payload, if any) */ typedef struct SSHHeader_ { uint32_t pkt_len; uint8_t padding_len; uint8_t msg_code; } SshHeader; /** structure to store the SSH state values */ typedef struct SshState_ { uint8_t flags; /**< Flags to indicate the current SSH sessoin state */ uint8_t client_msg_code; /**< Client content type storage field */ uint8_t server_msg_code; /**< Server content type storage field */ uint8_t *client_proto_version; /**< Client SSH version storage field */ uint8_t *client_software_version; /**< Client SSH version storage field */ uint8_t *server_proto_version; /**< Server SSH version storage field */ uint8_t *server_software_version; /**< Server SSH version storage field */ SshHeader srv_hdr; SshHeader cli_hdr; } SshState; void RegisterSSHParsers(void); void SSHParserRegisterTests(void); #endif /* __APP_LAYER_SSH_H__ */ suricata-1.4.7/src/detect-metadata.c0000644000000000000000000000324612253546156014224 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements metadata keyword support * * \todo Do we need to do anything more this is used in snort host attribute table * It is also used for rule managment. */ #include "suricata-common.h" #include "detect.h" static int DetectMetadataSetup (DetectEngineCtx *, Signature *, char *); void DetectMetadataRegister (void) { sigmatch_table[DETECT_METADATA].name = "metadata"; sigmatch_table[DETECT_METADATA].desc = "ignored by suricata"; sigmatch_table[DETECT_METADATA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#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; } static int DetectMetadataSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { return 0; } suricata-1.4.7/src/log-droplog.c0000644000000000000000000003741012253546156013423 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * Drop log module to log the dropped packet information * */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "conf.h" #include "threads.h" #include "tm-threads.h" #include "threadvars.h" #include "util-debug.h" #include "decode-ipv4.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-reference.h" #include "output.h" #include "log-droplog.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-classification-config.h" #include "util-mpm-b2g-cuda.h" #include "util-cuda-handlers.h" #include "util-privs.h" #include "util-print.h" #include "util-proto-name.h" #include "util-logopenfile.h" #define DEFAULT_LOG_FILENAME "drop.log" #define MODULE_NAME "LogDropLog" TmEcode LogDropLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogDropLogNetFilter(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogDropLogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogDropLogDecoderEvent(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogDropLogThreadInit(ThreadVars *, void *, void **); TmEcode LogDropLogThreadDeinit(ThreadVars *, void *); OutputCtx *LogDropLogInitCtx(ConfNode *); static void LogDropLogDeInitCtx(OutputCtx *); void LogDropLogRegisterTests(void); void LogDropLogExitPrintStats(ThreadVars *, void *); /** \brief function to register the drop log module */ void TmModuleLogDropLogRegister (void) { tmm_modules[TMM_LOGDROPLOG].name = MODULE_NAME; tmm_modules[TMM_LOGDROPLOG].ThreadInit = LogDropLogThreadInit; tmm_modules[TMM_LOGDROPLOG].Func = LogDropLog; tmm_modules[TMM_LOGDROPLOG].ThreadExitPrintStats = LogDropLogExitPrintStats; tmm_modules[TMM_LOGDROPLOG].ThreadDeinit = LogDropLogThreadDeinit; tmm_modules[TMM_LOGDROPLOG].RegisterTests = LogDropLogRegisterTests; tmm_modules[TMM_LOGDROPLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "drop", LogDropLogInitCtx); } typedef struct LogDropLogThread_ { /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ LogFileCtx* file_ctx; uint64_t drop_cnt; } LogDropLogThread; /** * \brief Initialize the droplog thread * \param t Pointer the current thread variable * \param initdata pointer to the output context * \param data Pointer to the pointer to droplog thread to be initialized * * \return TM_ECODE_OK on success */ TmEcode LogDropLogThreadInit(ThreadVars *t, void *initdata, void **data) { if(initdata == NULL) { SCLogDebug("Error getting context for LogDropLog. \"initdata\" argument NULL"); return TM_ECODE_FAILED; } LogDropLogThread *dlt = SCMalloc(sizeof(LogDropLogThread)); if (unlikely(dlt == NULL)) return TM_ECODE_FAILED; memset(dlt, 0, sizeof(LogDropLogThread)); /** Use the Ouptut Context (file pointer and mutex) */ dlt->file_ctx = ((OutputCtx *)initdata)->data; *data = (void *)dlt; return TM_ECODE_OK; } /** * \brief Deinitialize the droplog thread * \param t Pointer the current thread variable * \param data Pointer to the droplog thread to be cleared * * \return TM_ECODE_OK on success */ TmEcode LogDropLogThreadDeinit(ThreadVars *t, void *data) { LogDropLogThread *dlt = (LogDropLogThread *)data; if (dlt == NULL) { return TM_ECODE_OK; } /* clear memory */ memset(dlt, 0, sizeof(LogDropLogThread)); SCFree(dlt); return TM_ECODE_OK; } /** * \brief Create a new LogFileCtx for "drop" output style. * \param conf The configuration node for this output. * \return A LogFileCtx pointer on success, NULL on failure. */ OutputCtx *LogDropLogInitCtx(ConfNode *conf) { LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("LogDropLogInitCtx: Could not create new LogFileCtx"); return NULL; } if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { LogFileFreeCtx(logfile_ctx); return NULL; } output_ctx->data = logfile_ctx; output_ctx->DeInit = LogDropLogDeInitCtx; return output_ctx; } /** * \brief Destroy the LogFileCtx and cleared "drop" output module * * \param output_ctx pointer the output context to be cleared */ static void LogDropLogDeInitCtx(OutputCtx *output_ctx) { if (output_ctx != NULL) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; if (logfile_ctx != NULL) { LogFileFreeCtx(logfile_ctx); } SCFree(output_ctx); } } /** \brief Function to create the time string from the packet timestamp */ static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); } /** * \brief Log the dropped packets in netfilter format when engine is running * in inline mode * * \param tv Pointer the current thread variables * \param p Pointer the packet which is being logged * \param data Pointer to the droplog struct * \param pq Pointer the packet queue * \param postpq Pointer the packet queue where this packet will be sent * * \return return TM_EODE_OK on success */ TmEcode LogDropLogNetFilter (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { LogDropLogThread *dlt = (LogDropLogThread *)data; uint16_t proto = 0; char timebuf[64]; if (!(PACKET_TEST_ACTION(p, ACTION_DROP)) || PKT_IS_PSEUDOPKT(p)) { return TM_ECODE_OK; } CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); SCMutexLock(&dlt->file_ctx->fp_mutex); char srcip[46] = ""; char dstip[46] = ""; if (PKT_IS_IPV4(p)) { PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, 16); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, 16); fprintf(dlt->file_ctx->fp, "%s: IN= OUT= SRC=%s DST=%s LEN=%"PRIu16" " "TOS=0x%02"PRIu8" TTL=%"PRIu8" ID=%"PRIu16"", timebuf, srcip, dstip, IPV4_GET_IPLEN(p), IPV4_GET_IPTOS(p), IPV4_GET_IPTTL(p), IPV4_GET_IPID(p)); proto = IPV4_GET_IPPROTO(p); } else if (PKT_IS_IPV6(p)) { PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); fprintf(dlt->file_ctx->fp, "%s: IN= OUT= SRC=%s DST=%s LEN=%"PRIu16"" " TC=%"PRIu32" HOPLIMIT=%"PRIu8" FLOWLBL=%"PRIu32"", timebuf, srcip, dstip, IPV6_GET_PLEN(p), IPV6_GET_CLASS(p), IPV6_GET_HLIM(p), IPV6_GET_FLOW(p)); proto = IPV6_GET_L4PROTO(p); } if (SCProtoNameValid(proto) == TRUE) { fprintf(dlt->file_ctx->fp, " PROTO=%s",known_proto[proto]); } else { fprintf(dlt->file_ctx->fp, " PROTO=%03"PRIu16"",proto); } switch (proto) { case IPPROTO_TCP: fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16" " "SEQ=%"PRIu32" ACK=%"PRIu32" WINDOW=%"PRIu32"", GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p)); fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_SYN(p) ? " SYN" : ""); fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_ACK(p) ? " ACK" : ""); fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_PUSH(p) ? " PSH" : ""); fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_RST(p) ? " RST" : ""); fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_URG(p) ? " URG" : ""); fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_FIN(p) ? " FIN" : ""); fprintf(dlt->file_ctx->fp, " RES=0x%02"PRIu8" URGP=%"PRIu16"", TCP_GET_RAW_X2(p->tcph), TCP_GET_URG_POINTER(p)); break; case IPPROTO_UDP: fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16"" " LEN=%"PRIu16"", UDP_GET_SRC_PORT(p), UDP_GET_DST_PORT(p), UDP_GET_LEN(p)); break; case IPPROTO_ICMP: if (PKT_IS_ICMPV4(p)) { fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu16" CODE=%"PRIu16"" " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV4_GET_TYPE(p), ICMPV4_GET_CODE(p), ICMPV4_GET_ID(p), ICMPV4_GET_SEQ(p)); } else if(PKT_IS_ICMPV6(p)) { fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu16" CODE=%"PRIu16"" " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); } break; default: fprintf(dlt->file_ctx->fp," Unknown protocol"); } fprintf(dlt->file_ctx->fp,"\n"); fflush(dlt->file_ctx->fp); dlt->drop_cnt++; SCMutexUnlock(&dlt->file_ctx->fp_mutex); return TM_ECODE_OK; } /** * \brief Log the dropped packets when engine is running in inline mode * * \param tv Pointer the current thread variables * \param p Pointer the packet which is being logged * \param data Pointer to the droplog struct * \param pq Pointer the packet queue * \param postpq Pointer the packet queue where this packet will be sent * * \return return TM_EODE_OK on success */ TmEcode LogDropLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { /* Check if we are in inline mode or not, if not then no need to log */ extern uint8_t engine_mode; if (!IS_ENGINE_MODE_IPS(engine_mode)) { SCLogDebug("engine is not running in inline mode, so returning"); return TM_ECODE_OK; } if ((p->flow != NULL) && (p->flow->flags & FLOW_ACTION_DROP)) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) { p->flow->flags |= FLOW_TOSERVER_DROP_LOGGED; return LogDropLogNetFilter(tv, p, data, pq, NULL); } else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) { p->flow->flags |= FLOW_TOCLIENT_DROP_LOGGED; return LogDropLogNetFilter(tv, p, data, pq, NULL); } } else { return LogDropLogNetFilter(tv, p, data, pq, postpq); } return TM_ECODE_OK; } void LogDropLogExitPrintStats(ThreadVars *tv, void *data) { LogDropLogThread *dlt = (LogDropLogThread *)data; if (dlt == NULL) { return; } SCLogInfo("(%s) Dropped Packets %" PRIu64 "", tv->name, dlt->drop_cnt); } /***************************** Unittests ****************************/ #ifdef UNITTESTS /** \brief test if the action is drop then packet should be logged */ int LogDropLogTest01() { int result = 0; extern uint8_t engine_mode; SET_ENGINE_MODE_IPS(engine_mode); uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; LogDropLogThread dlt; LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { printf("Could not create new LogFileCtx\n"); return 0; } memset (&dlt, 0, sizeof(LogDropLogThread)); dlt.file_ctx = logfile_ctx; dlt.file_ctx->fp = stdout; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { return result; } de_ctx->flags |= DE_QUIET; SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any " "(msg:\"LogDropLog test\"; content:\"GET\"; Classtype:unknown; sid:1;)"); result = (de_ctx->sig_list != NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1 && (PACKET_TEST_ACTION(p, ACTION_DROP))) result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); else result = 0; LogDropLog(NULL, p, &dlt, NULL, NULL); if (dlt.drop_cnt == 0) { printf("Packet should be logged but its not\n"); result = 0; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); return result; } /** \brief test if the action is alert then packet shouldn't be logged */ int LogDropLogTest02() { int result = 0; extern uint8_t engine_mode; SET_ENGINE_MODE_IPS(engine_mode); uint8_t *buf = (uint8_t *) "GET"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; LogDropLogThread dlt; LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { printf("Could not create new LogFileCtx\n"); return 0; } memset (&dlt, 0, sizeof(LogDropLogThread)); dlt.file_ctx = logfile_ctx; dlt.file_ctx->fp = stdout; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_UDP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { return result; } de_ctx->flags |= DE_QUIET; SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfDeleteDummyClassificationConfigFD(); de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"LogDropLog test\"; content:\"GET\"; Classtype:unknown; sid:1;)"); result = (de_ctx->sig_list != NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1 && p->alerts.alerts[0].action != ACTION_DROP) result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); else result = 0; LogDropLog(NULL, p, &dlt, NULL, NULL); if (dlt.drop_cnt != 0) { printf("Packet shouldn't be logged but it is\n"); result = 0; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); return result; } #endif /** * \brief This function registers unit tests for AlertFastLog API. */ void LogDropLogRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("LogDropLogTest01", LogDropLogTest01, 1); UtRegisterTest("LogDropLogTest02", LogDropLogTest02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-engine-address.h0000644000000000000000000000422212253546156015334 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ADDRESS_H__ #define __DETECT_ADDRESS_H__ /* prototypes */ void DetectAddressRegister (void); void DetectAddressPrintMemory(void); DetectAddressHead *DetectAddressHeadInit(void); void DetectAddressHeadFree(DetectAddressHead *); void DetectAddressHeadCleanup(DetectAddressHead *); int DetectAddressParseString(DetectAddress *, char *); int DetectAddressParse(DetectAddressHead *, char *); DetectAddress *DetectAddressInit(void); void DetectAddressFree(DetectAddress *); void DetectAddressCleanupList (DetectAddress *); int DetectAddressAdd(DetectAddress **, DetectAddress *); void DetectAddressPrintList(DetectAddress *); int DetectAddressInsert(DetectEngineCtx *, DetectAddressHead *, DetectAddress *); int DetectAddressJoin(DetectEngineCtx *, DetectAddress *, DetectAddress *); DetectAddress *DetectAddressLookupInHead(DetectAddressHead *, Address *); DetectAddress *DetectAddressLookupInList(DetectAddress *, DetectAddress *); int DetectAddressMatch(DetectAddress *, Address *); DetectAddress *DetectAddressCopy(DetectAddress *); void DetectAddressPrint(DetectAddress *); int DetectAddressCmp(DetectAddress *, DetectAddress *); int DetectAddressMatchIPv4(DetectMatchAddressIPv4 *, uint16_t, Address *); int DetectAddressMatchIPv6(DetectMatchAddressIPv6 *, uint16_t, Address *); int DetectAddressTestConfVars(void); void DetectAddressTests(void); #endif /* __DETECT_ADDRESS_H__ */ suricata-1.4.7/src/detect-engine-iponly.h0000644000000000000000000000401012253546156015214 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_IPONLY_H__ #define __DETECT_ENGINE_IPONLY_H__ /** * SigNumArray is a bit array representing signatures * it can be used linked to src/dst address to indicate * which signatures apply to this addres * at IP Only we store SigNumArrays at the radix trees */ typedef struct SigNumArray_ { uint8_t *array; /* bit array of sig nums */ uint32_t size; /* size in bytes of the array */ } SigNumArray; void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead); int IPOnlySigParseAddress(Signature *, const char *, char); void IPOnlyMatchPacket(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, DetectEngineIPOnlyCtx *, DetectEngineIPOnlyThreadCtx *, Packet *); void IPOnlyInit(DetectEngineCtx *, DetectEngineIPOnlyCtx *); void IPOnlyPrint(DetectEngineCtx *, DetectEngineIPOnlyCtx *); void IPOnlyDeinit(DetectEngineCtx *, DetectEngineIPOnlyCtx *); void IPOnlyPrepare(DetectEngineCtx *); void DetectEngineIPOnlyThreadInit(DetectEngineCtx *, DetectEngineIPOnlyThreadCtx *); void DetectEngineIPOnlyThreadDeinit(DetectEngineIPOnlyThreadCtx *); void IPOnlyAddSignature(DetectEngineCtx *, DetectEngineIPOnlyCtx *, Signature *); void IPOnlyRegisterTests(void); #endif /* __DETECT_ENGINE_IPONLY_H__ */ suricata-1.4.7/src/util-logopenfile.c0000644000000000000000000001231512253546156014451 00000000000000/* vi: set et ts=4: */ /* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Mike Pomraning * * File-like output for logging: regular files and sockets. */ #include #include #include #include "suricata-common.h" /* errno.h, string.h, etc. */ #include "tm-modules.h" /* LogFileCtx */ #include "conf.h" /* ConfNode, etc. */ #include "output.h" /* DEFAULT_LOG_* */ /** \brief connect to the indicated local stream socket, logging any errors * \param path filesystem path to connect to * \retval FILE* on success (fdopen'd wrapper of underlying socket) * \retval NULL on error */ static FILE * SCLogOpenUnixSocketFp(const char *path, int sock_type) { struct sockaddr_un sun; int s = -1; FILE * ret = NULL; memset(&sun, 0x00, sizeof(sun)); s = socket(PF_UNIX, sock_type, 0); if (s < 0) goto err; sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); if (connect(s, (const struct sockaddr *)&sun, sizeof(sun)) < 0) goto err; ret = fdopen(s, "w"); if (ret == NULL) goto err; return ret; err: SCLogError(SC_ERR_SOCKET, "Error connecting to socket \"%s\": %s", path, strerror(errno)); if (s >= 0) close(s); return NULL; } /** \brief open the indicated file, logging any errors * \param path filesystem path to open * \param append_setting open file with O_APPEND: "yes" or "no" * \retval FILE* on success * \retval NULL on error */ static FILE * SCLogOpenFileFp(const char *path, const char *append_setting) { FILE *ret = NULL; if (strcasecmp(append_setting, "yes") == 0) { ret = fopen(path, "a"); } else { ret = fopen(path, "w"); } if (ret == NULL) SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", path, strerror(errno)); return ret; } /** \brief open a generic output "log file", which may be a regular file or a socket * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \param default_filename Default name of file to open, if not specified in ConfNode * \retval 0 on success * \retval -1 on error */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename) { char log_path[PATH_MAX]; char *log_dir; const char *filename, *filetype; // Arg check if (conf == NULL || log_ctx == NULL || default_filename == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric(conf %p, ctx %p, default %p) " "missing an argument", conf, log_ctx, default_filename); return -1; } if (log_ctx->fp != NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric: previously initialized Log CTX " "encountered"); return -1; } // Resolve the given config filename = ConfNodeLookupChildValue(conf, "filename"); if (filename == NULL) filename = default_filename; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; if (PathIsAbsolute(filename)) { snprintf(log_path, PATH_MAX, "%s", filename); } else { snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); } filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM); } else if (strcasecmp(filetype, "unix_dgram") == 0) { log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM); } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0) { const char *append; append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; log_ctx->fp = SCLogOpenFileFp(log_path, append); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "%s.type. Expected \"regular\" (default), \"unix_stream\" " "or \"unix_dgram\"", conf->name); } if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); return 0; } suricata-1.4.7/src/output.c0000644000000000000000000000506512253546156012537 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited, Jason Ish * * Output registration functions */ #include "suricata-common.h" #include "flow.h" #include "conf.h" #include "tm-threads.h" #include "util-error.h" #include "util-debug.h" #include "output.h" static TAILQ_HEAD(, OutputModule_) output_modules = TAILQ_HEAD_INITIALIZER(output_modules); /** * \brief Register an output module. * * This function will register an output module so it can be * configured with the configuration file. * * \retval Returns 0 on success, -1 on failure. */ void OutputRegisterModule(char *name, char *conf_name, OutputCtx *(*InitFunc)(ConfNode *)) { OutputModule *module = SCCalloc(1, sizeof(*module)); if (unlikely(module == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in OutputRegisterModule. Exiting..."); exit(EXIT_FAILURE); } module->name = SCStrdup(name); module->conf_name = SCStrdup(conf_name); module->InitFunc = InitFunc; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Output module \"%s\" registered.", name); } /** * \brief Get an output module by name. * * \retval The OutputModule with the given name or NULL if no output module * with the given name is registered. */ OutputModule * OutputGetModuleByConfName(char *conf_name) { OutputModule *module; TAILQ_FOREACH(module, &output_modules, entries) { if (strcmp(module->conf_name, conf_name) == 0) return module; } return NULL; } /** * \brief Deregister all modules. Useful for a memory clean exit. */ void OutputDeregisterAll(void) { OutputModule *module; while ((module = TAILQ_FIRST(&output_modules))) { TAILQ_REMOVE(&output_modules, module, entries); SCFree(module->name); SCFree(module->conf_name); SCFree(module); } } suricata-1.4.7/src/detect-ssh-software-version.c0000644000000000000000000004464112253546156016560 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * * Implements the ssh.softwareversion keyword * You can match over the software version string of ssh, and it will * be compared from the beginning of the string so you can say for * example ssh.softwareversion:"PuTTY" and it can match, or you can * also specify the version, something like * ssh.softwareversion:"PuTTY-Release-0.55" * I find this useful to match over a known vulnerable server/client * software version incombination to other checks, so you can know * that the risk is higher */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-ssh.h" #include "detect-ssh-software-version.h" #include "stream-tcp.h" /** * \brief Regex for parsing the softwareversion string */ #define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\.\\-\\_]+)\\s*\"?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectSshSoftwareVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectSshSoftwareVersionRegisterTests(void); void DetectSshSoftwareVersionFree(void *); void DetectSshSoftwareVersionRegister(void); /** * \brief Registration function for keyword: ssh.softwareversion */ void DetectSshSoftwareVersionRegister(void) { sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].name = "ssh.softwareversion"; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Match = NULL; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerMatch = DetectSshSoftwareVersionMatch; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].alproto = ALPROTO_SSH; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests; const char *eb; int eo; int opts = 0; SCLogDebug("registering ssh.softwareversion rule option"); parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief match the specified version on a ssh session * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectSshSoftwareVersionData * * \retval 0 no match * \retval 1 match */ int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m->ctx; SshState *ssh_state = (SshState *)state; if (ssh_state == NULL) { SCLogDebug("no ssh state, no match"); SCReturnInt(0); } int ret = 0; FLOWLOCK_RDLOCK(f); if ((flags & STREAM_TOCLIENT) && (ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { SCLogDebug("looking for ssh server softwareversion %s length %"PRIu16" on %s", ssh->software_ver, ssh->len, ssh_state->server_software_version); ret = (strncmp((char *) ssh_state->server_software_version, (char *) ssh->software_ver, ssh->len) == 0)? 1 : 0; } else if ((flags & STREAM_TOSERVER) && (ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { SCLogDebug("looking for ssh client softwareversion %s length %"PRIu16" on %s", ssh->software_ver, ssh->len, ssh_state->client_software_version); ret = (strncmp((char *) ssh_state->client_software_version, (char *) ssh->software_ver, ssh->len) == 0)? 1 : 0; } FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" * * \param idstr Pointer to the user provided id option * * \retval id_d pointer to DetectSshSoftwareVersionData on success * \retval NULL on failure */ DetectSshSoftwareVersionData *DetectSshSoftwareVersionParse (char *str) { DetectSshSoftwareVersionData *ssh = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 3) { SCLogError(SC_ERR_PCRE_MATCH, "invalid ssh.softwareversion option"); goto error; } if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct id option */ ssh = SCMalloc(sizeof(DetectSshSoftwareVersionData)); if (unlikely(ssh == NULL)) goto error; ssh->software_ver = (uint8_t *)SCStrdup((char*)str_ptr); if (ssh->software_ver == NULL) { goto error; } ssh->len = strlen((char *) ssh->software_ver); SCLogDebug("will look for ssh %s", ssh->software_ver); } return ssh; error: if (ssh != NULL) DetectSshSoftwareVersionFree(ssh); return NULL; } /** * \brief this function is used to add the parsed "id" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "id" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectSshSoftwareVersionData *ssh = NULL; SigMatch *sm = NULL; ssh = DetectSshSoftwareVersionParse(str); if (ssh == 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_AL_SSH_SOFTWAREVERSION; sm->ctx = (void *)ssh; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_SSH; return 0; error: if (ssh != NULL) DetectSshSoftwareVersionFree(ssh); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectSshSoftwareVersionData * * \param id_d pointer to DetectSshSoftwareVersionData */ void DetectSshSoftwareVersionFree(void *ptr) { DetectSshSoftwareVersionData *id_d = (DetectSshSoftwareVersionData *)ptr; SCFree(id_d); } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectSshSoftwareVersionTestParse01 is a test to make sure that we parse * a software version correctly */ int DetectSshSoftwareVersionTestParse01 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse("PuTTY_1.0"); if (ssh != NULL && strncmp((char *) ssh->software_ver, "PuTTY_1.0", 9) == 0) { DetectSshSoftwareVersionFree(ssh); return 1; } return 0; } /** * \test DetectSshSoftwareVersionTestParse02 is a test to make sure that we parse * the software version correctly */ int DetectSshSoftwareVersionTestParse02 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse("\"SecureCRT-4.0\""); if (ssh != NULL && strncmp((char *) ssh->software_ver, "SecureCRT-4.0", 13) == 0) { DetectSshSoftwareVersionFree(ssh); return 1; } return 0; } /** * \test DetectSshSoftwareVersionTestParse03 is a test to make sure that we * don't return a ssh_data with an empty value specified */ int DetectSshSoftwareVersionTestParse03 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse(""); if (ssh != NULL) { DetectSshSoftwareVersionFree(ssh); return 0; } return 1; } #include "stream-tcp-reassemble.h" /** \test Send a get request in three chunks + more data. */ static int DetectSshSoftwareVersionTestDetect01(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "SSH-1."; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "10-PuTTY_2.123" ; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = "\n"; uint32_t sshlen3 = sizeof(sshbuf3) - 1; uint8_t sshbuf4[] = "whatever..."; uint32_t sshlen4 = sizeof(sshbuf4) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ( !(PacketAlertCheck(p, 1))) { printf("Error, the sig should match: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Send a get request in three chunks + more data. */ static int DetectSshSoftwareVersionTestDetect02(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "SSH-1.99-Pu"; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "TTY_2.123" ; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = "\n"; uint32_t sshlen3 = sizeof(sshbuf3) - 1; uint8_t sshbuf4[] = "whatever..."; uint32_t sshlen4 = sizeof(sshbuf4) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ( !(PacketAlertCheck(p, 1))) { printf("Error, the sig should match: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Send a get request in three chunks + more data. */ static int DetectSshSoftwareVersionTestDetect03(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "SSH-1."; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "7-PuTTY_2.123" ; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = "\n"; uint32_t sshlen3 = sizeof(sshbuf3) - 1; uint8_t sshbuf4[] = "whatever..."; uint32_t sshlen4 = sizeof(sshbuf4) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:lalala-3.1.4; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("Error, 1.7 version is not 2 compat, so the sig should not match: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectSshSoftwareVersion */ void DetectSshSoftwareVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectSshSoftwareVersionTestParse01", DetectSshSoftwareVersionTestParse01, 1); UtRegisterTest("DetectSshSoftwareVersionTestParse02", DetectSshSoftwareVersionTestParse02, 1); UtRegisterTest("DetectSshSoftwareVersionTestParse03", DetectSshSoftwareVersionTestParse03, 1); UtRegisterTest("DetectSshSoftwareVersionTestDetect01", DetectSshSoftwareVersionTestDetect01, 1); UtRegisterTest("DetectSshSoftwareVersionTestDetect02", DetectSshSoftwareVersionTestDetect02, 1); UtRegisterTest("DetectSshSoftwareVersionTestDetect03", DetectSshSoftwareVersionTestDetect03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/source-pcap-file.c0000644000000000000000000002763712253546156014346 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * File based pcap packet acquisition support */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "packet-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "source-pcap-file.h" #include "util-time.h" #include "util-debug.h" #include "conf.h" #include "util-error.h" #include "util-privs.h" #include "tmqh-packetpool.h" #include "tm-threads.h" #include "util-optimize.h" #include "flow-manager.h" #include "util-profiling.h" #include "runmode-unix-socket.h" extern uint8_t suricata_ctl_flags; extern int max_pending_packets; //static int pcap_max_read_packets = 0; typedef struct PcapFileGlobalVars_ { pcap_t *pcap_handle; void (*Decoder)(ThreadVars *, DecodeThreadVars *, Packet *, u_int8_t *, u_int16_t, PacketQueue *); int datalink; struct bpf_program filter; uint64_t cnt; /** packet counter */ } PcapFileGlobalVars; /** max packets < 65536 */ //#define PCAP_FILE_MAX_PKTS 256 typedef struct PcapFileThreadVars_ { /* counters */ uint32_t pkts; uint64_t bytes; ThreadVars *tv; TmSlot *slot; /** callback result -- set if one of the thread module failed. */ int cb_result; uint8_t done; uint32_t errs; } PcapFileThreadVars; static PcapFileGlobalVars pcap_g; TmEcode ReceivePcapFileLoop(ThreadVars *, void *, void *); TmEcode ReceivePcapFileThreadInit(ThreadVars *, void *, void **); void ReceivePcapFileThreadExitStats(ThreadVars *, void *); TmEcode ReceivePcapFileThreadDeinit(ThreadVars *, void *); TmEcode DecodePcapFile(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode DecodePcapFileThreadInit(ThreadVars *, void *, void **); void TmModuleReceivePcapFileRegister (void) { memset(&pcap_g, 0x00, sizeof(pcap_g)); tmm_modules[TMM_RECEIVEPCAPFILE].name = "ReceivePcapFile"; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit = ReceivePcapFileThreadInit; tmm_modules[TMM_RECEIVEPCAPFILE].Func = NULL; tmm_modules[TMM_RECEIVEPCAPFILE].PktAcqLoop = ReceivePcapFileLoop; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadExitPrintStats = ReceivePcapFileThreadExitStats; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadDeinit = ReceivePcapFileThreadDeinit; tmm_modules[TMM_RECEIVEPCAPFILE].RegisterTests = NULL; tmm_modules[TMM_RECEIVEPCAPFILE].cap_flags = 0; tmm_modules[TMM_RECEIVEPCAPFILE].flags = TM_FLAG_RECEIVE_TM; } void TmModuleDecodePcapFileRegister (void) { tmm_modules[TMM_DECODEPCAPFILE].name = "DecodePcapFile"; tmm_modules[TMM_DECODEPCAPFILE].ThreadInit = DecodePcapFileThreadInit; tmm_modules[TMM_DECODEPCAPFILE].Func = DecodePcapFile; tmm_modules[TMM_DECODEPCAPFILE].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEPCAPFILE].ThreadDeinit = NULL; tmm_modules[TMM_DECODEPCAPFILE].RegisterTests = NULL; tmm_modules[TMM_DECODEPCAPFILE].cap_flags = 0; tmm_modules[TMM_DECODEPCAPFILE].flags = TM_FLAG_DECODE_TM; } void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { SCEnter(); PcapFileThreadVars *ptv = (PcapFileThreadVars *)user; Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { SCReturn; } PACKET_PROFILING_TMM_START(p, TMM_RECEIVEPCAPFILE); PKT_SET_SRC(p, PKT_SRC_WIRE); p->ts.tv_sec = h->ts.tv_sec; p->ts.tv_usec = h->ts.tv_usec; SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); p->datalink = pcap_g.datalink; p->pcap_cnt = ++pcap_g.cnt; ptv->pkts++; ptv->bytes += h->caplen; if (unlikely(PacketCopyData(p, pkt, h->caplen))) { TmqhOutputPacketpool(ptv->tv, p); PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE); SCReturn; } PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE); if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { pcap_breakloop(pcap_g.pcap_handle); ptv->cb_result = TM_ECODE_FAILED; } SCReturn; } /** * \brief Main PCAP file reading Loop function */ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); uint16_t packet_q_len = 0; PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; int r; TmSlot *s = (TmSlot *)slot; ptv->slot = s->slot_next; ptv->cb_result = TM_ECODE_OK; while (1) { if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); /* Right now we just support reading packets one at a time. */ r = pcap_dispatch(pcap_g.pcap_handle, (int)packet_q_len, (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv); if (unlikely(r == -1)) { SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s", r, pcap_geterr(pcap_g.pcap_handle)); if (! RunModeUnixSocketIsActive()) { /* in the error state we just kill the engine */ EngineKill(); SCReturnInt(TM_ECODE_FAILED); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; UnixSocketPcapFile(TM_ECODE_DONE); SCReturnInt(TM_ECODE_DONE); } } else if (unlikely(r == 0)) { SCLogInfo("pcap file end of file reached (pcap err code %" PRId32 ")", r); if (! RunModeUnixSocketIsActive()) { EngineStop(); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; UnixSocketPcapFile(TM_ECODE_DONE); SCReturnInt(TM_ECODE_DONE); } break; } else if (ptv->cb_result == TM_ECODE_FAILED) { SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapFileCallbackLoop failed"); if (! RunModeUnixSocketIsActive()) { EngineKill(); SCReturnInt(TM_ECODE_FAILED); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; UnixSocketPcapFile(TM_ECODE_DONE); SCReturnInt(TM_ECODE_DONE); } } SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); } TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); char *tmpbpfstring = NULL; if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "error: initdata == NULL"); SCReturnInt(TM_ECODE_FAILED); } SCLogInfo("reading pcap file %s", (char *)initdata); PcapFileThreadVars *ptv = SCMalloc(sizeof(PcapFileThreadVars)); if (unlikely(ptv == NULL)) SCReturnInt(TM_ECODE_FAILED); memset(ptv, 0, sizeof(PcapFileThreadVars)); char errbuf[PCAP_ERRBUF_SIZE] = ""; pcap_g.pcap_handle = pcap_open_offline((char *)initdata, errbuf); if (pcap_g.pcap_handle == NULL) { SCLogError(SC_ERR_FOPEN, "%s\n", errbuf); SCFree(ptv); if (! RunModeUnixSocketIsActive()) { return TM_ECODE_FAILED; } else { UnixSocketPcapFile(TM_ECODE_FAILED); SCReturnInt(TM_ECODE_DONE); } } if (ConfGet("bpf-filter", &tmpbpfstring) != 1) { SCLogDebug("could not get bpf or none specified"); } else { SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring); if(pcap_compile(pcap_g.pcap_handle,&pcap_g.filter,tmpbpfstring,1,0) < 0) { SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(pcap_g.pcap_handle)); SCFree(ptv); return TM_ECODE_FAILED; } if(pcap_setfilter(pcap_g.pcap_handle,&pcap_g.filter) < 0) { SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(pcap_g.pcap_handle)); SCFree(ptv); return TM_ECODE_FAILED; } } pcap_g.datalink = pcap_datalink(pcap_g.pcap_handle); SCLogDebug("datalink %" PRId32 "", pcap_g.datalink); switch(pcap_g.datalink) { case LINKTYPE_LINUX_SLL: pcap_g.Decoder = DecodeSll; break; case LINKTYPE_ETHERNET: pcap_g.Decoder = DecodeEthernet; break; case LINKTYPE_PPP: pcap_g.Decoder = DecodePPP; break; case LINKTYPE_RAW: pcap_g.Decoder = DecodeRaw; break; default: SCLogError(SC_ERR_UNIMPLEMENTED, "datalink type %" PRId32 " not " "(yet) supported in module PcapFile.\n", pcap_g.datalink); SCFree(ptv); if (! RunModeUnixSocketIsActive()) { SCReturnInt(TM_ECODE_FAILED); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; UnixSocketPcapFile(TM_ECODE_DONE); SCReturnInt(TM_ECODE_DONE); } } ptv->tv = tv; *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); } void ReceivePcapFileThreadExitStats(ThreadVars *tv, void *data) { SCEnter(); PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; SCLogInfo("Pcap-file module read %" PRIu32 " packets, %" PRIu64 " bytes", ptv->pkts, ptv->bytes); return; } TmEcode ReceivePcapFileThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; if (ptv) { SCFree(ptv); } SCReturnInt(TM_ECODE_OK); } double prev_signaled_ts = 0; TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) { prev_signaled_ts = curr_ts; FlowWakeupFlowManagerThread(); } /* update the engine time representation based on the timestamp * of the packet. */ TimeSet(&p->ts); /* call the decoder */ pcap_g.Decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); SCReturnInt(TM_ECODE_OK); } TmEcode DecodePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); DecodeThreadVars *dtv = NULL; dtv = DecodeThreadVarsAlloc(); if (dtv == NULL) SCReturnInt(TM_ECODE_FAILED); DecodeRegisterPerfCounters(dtv, tv); *data = (void *)dtv; SCReturnInt(TM_ECODE_OK); } /* eof */ suricata-1.4.7/src/detect-engine-content-inspection.h0000644000000000000000000000411512253546156017533 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_CONTENT_INSPECTION_H__ #define __DETECT_ENGINE_CONTENT_INSPECTION_H__ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD = 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_URI, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRUD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSCD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSMD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t inspection_mode, void *data); #endif /* __DETECT_ENGINE_CONTENT_INSPECTION_H__ */ suricata-1.4.7/src/flow-bit.c0000644000000000000000000002251612253546156012722 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements per flow bits. Actually, not a bit, * but called that way because of Snort's flowbits. * It's a binary storage. * * \todo move away from a linked list implementation * \todo use different datatypes, such as string, int, etc. * \todo have more than one instance of the same var, and be able to match on a * specific one, or one all at a time. So if a certain capture matches * multiple times, we can operate on all of them. */ #include "suricata-common.h" #include "threads.h" #include "flow-bit.h" #include "flow.h" #include "flow-util.h" #include "flow-private.h" #include "detect.h" #include "util-var.h" #include "util-debug.h" #include "util-unittest.h" /* get the flowbit with idx from the flow */ static FlowBit *FlowBitGet(Flow *f, uint16_t idx) { GenericVar *gv = f->flowvar; for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { return (FlowBit *)gv; } } return NULL; } /* add a flowbit to the flow */ static void FlowBitAdd(Flow *f, uint16_t idx) { FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) { fb = SCMalloc(sizeof(FlowBit)); if (unlikely(fb == NULL)) return; fb->type = DETECT_FLOWBITS; fb->idx = idx; fb->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fb); //printf("FlowBitAdd: adding flowbit with idx %" PRIu32 "\n", idx); #ifdef FLOWBITS_STATS SCMutexLock(&flowbits_mutex); flowbits_added++; flowbits_memuse += sizeof(FlowBit); if (flowbits_memuse > flowbits_memuse_max) flowbits_memuse_max = flowbits_memuse; SCMutexUnlock(&flowbits_mutex); #endif /* FLOWBITS_STATS */ } } static void FlowBitRemove(Flow *f, uint16_t idx) { FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) return; GenericVarRemove(&f->flowvar, (GenericVar *)fb); //printf("FlowBitRemove: remove flowbit with idx %" PRIu32 "\n", idx); #ifdef FLOWBITS_STATS SCMutexLock(&flowbits_mutex); flowbits_removed++; if (flowbits_memuse >= sizeof(FlowBit)) flowbits_memuse -= sizeof(FlowBit); else { printf("ERROR: flowbits memory usage going below 0!\n"); flowbits_memuse = 0; } SCMutexUnlock(&flowbits_mutex); #endif /* FLOWBITS_STATS */ } void FlowBitSet(Flow *f, uint16_t idx) { FLOWLOCK_WRLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) { FlowBitAdd(f, idx); } FLOWLOCK_UNLOCK(f); } void FlowBitUnset(Flow *f, uint16_t idx) { FLOWLOCK_WRLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { FlowBitRemove(f, idx); } FLOWLOCK_UNLOCK(f); } void FlowBitToggle(Flow *f, uint16_t idx) { FLOWLOCK_WRLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { FlowBitRemove(f, idx); } else { FlowBitAdd(f, idx); } FLOWLOCK_UNLOCK(f); } int FlowBitIsset(Flow *f, uint16_t idx) { int r = 0; FLOWLOCK_RDLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { r = 1; } FLOWLOCK_UNLOCK(f); return r; } int FlowBitIsnotset(Flow *f, uint16_t idx) { int r = 0; FLOWLOCK_RDLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) { r = 1; } FLOWLOCK_UNLOCK(f); return r; } void FlowBitFree(FlowBit *fb) { if (fb == NULL) return; SCFree(fb); #ifdef FLOWBITS_STATS SCMutexLock(&flowbits_mutex); flowbits_removed++; if (flowbits_memuse >= sizeof(FlowBit)) flowbits_memuse -= sizeof(FlowBit); else { printf("ERROR: flowbits memory usage going below 0!\n"); flowbits_memuse = 0; } SCMutexUnlock(&flowbits_mutex); #endif /* FLOWBITS_STATS */ } /* TESTS */ #ifdef UNITTESTS static int FlowBitTest01 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBit *fb = FlowBitGet(&f,0); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowBitTest02 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBit *fb = FlowBitGet(&f,0); if (fb == NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowBitTest03 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBit *fb = FlowBitGet(&f,0); if (fb == NULL) { printf("fb == NULL although it was just added: "); goto end; } FlowBitRemove(&f, 0); fb = FlowBitGet(&f,0); if (fb != NULL) { printf("fb != NULL although it was just removed: "); goto end; } else { ret = 1; } end: GenericVarFree(f.flowvar); return ret; } static int FlowBitTest04 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBitAdd(&f, 1); FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); FlowBit *fb = FlowBitGet(&f,0); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowBitTest05 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBitAdd(&f, 1); FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); FlowBit *fb = FlowBitGet(&f,1); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowBitTest06 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBitAdd(&f, 1); FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); FlowBit *fb = FlowBitGet(&f,2); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowBitTest07 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBitAdd(&f, 1); FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); FlowBit *fb = FlowBitGet(&f,3); if (fb != NULL) ret = 1; GenericVarFree(f.flowvar); return ret; } static int FlowBitTest08 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBitAdd(&f, 1); FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); FlowBit *fb = FlowBitGet(&f,0); if (fb == NULL) goto end; FlowBitRemove(&f,0); fb = FlowBitGet(&f,0); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } static int FlowBitTest09 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBitAdd(&f, 1); FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); FlowBit *fb = FlowBitGet(&f,1); if (fb == NULL) goto end; FlowBitRemove(&f,1); fb = FlowBitGet(&f,1); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } static int FlowBitTest10 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBitAdd(&f, 1); FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); FlowBit *fb = FlowBitGet(&f,2); if (fb == NULL) goto end; FlowBitRemove(&f,2); fb = FlowBitGet(&f,2); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } static int FlowBitTest11 (void) { int ret = 0; Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); FlowBitAdd(&f, 1); FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); FlowBit *fb = FlowBitGet(&f,3); if (fb == NULL) goto end; FlowBitRemove(&f,3); fb = FlowBitGet(&f,3); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; } ret = 1; end: GenericVarFree(f.flowvar); return ret; } #endif /* UNITTESTS */ void FlowBitRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FlowBitTest01", FlowBitTest01, 1); UtRegisterTest("FlowBitTest02", FlowBitTest02, 1); UtRegisterTest("FlowBitTest03", FlowBitTest03, 1); UtRegisterTest("FlowBitTest04", FlowBitTest04, 1); UtRegisterTest("FlowBitTest05", FlowBitTest05, 1); UtRegisterTest("FlowBitTest06", FlowBitTest06, 1); UtRegisterTest("FlowBitTest07", FlowBitTest07, 1); UtRegisterTest("FlowBitTest08", FlowBitTest08, 1); UtRegisterTest("FlowBitTest09", FlowBitTest09, 1); UtRegisterTest("FlowBitTest10", FlowBitTest10, 1); UtRegisterTest("FlowBitTest11", FlowBitTest11, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/stream-tcp-inline.c0000644000000000000000000004472012253546156014533 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Functions for the "inline mode" of the stream engine. */ #include "suricata-common.h" #include "stream-tcp-inline.h" #include "util-memcmp.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" /** defined in stream-tcp-reassemble.c */ extern int stream_inline; /** * \brief See if stream engine is operating in inline mode * * \retval 0 no * \retval 1 yes */ int StreamTcpInlineMode(void) { return stream_inline; } /** * \brief Compare the shared data portion of two segments * * If no data is shared, 0 will be returned. * * \param seg1 first segment * \param seg2 second segment * * \retval 0 shared data is the same (or no data is shared) * \retval 1 shared data is different */ int StreamTcpInlineSegmentCompare(TcpSegment *seg1, TcpSegment *seg2) { SCEnter(); if (seg1 == NULL || seg2 == NULL) { SCReturnInt(0); } if (SEQ_EQ(seg1->seq, seg2->seq) && seg1->payload_len == seg2->payload_len) { int r = SCMemcmp(seg1->payload, seg2->payload, seg1->payload_len); #if 0 if (r) { PrintRawDataFp(stdout,seg1->payload,seg1->payload_len); PrintRawDataFp(stdout,seg2->payload,seg2->payload_len); } #endif SCReturnInt(r); } else if (SEQ_GT(seg1->seq, (seg2->seq + seg2->payload_len))) { SCReturnInt(0); } else if (SEQ_GT(seg2->seq, (seg1->seq + seg1->payload_len))) { SCReturnInt(0); } else { SCLogDebug("seg1 %u (%u), seg2 %u (%u)", seg1->seq, seg1->payload_len, seg2->seq, seg2->payload_len); uint32_t seg1_end = seg1->seq + seg1->payload_len; uint32_t seg2_end = seg2->seq + seg2->payload_len; SCLogDebug("seg1_end %u, seg2_end %u", seg1_end, seg2_end); #if 0 SCLogDebug("seg1"); PrintRawDataFp(stdout,seg1->payload,seg1->payload_len); SCLogDebug("seg2"); PrintRawDataFp(stdout,seg2->payload,seg2->payload_len); #endif /* get the minimal seg*_end */ uint32_t end = (SEQ_GT(seg1_end, seg2_end)) ? seg2_end : seg1_end; /* and the max seq */ uint32_t seq = (SEQ_LT(seg1->seq, seg2->seq)) ? seg2->seq : seg1->seq; SCLogDebug("seq %u, end %u", seq, end); uint16_t seg1_off = seq - seg1->seq; uint16_t seg2_off = seq - seg2->seq; SCLogDebug("seg1_off %u, seg2_off %u", seg1_off, seg2_off); uint32_t range = end - seq; SCLogDebug("range %u", range); BUG_ON(range > 65536); if (range) { int r = SCMemcmp(seg1->payload+seg1_off, seg2->payload+seg2_off, range); #if 0 if (r) { PrintRawDataFp(stdout,seg1->payload+seg1_off,range); PrintRawDataFp(stdout,seg2->payload+seg2_off,range); PrintRawDataFp(stdout,seg1->payload,seg1->payload_len); PrintRawDataFp(stdout,seg2->payload,seg2->payload_len); } #endif SCReturnInt(r); } SCReturnInt(0); } } /** * \brief Replace (part of) the payload portion of a packet by the data * in a TCP segment * * \param p Packet * \param seg TCP segment * * \todo What about reassembled fragments? * \todo What about unwrapped tunnel packets? */ void StreamTcpInlineSegmentReplacePacket(Packet *p, TcpSegment *seg) { SCEnter(); uint32_t pseq = TCP_GET_SEQ(p); uint32_t tseq = seg->seq; /* check if segment is within the packet */ if (tseq + seg->payload_len < pseq) { SCReturn; } else if (pseq + p->payload_len < tseq) { SCReturn; } else { /** \todo review logic */ uint32_t pend = pseq + p->payload_len; uint32_t tend = tseq + seg->payload_len; SCLogDebug("pend %u, tend %u", pend, tend); //SCLogDebug("packet"); //PrintRawDataFp(stdout,p->payload,p->payload_len); //SCLogDebug("seg"); //PrintRawDataFp(stdout,seg->payload,seg->payload_len); /* get the minimal seg*_end */ uint32_t end = (SEQ_GT(pend, tend)) ? tend : pend; /* and the max seq */ uint32_t seq = (SEQ_LT(pseq, tseq)) ? tseq : pseq; SCLogDebug("seq %u, end %u", seq, end); uint16_t poff = seq - pseq; uint16_t toff = seq - tseq; SCLogDebug("poff %u, toff %u", poff, toff); uint32_t range = end - seq; SCLogDebug("range %u", range); BUG_ON(range > 65536); if (range) { /* update the packets payload. As payload is a ptr to either * p->pkt or p->ext_pkt that is updated as well */ memcpy(p->payload+poff, seg->payload+toff, range); /* flag as modified so we can reinject / replace after * recalculating the checksum */ p->flags |= PKT_STREAM_MODIFIED; } } } #ifdef UNITTESTS /** \test full overlap */ static int StreamTcpInlineTest01(void) { SCEnter(); uint8_t payload1[] = "AAC"; /* packet */ uint8_t payload2[] = "ABC"; /* segment */ int result = 0; TcpSegment *t = NULL; Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80); if (p == NULL || p->tcph == NULL) { printf("generating test packet failed: "); goto end; } p->tcph->th_seq = htonl(10000000UL); t = SCMalloc(sizeof(TcpSegment)); if (unlikely(t == NULL)) { printf("alloc TcpSegment failed: "); goto end; } memset(t, 0x00, sizeof(TcpSegment)); t->payload = payload2; t->payload_len = sizeof(payload2)-1; t->seq = 10000000UL; StreamTcpInlineSegmentReplacePacket(p, t); if (!(p->flags & PKT_STREAM_MODIFIED)) { printf("PKT_STREAM_MODIFIED pkt flag not set: "); goto end; } if (memcmp(p->payload, t->payload, p->payload_len) != 0) { printf("Packet:\n"); PrintRawDataFp(stdout,p->payload,p->payload_len); printf("Segment:\n"); PrintRawDataFp(stdout,t->payload,t->payload_len); printf("payloads didn't match: "); goto end; } uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1); if (memcmp(pkt,payload2,sizeof(payload2)-1) != 0) { PrintRawDataFp(stdout,pkt,3); PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p)); goto end; } result = 1; end: if (p != NULL) { UTHFreePacket(p); } if (t != NULL) { SCFree(t); } SCReturnInt(result); } /** \test full overlap */ static int StreamTcpInlineTest02(void) { SCEnter(); uint8_t payload1[] = "xxx"; /* packet */ uint8_t payload2[] = "ABCDE"; /* segment */ int result = 0; TcpSegment *t = NULL; Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80); if (p == NULL || p->tcph == NULL) { printf("generating test packet failed: "); goto end; } p->tcph->th_seq = htonl(10000001UL); t = SCMalloc(sizeof(TcpSegment)); if (unlikely(t == NULL)) { printf("alloc TcpSegment failed: "); goto end; } memset(t, 0x00, sizeof(TcpSegment)); t->payload = payload2; t->payload_len = sizeof(payload2)-1; t->seq = 10000000UL; StreamTcpInlineSegmentReplacePacket(p, t); if (!(p->flags & PKT_STREAM_MODIFIED)) { printf("PKT_STREAM_MODIFIED pkt flag not set: "); goto end; } if (memcmp(p->payload, t->payload+1, p->payload_len) != 0) { printf("Packet:\n"); PrintRawDataFp(stdout,p->payload,p->payload_len); printf("Segment:\n"); PrintRawDataFp(stdout,t->payload,t->payload_len); printf("payloads didn't match: "); goto end; } uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1); if (memcmp(pkt,payload2+1,sizeof(payload2)-3) != 0) { printf("Segment:\n"); PrintRawDataFp(stdout,payload2+1,sizeof(payload2)-3); printf("Packet:\n"); PrintRawDataFp(stdout,pkt,3); printf("Packet (full):\n"); PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p)); printf("packet data doesn't match: "); goto end; } result = 1; end: if (p != NULL) { UTHFreePacket(p); } if (t != NULL) { SCFree(t); } SCReturnInt(result); } /** \test partial overlap */ static int StreamTcpInlineTest03(void) { SCEnter(); uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */ uint8_t payload2[] = "ABCDE"; /* segment */ int result = 0; TcpSegment *t = NULL; Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80); if (p == NULL || p->tcph == NULL) { printf("generating test packet failed: "); goto end; } p->tcph->th_seq = htonl(10000000UL); t = SCMalloc(sizeof(TcpSegment)); if (unlikely(t == NULL)) { printf("alloc TcpSegment failed: "); goto end; } memset(t, 0x00, sizeof(TcpSegment)); t->payload = payload2; t->payload_len = sizeof(payload2)-1; t->seq = 10000003UL; StreamTcpInlineSegmentReplacePacket(p, t); if (!(p->flags & PKT_STREAM_MODIFIED)) { printf("PKT_STREAM_MODIFIED pkt flag not set: "); goto end; } if (memcmp(p->payload+3, t->payload, t->payload_len) != 0) { printf("Packet:\n"); PrintRawDataFp(stdout,p->payload,p->payload_len); printf("Segment:\n"); PrintRawDataFp(stdout,t->payload,t->payload_len); printf("payloads didn't match: "); goto end; } uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1 + 3); if (memcmp(pkt,payload2,sizeof(payload2)-1) != 0) { printf("Segment:\n"); PrintRawDataFp(stdout,payload2+1,sizeof(payload2)-3); printf("Packet:\n"); PrintRawDataFp(stdout,pkt,3); printf("Packet (full):\n"); PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p)); printf("packet data doesn't match: "); goto end; } result = 1; end: if (p != NULL) { UTHFreePacket(p); } if (t != NULL) { SCFree(t); } SCReturnInt(result); } /** \test partial overlap */ static int StreamTcpInlineTest04(void) { SCEnter(); uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */ uint8_t payload2[] = "ABCDE"; /* segment */ int result = 0; TcpSegment *t = NULL; Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80); if (p == NULL || p->tcph == NULL) { printf("generating test packet failed: "); goto end; } p->tcph->th_seq = htonl(10000003UL); t = SCMalloc(sizeof(TcpSegment)); if (unlikely(t == NULL)) { printf("alloc TcpSegment failed: "); goto end; } memset(t, 0x00, sizeof(TcpSegment)); t->payload = payload2; t->payload_len = sizeof(payload2)-1; t->seq = 10000000UL; StreamTcpInlineSegmentReplacePacket(p, t); if (!(p->flags & PKT_STREAM_MODIFIED)) { printf("PKT_STREAM_MODIFIED pkt flag not set: "); goto end; } if (memcmp(p->payload, t->payload+3, 2) != 0) { printf("Packet:\n"); PrintRawDataFp(stdout,p->payload,p->payload_len); printf("Segment:\n"); PrintRawDataFp(stdout,t->payload,t->payload_len); printf("payloads didn't match: "); goto end; } uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1); if (memcmp(pkt,payload2+3,2) != 0) { printf("Segment:\n"); PrintRawDataFp(stdout,payload2+3,2); printf("Packet:\n"); PrintRawDataFp(stdout,pkt,3); printf("Packet (full):\n"); PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p)); printf("packet data doesn't match: "); goto end; } result = 1; end: if (p != NULL) { UTHFreePacket(p); } if (t != NULL) { SCFree(t); } SCReturnInt(result); } /** \test partial overlap */ static int StreamTcpInlineTest05(void) { SCEnter(); uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */ uint8_t payload2[] = "ABCDE"; /* segment */ int result = 0; TcpSegment *t = NULL; Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80); if (p == NULL || p->tcph == NULL) { printf("generating test packet failed: "); goto end; } p->tcph->th_seq = htonl(10000000UL); t = SCMalloc(sizeof(TcpSegment)); if (unlikely(t == NULL)) { printf("alloc TcpSegment failed: "); goto end; } memset(t, 0x00, sizeof(TcpSegment)); t->payload = payload2; t->payload_len = sizeof(payload2)-1; t->seq = 10000010UL; StreamTcpInlineSegmentReplacePacket(p, t); if (!(p->flags & PKT_STREAM_MODIFIED)) { printf("PKT_STREAM_MODIFIED pkt flag not set: "); goto end; } if (memcmp(p->payload+10, t->payload, 2) != 0) { printf("Packet:\n"); PrintRawDataFp(stdout,p->payload,p->payload_len); printf("Segment:\n"); PrintRawDataFp(stdout,t->payload,t->payload_len); printf("payloads didn't match: "); goto end; } uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1); if (memcmp(pkt+10,payload2,2) != 0) { printf("Segment:\n"); PrintRawDataFp(stdout,payload2,2); printf("Packet:\n"); PrintRawDataFp(stdout,pkt,3); printf("Packet (full):\n"); PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p)); printf("packet data doesn't match: "); goto end; } result = 1; end: if (p != NULL) { UTHFreePacket(p); } if (t != NULL) { SCFree(t); } SCReturnInt(result); } /** \test no overlap */ static int StreamTcpInlineTest06(void) { SCEnter(); uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */ uint8_t payload2[] = "ABCDE"; /* segment */ int result = 0; TcpSegment *t = NULL; Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80); if (p == NULL || p->tcph == NULL) { printf("generating test packet failed: "); goto end; } p->tcph->th_seq = htonl(10000020UL); t = SCMalloc(sizeof(TcpSegment)); if (unlikely(t == NULL)) { printf("alloc TcpSegment failed: "); goto end; } memset(t, 0x00, sizeof(TcpSegment)); t->payload = payload2; t->payload_len = sizeof(payload2)-1; t->seq = 10000000UL; StreamTcpInlineSegmentReplacePacket(p, t); if (p->flags & PKT_STREAM_MODIFIED) { printf("PKT_STREAM_MODIFIED pkt flag set, but it shouldn't: "); goto end; } if (memcmp(p->payload, payload1, sizeof(payload1)-1) != 0) { printf("Packet:\n"); PrintRawDataFp(stdout,p->payload,p->payload_len); printf("Original payload:\n"); PrintRawDataFp(stdout,payload1,sizeof(payload1)-1); printf("payloads didn't match: "); goto end; } uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1); if (memcmp(pkt,payload1,sizeof(payload1)-1) != 0) { printf("Segment:\n"); PrintRawDataFp(stdout,payload2,2); printf("Packet:\n"); PrintRawDataFp(stdout,pkt,3); printf("Packet (full):\n"); PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p)); printf("packet data doesn't match: "); goto end; } result = 1; end: if (p != NULL) { UTHFreePacket(p); } if (t != NULL) { SCFree(t); } SCReturnInt(result); } /** \test no overlap */ static int StreamTcpInlineTest07(void) { SCEnter(); uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */ uint8_t payload2[] = "ABCDE"; /* segment */ int result = 0; TcpSegment *t = NULL; Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80); if (p == NULL || p->tcph == NULL) { printf("generating test packet failed: "); goto end; } p->tcph->th_seq = htonl(10000000UL); t = SCMalloc(sizeof(TcpSegment)); if (unlikely(t == NULL)) { printf("alloc TcpSegment failed: "); goto end; } memset(t, 0x00, sizeof(TcpSegment)); t->payload = payload2; t->payload_len = sizeof(payload2)-1; t->seq = 10000020UL; StreamTcpInlineSegmentReplacePacket(p, t); if (p->flags & PKT_STREAM_MODIFIED) { printf("PKT_STREAM_MODIFIED pkt flag set, but it shouldn't: "); goto end; } if (memcmp(p->payload, payload1, sizeof(payload1)-1) != 0) { printf("Packet:\n"); PrintRawDataFp(stdout,p->payload,p->payload_len); printf("Original payload:\n"); PrintRawDataFp(stdout,payload1,sizeof(payload1)-1); printf("payloads didn't match: "); goto end; } uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1); if (memcmp(pkt,payload1,sizeof(payload1)-1) != 0) { printf("Segment:\n"); PrintRawDataFp(stdout,payload2,2); printf("Packet:\n"); PrintRawDataFp(stdout,pkt,3); printf("Packet (full):\n"); PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p)); printf("packet data doesn't match: "); goto end; } result = 1; end: if (p != NULL) { UTHFreePacket(p); } if (t != NULL) { SCFree(t); } SCReturnInt(result); } #endif /* UNITTESTS */ void StreamTcpInlineRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("StreamTcpInlineTest01", StreamTcpInlineTest01, 1); UtRegisterTest("StreamTcpInlineTest02", StreamTcpInlineTest02, 1); UtRegisterTest("StreamTcpInlineTest03", StreamTcpInlineTest03, 1); UtRegisterTest("StreamTcpInlineTest04", StreamTcpInlineTest04, 1); UtRegisterTest("StreamTcpInlineTest05", StreamTcpInlineTest05, 1); UtRegisterTest("StreamTcpInlineTest06", StreamTcpInlineTest06, 1); UtRegisterTest("StreamTcpInlineTest07", StreamTcpInlineTest07, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-ssh-proto-version.h0000644000000000000000000000232612253546156016070 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_SSH_VERSION_H__ #define __DETECT_SSH_VERSION_H__ /** proto version 1.99 is considered proto version 2 */ #define SSH_FLAG_PROTOVERSION_2_COMPAT 0x01 typedef struct DetectSshVersionData_ { uint8_t *ver; /** ssh version to match */ uint16_t len; /** ssh version length to match */ uint8_t flags; } DetectSshVersionData; /* prototypes */ void DetectSshVersionRegister (void); #endif /* __DETECT_SSH_VERSION_H__ */ suricata-1.4.7/src/detect-ttl.c0000644000000000000000000004051012253546156013242 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * * Implements the ttl keyword */ #include "suricata-common.h" #include "stream-tcp.h" #include "util-unittest.h" #include "detect.h" #include "detect-parse.h" #include "detect-ttl.h" #include "util-debug.h" /** * \brief Regex for parsing our flow options */ #define PARSE_REGEX "^\\s*([0-9]*)?\\s*([<>=-]+)?\\s*([0-9]+)?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ int DetectTtlMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectTtlSetup (DetectEngineCtx *, Signature *, char *); void DetectTtlFree (void *); void DetectTtlRegisterTests (void); /** * \brief Registration function for ttl: keyword */ void DetectTtlRegister(void) { sigmatch_table[DETECT_TTL].name = "ttl"; sigmatch_table[DETECT_TTL].desc = "check for a specific IP time-to-live value"; sigmatch_table[DETECT_TTL].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ttl"; sigmatch_table[DETECT_TTL].Match = DetectTtlMatch; sigmatch_table[DETECT_TTL].Setup = DetectTtlSetup; sigmatch_table[DETECT_TTL].Free = DetectTtlFree; sigmatch_table[DETECT_TTL].RegisterTests = DetectTtlRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: if (parse_regex != NULL) SCFree(parse_regex); if (parse_regex_study != NULL) SCFree(parse_regex_study); return; } /** * \brief This function is used to match TTL rule option on a packet with those passed via ttl: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectTtlData * * \retval 0 no match * \retval 1 match */ int DetectTtlMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { int ret = 0; uint8_t pttl; DetectTtlData *ttld = (DetectTtlData *) m->ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; if (PKT_IS_IPV4(p)) { pttl = IPV4_GET_IPTTL(p); } else if (PKT_IS_IPV6(p)) { pttl = IPV6_GET_HLIM(p); } else { SCLogDebug("Packet is of not IPv4 or IPv6"); return ret; } if (ttld->mode == DETECT_TTL_EQ && pttl == ttld->ttl1) ret = 1; else if (ttld->mode == DETECT_TTL_LT && pttl < ttld->ttl1) ret = 1; else if (ttld->mode == DETECT_TTL_GT && pttl > ttld->ttl1) ret = 1; else if (ttld->mode == DETECT_TTL_RA && (pttl > ttld->ttl1 && pttl < ttld->ttl2)) ret = 1; return ret; } /** * \brief This function is used to parse ttl options passed via ttl: keyword * * \param ttlstr Pointer to the user provided ttl options * * \retval ttld pointer to DetectTtlData on success * \retval NULL on failure */ DetectTtlData *DetectTtlParse (char *ttlstr) { DetectTtlData *ttld = NULL; char *arg1 = NULL; char *arg2 = NULL; char *arg3 = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, ttlstr, strlen(ttlstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret); goto error; } const char *str_ptr; res = pcre_get_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg1 = (char *) str_ptr; SCLogDebug("Arg1 \"%s\"", arg1); if (ret >= 3) { res = pcre_get_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg2 = (char *) str_ptr; SCLogDebug("Arg2 \"%s\"", arg2); if (ret >= 4) { res = pcre_get_substring((char *) ttlstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg3 = (char *) str_ptr; SCLogDebug("Arg3 \"%s\"", arg3); } } ttld = SCMalloc(sizeof (DetectTtlData)); if (unlikely(ttld == NULL)) goto error; ttld->ttl1 = 0; ttld->ttl2 = 0; if (arg2 != NULL) { /*set the values*/ switch(arg2[0]) { case '<': if (arg3 == NULL) goto error; ttld->mode = DETECT_TTL_LT; ttld->ttl1 = (uint8_t) atoi(arg3); SCLogDebug("ttl is %"PRIu8"",ttld->ttl1); if (strlen(arg1) > 0) goto error; break; case '>': if (arg3 == NULL) goto error; ttld->mode = DETECT_TTL_GT; ttld->ttl1 = (uint8_t) atoi(arg3); SCLogDebug("ttl is %"PRIu8"",ttld->ttl1); if (strlen(arg1) > 0) goto error; break; case '-': if (arg1 == NULL || strlen(arg1)== 0) goto error; if (arg3 == NULL || strlen(arg3)== 0) goto error; ttld->mode = DETECT_TTL_RA; ttld->ttl1 = (uint8_t) atoi(arg1); ttld->ttl2 = (uint8_t) atoi(arg3); SCLogDebug("ttl is %"PRIu8" to %"PRIu8"",ttld->ttl1, ttld->ttl2); if (ttld->ttl1 >= ttld->ttl2) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid ttl range. "); goto error; } break; default: ttld->mode = DETECT_TTL_EQ; if ((arg2 != NULL && strlen(arg2) > 0) || (arg3 != NULL && strlen(arg3) > 0) || (arg1 == NULL ||strlen(arg1) == 0)) goto error; ttld->ttl1 = (uint8_t) atoi(arg1); break; } } else { ttld->mode = DETECT_TTL_EQ; if ((arg2 != NULL && strlen(arg2) > 0) || (arg3 != NULL && strlen(arg3) > 0) || (arg1 == NULL ||strlen(arg1) == 0)) goto error; ttld->ttl1 = (uint8_t) atoi(arg1); } SCFree(arg1); SCFree(arg2); SCFree(arg3); return ttld; error: if (ttld) SCFree(ttld); if (arg1) SCFree(arg1); if (arg2) SCFree(arg2); if (arg3) SCFree(arg3); return NULL; } /** * \brief this function is used to attld the parsed ttl data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param ttlstr pointer to the user provided ttl options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectTtlSetup (DetectEngineCtx *de_ctx, Signature *s, char *ttlstr) { DetectTtlData *ttld = NULL; SigMatch *sm = NULL; ttld = DetectTtlParse(ttlstr); if (ttld == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_TTL; sm->ctx = (void *)ttld; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (ttld != NULL) DetectTtlFree(ttld); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectTtlData * * \param ptr pointer to DetectTtlData */ void DetectTtlFree(void *ptr) { DetectTtlData *ttld = (DetectTtlData *)ptr; SCFree(ttld); } #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" /** * \brief this function is used to initialize the detection engine context and * setup the signature with passed values. * */ static int DetectTtlInitTest(DetectEngineCtx **de_ctx, Signature **sig, DetectTtlData **ttld, char *str) { char fullstr[1024]; int result = 0; *de_ctx = NULL; *sig = NULL; if (snprintf(fullstr, 1024, "alert ip any any -> any any (msg:\"Ttl test\"; ttl:%s; sid:1;)", str) >= 1024) { goto end; } *de_ctx = DetectEngineCtxInit(); if (*de_ctx == NULL) { goto end; } (*de_ctx)->flags |= DE_QUIET; (*de_ctx)->sig_list = SigInit(*de_ctx, fullstr); if ((*de_ctx)->sig_list == NULL) { goto end; } *sig = (*de_ctx)->sig_list; *ttld = DetectTtlParse(str); result = 1; end: return result; } /** * \test DetectTtlParseTest01 is a test for setting up an valid ttl value. */ static int DetectTtlParseTest01 (void) { DetectTtlData *ttld = NULL; uint8_t res = 0; ttld = DetectTtlParse("10"); if (ttld != NULL) { if (ttld->ttl1 == 10 && ttld->mode == DETECT_TTL_EQ) res = 1; DetectTtlFree(ttld); } return res; } /** * \test DetectTtlParseTest02 is a test for setting up an valid ttl value with * "<" operator. */ static int DetectTtlParseTest02 (void) { DetectTtlData *ttld = NULL; uint8_t res = 0; ttld = DetectTtlParse("<10"); if (ttld != NULL) { if (ttld->ttl1 == 10 && ttld->mode == DETECT_TTL_LT) res = 1; DetectTtlFree(ttld); } return res; } /** * \test DetectTtlParseTest03 is a test for setting up an valid ttl values with * "-" operator. */ static int DetectTtlParseTest03 (void) { DetectTtlData *ttld = NULL; uint8_t res = 0; ttld = DetectTtlParse("1-2"); if (ttld != NULL) { if (ttld->ttl1 == 1 && ttld->ttl2 == 2 && ttld->mode == DETECT_TTL_RA) res = 1; DetectTtlFree(ttld); } return res; } /** * \test DetectTtlParseTest04 is a test for setting up an valid ttl value with * ">" operator and include spaces arround the given values. */ static int DetectTtlParseTest04 (void) { DetectTtlData *ttld = NULL; uint8_t res = 0; ttld = DetectTtlParse(" > 10 "); if (ttld != NULL) { if (ttld->ttl1 == 10 && ttld->mode == DETECT_TTL_GT) res = 1; DetectTtlFree(ttld); } return res; } /** * \test DetectTtlParseTest05 is a test for setting up an valid ttl values with * "-" operator and include spaces arround the given values. */ static int DetectTtlParseTest05 (void) { DetectTtlData *ttld = NULL; uint8_t res = 0; ttld = DetectTtlParse(" 1 - 2 "); if (ttld != NULL) { if (ttld->ttl1 == 1 && ttld->ttl2 == 2 && ttld->mode == DETECT_TTL_RA) res = 1; DetectTtlFree(ttld); } return res; } /** * \test DetectTtlParseTest06 is a test for setting up an valid ttl values with * invalid "=" operator and include spaces arround the given values. */ static int DetectTtlParseTest06 (void) { DetectTtlData *ttld = NULL; uint8_t res = 0; ttld = DetectTtlParse(" 1 = 2 "); if (ttld == NULL) res = 1; if (ttld) SCFree(ttld); return res; } /** * \test DetectTtlParseTest07 is a test for setting up an valid ttl values with * invalid "<>" operator and include spaces arround the given values. */ static int DetectTtlParseTest07 (void) { DetectTtlData *ttld = NULL; uint8_t res = 0; ttld = DetectTtlParse(" 1<>2 "); if (ttld == NULL) res = 1; if (ttld) SCFree(ttld); return res; } /** * \test DetectTtlSetpTest01 is a test for setting up an valid ttl values with * valid "-" operator and include spaces arround the given values. In the * test the values are setup with initializing the detection engine context * setting up the signature itself. */ static int DetectTtlSetpTest01(void) { DetectTtlData *ttld = NULL; uint8_t res = 0; Signature *sig = NULL; DetectEngineCtx *de_ctx = NULL; res = DetectTtlInitTest(&de_ctx, &sig, &ttld, "1 - 2 "); if (res == 0) { goto end; } if(ttld == NULL) goto cleanup; if (ttld != NULL) { if (ttld->ttl1 == 1 && ttld->ttl2 == 2 && ttld->mode == DETECT_TTL_RA) res = 1; } cleanup: if (ttld) SCFree(ttld); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); end: return res; } /** * \test DetectTtlTestSig01 is a test for checking the working of ttl keyword * by setting up the signature and later testing its working by matching * the received packet against the sig. */ static int DetectTtlTestSig1(void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; IPV4Hdr ip4h; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&ip4h, 0, sizeof(ip4h)); p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; ip4h.ip_ttl = 15; p->ip4h = &ip4h; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"with in ttl limit\"; ttl: >16; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Less than 17\"; ttl: <17; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Greater than 5\"; ttl:15; sid:3;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Equals tcp\"; ttl: 1-30; sid:4;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 alerted, but should not have: "); goto cleanup; } else if (PacketAlertCheck(p, 2) == 0) { printf("sid 2 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 3) == 0) { printf("sid 3 did not alert, but should have: "); goto cleanup; } else if (PacketAlertCheck(p, 4) == 0) { printf("sid 4 did not alert, but should have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectTtl */ void DetectTtlRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectTtlParseTest01", DetectTtlParseTest01, 1); UtRegisterTest("DetectTtlParseTest02", DetectTtlParseTest02, 1); UtRegisterTest("DetectTtlParseTest03", DetectTtlParseTest03, 1); UtRegisterTest("DetectTtlParseTest04", DetectTtlParseTest04, 1); UtRegisterTest("DetectTtlParseTest05", DetectTtlParseTest05, 1); UtRegisterTest("DetectTtlParseTest06", DetectTtlParseTest06, 1); UtRegisterTest("DetectTtlParseTest07", DetectTtlParseTest07, 1); UtRegisterTest("DetectTtlSetpTest01", DetectTtlSetpTest01, 1); UtRegisterTest("DetectTtlTestSig1", DetectTtlTestSig1, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-ringbuffer.h0000644000000000000000000001142212253546156014302 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * See the .c file for a full explanation. */ #ifndef __UTIL_RINGBUFFER_H__ #include "util-atomic.h" #include "threads.h" /** When the ringbuffer is full we have two options, either we spin & sleep * or we use a pthread condition to wait. * * \warning this approach isn't working due to a race condition between the * time it takes for a thread to enter the condwait and the * signalling. I've obverved the following case: T1 sees that the * ringbuffer is empty, so it decides to start the wait condition. * While it is acquiring the lock and entering the wait, T0 puts a * number of items in the buffer. For each of these it signals T1. * However, as that thread isn't in the "wait" mode yet, the signals * are lost. T0 now is done as well and enters it's own wait * condition. T1 completes it's "wait" initialization. It waits for * signals, but T0 won't be able to send them as it's waiting itself. */ //#define RINGBUFFER_MUTEX_WAIT /** \brief ring buffer api * * Ring buffer api for a single writer and a single reader. It uses a * read and write pointer. Only the read ptr needs atomic updating. */ #define RING_BUFFER_8_SIZE 256 typedef struct RingBuffer8_ { SC_ATOMIC_DECLARE(unsigned char, write); /**< idx where we put data */ SC_ATOMIC_DECLARE(unsigned char, read); /**< idx where we read data */ uint8_t shutdown; #ifdef RINGBUFFER_MUTEX_WAIT SCCondT wait_cond; SCMutex wait_mutex; #endif /* RINGBUFFER_MUTEX_WAIT */ SCSpinlock spin; /**< lock protecting writes for multi writer mode*/ void *array[RING_BUFFER_8_SIZE]; } RingBuffer8; #define RING_BUFFER_16_SIZE 65536 typedef struct RingBuffer16_ { SC_ATOMIC_DECLARE(unsigned short, write); /**< idx where we put data */ SC_ATOMIC_DECLARE(unsigned short, read); /**< idx where we read data */ uint8_t shutdown; #ifdef RINGBUFFER_MUTEX_WAIT SCCondT wait_cond; SCMutex wait_mutex; #endif /* RINGBUFFER_MUTEX_WAIT */ SCSpinlock spin; /**< lock protecting writes for multi writer mode*/ void *array[RING_BUFFER_16_SIZE]; } RingBuffer16; RingBuffer8 *RingBuffer8Init(void); void RingBuffer8Destroy(RingBuffer8 *); RingBuffer16 *RingBufferInit(void); void RingBufferDestroy(RingBuffer16 *); int RingBufferIsEmpty(RingBuffer16 *); int RingBufferIsFull(RingBuffer16 *); uint16_t RingBufferSize(RingBuffer16 *); void RingBuffer8Shutdown(RingBuffer8 *); void RingBufferShutdown(RingBuffer16 *); void RingBufferWait(RingBuffer16 *rb); /** Single Reader, Single Writer ring buffer, fixed at * 256 items so we can use unsigned char's that just * wrap around */ void *RingBufferSrSw8Get(RingBuffer8 *); int RingBufferSrSw8Put(RingBuffer8 *, void *); /** Multiple Reader, Single Writer ring buffer, fixed at * 256 items so we can use unsigned char's that just * wrap around */ void *RingBufferMrSw8Get(RingBuffer8 *); int RingBufferMrSw8Put(RingBuffer8 *, void *); /** Multiple Reader, Single Writer ring buffer, fixed at * 65536 items so we can use unsigned shorts that just * wrap around */ void *RingBufferMrSwGet(RingBuffer16 *); int RingBufferMrSwPut(RingBuffer16 *, void *); /** Single Reader, Single Writer ring buffer, fixed at * 65536 items so we can use unsigned shorts that just * wrap around */ void *RingBufferSrSwGet(RingBuffer16 *); int RingBufferSrSwPut(RingBuffer16 *, void *); /** Multiple Reader, Multi Writer ring buffer, fixed at * 256 items so we can use unsigned char's that just * wrap around */ void *RingBufferMrMw8Get(RingBuffer8 *); int RingBufferMrMw8Put(RingBuffer8 *, void *); /** Multiple Reader, Multi Writer ring buffer, fixed at * 65536 items so we can use unsigned char's that just * wrap around */ void *RingBufferMrMwGet(RingBuffer16 *); void *RingBufferMrMwGetNoWait(RingBuffer16 *); int RingBufferMrMwPut(RingBuffer16 *, void *); void *RingBufferSrMw8Get(RingBuffer8 *); int RingBufferSrMw8Put(RingBuffer8 *, void *); void DetectRingBufferRegisterTests(void); #endif /* __UTIL_RINGBUFFER_H__ */ suricata-1.4.7/src/detect-http-method.c0000644000000000000000000010217112253546156014676 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Brian Rectanus * * Implements the http_method keyword */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-content.h" #include "detect-pcre.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-method.h" #include "stream-tcp.h" static int DetectHttpMethodSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpMethodRegisterTests(void); void DetectHttpMethodFree(void *); /** * \brief Registration function for keyword: http_method */ void DetectHttpMethodRegister(void) { sigmatch_table[DETECT_AL_HTTP_METHOD].name = "http_method"; sigmatch_table[DETECT_AL_HTTP_METHOD].desc = "content modifier to match only on the HTTP method-buffer"; sigmatch_table[DETECT_AL_HTTP_METHOD].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_method"; sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; sigmatch_table[DETECT_AL_HTTP_METHOD].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_METHOD].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; sigmatch_table[DETECT_AL_HTTP_METHOD].Free = DetectHttpMethodFree; sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_PAYLOAD; SCLogDebug("registering http_method rule option"); } /** * \brief This function is used to add the parsed "http_method" option * into the current signature. * * \param de_ctx Pointer to the Detection Engine Context. * \param s Pointer to the Current Signature. * \param str Pointer to the user provided option string. * * \retval 0 on Success. * \retval -1 on Failure. */ static int DetectHttpMethodSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); DetectContentData *cd = NULL; if ((str != NULL) && (strcmp(str, "") != 0)) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_method does not take an argument"); SCReturnInt(-1); } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { SCLogError(SC_ERR_HTTP_METHOD_NEEDS_PRECEEDING_CONTENT, "http_method " "modifies preceding \"content\", but none was found"); SCReturnInt(-1); } SigMatch *sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (sm == NULL) { SCLogError(SC_ERR_HTTP_METHOD_NEEDS_PRECEEDING_CONTENT, "http_method " "modifies preceding \"content\", but none was found"); SCReturnInt(-1); } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_HTTP_METHOD_INCOMPATIBLE_WITH_RAWBYTES, "http_method " "cannot be used with \"rawbytes\""); SCReturnInt(-1); } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains keywords" "that conflict with http_method"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); if (pm != NULL) { /* pm is never NULL. So no NULL check */ if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* please note. reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_HTTP_METHOD_RELATIVE_MISSING, "http_method with " "a distance or within requires preceding http_method " "content, but none was found"); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HMDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hmdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HMDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; SCReturnInt(0); error: SCReturnInt(-1); } /** * \brief this function will free memory associated with DetectContentData * * \param id_d pointer to DetectContentData */ void DetectHttpMethodFree(void *ptr) { DetectContentData *data = (DetectContentData *)ptr; if (data->content != NULL) SCFree(data->content); SCFree(data); } #ifdef UNITTESTS /* UNITTESTS */ #include "stream-tcp-reassemble.h" /** \test Check a signature with content */ int DetectHttpMethodTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\"GET\"; " "http_method; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { printf("sig parse failed: "); } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature without content (fail) */ int DetectHttpMethodTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "http_method; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with parameter (fail) */ int DetectHttpMethodTest03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\"foobar\"; " "http_method:\"GET\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with fast_pattern (should work) */ int DetectHttpMethodTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\"GET\"; " "fast_pattern; " "http_method; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with rawbytes (fail) */ int DetectHttpMethodTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\"GET\"; " "rawbytes; " "http_method; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } int DetectHttpMethodTest06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hmd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (cd->id == hmd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpMethodTest07(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hmd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (cd->id == hmd->id) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpMethodTest08(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; content:\"one\"; content:\"one\"; http_method; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hmd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (cd->id != 0 || hmd->id != 1) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpMethodTest09(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; content:\"one\"; content:\"one\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hmd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (cd->id != 1 || hmd->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpMethodTest10(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; " "content:\"one\"; content:\"one\"; http_method; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hmd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; DetectContentData *hmd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (cd->id != 1 || hmd1->id != 0 || hmd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectHttpMethodTest11(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"one\"; http_method; " "content:\"one\"; content:\"one\"; http_method; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] == NULL\n"); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL\n"); goto end; } DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; DetectContentData *hmd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; DetectContentData *hmd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; if (cd->id != 2 || hmd1->id != 0 || hmd2->id != 0) goto end; result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** \test setting the nocase flag */ static int DetectHttpMethodTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; if (DetectEngineAppendSig(de_ctx, "alert http any any -> any any " "(content:\"one\"; http_method; nocase; sid:1;)") == NULL) { printf("DetectEngineAppend == NULL: "); goto end; } if (DetectEngineAppendSig(de_ctx, "alert http any any -> any any " "(content:\"one\"; nocase; http_method; sid:2;)") == NULL) { printf("DetectEngineAppend == NULL: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL: "); goto end; } DetectContentData *hmd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; DetectContentData *hmd2 = de_ctx->sig_list->next->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if (!(hmd1->flags & DETECT_CONTENT_NOCASE)) { printf("nocase flag not set on sig 1: "); goto end; } if (!(hmd2->flags & DETECT_CONTENT_NOCASE)) { printf("nocase flag not set on sig 2: "); goto end; } result = 1; end: SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with method + within and pcre with /M (should work) */ int DetectHttpMethodTest13(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "pcre:\"/HE/M\"; " "content:\"AD\"; " "within:2; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with method + within and pcre without /M (should fail) */ int DetectHttpMethodTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "pcre:\"/HE/\"; " "content:\"AD\"; " "http_method; within:2; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with method + within and pcre with /M (should work) */ int DetectHttpMethodTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "pcre:\"/HE/M\"; " "content:\"AD\"; " "http_method; within:2; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check a signature with an known request method */ static int DetectHttpMethodSigTest01(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\n" "Host: foo.bar.tld\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\"GET\"; " "http_method; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\"POST\"; " "http_method; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { SCLogDebug("no http state: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { goto end; } if (PacketAlertCheck(p, 2)) { goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Check a signature with an unknown request method */ static int DetectHttpMethodSigTest02(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "FOO / HTTP/1.0\r\n" "Host: foo.bar.tld\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\"FOO\"; " "http_method; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\"BAR\"; " "http_method; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { SCLogDebug("no http state: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { goto end; } if (PacketAlertCheck(p, 2)) { goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *) det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Check a signature against an unparsable request */ static int DetectHttpMethodSigTest03(void) { int result = 0; Flow f; uint8_t httpbuf1[] = " "; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " "content:\" \"; " "http_method; sid:1;)"); if (s == NULL) { SCLogDebug("Bad signature"); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { SCLogDebug("no http state: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Check a signature with an request method and negation of the same */ static int DetectHttpMethodSigTest04(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\n" "Host: foo.bar.tld\r\n" "\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Testing http_method\"; " "content:\"GET\"; http_method; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Testing http_method\"; " "content:!\"GET\"; http_method; sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { SCLogDebug("no http state: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sid 2 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *) det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectHttpMethod */ void DetectHttpMethodRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ SCLogDebug("Registering tests for DetectHttpMethod..."); UtRegisterTest("DetectHttpMethodTest01", DetectHttpMethodTest01, 1); UtRegisterTest("DetectHttpMethodTest02", DetectHttpMethodTest02, 1); UtRegisterTest("DetectHttpMethodTest03", DetectHttpMethodTest03, 1); UtRegisterTest("DetectHttpMethodTest04", DetectHttpMethodTest04, 1); UtRegisterTest("DetectHttpMethodTest05", DetectHttpMethodTest05, 1); UtRegisterTest("DetectHttpMethodTest06", DetectHttpMethodTest06, 1); UtRegisterTest("DetectHttpMethodTest07", DetectHttpMethodTest07, 1); UtRegisterTest("DetectHttpMethodTest08", DetectHttpMethodTest08, 1); UtRegisterTest("DetectHttpMethodTest09", DetectHttpMethodTest09, 1); UtRegisterTest("DetectHttpMethodTest10", DetectHttpMethodTest10, 1); UtRegisterTest("DetectHttpMethodTest11", DetectHttpMethodTest11, 1); UtRegisterTest("DetectHttpMethodTest12 -- nocase flag", DetectHttpMethodTest12, 1); UtRegisterTest("DetectHttpMethodTest13", DetectHttpMethodTest13, 1); UtRegisterTest("DetectHttpMethodTest14", DetectHttpMethodTest14, 1); UtRegisterTest("DetectHttpMethodTest15", DetectHttpMethodTest15, 1); UtRegisterTest("DetectHttpMethodSigTest01", DetectHttpMethodSigTest01, 1); UtRegisterTest("DetectHttpMethodSigTest02", DetectHttpMethodSigTest02, 1); UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03, 1); UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/detect-flow.h0000644000000000000000000000205612253546156013416 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_FLOW_H__ #define __DETECT_FLOW_H__ typedef struct DetectFlowData_ { uint8_t flags; /* flags to match */ uint8_t match_cnt; /* number of matches we need */ } DetectFlowData; /* prototypes */ void DetectFlowRegister (void); #endif /* __DETECT_FLOW_H__ */ suricata-1.4.7/src/util-radix-tree.h0000644000000000000000000001271612253546156014224 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_RADIX_TREE_H__ #define __UTIL_RADIX_TREE_H__ #define SC_RADIX_BITTEST(x, y) ((x) & (y)) /** * \brief Macro to fetch the user data from a node. It checks if node is a * valid pointer and if node->prefix is as well. * * \param node Variable name/expression containing the node * \param type User data type in which the node points to * * \returns User data within the node */ #define SC_RADIX_NODE_USERDATA(node, type) \ ((type *)(((node) != NULL) ? (((node)->prefix != NULL) ? \ (node)->prefix->user_data_result : NULL) : NULL)) /** * \brief Structure that hold the user data and the netmask associated with it. */ typedef struct SCRadixUserData_ { /* holds a pointer to the user data associated with the particular netmask */ void *user; /* pointer to the next user data in the list */ struct SCRadixUserData_ *next; /* holds the netmask value that corresponds to this user data pointer */ uint8_t netmask; } SCRadixUserData; /** * \brief Structure for the prefix/key in the radix tree */ typedef struct SCRadixPrefix_ { /* length of the stream */ uint16_t bitlen; /* the key that has been stored in the tree */ uint8_t *stream; /* any user data that has to be associated with this key. We need a user * data field for each netblock value possible since one ip can be associated * with any of the the 32 or 128 netblocks. Also for non-ips, we store the * netmask as 255 in SCRadixUserData->netmask */ SCRadixUserData *user_data; /* Used to hold the user data from radix tree search. More of a convenience * that lets anyone using the API, directly get a reference to the user * data which is associated with the search results */ void *user_data_result; } SCRadixPrefix; /** * \brief Structure for the node in the radix tree */ typedef struct SCRadixNode_ { /* the bit position where the bits differ in the nodes children. Used * to determine the path to be taken during a lookup*/ uint16_t bit; uint16_t pad0; /* total no of netmasks that are registered under this node */ int netmask_cnt; /* holds a list of netmaks that come under this node in the tree */ uint8_t *netmasks; /* holds the prefix that the path to this node holds */ SCRadixPrefix *prefix; /* the left and the right children of a node */ struct SCRadixNode_ *left, *right; /* the parent node for this tree */ struct SCRadixNode_ *parent; } SCRadixNode; /** * \brief Structure for the radix tree */ typedef struct SCRadixTree_ { /* the root node in the radix tree */ SCRadixNode *head; /* function pointer that is supplied by the user to free the user data * held by the user field of SCRadixNode */ void (*PrintData)(void *); void (*Free)(void *); } SCRadixTree; struct in_addr *SCRadixValidateIPV4Address(const char *); struct in6_addr *SCRadixValidateIPV6Address(const char *); void SCRadixChopIPAddressAgainstNetmask(uint8_t *, uint8_t, uint16_t); SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void*), void (*PrintData)(void*)); void SCRadixReleaseRadixTree(SCRadixTree *); SCRadixNode *SCRadixAddKeyGeneric(uint8_t *, uint16_t, SCRadixTree *, void *); SCRadixNode *SCRadixAddKeyIPV4(uint8_t *, SCRadixTree *, void *); SCRadixNode *SCRadixAddKeyIPV6(uint8_t *, SCRadixTree *, void *); SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *, SCRadixTree *, void *, uint8_t); SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *, SCRadixTree *, void *, uint8_t); SCRadixNode *SCRadixAddKeyIPV4String(const char *, SCRadixTree *, void *); SCRadixNode *SCRadixAddKeyIPV6String(const char *, SCRadixTree *, void *); void SCRadixRemoveKeyGeneric(uint8_t *, uint16_t, SCRadixTree *); void SCRadixRemoveKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t); void SCRadixRemoveKeyIPV4(uint8_t *, SCRadixTree *); void SCRadixRemoveKeyIPV6Netblock(uint8_t *, SCRadixTree *, uint8_t); void SCRadixRemoveKeyIPV6(uint8_t *, SCRadixTree *); SCRadixNode *SCRadixFindKeyGeneric(uint8_t *, uint16_t, SCRadixTree *); SCRadixNode *SCRadixFindKeyIPV4ExactMatch(uint8_t *, SCRadixTree *); SCRadixNode *SCRadixFindKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t); SCRadixNode *SCRadixFindKeyIPV4BestMatch(uint8_t *, SCRadixTree *); SCRadixNode *SCRadixFindKeyIPV6ExactMatch(uint8_t *, SCRadixTree *); SCRadixNode *SCRadixFindKeyIPV6Netblock(uint8_t *, SCRadixTree *, uint8_t); SCRadixNode *SCRadixFindKeyIPV6BestMatch(uint8_t *, SCRadixTree *); void SCRadixPrintTree(SCRadixTree *); void SCRadixPrintNodeInfo(SCRadixNode *, int, void (*PrintData)(void*)); void SCRadixRegisterTests(void); #endif /* __UTIL_RADIX_TREE_H__ */ suricata-1.4.7/src/detect-bytetest.c0000644000000000000000000013607312253546156014314 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus * * Implements byte_test keyword. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-bytetest.h" #include "detect-bytejump.h" #include "detect-byte-extract.h" #include "app-layer.h" #include "util-byte.h" #include "util-unittest.h" #include "util-debug.h" #include "detect-pcre.h" /** * \brief Regex for parsing our options */ /** \todo We probably just need a simple tokenizer here */ #define PARSE_REGEX "^\\s*" \ "([^\\s,]+)" \ "\\s*,\\s*(\\!?)\\s*([^\\s,]*)" \ "\\s*,\\s*([^\\s,]+)" \ "\\s*,\\s*([^\\s,]+)" \ "(?:\\s*,\\s*([^\\s,]+))?" \ "(?:\\s*,\\s*([^\\s,]+))?" \ "(?:\\s*,\\s*([^\\s,]+))?" \ "(?:\\s*,\\s*([^\\s,]+))?" \ "(?:\\s*,\\s*([^\\s,]+))?" \ "\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; void DetectBytetestRegisterTests(void); void DetectBytetestRegister (void) { const char *eb; int eo; int opts = 0; sigmatch_table[DETECT_BYTETEST].name = "byte_test"; sigmatch_table[DETECT_BYTETEST].Match = DetectBytetestMatch; sigmatch_table[DETECT_BYTETEST].Setup = DetectBytetestSetup; sigmatch_table[DETECT_BYTETEST].Free = DetectBytetestFree; sigmatch_table[DETECT_BYTETEST].RegisterTests = DetectBytetestRegisterTests; sigmatch_table[DETECT_BYTETEST].flags |= SIGMATCH_PAYLOAD; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /** \brief Bytetest detection code * * Byte test works on the packet payload. * * \param det_ctx thread de ctx * \param s signature * \param m sigmatch for this bytettest * \param payload ptr to the start of the buffer to inspect * \param payload_len length of the payload * \retval 1 match * \retval 0 no match */ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *m, uint8_t *payload, uint32_t payload_len, uint8_t flags, int32_t offset, uint64_t value) { SCEnter(); DetectBytetestData *data = (DetectBytetestData *)m->ctx; uint8_t *ptr = NULL; int32_t len = 0; uint64_t val = 0; int extbytes; int neg; int match; if (payload_len == 0) { SCReturnInt(0); } /* Calculate the ptr value for the bytetest and length remaining in * the packet from that point. */ if (flags & DETECT_BYTETEST_RELATIVE) { SCLogDebug("relative, working with det_ctx->buffer_offset %"PRIu32", " "data->offset %"PRIi32"", det_ctx->buffer_offset, data->offset); ptr = payload + det_ctx->buffer_offset; len = payload_len - det_ctx->buffer_offset; ptr += offset; len -= offset; /* No match if there is no relative base */ if (ptr == NULL || len <= 0) { SCReturnInt(0); } //PrintRawDataFp(stdout,ptr,len); } else { SCLogDebug("absolute, data->offset %"PRIi32"", data->offset); ptr = payload + offset; len = payload_len - offset; } /* Validate that the to-be-extracted is within the packet * \todo Should this validate it is in the *payload*? */ if (ptr < payload || data->nbytes > len) { SCLogDebug("Data not within payload pkt=%p, ptr=%p, len=%"PRIu32", nbytes=%d", payload, ptr, len, data->nbytes); SCReturnInt(0); } neg = flags & DETECT_BYTETEST_NEGOP; /* Extract the byte data */ if (flags & DETECT_BYTETEST_STRING) { extbytes = ByteExtractStringUint64(&val, data->base, data->nbytes, (const char *)ptr); if (extbytes <= 0) { /* strtoull() return 0 if there is no numeric value in data string */ if (val == 0) { SCLogDebug("No Numeric value"); SCReturnInt(0); } else { SCLogError(SC_ERR_INVALID_NUM_BYTES, "Error extracting %d " "bytes of string data: %d", data->nbytes, extbytes); SCReturnInt(-1); } } SCLogDebug("comparing base %d string 0x%" PRIx64 " %s%c 0x%" PRIx64 "", data->base, val, (neg ? "!" : ""), data->op, data->value); } else { int endianness = (flags & DETECT_BYTETEST_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, data->nbytes, ptr); if (extbytes != data->nbytes) { SCLogError(SC_ERR_INVALID_NUM_BYTES, "Error extracting %d bytes " "of numeric data: %d\n", data->nbytes, extbytes); SCReturnInt(-1); } SCLogDebug("comparing numeric 0x%" PRIx64 " %s%c 0x%" PRIx64 "", val, (neg ? "!" : ""), data->op, data->value); } /* Compare using the configured operator */ match = 0; switch (data->op) { case DETECT_BYTETEST_OP_EQ: if (val == value) { match = 1; } break; case DETECT_BYTETEST_OP_LT: if (val < value) { match = 1; } break; case DETECT_BYTETEST_OP_GT: if (val > value) { match = 1; } break; case DETECT_BYTETEST_OP_AND: if (val & value) { match = 1; } break; case DETECT_BYTETEST_OP_OR: if (val ^ value) { match = 1; } break; case DETECT_BYTETEST_OP_GE: if (val >= value) { match = 1; } break; case DETECT_BYTETEST_OP_LE: if (val <= value) { match = 1; } break; default: /* Should never get here as we handle this in parsing. */ SCReturnInt(-1); } /* A successful match depends on negation */ if ((!neg && match) || (neg && !match)) { SCLogDebug("MATCH"); SCReturnInt(1); } SCLogDebug("NO MATCH"); SCReturnInt(0); } int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { return DetectBytetestDoMatch(det_ctx, s, m, p->payload, p->payload_len, ((DetectBytetestData *)m->ctx)->flags, 0, 0); } DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offset) { DetectBytetestData *data = NULL; char *args[9] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int i; uint32_t nbytes; const char *str_ptr = NULL; /* Execute the regex and populate args with captures. */ ret = pcre_exec(parse_regex, parse_regex_study, optstr, strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 6 || ret > 10) { SCLogError(SC_ERR_PCRE_PARSE, "parse error, ret %" PRId32 ", string %s", ret, optstr); goto error; } for (i = 0; i < (ret - 1); i++) { res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS, i + 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for arg %d", i + 1); goto error; } args[i] = (char *)str_ptr; } /* Initialize the data */ data = SCMalloc(sizeof(DetectBytetestData)); if (unlikely(data == NULL)) goto error; data->base = DETECT_BYTETEST_BASE_UNSET; data->flags = 0; /* * The first four options are required and positional. The * remaining arguments are flags and are not positional. */ /* Number of bytes */ if (ByteExtractStringUint32(&nbytes, 10, 0, args[0]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed number of bytes: %s", str_ptr); goto error; } /* Operator is next two args: neg + op */ data->op = 0; if (args[1] != NULL && *args[1] == '!') { data->flags |= DETECT_BYTETEST_NEGOP; } if (args[2] != NULL) { if ((strcmp("=", args[2]) == 0) || ((data->flags & DETECT_BYTETEST_NEGOP) && strcmp("", args[2]) == 0)) { data->op |= DETECT_BYTETEST_OP_EQ; } else if (strcmp("<", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_LT; } else if (strcmp(">", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_GT; } else if (strcmp("&", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_AND; } else if (strcmp("^", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_OR; } else if (strcmp(">=", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_GE; } else if (strcmp("<=", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_LE; } else { SCLogError(SC_ERR_INVALID_OPERATOR, "Invalid operator"); goto error; } } /* Value */ if (args[3][0] != '-' && isalpha((unsigned char)args[3][0])) { if (value == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_test supplied with " "var name for value. \"value\" argument supplied to " "this function has to be non-NULL"); goto error; } *value = SCStrdup(args[3]); if (*value == NULL) goto error; } else { if (ByteExtractStringUint64(&data->value, 0, 0, args[3]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed value: %s", str_ptr); goto error; } } /* Offset */ if (args[4][0] != '-' && isalpha((unsigned char)args[4][0])) { if (offset == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_test supplied with " "var name for offset. \"offset\" argument supplied to " "this function has to be non-NULL"); goto error; } *offset = SCStrdup(args[4]); if (*offset == NULL) goto error; } else { if (ByteExtractStringInt32(&data->offset, 0, 0, args[4]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, " Malformed offset: %s", str_ptr); goto error; } } /* The remaining options are flags. */ /** \todo Error on dups? */ for (i = 5; i < (ret - 1); i++) { if (args[i] != NULL) { if (strcmp("relative", args[i]) == 0) { data->flags |= DETECT_BYTETEST_RELATIVE; } else if (strcasecmp("string", args[i]) == 0) { data->flags |= DETECT_BYTETEST_STRING; } else if (strcasecmp("dec", args[i]) == 0) { data->base |= DETECT_BYTETEST_BASE_DEC; } else if (strcasecmp("hex", args[i]) == 0) { data->base |= DETECT_BYTETEST_BASE_HEX; } else if (strcasecmp("oct", args[i]) == 0) { data->base |= DETECT_BYTETEST_BASE_OCT; } else if (strcasecmp("big", args[i]) == 0) { if (data->flags & DETECT_BYTETEST_LITTLE) { data->flags ^= DETECT_BYTETEST_LITTLE; } data->flags |= DETECT_BYTETEST_BIG; } else if (strcasecmp("little", args[i]) == 0) { data->flags |= DETECT_BYTETEST_LITTLE; } else if (strcasecmp("dce", args[i]) == 0) { data->flags |= DETECT_BYTETEST_DCE; } else { SCLogError(SC_ERR_UNKNOWN_VALUE, "Unknown value: \"%s\"", args[i]); goto error; } } } if (data->flags & DETECT_BYTETEST_STRING) { /* 23 - This is the largest string (octal, with a zero prefix) that * will not overflow uint64_t. The only way this length * could be over 23 and still not overflow is if it were zero * prefixed and we only support 1 byte of zero prefix for octal. * * "01777777777777777777777" = 0xffffffffffffffff */ if (nbytes > 23) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 23 bytes with \"string\": %s", optstr); goto error; } } else { if (nbytes > 8) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 8 bytes without \"string\": %s", optstr); goto error; } if (data->base != DETECT_BYTETEST_BASE_UNSET) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot use a base without \"string\": %s", optstr); goto error; } } /* This is max 23 so it will fit in a byte (see above) */ data->nbytes = (uint8_t)nbytes; for (i = 0; i < (ret - 1); i++){ if (args[i] != NULL) SCFree(args[i]); } return data; error: for (i = 0; i < (ret - 1); i++){ if (args[i] != NULL) SCFree(args[i]); } if (data != NULL) DetectBytetestFree(data); return NULL; } int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { DetectBytetestData *data = NULL; SigMatch *sm = NULL; char *value = NULL; char *offset = NULL; data = DetectBytetestParse(optstr, &value, &offset); if (data == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_BYTETEST; sm->ctx = (void *)data; /* check bytetest modifiers against the signature alproto. In case they conflict * chuck out invalid signature */ if (data-> flags & DETECT_BYTETEST_DCE) { if (s->alproto != ALPROTO_DCERPC) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " "bytetest with dce enabled"); goto error; } if ( (data->flags & DETECT_BYTETEST_STRING) || (data->flags & DETECT_BYTETEST_LITTLE) || (data->flags & DETECT_BYTETEST_BIG) || (data->base == DETECT_BYTETEST_BASE_DEC) || (data->base == DETECT_BYTETEST_BASE_HEX) || (data->base == DETECT_BYTETEST_BASE_OCT) ) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " "a byte_test keyword with dce holds other invalid modifiers."); goto error; } } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { if (data->flags & DETECT_BYTETEST_RELATIVE) { SigMatch *prev_sm = NULL; prev_sm = SigMatchGetLastSMFromLists(s, 8, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); if (prev_sm == NULL) { data->flags &= ~DETECT_BYTETEST_RELATIVE; } s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else { s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } } else if (s->alproto == ALPROTO_DCERPC && (data->flags & DETECT_BYTETEST_RELATIVE)) { SigMatch *pm = NULL; SigMatch *dm = NULL; pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (dm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (pm->idx > dm->idx) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } if (value != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(value, s, SigMatchListSMBelongsTo(s, sm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in byte_test - %s\n", value); goto error; } DetectBytetestData *btd = sm->ctx; btd->value = ((DetectByteExtractData *)bed_sm->ctx)->local_id; btd->flags |= DETECT_BYTETEST_VALUE_BE; SCFree(value); } if (offset != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, SigMatchListSMBelongsTo(s, sm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in byte_test - %s\n", offset); goto error; } DetectBytetestData *btd = sm->ctx; btd->offset = ((DetectByteExtractData *)bed_sm->ctx)->local_id; btd->flags |= DETECT_BYTETEST_OFFSET_BE; SCFree(offset); } if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { return 0; } if ( !(data->flags & DETECT_BYTETEST_RELATIVE)) { return 0; } SigMatch *prev_sm = NULL; prev_sm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, sm->prev, DETECT_BYTEJUMP, sm->prev, DETECT_PCRE, sm->prev); if (prev_sm == NULL) { if (s->alproto == ALPROTO_DCERPC) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is an alproto sig."); return 0; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "No preceding content " "or uricontent or pcre option"); return -1; } } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (prev_sm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_sm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; break; case DETECT_PCRE: pe = (DetectPcreData *)prev_sm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: SCLogDebug("No setting relative_next for bytejump. We " "have no use for it"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } /* switch */ return 0; error: //if (data != NULL) // DetectBytetestFree(data); //if (sm != NULL) // SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectBytetestData * * \param data pointer to DetectBytetestData */ void DetectBytetestFree(void *ptr) { DetectBytetestData *data = (DetectBytetestData *)ptr; SCFree(data); } /* UNITTESTS */ #ifdef UNITTESTS #include "util-unittest-helper.h" /** * \test DetectBytetestTestParse01 is a test to make sure that we return "something" * when given valid bytetest opt */ int DetectBytetestTestParse01(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, =, 1 , 0", NULL, NULL); if (data != NULL) { DetectBytetestFree(data); result = 1; } return result; } /** * \test DetectBytetestTestParse02 is a test for setting the required opts */ int DetectBytetestTestParse02(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, !=, 1, 0", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_EQ) && (data->nbytes == 4) && (data->value == 1) && (data->offset == 0) && (data->flags == DETECT_BYTETEST_NEGOP) && (data->base == DETECT_BYTETEST_BASE_UNSET)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse03 is a test for setting the relative flag */ int DetectBytetestTestParse03(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, !=, 1, 0, relative", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_EQ) && (data->nbytes == 4) && (data->value == 1) && (data->offset == 0) && (data->flags == ( DETECT_BYTETEST_NEGOP |DETECT_BYTETEST_RELATIVE)) && (data->base == DETECT_BYTETEST_BASE_UNSET)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse04 is a test for setting the string/oct flags */ int DetectBytetestTestParse04(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, !=, 1, 0, string, oct", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_EQ) && (data->nbytes == 4) && (data->value == 1) && (data->offset == 0) && (data->flags == ( DETECT_BYTETEST_NEGOP |DETECT_BYTETEST_STRING)) && (data->base == DETECT_BYTETEST_BASE_OCT)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse05 is a test for setting the string/dec flags */ int DetectBytetestTestParse05(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, =, 1, 0, string, dec", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_EQ) && (data->nbytes == 4) && (data->value == 1) && (data->offset == 0) && (data->flags == DETECT_BYTETEST_STRING) && (data->base == DETECT_BYTETEST_BASE_DEC)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse06 is a test for setting the string/hex flags */ int DetectBytetestTestParse06(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, >, 1, 0, string, hex", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_GT) && (data->nbytes == 4) && (data->value == 1) && (data->offset == 0) && (data->flags == DETECT_BYTETEST_STRING) && (data->base == DETECT_BYTETEST_BASE_HEX)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse07 is a test for setting the big flag */ int DetectBytetestTestParse07(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, <, 5, 0, big", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_LT) && (data->nbytes == 4) && (data->value == 5) && (data->offset == 0) && (data->flags == 4) && (data->base == DETECT_BYTETEST_BASE_UNSET)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse08 is a test for setting the little flag */ int DetectBytetestTestParse08(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, <, 5, 0, little", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_LT) && (data->nbytes == 4) && (data->value == 5) && (data->offset == 0) && (data->flags == DETECT_BYTETEST_LITTLE) && (data->base == DETECT_BYTETEST_BASE_UNSET)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse09 is a test for neg operator only */ int DetectBytetestTestParse09(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, !, 5, 0", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_EQ) && (data->nbytes == 4) && (data->value == 5) && (data->offset == 0) && (data->flags == DETECT_BYTETEST_NEGOP) && (data->base == DETECT_BYTETEST_BASE_UNSET)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse10 is a test for whitespace */ int DetectBytetestTestParse10(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse(" 4 , ! &, 5 , 0 , little ", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_AND) && (data->nbytes == 4) && (data->value == 5) && (data->offset == 0) && (data->flags == (DETECT_BYTETEST_NEGOP|DETECT_BYTETEST_LITTLE)) && (data->base == DETECT_BYTETEST_BASE_UNSET)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse11 is a test for whitespace */ int DetectBytetestTestParse11(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4,!^,5,0,little,string,relative,hex", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_OR) && (data->nbytes == 4) && (data->value == 5) && (data->offset == 0) && (data->flags == ( DETECT_BYTETEST_NEGOP |DETECT_BYTETEST_LITTLE |DETECT_BYTETEST_STRING |DETECT_BYTETEST_RELATIVE)) && (data->base == DETECT_BYTETEST_BASE_HEX)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse12 is a test for hex w/o string */ int DetectBytetestTestParse12(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, =, 1, 0, hex", NULL, NULL); if (data == NULL) { result = 1; } return result; } /** * \test DetectBytetestTestParse13 is a test for too many bytes to extract */ int DetectBytetestTestParse13(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("9, =, 1, 0", NULL, NULL); if (data == NULL) { result = 1; } return result; } /** * \test DetectBytetestTestParse14 is a test for large string extraction */ int DetectBytetestTestParse14(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("23,=,0xffffffffffffffffULL,0,string,oct", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_EQ) && (data->nbytes == 23) && (data->value == 0xffffffffffffffffULL) && (data->offset == 0) && (data->flags == DETECT_BYTETEST_STRING) && (data->base == DETECT_BYTETEST_BASE_OCT)) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test DetectBytetestTestParse15 is a test for too many bytes to extract (string) */ int DetectBytetestTestParse15(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("24, =, 0xffffffffffffffffULL, 0, string", NULL, NULL); if (data == NULL) { result = 1; } return result; } /** * \test DetectBytetestTestParse16 is a test for offset too big */ int DetectBytetestTestParse16(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4,=,0,0xffffffffffffffffULL", NULL, NULL); if (data == NULL) { result = 1; } return result; } /** * \test Test dce option. */ int DetectBytetestTestParse17(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, <, 5, 0, dce", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_LT) && (data->nbytes == 4) && (data->value == 5) && (data->offset == 0) && (data->flags & DETECT_BYTETEST_DCE) ) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test Test dce option. */ int DetectBytetestTestParse18(void) { int result = 0; DetectBytetestData *data = NULL; data = DetectBytetestParse("4, <, 5, 0", NULL, NULL); if (data != NULL) { if ( (data->op == DETECT_BYTETEST_OP_LT) && (data->nbytes == 4) && (data->value == 5) && (data->offset == 0) && !(data->flags & DETECT_BYTETEST_DCE) ) { result = 1; } DetectBytetestFree(data); } return result; } /** * \test Test dce option. */ int DetectBytetestTestParse19(void) { Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 1; s->alproto = ALPROTO_DCERPC; result &= (DetectBytetestSetup(NULL, s, "1,=,1,6,dce") == 0); result &= (DetectBytetestSetup(NULL, s, "1,=,1,6,string,dce") == -1); result &= (DetectBytetestSetup(NULL, s, "1,=,1,6,big,dce") == -1); result &= (DetectBytetestSetup(NULL, s, "1,=,1,6,little,dce") == -1); result &= (DetectBytetestSetup(NULL, s, "1,=,1,6,hex,dce") == -1); result &= (DetectBytetestSetup(NULL, s, "1,=,1,6,oct,dce") == -1); result &= (DetectBytetestSetup(NULL, s, "1,=,1,6,dec,dce") == -1); SigFree(s); return result; } /** * \test Test dce option. */ int DetectBytetestTestParse20(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; DetectBytetestData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "byte_test:1,=,1,6,relative,dce; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (!(bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && (bd->flags & DETECT_BYTETEST_BIG) && (bd->flags & DETECT_BYTETEST_LITTLE) && (bd->flags & DETECT_BYTETEST_NEGOP) ) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "byte_test:1,=,1,6,relative,dce; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (!(bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && (bd->flags & DETECT_BYTETEST_BIG) && (bd->flags & DETECT_BYTETEST_LITTLE) && (bd->flags & DETECT_BYTETEST_NEGOP) ) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "byte_test:1,=,1,6,relative; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if ((bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && (bd->flags & DETECT_BYTETEST_BIG) && (bd->flags & DETECT_BYTETEST_LITTLE) && (bd->flags & DETECT_BYTETEST_NEGOP) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test dce option. */ int DetectBytetestTestParse21(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,string,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,big,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,little,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,hex,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,dec,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,oct,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,string,hex,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,big,string,hex,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,big,string,oct,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,little,string,hex,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } s = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytetest_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "content:\"one\"; byte_test:1,=,1,6,big,string,dec,dce; sid:1;)"); if (s != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test file_data */ static int DetectBytetestTestParse22(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectBytetestData *bd = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; byte_test:1,=,1,6,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("empty server body list: "); goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_BYTETEST) { printf("bytetest not last sm in server body list: "); goto end; } bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if (bd->flags & DETECT_BYTETEST_DCE && bd->flags & DETECT_BYTETEST_RELATIVE && (bd->flags & DETECT_BYTETEST_STRING) && (bd->flags & DETECT_BYTETEST_BIG) && (bd->flags & DETECT_BYTETEST_LITTLE) && (bd->flags & DETECT_BYTETEST_NEGOP) ) { printf("wrong flags: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectByteTestTestPacket01 is a test to check matches of * byte_test and byte_test relative works if the previous keyword is pcre * (bug 142) */ int DetectByteTestTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" "User-Agent: Wget/1.11.4" "Accept: */*" "Host: www.google.com" "Connection: Keep-Alive" "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"pcre + byte_test + " "relative\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\"; byte_test:1,=,1" ",6,relative,string,dec; sid:126; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } /** * \test DetectByteTestTestPacket02 is a test to check matches of * byte_test and byte_test relative works if the previous keyword is byte_jump * (bug 158) */ int DetectByteTestTestPacket02 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" "User-Agent: Wget/1.11.4" "Accept: */*" "Host: www.google.com" "Connection: Keep-Alive" "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"content + byte_test + " "relative\"; byte_jump:1,44,string,dec; byte_test:1,=,0,0,relative,string," "dec; sid:777; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } int DetectByteTestTestPacket03(void) { int result = 0; uint8_t *buf = NULL; uint16_t buflen = 0; buf = SCMalloc(4); if (unlikely(buf == NULL)) { printf("malloc failed\n"); exit(EXIT_FAILURE); } memcpy(buf, "boom", 4); buflen = 4; Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"content + byte_test\"; " "byte_test:1,=,65,214748364; sid:1; rev:1;)"; result = !UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } /** \test Test the byte_test signature matching with operator <= */ int DetectByteTestTestPacket04(void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" "User-Agent: Wget/1.11.4" "Accept: */*" "Host: www.google.com" "Connection: Keep-Alive" "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"content + byte_test +" "relative\"; content:\"GET \"; depth:4; content:\"HTTP/1.\"; " "byte_test:1,<=,0,0,relative,string,dec; sid:124; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } /** \test Test the byte_test signature matching with operator >= */ int DetectByteTestTestPacket05(void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" "User-Agent: Wget/1.11.4" "Accept: */*" "Host: www.google.com" "Connection: Keep-Alive" "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"content + byte_test +" "relative\"; content:\"GET \"; depth:4; content:\"HTTP/1.\"; " "byte_test:1,>=,0,0,relative,string,dec; sid:125; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectBytetest */ void DetectBytetestRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectBytetestTestParse01", DetectBytetestTestParse01, 1); UtRegisterTest("DetectBytetestTestParse02", DetectBytetestTestParse02, 1); UtRegisterTest("DetectBytetestTestParse03", DetectBytetestTestParse03, 1); UtRegisterTest("DetectBytetestTestParse04", DetectBytetestTestParse04, 1); UtRegisterTest("DetectBytetestTestParse05", DetectBytetestTestParse05, 1); UtRegisterTest("DetectBytetestTestParse06", DetectBytetestTestParse06, 1); UtRegisterTest("DetectBytetestTestParse07", DetectBytetestTestParse07, 1); UtRegisterTest("DetectBytetestTestParse08", DetectBytetestTestParse08, 1); UtRegisterTest("DetectBytetestTestParse09", DetectBytetestTestParse09, 1); UtRegisterTest("DetectBytetestTestParse10", DetectBytetestTestParse10, 1); UtRegisterTest("DetectBytetestTestParse11", DetectBytetestTestParse11, 1); UtRegisterTest("DetectBytetestTestParse12", DetectBytetestTestParse12, 1); UtRegisterTest("DetectBytetestTestParse13", DetectBytetestTestParse13, 1); UtRegisterTest("DetectBytetestTestParse14", DetectBytetestTestParse14, 1); UtRegisterTest("DetectBytetestTestParse15", DetectBytetestTestParse15, 1); UtRegisterTest("DetectBytetestTestParse17", DetectBytetestTestParse17, 1); UtRegisterTest("DetectBytetestTestParse18", DetectBytetestTestParse18, 1); UtRegisterTest("DetectBytetestTestParse19", DetectBytetestTestParse19, 1); UtRegisterTest("DetectBytetestTestParse20", DetectBytetestTestParse20, 1); UtRegisterTest("DetectBytetestTestParse21", DetectBytetestTestParse21, 1); UtRegisterTest("DetectBytetestTestParse22", DetectBytetestTestParse22, 1); UtRegisterTest("DetectByteTestTestPacket01", DetectByteTestTestPacket01, 1); UtRegisterTest("DetectByteTestTestPacket02", DetectByteTestTestPacket02, 1); UtRegisterTest("DetectByteTestTestPacket03", DetectByteTestTestPacket03, 1); UtRegisterTest("DetectByteTestTestPacket04", DetectByteTestTestPacket04, 1); UtRegisterTest("DetectByteTestTestPacket05", DetectByteTestTestPacket05, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/app-layer-htp-file.h0000644000000000000000000000220512253546156014575 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * */ #ifndef __APP_LAYER_HTP_FILE_H__ #define __APP_LAYER_HTP_FILE_H__ int HTPFileOpen(HtpState *, uint8_t *, uint16_t, uint8_t *, uint32_t, uint16_t, uint8_t); int HTPFileStoreChunk(HtpState *, uint8_t *, uint32_t, uint8_t); int HTPFileClose(HtpState *, uint8_t *, uint32_t, uint8_t, uint8_t); void HTPFileParserRegisterTests(void); #endif /* __APP_LAYER_HTP_FILE_H__ */ suricata-1.4.7/src/util-bloomfilter-counting.h0000644000000000000000000000324212253546156016314 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __BLOOMFILTERCOUNTING_H__ #define __BLOOMFILTERCOUNTING_H__ /* Bloom filter structure */ typedef struct BloomFilterCounting_ { uint8_t *array; uint32_t array_size; /* size in buckets */ uint8_t type; /* 1, 2 or 4 byte counters */ uint8_t hash_iterations; uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t); } BloomFilterCounting; /* prototypes */ BloomFilterCounting *BloomFilterCountingInit(uint32_t, uint8_t, uint8_t, uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t)); void BloomFilterCountingFree(BloomFilterCounting *); void BloomFilterCountingPrint(BloomFilterCounting *); int BloomFilterCountingAdd(BloomFilterCounting *, void *, uint16_t); int BloomFilterCountingRemove(BloomFilterCounting *, void *, uint16_t); int BloomFilterCountingTest(BloomFilterCounting *, void *, uint16_t); void BloomFilterCountingRegisterTests(void); #endif /* __BLOOMFILTERCOUNTING_H__ */ suricata-1.4.7/src/app-layer.h0000644000000000000000000000272512253546156013076 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __APP_LAYER_H__ #define __APP_LAYER_H__ #include "flow.h" #include "decode.h" #include "stream-tcp.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-detect-proto.h" #include "stream.h" uint16_t AppLayerGetProtoFromPacket(Packet *); void *AppLayerGetProtoStateFromPacket(Packet *); void *AppLayerGetProtoStateFromFlow(Flow *); int AppLayerHandleTCPData(AlpProtoDetectThreadCtx *, Flow *, TcpSession *, uint8_t *, uint32_t, uint8_t); int AppLayerHandleTCPMsg(AlpProtoDetectThreadCtx *, StreamMsg *); //int AppLayerHandleMsg(AlpProtoDetectThreadCtx *, StreamMsg *); int AppLayerHandleUdp(AlpProtoDetectThreadCtx *, Flow *, Packet *p); #endif /* __APP_LAYER_H__ */ suricata-1.4.7/src/detect-window.h0000644000000000000000000000206712253546156013760 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef __DETECT_WINDOW_H__ #define __DETECT_WINDOW_H__ #define MIN_WINDOW_VALUE 0 #define MAX_WINDOW_VALUE 65535 typedef struct DetectWindowData_ { uint8_t negated; /** negated? 1=True : 0=False */ uint16_t size; /** window size to match */ } DetectWindowData; /* prototypes */ void DetectWindowRegister (void); #endif /* __DETECT_WINDOW_H__ */ suricata-1.4.7/src/defrag.h0000644000000000000000000001032212253546156012424 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited, Jason Ish */ #ifndef __DEFRAG_H__ #define __DEFRAG_H__ #include "util-pool.h" /** * A context for an instance of a fragmentation re-assembler, in case * we ever need more than one. */ typedef struct DefragContext_ { Pool *frag_pool; /**< Pool of fragments. */ SCMutex frag_pool_lock; time_t timeout; /**< Default timeout. */ } DefragContext; /** * Storage for an individual fragment. */ typedef struct Frag_ { uint16_t offset; /**< The offset of this fragment, already * multiplied by 8. */ uint16_t len; /**< The length of this fragment. */ uint8_t hlen; /**< The length of this fragments IP header. */ uint8_t more_frags:4; /**< More frags? */ uint8_t skip:4; /**< Skip this fragment during re-assembly. */ uint16_t ip_hdr_offset; /**< Offset in the packet where the IP * header starts. */ uint16_t frag_hdr_offset; /**< Offset in the packet where the frag * header starts. */ uint16_t data_offset; /**< Offset to the packet data. */ uint16_t data_len; /**< Length of data. */ uint16_t ltrim; /**< Number of leading bytes to trim when * re-assembling the packet. */ uint8_t *pkt; /**< The actual packet. */ #ifdef DEBUG uint64_t pcap_cnt; /**< pcap_cnt of original packet */ #endif TAILQ_ENTRY(Frag_) next; /**< Pointer to next fragment for tailq. */ } Frag; /** \brief Reset tracker fields except "lock" */ #define DEFRAG_TRACKER_RESET(t) { \ (t)->timeout = 0; \ (t)->id = 0; \ (t)->policy = 0; \ (t)->af = 0; \ (t)->seen_last = 0; \ (t)->remove = 0; \ CLEAR_ADDR(&(t)->src_addr); \ CLEAR_ADDR(&(t)->dst_addr); \ (t)->frags.tqh_first = NULL; \ (t)->frags.tqh_last = NULL; \ } /** * A defragmentation tracker. Used to track fragments that make up a * single packet. */ typedef struct DefragTracker_ { SCMutex lock; /**< Mutex for locking list operations on * this tracker. */ uint32_t id; /**< IP ID for this tracker. 32 bits for IPv6, 16 * for IPv4. */ uint8_t policy; /**< Reassembly policy this tracker will use. */ uint8_t af; /**< Address family for this tracker, AF_INET or * AF_INET6. */ uint8_t seen_last; /**< Has this tracker seen the last fragment? */ uint8_t remove; /**< remove */ Address src_addr; /**< Source address for this tracker. */ Address dst_addr; /**< Destination address for this tracker. */ uint32_t timeout; /**< When this tracker will timeout. */ /** use cnt, reference counter */ SC_ATOMIC_DECLARE(unsigned short, use_cnt); TAILQ_HEAD(frag_tailq, Frag_) frags; /**< Head of list of fragments. */ /** hash pointers, protected by hash row mutex/spin */ struct DefragTracker_ *hnext; struct DefragTracker_ *hprev; /** list pointers, protected by tracker-queue mutex/spin */ struct DefragTracker_ *lnext; struct DefragTracker_ *lprev; } DefragTracker; void DefragInit(void); void DefragDestroy(void); void DefragReload(void); /**< use only in unittests */ uint8_t DefragGetOsPolicy(Packet *); void DefragTrackerFreeFrags(DefragTracker *); Packet *Defrag(ThreadVars *, DecodeThreadVars *, Packet *); void DefragRegisterTests(void); #endif /* __DEFRAG_H__ */ suricata-1.4.7/src/detect-ssl-version.c0000644000000000000000000005404312253546156014731 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file detect-ssl-version.c * * \author Gurvinder Singh * * Implements the ssl_version keyword */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "detect-ssl-version.h" #include "stream-tcp.h" #include "app-layer-ssl.h" /** * \brief Regex for parsing "id" option, matching number or "number" */ #define PARSE_REGEX "^\\s*(!?[A-z0-9.]+)\\s*,?\\s*(!?[A-z0-9.]+)?\\s*\\,?\\s*" \ "(!?[A-z0-9.]+)?\\s*,?\\s*(!?[A-z0-9.]+)?\\s*,?\\s*(!?[A-z0-9.]+)?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, char *); void DetectSslVersionRegisterTests(void); void DetectSslVersionFree(void *); /** * \brief Registration function for keyword: ssl_version */ void DetectSslVersionRegister(void) { sigmatch_table[DETECT_AL_SSL_VERSION].name = "ssl_version"; sigmatch_table[DETECT_AL_SSL_VERSION].Match = NULL; sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerMatch = DetectSslVersionMatch; sigmatch_table[DETECT_AL_SSL_VERSION].alproto = ALPROTO_TLS; sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup; sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree; sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests; const char *eb; int eo; int opts = 0; SCLogDebug("registering ssl_version rule option"); parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief match the specified version on a ssl session * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectSslVersionData * * \retval 0 no match * \retval 1 match */ int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; uint16_t ver = 0; uint8_t sig_ver = TLS_UNKNOWN; DetectSslVersionData *ssl = (DetectSslVersionData *)m->ctx; SSLState *app_state = (SSLState *)state; if (app_state == NULL) { SCLogDebug("no app state, no match"); SCReturnInt(0); } FLOWLOCK_RDLOCK(f); if (flags & STREAM_TOCLIENT) { SCLogDebug("server (toclient) version is 0x%02X", app_state->server_connp.version); ver = app_state->server_connp.version; } else if (flags & STREAM_TOSERVER) { SCLogDebug("client (toserver) version is 0x%02X", app_state->client_connp.version); ver = app_state->client_connp.version; } FLOWLOCK_UNLOCK(f); switch (ver) { case SSL_VERSION_2: if (ver == ssl->data[SSLv2].ver) ret = 1; sig_ver = SSLv2; break; case SSL_VERSION_3: if (ver == ssl->data[SSLv3].ver) ret = 1; sig_ver = SSLv3; break; case TLS_VERSION_10: if (ver == ssl->data[TLS10].ver) ret = 1; sig_ver = TLS10; break; case TLS_VERSION_11: if (ver == ssl->data[TLS11].ver) ret = 1; sig_ver = TLS11; break; case TLS_VERSION_12: if (ver == ssl->data[TLS12].ver) ret = 1; sig_ver = TLS12; break; } if (sig_ver == TLS_UNKNOWN) SCReturnInt(0); SCReturnInt(ret ^ ((ssl->data[sig_ver].flags & DETECT_SSL_VERSION_NEGATED) ? 1 : 0)); } /** * \brief This function is used to parse ssl_version data passed via * keyword: "ssl_version" * * \param str Pointer to the user provided options * * \retval ssl pointer to DetectSslVersionData on success * \retval NULL on failure */ DetectSslVersionData *DetectSslVersionParse(char *str) { DetectSslVersionData *ssl = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 5) { SCLogError(SC_ERR_PCRE_MATCH, "invalid ssl_version option"); goto error; } if (ret > 1) { const char *str_ptr[5]; char *orig; uint8_t found = 0, neg = 0; char *tmp_str; /* We have a correct ssl_version options */ ssl = SCCalloc(1, sizeof (DetectSslVersionData)); if (unlikely(ssl == NULL)) goto error; int i; for (i = 1; i < ret; i++) { res = pcre_get_substring((char *) str, ov, MAX_SUBSTRINGS, i, &str_ptr[i]); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); if (found == 0) goto error; break; } orig = SCStrdup((char*) str_ptr[i]); if (unlikely(orig == NULL)) { goto error; } tmp_str = orig; /* Let's see if we need to scape "'s */ if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } if (tmp_str[0] == '!') { neg = 1; tmp_str++; } if (strncasecmp("sslv2", tmp_str, 5) == 0) { ssl->data[SSLv2].ver = SSL_VERSION_2; if (neg == 1) ssl->data[SSLv2].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strncasecmp("sslv3", tmp_str, 5) == 0) { ssl->data[SSLv3].ver = SSL_VERSION_3; if (neg == 1) ssl->data[SSLv3].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strncasecmp("tls1.0", tmp_str, 6) == 0) { ssl->data[TLS10].ver = TLS_VERSION_10; if (neg == 1) ssl->data[TLS10].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strncasecmp("tls1.1", tmp_str, 6) == 0) { ssl->data[TLS11].ver = TLS_VERSION_11; if (neg == 1) ssl->data[TLS11].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strncasecmp("tls1.2", tmp_str, 6) == 0) { ssl->data[TLS12].ver = TLS_VERSION_12; if (neg == 1) ssl->data[TLS12].flags |= DETECT_SSL_VERSION_NEGATED; } else if (strcmp(tmp_str, "") == 0) { SCFree(orig); if (found == 0) goto error; break; } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid value"); neg = 0; SCFree(orig); goto error; } found = 1; neg = 0; SCFree(orig); } } return ssl; error: if (ssl != NULL) DetectSslVersionFree(ssl); return NULL; } /** * \brief this function is used to add the parsed "id" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "id" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectSslVersionData *ssl = NULL; SigMatch *sm = NULL; ssl = DetectSslVersionParse(str); if (ssl == 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_AL_SSL_VERSION; sm->ctx = (void *)ssl; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_TLS; return 0; error: if (ssl != NULL) DetectSslVersionFree(ssl); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectSslVersionData * * \param id_d pointer to DetectSslVersionData */ void DetectSslVersionFree(void *ptr) { if (ptr != NULL) SCFree(ptr); } /**********************************Unittests***********************************/ #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectSslVersionTestParse01 is a test to make sure that we parse the * "ssl_version" option correctly when given valid ssl_version option */ int DetectSslVersionTestParse01(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("SSlv3"); if (ssl != NULL && ssl->data[SSLv3].ver == SSL_VERSION_3) { DetectSslVersionFree(ssl); return 1; } return 0; } /** * \test DetectSslVersionTestParse02 is a test to make sure that we parse the * "ssl_version" option correctly when given an invalid ssl_version option * it should return ssl = NULL */ int DetectSslVersionTestParse02(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("2.5"); if (ssl == NULL) { DetectSslVersionFree(ssl); return 1; } return 0; } /** * \test DetectSslVersionTestParse03 is a test to make sure that we parse the * "ssl_version" options correctly when given valid ssl_version options */ int DetectSslVersionTestParse03(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("SSlv3,tls1.0, !tls1.2"); if (ssl != NULL && ssl->data[SSLv3].ver == SSL_VERSION_3 && ssl->data[TLS10].ver == TLS_VERSION_10 && ssl->data[TLS12].ver == TLS_VERSION_12 && ssl->data[TLS12].flags & DETECT_SSL_VERSION_NEGATED) { DetectSslVersionFree(ssl); return 1; } return 0; } #include "stream-tcp-reassemble.h" /** \test Send a get request in three chunks + more data. */ static int DetectSslVersionTestDetect01(void) { int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); uint8_t sslbuf2[] = { 0x03 }; uint32_t ssllen2 = sizeof(sslbuf2); uint8_t sslbuf3[] = { 0x01 }; uint32_t ssllen3 = sizeof(sslbuf3); uint8_t sslbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x01 }; uint32_t ssllen4 = sizeof(sslbuf4); TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_TLS; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SSLState *app_state = f.alstate; if (app_state == NULL) { printf("no ssl state: "); goto end; } if (app_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); goto end; } if (app_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); goto end; } SCLogDebug("app_state is at %p, app_state->server_connp.version 0x%02X app_state->client_connp.version 0x%02X", app_state, app_state->server_connp.version, app_state->client_connp.version); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectSslVersionTestDetect02(void) { int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); uint8_t sslbuf2[] = { 0x03 }; uint32_t ssllen2 = sizeof(sslbuf2); uint8_t sslbuf3[] = { 0x01 }; uint32_t ssllen3 = sizeof(sslbuf3); uint8_t sslbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x02 }; uint32_t ssllen4 = sizeof(sslbuf4); TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_TLS; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SSLState *app_state = f.alstate; if (app_state == NULL) { printf("no ssl state: "); goto end; } if (app_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); goto end; } if (app_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("signature 1 didn't match while it should have: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectSslVersionTestDetect03(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); uint8_t sslbuf2[] = { 0x03 }; uint32_t ssllen2 = sizeof(sslbuf2); uint8_t sslbuf3[] = { 0x01 }; uint32_t ssllen3 = sizeof(sslbuf3); uint8_t sslbuf4[] = { 0x01, 0x00, 0x00, 0xad, 0x03, 0x02 }; uint32_t ssllen4 = sizeof(sslbuf4); TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->tcph->th_seq = htonl(1000); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_TLS; f.proto = p->proto; StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); if (stream_msg == NULL) { printf("no stream_msg: "); goto end; } memcpy(stream_msg->data.data, sslbuf4, ssllen4); stream_msg->data.data_len = ssllen4; ssn.toserver_smsg_head = stream_msg; ssn.toserver_smsg_tail = stream_msg; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; content:\"|01 00 00 AD|\"; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SSLState *app_state = f.alstate; if (app_state == NULL) { printf("no ssl state: "); goto end; } if (app_state->client_connp.content_type != 0x16) { printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); goto end; } if (app_state->client_connp.version != TLS_VERSION_10) { printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("signature 1 didn't match while it should have: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectSslVersion */ void DetectSslVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectSslVersionTestParse01", DetectSslVersionTestParse01, 1); UtRegisterTest("DetectSslVersionTestParse02", DetectSslVersionTestParse02, 1); UtRegisterTest("DetectSslVersionTestParse03", DetectSslVersionTestParse03, 1); UtRegisterTest("DetectSslVersionTestDetect01", DetectSslVersionTestDetect01, 1); UtRegisterTest("DetectSslVersionTestDetect02", DetectSslVersionTestDetect02, 1); UtRegisterTest("DetectSslVersionTestDetect03", DetectSslVersionTestDetect03, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/detect-priority.h0000644000000000000000000000200112253546156014316 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * * Implements the priority keyword */ #ifndef __DETECT_PRIORITY_H__ #define __DETECT_PRIORITY_H__ /* prototypes */ void DetectPriorityRegister (void); #endif /* __DETECT_PRIORITY_H__ */ suricata-1.4.7/src/detect-http-stat-code.c0000644000000000000000000005343712253546156015313 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** * \file * * \author Gurvinder Singh * \author Anoop Saldanha * * Implements the http_stat_code keyword */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-content.h" #include "detect-pcre.h" #include "detect-engine-mpm.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-error.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-spm.h" #include "util-print.h" #include "app-layer.h" #include "app-layer-htp.h" #include "detect-http-stat-code.h" #include "stream-tcp-private.h" #include "stream-tcp.h" int DetectHttpStatCodeMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t , void *, Signature *, SigMatch *); static int DetectHttpStatCodeSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpStatCodeRegisterTests(void); void DetectHttpStatCodeFree(void *); /** * \brief Registration function for keyword: http_stat_code */ void DetectHttpStatCodeRegister (void) { sigmatch_table[DETECT_AL_HTTP_STAT_CODE].name = "http_stat_code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].desc = "content modifier to match only on HTTP stat-code-buffer"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_stat_code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Match = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Free = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].RegisterTests = DetectHttpStatCodeRegisterTests; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_PAYLOAD; } /** * \brief this function setups the http_stat_code modifier keyword used in the rule * * \param de_ctx Pointer to the Detection Engine Context * \param s Pointer to the Signature to which the current keyword belongs * \param str Should hold an empty string always * * \retval 0 On success * \retval -1 On failure */ static int DetectHttpStatCodeSetup (DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectContentData *cd = NULL; SigMatch *sm = NULL; if (arg != NULL && strcmp(arg, "") != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_code supplied with args"); return -1; } sm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); /* if still we are unable to find any content previous keywords, it is an * invalid rule */ if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_stat_code\" keyword " "found inside the rule without a content context. " "Please use a \"content\" keyword before using the " "\"http_stat_code\" keyword"); return -1; } cd = (DetectContentData *)sm->ctx; /* http_stat_msg should not be used with the rawbytes rule */ if (cd->flags & DETECT_CONTENT_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_code rule can not " "be used with the rawbytes rule keyword"); return -1; } if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " "alproto set"); goto error; } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, sm->prev, DETECT_PCRE, sm->prev); /* pm can be NULL now. To accomodate parsing sigs like - * content:one; http_modifier; content:two; distance:0; http_modifier */ if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; } else { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT; } } /* if (pm != NULL) */ /* reassigning pm */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_code seen with a " "distance or within without a previous http_stat_code " "content. Invalidating signature."); goto error; } if (pm->type == DETECT_PCRE) { DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } else { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } } cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HSCDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hcbdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HSCDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; return 0; error: return -1; } #ifdef UNITTESTS /** * \test Checks if a http_stat_code is registered in a Signature, if content is not * specified in the signature or rawbyes is specified or fast_pattern is * provided in the signature. */ int DetectHttpStatCodeTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; if ((de_ctx = DetectEngineCtxInit()) == NULL) { printf("DetectEngineCtxInit failed: "); goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_code\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) { printf("sid 1 parse failed to error out: "); goto end; } de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_code\"; content:\"|FF F1|\";" " rawbytes; http_stat_code; sid:2;)"); if (de_ctx->sig_list != NULL) { printf("sid 2 parse failed to error out: "); goto end; } de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_code\"; content:\"100\";" "fast_pattern; http_stat_code; sid:3;)"); if (de_ctx->sig_list == NULL) { printf("sid 3 parse failed: "); goto end; } if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { goto end; } result = 1; end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Checks if a http_stat_code is registered in a Signature and also checks * the nocase */ int DetectHttpStatCodeTest02(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_stat_code\"; content:\"one\"; " "http_stat_code; content:\"200\"; http_stat_code; " "content:\"two hundred\"; nocase; http_stat_code; " "sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; } SigMatch *prev = NULL; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { result = 1; } else { printf("expected DETECT_CONTENT for http_stat_code, got %d: ", sm->type); goto end; } prev = sm; sm = sm->next; } if (! (((DetectContentData *)prev->ctx)->flags & DETECT_CONTENT_NOCASE)) { result = 0; } end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** \test Check the signature working to alert when http_stat_code is matched . */ static int DetectHttpStatCodeSigTest01(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("DetectEngineCtxInit failed: "); goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP status code\"; content:\"200\"; http_stat_code; sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_stat_code is not matched . */ static int DetectHttpStatCodeSigTest02(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP status code\"; content:\"no\"; " "http_stat_code; sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " "Status code\"; content:\"100\";" "http_stat_code; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't: "); goto end; } if ((PacketAlertCheck(p, 2))) { printf("sid 2 match but shouldn't have: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_stat_code is matched for * for nocase or not */ static int DetectHttpStatCodeSigTest03(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 FAIL OK\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP status code\"; content:\"FAIL\"; " "http_stat_code; sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " "Status code nocase\"; content:\"fail\"; nocase; " "http_stat_code; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** \test Check the signature working to alert when http_stat_code is matched for * for negatoin or not */ static int DetectHttpStatCodeSigTest04(void) { int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\n\r\n"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP status code\"; content:\"200\"; " "http_stat_code; sid:1;)"); if (s == NULL) { goto end; } s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " "Status code negation\"; content:!\"100\"; nocase; " "http_stat_code; sid:2;)"); if (s->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } if (!(PacketAlertCheck(p, 2))) { printf("sid 2 didn't match but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); } StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief Register the UNITTESTS for the http_stat_code keyword */ void DetectHttpStatCodeRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectHttpStatCodeTest01", DetectHttpStatCodeTest01, 1); UtRegisterTest("DetectHttpStatCodeTest02", DetectHttpStatCodeTest02, 1); UtRegisterTest("DetectHttpStatCodeSigTest01", DetectHttpStatCodeSigTest01, 1); UtRegisterTest("DetectHttpStatCodeSigTest02", DetectHttpStatCodeSigTest02, 1); UtRegisterTest("DetectHttpStatCodeSigTest03", DetectHttpStatCodeSigTest03, 1); UtRegisterTest("DetectHttpStatCodeSigTest04", DetectHttpStatCodeSigTest04, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/tmqh-flow.c0000644000000000000000000003207612253546156013117 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * * Simple output queue handler that makes sure all packets of the same flow * are sent to the same queue. We support different kind of q handlers. Have * a look at "autofp-scheduler" conf to further undertsand the various q * handlers we provide. */ #include "suricata.h" #include "packet-queue.h" #include "decode.h" #include "threads.h" #include "threadvars.h" #include "tmqh-flow.h" #include "tm-queuehandlers.h" #include "conf.h" #include "util-unittest.h" Packet *TmqhInputFlow(ThreadVars *t); void TmqhOutputFlowHash(ThreadVars *t, Packet *p); void TmqhOutputFlowActivePackets(ThreadVars *t, Packet *p); void TmqhOutputFlowRoundRobin(ThreadVars *t, Packet *p); void *TmqhOutputFlowSetupCtx(char *queue_str); void TmqhOutputFlowFreeCtx(void *ctx); void TmqhFlowRegisterTests(void); void TmqhFlowRegister(void) { tmqh_table[TMQH_FLOW].name = "flow"; tmqh_table[TMQH_FLOW].InHandler = TmqhInputFlow; tmqh_table[TMQH_FLOW].OutHandlerCtxSetup = TmqhOutputFlowSetupCtx; tmqh_table[TMQH_FLOW].OutHandlerCtxFree = TmqhOutputFlowFreeCtx; tmqh_table[TMQH_FLOW].RegisterTests = TmqhFlowRegisterTests; char *scheduler = NULL; if (ConfGet("autofp-scheduler", &scheduler) == 1) { if (strcasecmp(scheduler, "round-robin") == 0) { SCLogInfo("AutoFP mode using \"Round Robin\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowRoundRobin; } else if (strcasecmp(scheduler, "active-packets") == 0) { SCLogInfo("AutoFP mode using \"Active Packets\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; } else if (strcasecmp(scheduler, "hash") == 0) { SCLogInfo("AutoFP mode using \"Hash\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry \"%s\" " "for autofp-scheduler in conf. Killing engine.", scheduler); exit(EXIT_FAILURE); } } else { SCLogInfo("AutoFP mode using default \"Active Packets\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; } return; } /* same as 'simple' */ Packet *TmqhInputFlow(ThreadVars *tv) { PacketQueue *q = &trans_q[tv->inq->id]; SCPerfSyncCountersIfSignalled(tv, 0); SCMutexLock(&q->mutex_q); if (q->len == 0) { /* if we have no packets in queue, wait... */ SCCondWait(&q->cond_q, &q->mutex_q); } if (q->len > 0) { Packet *p = PacketDequeue(q); SCMutexUnlock(&q->mutex_q); return p; } else { /* return NULL if we have no pkt. Should only happen on signals. */ SCMutexUnlock(&q->mutex_q); return NULL; } } static int StoreQueueId(TmqhFlowCtx *ctx, char *name) { Tmq *tmq = TmqGetQueueByName(name); if (tmq == NULL) { tmq = TmqCreateQueue(SCStrdup(name)); if (tmq == NULL) return -1; } tmq->writer_cnt++; uint16_t id = tmq->id; if (ctx->queues == NULL) { ctx->size = 1; ctx->queues = SCMalloc(ctx->size * sizeof(TmqhFlowMode)); if (ctx->queues == NULL) { return -1; } memset(ctx->queues, 0, ctx->size * sizeof(TmqhFlowMode)); } else { ctx->size++; ctx->queues = SCRealloc(ctx->queues, ctx->size * sizeof(TmqhFlowMode)); if (ctx->queues == NULL) { return -1; } memset(ctx->queues + (ctx->size - 1), 0, sizeof(TmqhFlowMode)); } ctx->queues[ctx->size - 1].q = &trans_q[id]; SC_ATOMIC_INIT(ctx->queues[ctx->size - 1].total_packets); SC_ATOMIC_INIT(ctx->queues[ctx->size - 1].total_flows); return 0; } /** * \brief setup the queue handlers ctx * * Parses a comma separated string "queuename1,queuename2,etc" * and sets the ctx up to devide flows over these queue's. * * \param queue_str comma separated string with output queue names * * \retval ctx queues handlers ctx or NULL in error */ void *TmqhOutputFlowSetupCtx(char *queue_str) { if (queue_str == NULL || strlen(queue_str) == 0) return NULL; TmqhFlowCtx *ctx = SCMalloc(sizeof(TmqhFlowCtx)); if (unlikely(ctx == NULL)) return NULL; memset(ctx,0x00,sizeof(TmqhFlowCtx)); char *str = SCStrdup(queue_str); if (unlikely(str == NULL)) { goto error; } char *tstr = str; /* parse the comma separated string */ do { char *comma = strchr(tstr,','); if (comma != NULL) { *comma = '\0'; char *qname = tstr; int r = StoreQueueId(ctx,qname); if (r < 0) goto error; } else { char *qname = tstr; int r = StoreQueueId(ctx,qname); if (r < 0) goto error; } tstr = comma ? (comma + 1) : comma; } while (tstr != NULL); SC_ATOMIC_INIT(ctx->round_robin_idx); SCFree(str); return (void *)ctx; error: SCFree(ctx); if (str != NULL) SCFree(str); return NULL; } void TmqhOutputFlowFreeCtx(void *ctx) { int i; TmqhFlowCtx *fctx = (TmqhFlowCtx *)ctx; SCLogInfo("AutoFP - Total flow handler queues - %" PRIu16, fctx->size); for (i = 0; i < fctx->size; i++) { SCLogInfo("AutoFP - Queue %-2"PRIu32 " - pkts: %-12"PRIu64" flows: %-12"PRIu64, i, SC_ATOMIC_GET(fctx->queues[i].total_packets), SC_ATOMIC_GET(fctx->queues[i].total_flows)); SC_ATOMIC_DESTROY(fctx->queues[i].total_packets); SC_ATOMIC_DESTROY(fctx->queues[i].total_flows); } SCFree(fctx->queues); return; } /** * \brief select the queue to output in a round robin fashion. * * \param tv thread vars * \param p packet */ void TmqhOutputFlowRoundRobin(ThreadVars *tv, Packet *p) { int32_t qid = 0; TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; /* if no flow we use the first queue, * should be rare */ if (p->flow != NULL) { qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); if (qid == -1) { qid = SC_ATOMIC_ADD(ctx->round_robin_idx, 1); if (qid >= ctx->size) { SC_ATOMIC_RESET(ctx->round_robin_idx); qid = 0; } (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); } } else { qid = ctx->last++; if (ctx->last == ctx->size) ctx->last = 0; } (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); PacketQueue *q = ctx->queues[qid].q; SCMutexLock(&q->mutex_q); PacketEnqueue(q, p); SCCondSignal(&q->cond_q); SCMutexUnlock(&q->mutex_q); return; } /** * \brief select the queue to output to based on queue lengths. * * \param tv thread vars * \param p packet */ void TmqhOutputFlowActivePackets(ThreadVars *tv, Packet *p) { int32_t qid = 0; TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; /* if no flow we use the first queue, * should be rare */ if (p->flow != NULL) { qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); if (qid == -1) { uint16_t i = 0; int lowest_id = 0; TmqhFlowMode *queues = ctx->queues; uint32_t lowest = queues[i].q->len; for (i = 1; i < ctx->size; i++) { if (queues[i].q->len < lowest) { lowest = queues[i].q->len; lowest_id = i; } } qid = lowest_id; (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, lowest_id); (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); } } else { qid = ctx->last++; if (ctx->last == ctx->size) ctx->last = 0; } (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); PacketQueue *q = ctx->queues[qid].q; SCMutexLock(&q->mutex_q); PacketEnqueue(q, p); SCCondSignal(&q->cond_q); SCMutexUnlock(&q->mutex_q); return; } /** * \brief select the queue to output based on address hash. * * \param tv thread vars. * \param p packet. */ void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) { int32_t qid = 0; TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; /* if no flow we use the first queue, * should be rare */ if (p->flow != NULL) { qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); if (qid == -1) { #if __WORDSIZE == 64 uint64_t addr = (uint64_t)p->flow; #else uint32_t addr = (uint32_t)p->flow; #endif addr >>= 7; /* we don't have to worry about possible overflow, since * ctx->size will be lesser than 2 ** 31 for sure */ qid = addr % ctx->size; (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); } } else { qid = ctx->last++; if (ctx->last == ctx->size) ctx->last = 0; } (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); PacketQueue *q = ctx->queues[qid].q; SCMutexLock(&q->mutex_q); PacketEnqueue(q, p); SCCondSignal(&q->cond_q); SCMutexUnlock(&q->mutex_q); return; } #ifdef UNITTESTS static int TmqhOutputFlowSetupCtxTest01(void) { int retval = 0; Tmq *tmq = NULL; TmqhFlowCtx *fctx = NULL; TmqResetQueues(); tmq = TmqCreateQueue("queue1"); if (tmq == NULL) goto end; tmq = TmqCreateQueue("queue2"); if (tmq == NULL) goto end; tmq = TmqCreateQueue("another"); if (tmq == NULL) goto end; tmq = TmqCreateQueue("yetanother"); if (tmq == NULL) goto end; char *str = "queue1,queue2,another,yetanother"; void *ctx = TmqhOutputFlowSetupCtx(str); if (ctx == NULL) goto end; fctx = (TmqhFlowCtx *)ctx; if (fctx->size != 4) goto end; if (fctx->queues == NULL) goto end; if (fctx->queues[0].q != &trans_q[0]) goto end; if (fctx->queues[1].q != &trans_q[1]) goto end; if (fctx->queues[2].q != &trans_q[2]) goto end; if (fctx->queues[3].q != &trans_q[3]) goto end; retval = 1; end: if (fctx != NULL) TmqhOutputFlowFreeCtx(fctx); TmqResetQueues(); return retval; } static int TmqhOutputFlowSetupCtxTest02(void) { int retval = 0; Tmq *tmq = NULL; TmqhFlowCtx *fctx = NULL; TmqResetQueues(); tmq = TmqCreateQueue("queue1"); if (tmq == NULL) goto end; tmq = TmqCreateQueue("queue2"); if (tmq == NULL) goto end; tmq = TmqCreateQueue("another"); if (tmq == NULL) goto end; tmq = TmqCreateQueue("yetanother"); if (tmq == NULL) goto end; char *str = "queue1"; void *ctx = TmqhOutputFlowSetupCtx(str); if (ctx == NULL) goto end; fctx = (TmqhFlowCtx *)ctx; if (fctx->size != 1) goto end; if (fctx->queues == NULL) goto end; if (fctx->queues[0].q != &trans_q[0]) goto end; retval = 1; end: if (fctx != NULL) TmqhOutputFlowFreeCtx(fctx); TmqResetQueues(); return retval; } static int TmqhOutputFlowSetupCtxTest03(void) { int retval = 0; TmqhFlowCtx *fctx = NULL; TmqResetQueues(); char *str = "queue1,queue2,another,yetanother"; void *ctx = TmqhOutputFlowSetupCtx(str); if (ctx == NULL) goto end; fctx = (TmqhFlowCtx *)ctx; if (fctx->size != 4) goto end; if (fctx->queues == NULL) goto end; if (fctx->queues[0].q != &trans_q[0]) goto end; if (fctx->queues[1].q != &trans_q[1]) goto end; if (fctx->queues[2].q != &trans_q[2]) goto end; if (fctx->queues[3].q != &trans_q[3]) goto end; retval = 1; end: if (fctx != NULL) TmqhOutputFlowFreeCtx(fctx); TmqResetQueues(); return retval; } #endif /* UNITTESTS */ void TmqhFlowRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("TmqhOutputFlowSetupCtxTest01", TmqhOutputFlowSetupCtxTest01, 1); UtRegisterTest("TmqhOutputFlowSetupCtxTest02", TmqhOutputFlowSetupCtxTest02, 1); UtRegisterTest("TmqhOutputFlowSetupCtxTest03", TmqhOutputFlowSetupCtxTest03, 1); #endif return; } suricata-1.4.7/src/detect-ack.c0000644000000000000000000001747312253546156013211 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus * * Implements the "ack" keyword. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-ack.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" /* prototypes */ static int DetectAckSetup(DetectEngineCtx *, Signature *, char *); static int DetectAckMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static void DetectAckRegisterTests(void); static void DetectAckFree(void *); void DetectAckRegister(void) { sigmatch_table[DETECT_ACK].name = "ack"; sigmatch_table[DETECT_ACK].desc = "check for a specific TCP acknowledgement number"; sigmatch_table[DETECT_ACK].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ack"; sigmatch_table[DETECT_ACK].Match = DetectAckMatch; sigmatch_table[DETECT_ACK].Setup = DetectAckSetup; sigmatch_table[DETECT_ACK].Free = DetectAckFree; sigmatch_table[DETECT_ACK].RegisterTests = DetectAckRegisterTests; } /** * \internal * \brief This function is used to match packets with a given Ack number * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectAckData * * \retval 0 no match * \retval 1 match */ static int DetectAckMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectAckData *data = (DetectAckData *)m->ctx; /* This is only needed on TCP packets */ if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { return 0; } return (data->ack == TCP_GET_ACK(p)) ? 1 : 0; } /** * \internal * \brief this function is used to add the ack option into the signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param m pointer to the Current SigMatch * \param optstr pointer to the user provided options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectAckSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { DetectAckData *data; SigMatch *sm = NULL; data = SCMalloc(sizeof(DetectAckData)); if (unlikely(data == NULL)) goto error; sm = SigMatchAlloc(); if (sm == NULL) { goto error; } sm->type = DETECT_ACK; if (-1 == ByteExtractStringUint32(&data->ack, 10, 0, optstr)) { goto error; } sm->ctx = data; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (data) SCFree(data); return -1; } /** * \internal * \brief this function will free memory associated with ack option * * \param data pointer to ack configuration data */ static void DetectAckFree(void *ptr) { DetectAckData *data = (DetectAckData *)ptr; SCFree(data); } #ifdef UNITTESTS /** * \internal * \brief This test tests sameip success and failure. */ static int DetectAckSigTest01Real(int mpm_type) { Packet *p1 = NULL; Packet *p2 = NULL; Packet *p3 = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); /* TCP w/ack=42 */ p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p1->tcph->th_ack = htonl(42); /* TCP w/ack=100 */ p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2->tcph->th_ack = htonl(100); /* ICMP */ p3 = UTHBuildPacket(NULL, 0, IPPROTO_ICMP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; /* These three are crammed in here as there is no Parse */ if (SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing ack\";ack:foo;sid:1;)") != NULL) { printf("invalid ack accepted: "); goto cleanup_engine; } if (SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing ack\";ack:9999999999;sid:1;)") != NULL) { printf("overflowing ack accepted: "); goto cleanup_engine; } if (SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing ack\";ack:-100;sid:1;)") != NULL) { printf("negative ack accepted: "); goto cleanup_engine; } de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing ack\";ack:41;sid:1;)"); if (de_ctx->sig_list == NULL) { goto cleanup_engine; } de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing ack\";ack:42;sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto cleanup_engine; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1) != 0) { printf("sid 1 alerted, but should not have: "); goto cleanup; } if (PacketAlertCheck(p1, 2) == 0) { printf("sid 2 did not alert, but should have: "); goto cleanup; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1) != 0) { printf("sid 1 alerted, but should not have: "); goto cleanup; } if (PacketAlertCheck(p2, 2) != 0) { printf("sid 2 alerted, but should not have: "); goto cleanup; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p3); if (PacketAlertCheck(p3, 1) != 0) { printf("sid 1 alerted, but should not have: "); goto cleanup; } if (PacketAlertCheck(p3, 2) != 0) { printf("sid 2 alerted, but should not have: "); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); cleanup_engine: DetectEngineCtxFree(de_ctx); end: return result; } /** * \test DetectAckSigTest01B2g tests sameip under B2g MPM */ static int DetectAckSigTest01B2g(void) { return DetectAckSigTest01Real(MPM_B2G); } /** * \test DetectAckSigTest01B2g tests sameip under B3g MPM */ static int DetectAckSigTest01B3g(void) { return DetectAckSigTest01Real(MPM_B3G); } /** * \test DetectAckSigTest01B2g tests sameip under WuManber MPM */ static int DetectAckSigTest01Wm(void) { return DetectAckSigTest01Real(MPM_WUMANBER); } #endif /* UNITTESTS */ /** * \internal * \brief This function registers unit tests for DetectAck */ static void DetectAckRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectAckSigTest01B2g", DetectAckSigTest01B2g, 1); UtRegisterTest("DetectAckSigTest01B3g", DetectAckSigTest01B3g, 1); UtRegisterTest("DetectAckSigTest01Wm", DetectAckSigTest01Wm, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-ssh-software-version.h0000644000000000000000000000231312253546156016553 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __DETECT_SSH_SOFTWARE_VERSION_H__ #define __DETECT_SSH_SOFTWARE_VERSION_H__ typedef struct DetectSshSoftwareVersionData_ { uint8_t *software_ver; /** ssh version to match */ uint16_t len; /** ssh version length to match */ } DetectSshSoftwareVersionData; /* prototypes */ void DetectSshSoftwareVersionRegister(void); void DetectSshSoftwareVersionRegisterTests(void); #endif /* __DETECT_SSH_SOFTWARE_VERSION_H__ */ suricata-1.4.7/src/util-spm.h0000644000000000000000000000443712253546156012760 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo */ #ifndef __UTIL_SPM_H__ #define __UTIL_SPM_H__ #include "util-spm-bs.h" #include "util-spm-bs2bm.h" #include "util-spm-bm.h" /** Default algorithm to use: Boyer Moore */ uint8_t *Bs2bmSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); uint8_t *Bs2bmNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); uint8_t *BoyerMooreSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); uint8_t *BoyerMooreNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); /* Macros for automatic algorithm selection (use them only when you can't store the context) */ #define SpmSearch(text, textlen, needle, needlelen) ({\ uint8_t *mfound; \ if (needlelen < 4 && textlen < 512) \ mfound = BasicSearch(text, textlen, needle, needlelen); \ else if (needlelen < 4) \ mfound = BasicSearch(text, textlen, needle, needlelen); \ else \ mfound = BoyerMooreSearch(text, textlen, needle, needlelen); \ mfound; \ }) #define SpmNocaseSearch(text, textlen, needle, needlelen) ({\ uint8_t *mfound; \ if (needlelen < 4 && textlen < 512) \ mfound = BasicSearchNocase(text, textlen, needle, needlelen); \ else if (needlelen < 4) \ mfound = BasicSearchNocase(text, textlen, needle, needlelen); \ else \ mfound = BoyerMooreNocaseSearch(text, textlen, needle, needlelen); \ mfound; \ }) void UtilSpmSearchRegistertests(void); #endif /* __UTIL_SPM_H__ */ suricata-1.4.7/src/detect.c0000644000000000000000000140441612253546156012453 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Basic detection engine */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "flow-private.h" #include "flow-bit.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-alert.h" #include "detect-engine-siggroup.h" #include "detect-engine-address.h" #include "detect-engine-proto.h" #include "detect-engine-port.h" #include "detect-engine-mpm.h" #include "detect-engine-iponly.h" #include "detect-engine-threshold.h" #include "detect-engine-payload.h" #include "detect-engine-dcepayload.h" #include "detect-engine-uri.h" #include "detect-engine-state.h" #include "detect-engine-analyzer.h" #include "detect-http-cookie.h" #include "detect-http-method.h" #include "detect-http-ua.h" #include "detect-http-hh.h" #include "detect-http-hrh.h" #include "detect-engine-event.h" #include "decode.h" #include "detect-ipopts.h" #include "detect-flags.h" #include "detect-fragbits.h" #include "detect-fragoffset.h" #include "detect-gid.h" #include "detect-ack.h" #include "detect-seq.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-pcre.h" #include "detect-depth.h" #include "detect-nocase.h" #include "detect-rawbytes.h" #include "detect-bytetest.h" #include "detect-bytejump.h" #include "detect-sameip.h" #include "detect-l3proto.h" #include "detect-ipproto.h" #include "detect-within.h" #include "detect-distance.h" #include "detect-offset.h" #include "detect-sid.h" #include "detect-priority.h" #include "detect-classtype.h" #include "detect-reference.h" #include "detect-tag.h" #include "detect-threshold.h" #include "detect-metadata.h" #include "detect-msg.h" #include "detect-rev.h" #include "detect-flow.h" #include "detect-window.h" #include "detect-ftpbounce.h" #include "detect-isdataat.h" #include "detect-id.h" #include "detect-rpc.h" #include "detect-asn1.h" #include "detect-filename.h" #include "detect-fileext.h" #include "detect-filestore.h" #include "detect-filemagic.h" #include "detect-filemd5.h" #include "detect-filesize.h" #include "detect-dsize.h" #include "detect-flowvar.h" #include "detect-flowint.h" #include "detect-pktvar.h" #include "detect-noalert.h" #include "detect-flowbits.h" #include "detect-csum.h" #include "detect-stream_size.h" #include "detect-engine-sigorder.h" #include "detect-ttl.h" #include "detect-fast-pattern.h" #include "detect-itype.h" #include "detect-icode.h" #include "detect-icmp-id.h" #include "detect-icmp-seq.h" #include "detect-dce-iface.h" #include "detect-dce-opnum.h" #include "detect-dce-stub-data.h" #include "detect-urilen.h" #include "detect-detection-filter.h" #include "detect-http-client-body.h" #include "detect-http-server-body.h" #include "detect-http-header.h" #include "detect-http-raw-header.h" #include "detect-http-uri.h" #include "detect-http-raw-uri.h" #include "detect-http-stat-msg.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" #include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-hsmd.h" #include "detect-engine-hscd.h" #include "detect-engine-hua.h" #include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" #include "detect-byte-extract.h" #include "detect-file-data.h" #include "detect-pkt-data.h" #include "detect-replace.h" #include "detect-tos.h" #include "detect-app-layer-event.h" #include "detect-luajit.h" #include "detect-iprep.h" #include "detect-geoip.h" #include "util-rule-vars.h" #include "app-layer.h" #include "app-layer-protos.h" #include "app-layer-htp.h" #include "detect-tls.h" #include "detect-tls-version.h" #include "detect-ssh-proto-version.h" #include "detect-ssh-software-version.h" #include "detect-http-stat-code.h" #include "detect-ssl-version.h" #include "detect-ssl-state.h" #include "action-globals.h" #include "tm-threads.h" #include "pkt-var.h" #include "flow-alert-sid.h" #include "conf.h" #include "conf-yaml-loader.h" #include "stream-tcp.h" #include "stream-tcp-inline.h" #include "util-var-name.h" #include "util-classification-config.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" #include "util-hashlist.h" #include "util-cuda-handlers.h" #include "util-mpm-b2g-cuda.h" #include "util-cuda.h" #include "util-privs.h" #include "util-profiling.h" #include "util-validate.h" #include "util-optimize.h" #include "util-vector.h" #include "util-path.h" #include "runmodes.h" extern uint8_t engine_mode; extern int rule_reload; extern int engine_analysis; static int fp_engine_analysis_set = 0; static int rule_engine_analysis_set = 0; SigMatch *SigMatchAlloc(void); void DetectExitPrintStats(ThreadVars *tv, void *data); void DbgPrintSigs(DetectEngineCtx *, SigGroupHead *); void DbgPrintSigs2(DetectEngineCtx *, SigGroupHead *); static void PacketCreateMask(Packet *, SignatureMask *, uint16_t, void *, StreamMsg *, int); /* tm module api functions */ TmEcode Detect(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode DetectThreadInit(ThreadVars *, void *, void **); TmEcode DetectThreadDeinit(ThreadVars *, void *); void TmModuleDetectRegister (void) { tmm_modules[TMM_DETECT].name = "Detect"; tmm_modules[TMM_DETECT].ThreadInit = DetectThreadInit; tmm_modules[TMM_DETECT].Func = Detect; tmm_modules[TMM_DETECT].ThreadExitPrintStats = DetectExitPrintStats; tmm_modules[TMM_DETECT].ThreadDeinit = DetectThreadDeinit; tmm_modules[TMM_DETECT].RegisterTests = SigRegisterTests; tmm_modules[TMM_DETECT].cap_flags = 0; tmm_modules[TMM_DETECT].flags = TM_FLAG_DETECT_TM; PacketAlertTagInit(); } void DetectExitPrintStats(ThreadVars *tv, void *data) { DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; if (det_ctx == NULL) return; } /** * \brief Create the path if default-rule-path was specified * \param sig_file The name of the file * \retval str Pointer to the string path + sig_file */ char *DetectLoadCompleteSigPath(char *sig_file) { char *defaultpath = NULL; char *path = NULL; /* Path not specified */ if (PathIsRelative(sig_file)) { if (ConfGet("default-rule-path", &defaultpath) == 1) { SCLogDebug("Default path: %s", defaultpath); size_t path_len = sizeof(char) * (strlen(defaultpath) + strlen(sig_file) + 2); path = SCMalloc(path_len); if (unlikely(path == NULL)) return NULL; strlcpy(path, defaultpath, path_len); #if defined OS_WIN32 || defined __CYGWIN__ if (path[strlen(path) - 1] != '\\') strlcat(path, "\\\\", path_len); #else if (path[strlen(path) - 1] != '/') strlcat(path, "/", path_len); #endif strlcat(path, sig_file, path_len); } else { path = SCStrdup(sig_file); if (unlikely(path == NULL)) return NULL; } } else { path = SCStrdup(sig_file); if (unlikely(path == NULL)) return NULL; } return path; } /** * \brief Load a file with signatures * \param de_ctx Pointer to the detection engine context * \param sig_file Filename to load signatures from * \param sigs_tot Will store number of signatures processed in the file * \retval Number of rules loaded successfully, -1 on error */ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) { Signature *sig = NULL; int good = 0, bad = 0; char line[8192] = ""; size_t offset = 0; int lineno = 0, multiline = 0; if (sig_file == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "opening rule file null"); return -1; } FILE *fp = fopen(sig_file, "r"); if (fp == NULL) { SCLogError(SC_ERR_OPENING_RULE_FILE, "opening rule file %s:" " %s.", sig_file, strerror(errno)); return -1; } while(fgets(line + offset, (int)sizeof(line) - offset, fp) != NULL) { lineno++; size_t len = strlen(line); /* ignore comments and empty lines */ if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') continue; /* Check for multiline rules. */ while (len > 0 && isspace((unsigned char)line[--len])); if (line[len] == '\\') { multiline++; offset = len; if (offset < sizeof(line) - 1) { /* We have room for more. */ continue; } /* No more room in line buffer, continue, rule will fail * to parse. */ } /* Check if we have a trailing newline, and remove it */ len = strlen(line); if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { line[len - 1] = '\0'; } /* Reset offset. */ offset = 0; de_ctx->rule_file = sig_file; de_ctx->rule_line = lineno - multiline; sig = DetectEngineAppendSig(de_ctx, line); (*sigs_tot)++; if (sig != NULL) { if (rule_engine_analysis_set || fp_engine_analysis_set) { sig->mpm_sm = RetrieveFPForSig(sig); if (fp_engine_analysis_set) { EngineAnalysisFP(sig, line); } if (rule_engine_analysis_set) { EngineAnalysisRules(sig, line); } } SCLogDebug("signature %"PRIu32" loaded", sig->id); good++; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "error parsing signature \"%s\" from " "file %s at line %"PRId32"", line, sig_file, lineno - multiline); if (rule_engine_analysis_set) { EngineAnalysisRulesFailure(line, sig_file, lineno - multiline); } if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); } bad++; } multiline = 0; } fclose(fp); return good; } /** * \brief Load signatures * \param de_ctx Pointer to the detection engine context * \param sig_file Filename holding signatures * \param sig_file_exclusive File passed in 'sig_file' should be loaded exclusively. * \retval -1 on error */ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_exclusive) { SCEnter(); ConfNode *rule_files; ConfNode *file = NULL; int ret = 0; int r = 0; int cnt = 0; int cntf = 0; int sigtotal = 0; char *sfile = NULL; if (engine_analysis) { fp_engine_analysis_set = SetupFPAnalyzer(); rule_engine_analysis_set = SetupRuleAnalyzer(); } /* ok, let's load signature files from the general config */ if (!(sig_file != NULL && sig_file_exclusive == TRUE)) { rule_files = ConfGetNode("rule-files"); if (rule_files != NULL) { TAILQ_FOREACH(file, &rule_files->head, next) { sfile = DetectLoadCompleteSigPath(file->val); SCLogDebug("Loading rule file: %s", sfile); r = DetectLoadSigFile(de_ctx, sfile, &sigtotal); cntf++; if (r > 0) { cnt += r; } else if (r == 0){ SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sfile); if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); } } else if (r < 0){ if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); } } SCFree(sfile); } } } /* If a Signature file is specified from commandline, parse it too */ if (sig_file != NULL) { SCLogInfo("Loading rule file: %s", sig_file); r = DetectLoadSigFile(de_ctx, sig_file, &sigtotal); cntf++; if (r > 0) { cnt += r; } else if (r == 0) { SCLogError(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); } } else if (r < 0){ if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); } } } /* now we should have signatures to work with */ if (cnt <= 0) { if (cntf > 0) { SCLogError(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", cntf); if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); } ret = -1; } else { SCLogInfo("No signatures supplied."); goto end; } } else { /* we report the total of files and rules successfully loaded and failed */ SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", cntf, cnt, sigtotal-cnt); } if (ret < 0 && de_ctx->failure_fatal) { goto end; } SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); /* Setup the signature group lookup structure and pattern matchers */ SigGroupBuild(de_ctx); ret = 0; end: if (engine_analysis) { if (rule_engine_analysis_set) { CleanupRuleAnalyzer(); } if (fp_engine_analysis_set) { CleanupFPAnalyzer(); } } DetectParseDupSigHashFree(de_ctx); SCReturnInt(ret); } /** * \brief See if we can prefilter a signature on inexpensive checks * * Order of SignatureHeader access: * 1. flags * 2. alproto * 3. mpm_pattern_id_div8 * 4. mpm_pattern_id_mod8 * 5. num * * \retval 0 can't match, don't inspect * \retval 1 might match, further inspection required */ static inline int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThreadCtx *det_ctx, Packet *p, SignatureHeader *s, uint16_t alproto) { /* if the sig has alproto and the session as well they should match */ if (likely(s->flags & SIG_FLAG_APPLAYER)) { if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { if (s->alproto == ALPROTO_DCERPC) { if (alproto != ALPROTO_SMB && alproto != ALPROTO_SMB2) { SCLogDebug("DCERPC sig, alproto not SMB or SMB2"); return 0; } } else { SCLogDebug("alproto mismatch"); return 0; } } } if (unlikely(s->flags & SIG_FLAG_DSIZE)) { if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", p->payload_len, s->dsize_low, s->dsize_high); return 0; } } /* check for a pattern match of the one pattern in this sig. */ if (likely(s->flags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_HTTP))) { /* filter out sigs that want pattern matches, but * have no matches */ if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { if (s->flags & SIG_FLAG_MPM_PACKET) { if (!(s->flags & SIG_FLAG_MPM_PACKET_NEG)) { return 0; } } else if (s->flags & SIG_FLAG_MPM_STREAM) { /* filter out sigs that want pattern matches, but * have no matches */ if (!(s->flags & SIG_FLAG_MPM_STREAM_NEG)) { return 0; } } else if (s->flags & SIG_FLAG_MPM_HTTP) { if (!(s->flags & SIG_FLAG_MPM_HTTP_NEG)) { return 0; } } } } /* de_state check, filter out all signatures that already had a match before * or just partially match */ if (s->flags & SIG_FLAG_STATE_MATCH) { /* we run after DeStateDetectContinueDetection, so we might have * state NEW here. In that case we'd want to continue detection * for this sig. If we have NOSTATE, stateful detection didn't * start yet for this sig, so we will inspect it. */ if (det_ctx->de_state_sig_array[s->num] != DE_STATE_MATCH_NEW && det_ctx->de_state_sig_array[s->num] != DE_STATE_MATCH_NOSTATE) { SCLogDebug("de state not NEW or NOSTATE, ignoring"); return 0; } } return 1; } #if defined(__SSE3__) /** * \brief SIMD implementation of mask prefiltering. * * Mass mask matching is done creating a bitmap of signatures that need * futher inspection. * * On 32 bit systems we inspect in 32 sig batches, creating a u32 with flags. * On 64 bit systems we inspect in 64 sig batches, creating a u64 with flags. * The size of a register is leading here. */ static inline void SigMatchSignaturesBuildMatchArraySIMD(DetectEngineThreadCtx *det_ctx, Packet *p, SignatureMask mask, uint16_t alproto) { uint32_t u; SigIntId x; int bitno = 0; #if __WORDSIZE == 32 register uint32_t bm; /* bit mask, 32 bits used */ Vector pm, sm, r1, r2; /* load the packet mask into each byte of the vector */ pm.v = _mm_set1_epi8(mask); /* reset previous run */ det_ctx->match_array_cnt = 0; for (u = 0; u < det_ctx->sgh->sig_cnt; u += 32) { /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u]); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); /* convert into a bitarray */ bm = ((uint32_t) _mm_movemask_epi8(r2.v)); SCLogDebug("bm1 %08x", bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+16]); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); /* convert into a bitarray */ bm |= ((uint32_t) _mm_movemask_epi8(r2.v) << 16); SCLogDebug("bm2 %08x", bm); if (bm == 0) { continue; } /* Check each bit in the bit map. Little endian is assumed (SSE is x86), * so the bits are in memory backwards, 0 is on the right edge, * 31 on the left edge. This is why above we store the output of the * _mm_movemask_epi8 in this order as well */ bitno = 0; for (x = u; x < det_ctx->sgh->sig_cnt && bitno < 32; x++, bitno++) { if (bm & (1 << bitno)) { SignatureHeader *s = &det_ctx->sgh->head_array[x]; if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { /* okay, store it */ det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; det_ctx->match_array_cnt++; } } } } #elif __WORDSIZE == 64 register uint64_t bm; /* bit mask, 64 bits used */ Vector pm, sm, r1, r2; /* load the packet mask into each byte of the vector */ pm.v = _mm_set1_epi8(mask); /* reset previous run */ det_ctx->match_array_cnt = 0; for (u = 0; u < det_ctx->sgh->sig_cnt; u += 64) { /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u]); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); /* convert into a bitarray */ bm = ((uint64_t) _mm_movemask_epi8(r2.v)); SCLogDebug("bm1 %08"PRIx64, bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+16]); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); /* convert into a bitarray */ bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+32]); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); /* convert into a bitarray */ bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+48]); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); /* convert into a bitarray */ bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 48; SCLogDebug("bm2 %08"PRIx64, bm); if (bm == 0) { continue; } /* Check each bit in the bit map. Little endian is assumed (SSE is x86-64), * so the bits are in memory backwards, 0 is on the right edge, * 63 on the left edge. This is why above we store the output of the * _mm_movemask_epi8 in this order as well */ bitno = 0; for (x = u; x < det_ctx->sgh->sig_cnt && bitno < 64; x++, bitno++) { if (bm & ((uint64_t)1 << bitno)) { SignatureHeader *s = &det_ctx->sgh->head_array[x]; if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { /* okay, store it */ det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; det_ctx->match_array_cnt++; } } } } #else #error Wordsize (__WORDSIZE) neither 32 or 64. #endif } #endif /* defined(__SSE3__) */ static inline void SigMatchSignaturesBuildMatchArrayNoSIMD(DetectEngineThreadCtx *det_ctx, Packet *p, SignatureMask mask, uint16_t alproto) { uint32_t u; /* reset previous run */ det_ctx->match_array_cnt = 0; for (u = 0; u < det_ctx->sgh->sig_cnt; u++) { SignatureHeader *s = &det_ctx->sgh->head_array[u]; if ((mask & s->mask) == s->mask) { if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { /* okay, store it */ det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; det_ctx->match_array_cnt++; } } } } /** * \brief build an array of signatures that will be inspected * * All signatures that can be filtered out on forehand are not added to it. * * \param de_ctx detection engine ctx * \param det_ctx detection engine thread ctx -- array is stored here * \param p packet * \param mask Packets mask * \param alproto application layer protocol */ static void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *det_ctx, Packet *p, SignatureMask mask, uint16_t alproto) { #if defined(__SSE3__) SigMatchSignaturesBuildMatchArraySIMD(det_ctx, p, mask, alproto); #else SigMatchSignaturesBuildMatchArrayNoSIMD(det_ctx, p, mask, alproto); #endif } static int SigMatchSignaturesRunPostMatch(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s) { /* run the packet match functions */ if (s->sm_lists[DETECT_SM_LIST_POSTMATCH] != NULL) { SigMatch *sm = s->sm_lists[DETECT_SM_LIST_POSTMATCH]; SCLogDebug("running match functions, sm %p", sm); for ( ; sm != NULL; sm = sm->next) { (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm); } } DetectReplaceExecute(p, det_ctx->replist); det_ctx->replist = NULL; if (s->flags & SIG_FLAG_FILESTORE) DetectFilestorePostMatch(tv, det_ctx, p, s); return 1; } /** * \brief Get the SigGroupHead for a packet. * * \param de_ctx detection engine context * \param det_ctx thread detection engine content * \param p packet * * \retval sgh the SigGroupHead or NULL if non applies to the packet */ SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) { SCEnter(); int f; SigGroupHead *sgh = NULL; /* if the packet proto is 0 (not set), we're inspecting it against * the decoder events sgh we have. */ if (p->proto == 0 && p->events.cnt > 0) { SCReturnPtr(de_ctx->decoder_event_sgh, "SigGroupHead"); } /* select the flow_gh */ if (p->flowflags & FLOW_PKT_TOCLIENT) f = 0; else f = 1; SCLogDebug("f %d", f); SCLogDebug("IP_GET_IPPROTO(p) %u", IP_GET_IPPROTO(p)); /* find the right mpm instance */ DetectAddress *ag = DetectAddressLookupInHead(de_ctx->flow_gh[f].src_gh[IP_GET_IPPROTO(p)], &p->src); if (ag != NULL) { /* source group found, lets try a dst group */ ag = DetectAddressLookupInHead(ag->dst_gh, &p->dst); if (ag != NULL) { if (ag->port == NULL) { SCLogDebug("we don't have ports"); sgh = ag->sh; } else { SCLogDebug("we have ports"); DetectPort *sport = DetectPortLookupGroup(ag->port,p->sp); if (sport != NULL) { DetectPort *dport = DetectPortLookupGroup(sport->dst_ph,p->dp); if (dport != NULL) { sgh = dport->sh; } else { SCLogDebug("no dst port group found for the packet with dp %"PRIu16"", p->dp); } } else { SCLogDebug("no src port group found for the packet with sp %"PRIu16"", p->sp); } } } else { SCLogDebug("no dst address group found for the packet"); } } else { SCLogDebug("no src address group found for the packet"); } SCReturnPtr(sgh, "SigGroupHead"); } /** \brief Get the smsgs relevant to this packet * * Only for TCP, packets part of ESTABLISHED ssn (PKT_STREAM_EST set) * * \param f LOCKED flow * \param p packet * \param flags stream flags */ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); StreamMsg *smsg = NULL; if (p->proto == IPPROTO_TCP && f->protoctx != NULL && (p->flags & PKT_STREAM_EST)) { TcpSession *ssn = (TcpSession *)f->protoctx; /* at stream eof, or in inline mode, inspect all smsg's */ if ((flags & STREAM_EOF) || StreamTcpInlineMode()) { if (p->flowflags & FLOW_PKT_TOSERVER) { smsg = ssn->toserver_smsg_head; /* deref from the ssn */ ssn->toserver_smsg_head = NULL; ssn->toserver_smsg_tail = NULL; SCLogDebug("to_server smsg %p at stream eof", smsg); } else { smsg = ssn->toclient_smsg_head; /* deref from the ssn */ ssn->toclient_smsg_head = NULL; ssn->toclient_smsg_tail = NULL; SCLogDebug("to_client smsg %p at stream eof", smsg); } } else { if (p->flowflags & FLOW_PKT_TOSERVER) { StreamMsg *head = ssn->toserver_smsg_head; if (unlikely(head == NULL)) { SCLogDebug("no smsgs in to_server direction"); goto end; } /* if the smsg is bigger than the current packet, we will * process the smsg in a later run */ if ((head->data.seq + head->data.data_len) > (TCP_GET_SEQ(p) + p->payload_len)) { SCLogDebug("smsg ends beyond current packet, skipping for now %"PRIu32">%"PRIu32, (head->data.seq + head->data.data_len), (TCP_GET_SEQ(p) + p->payload_len)); goto end; } smsg = head; /* deref from the ssn */ ssn->toserver_smsg_head = NULL; ssn->toserver_smsg_tail = NULL; SCLogDebug("to_server smsg %p", smsg); } else { StreamMsg *head = ssn->toclient_smsg_head; if (unlikely(head == NULL)) goto end; /* if the smsg is bigger than the current packet, we will * process the smsg in a later run */ if ((head->data.seq + head->data.data_len) > (TCP_GET_SEQ(p) + p->payload_len)) { SCLogDebug("smsg ends beyond current packet, skipping for now %"PRIu32">%"PRIu32, (head->data.seq + head->data.data_len), (TCP_GET_SEQ(p) + p->payload_len)); goto end; } smsg = head; /* deref from the ssn */ ssn->toclient_smsg_head = NULL; ssn->toclient_smsg_tail = NULL; SCLogDebug("to_client smsg %p", smsg); } } } end: SCReturnPtr(smsg, "StreamMsg"); } #define SMS_USE_FLOW_SGH 0x01 #define SMS_USED_PM 0x02 #define SMS_USED_STREAM_PM 0x04 /** * \internal * \brief Run mpm on packet, stream and other buffers based on * alproto, sgh state. * * \param de_ctx Pointer to the detection engine context. * \param det_ctx Pointer to the detection engine thread context. * \param smsg The stream segment to inspect for stream mpm. * \param p Packet. * \param flags Flags. * \param alproto Flow alproto. * \param alstate Flow alstate. * \param sms_runflags Used to store state by detection engine. */ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg, Packet *p, uint8_t flags, uint16_t alproto, void *alstate, uint8_t *sms_runflags) { if (p->payload_len > 0 && (!(p->flags & PKT_NOPAYLOAD_INSPECTION))) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_PACKET) { /* run the multi packet matcher against the payload of the packet */ SCLogDebug("search: (%p, maxlen %" PRIu32 ", sgh->sig_cnt %" PRIu32 ")", det_ctx->sgh, det_ctx->sgh->mpm_content_maxlen, det_ctx->sgh->sig_cnt); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_PACKET); PacketPatternSearch(det_ctx, p); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_PACKET); *sms_runflags |= SMS_USED_PM; } if (!(p->flags & PKT_STREAM_ADD) && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_STREAM)) { *sms_runflags |= SMS_USED_PM; PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_PKT_STREAM); PacketPatternSearchWithStreamCtx(det_ctx, p); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_PKT_STREAM); } } /* have a look at the reassembled stream (if any) */ if (p->flowflags & FLOW_PKT_ESTABLISHED) { SCLogDebug("p->flowflags & FLOW_PKT_ESTABLISHED"); if (smsg != NULL && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_STREAM)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_STREAM); StreamPatternSearch(det_ctx, p, smsg, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_STREAM); *sms_runflags |= SMS_USED_STREAM_PM; } else { SCLogDebug("smsg NULL or no stream mpm for this sgh"); } /* all http based mpms */ if (alproto == ALPROTO_HTTP && alstate != NULL) { if (p->flowflags & FLOW_PKT_TOSERVER) { if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_URI) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_URI); DetectUricontentInspectMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_URI); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRUD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRUD); DetectEngineRunHttpRawUriMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRUD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCBD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCBD); DetectEngineRunHttpClientBodyMpm(de_ctx, det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCBD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HMD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HMD); DetectEngineRunHttpMethodMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HMD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HUAD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HUAD); DetectEngineRunHttpUAMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HUAD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHHD); DetectEngineRunHttpHHMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHHD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHHD); DetectEngineRunHttpHRHMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHHD); } } else { /* implied FLOW_PKT_TOCLIENT */ if ((p->flowflags & FLOW_PKT_TOCLIENT) && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSBD)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSBD); DetectEngineRunHttpServerBodyMpm(de_ctx, det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSBD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSMD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSMD); DetectEngineRunHttpStatMsgMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSMD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSCD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSCD); DetectEngineRunHttpStatCodeMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSCD); } } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); DetectEngineRunHttpRawHeaderMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHD); } if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCD); DetectEngineRunHttpCookieMpm(det_ctx, p->flow, alstate, flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCD); } } } else { SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); } } #ifdef DEBUG static void DebugInspectIds(Packet *p, Flow *f, StreamMsg *smsg) { AppLayerParserStateStore *parser_state_store = f->alparser; if (parser_state_store != NULL) { SCLogDebug("pcap_cnt %02"PRIu64", %s, %12s, avail_id %u, inspect_id %u, inspecting %u, smsg %s", p->pcap_cnt, p->flowflags & FLOW_PKT_TOSERVER ? "toserver" : "toclient", p->flags & PKT_STREAM_EST ? "established" : "stateless", parser_state_store->avail_id, parser_state_store->inspect_id, parser_state_store->inspect_id+1, smsg?"yes":"no"); //if (smsg) // PrintRawDataFp(stdout,smsg->data.data, smsg->data.data_len); } } #endif static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEngineCtx *de_ctx) { #define MALLOC_JUMP 5 int i = 0; GenericVar *gv = p->flow->flowvar; while (gv != NULL) { i++; gv = gv->next; } if (i == 0) return; p->debuglog_flowbits_names_len = i; p->debuglog_flowbits_names = SCMalloc(sizeof(char *) * p->debuglog_flowbits_names_len); if (p->debuglog_flowbits_names == NULL) { return; } memset(p->debuglog_flowbits_names, 0, sizeof(char *) * p->debuglog_flowbits_names_len); i = 0; gv = p->flow->flowvar; while (gv != NULL) { if (gv->type != DETECT_FLOWBITS) { gv = gv->next; continue; } FlowBit *fb = (FlowBit *) gv; char *name = VariableIdxGetName(de_ctx, fb->idx, fb->type); if (name != NULL) { p->debuglog_flowbits_names[i] = SCStrdup(name); if (p->debuglog_flowbits_names[i] == NULL) { return; } i++; } if (i == p->debuglog_flowbits_names_len) { p->debuglog_flowbits_names_len += MALLOC_JUMP; p->debuglog_flowbits_names = SCRealloc(p->debuglog_flowbits_names, sizeof(char *) * p->debuglog_flowbits_names_len); if (p->debuglog_flowbits_names == NULL) { return; } memset(p->debuglog_flowbits_names + p->debuglog_flowbits_names_len - MALLOC_JUMP, 0, sizeof(char *) * MALLOC_JUMP); } gv = gv->next; } return; } /** * \brief Signature match function * * \retval 1 one or more signatures matched * \retval 0 no matches were found */ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) { uint8_t sms_runflags = 0; /* function flags */ uint8_t alert_flags = 0; uint16_t alproto = ALPROTO_UNKNOWN; #ifdef PROFILING int smatch = 0; /* signature match: 1, no match: 0 */ #endif int fmatch = 0; uint32_t idx; uint8_t flags = 0; /* flow/state flags */ void *alstate = NULL; StreamMsg *smsg = NULL; Signature *s = NULL; SigMatch *sm = NULL; uint16_t alversion = 0; int reset_de_state = 0; AppLayerDecoderEvents *app_decoder_events = NULL; int app_decoder_events_cnt = 0; SCEnter(); SCLogDebug("pcap_cnt %"PRIu64, p->pcap_cnt); p->alerts.cnt = 0; det_ctx->filestore_cnt = 0; /* No need to perform any detection on this packet, if the the given flag is set.*/ if (p->flags & PKT_NOPACKET_INSPECTION) { SCReturnInt(0); } /* grab the protocol state we will detect on */ if (p->flags & PKT_HAS_FLOW) { if (p->flags & PKT_STREAM_EOF) { flags |= STREAM_EOF; SCLogDebug("STREAM_EOF set"); } FLOWLOCK_WRLOCK(p->flow); { /* live ruleswap check for flow updates */ if (p->flow->de_ctx_id == 0) { /* first time this flow is inspected, set id */ p->flow->de_ctx_id = de_ctx->id; } else if (p->flow->de_ctx_id != de_ctx->id) { /* first time we inspect flow with this de_ctx, reset */ p->flow->flags &= ~FLOW_SGH_TOSERVER; p->flow->flags &= ~FLOW_SGH_TOCLIENT; p->flow->sgh_toserver = NULL; p->flow->sgh_toclient = NULL; reset_de_state = 1; p->flow->de_ctx_id = de_ctx->id; GenericVarFree(p->flow->flowvar); p->flow->flowvar = NULL; } /* set the iponly stuff */ if (p->flow->flags & FLOW_TOCLIENT_IPONLY_SET) p->flowflags |= FLOW_PKT_TOCLIENT_IPONLY_SET; if (p->flow->flags & FLOW_TOSERVER_IPONLY_SET) p->flowflags |= FLOW_PKT_TOSERVER_IPONLY_SET; /* Get the stored sgh from the flow (if any). Make sure we're not using * the sgh for icmp error packets part of the same stream. */ if (IP_GET_IPPROTO(p) == p->flow->proto) { /* filter out icmp */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_GETSGH); if ((p->flowflags & FLOW_PKT_TOSERVER) && (p->flow->flags & FLOW_SGH_TOSERVER)) { det_ctx->sgh = p->flow->sgh_toserver; sms_runflags |= SMS_USE_FLOW_SGH; } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && (p->flow->flags & FLOW_SGH_TOCLIENT)) { det_ctx->sgh = p->flow->sgh_toclient; sms_runflags |= SMS_USE_FLOW_SGH; } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_GETSGH); smsg = SigMatchSignaturesGetSmsg(p->flow, p, flags); #if 0 StreamMsg *tmpsmsg = smsg; while (tmpsmsg) { printf("detect ---start---:\n"); PrintRawDataFp(stdout,tmpsmsg->data.data,tmpsmsg->data.data_len); printf("detect ---end---:\n"); tmpsmsg = tmpsmsg->next; } #endif } /* Retrieve the app layer state and protocol and the tcp reassembled * stream chunks. */ if ((p->proto == IPPROTO_TCP && (p->flags & PKT_STREAM_EST)) || (p->proto == IPPROTO_UDP && (p->flowflags & FLOW_PKT_ESTABLISHED)) || (p->proto == IPPROTO_SCTP && (p->flowflags & FLOW_PKT_ESTABLISHED))) { alstate = AppLayerGetProtoStateFromPacket(p); alproto = AppLayerGetProtoFromPacket(p); alversion = AppLayerGetStateVersion(p->flow); SCLogDebug("alstate %p, alproto %u", alstate, alproto); } else { SCLogDebug("packet doesn't have established flag set (proto %d)", p->proto); } app_decoder_events = AppLayerGetDecoderEventsForFlow(p->flow); if (app_decoder_events != NULL) app_decoder_events_cnt = app_decoder_events->cnt; } FLOWLOCK_UNLOCK(p->flow); if (p->flowflags & FLOW_PKT_TOSERVER) { flags |= STREAM_TOSERVER; SCLogDebug("flag STREAM_TOSERVER set"); } else if (p->flowflags & FLOW_PKT_TOCLIENT) { flags |= STREAM_TOCLIENT; SCLogDebug("flag STREAM_TOCLIENT set"); } SCLogDebug("p->flowflags 0x%02x", p->flowflags); /* reset because of ruleswap */ if (reset_de_state) { SCMutexLock(&p->flow->de_state_m); DetectEngineStateReset(p->flow->de_state); SCMutexUnlock(&p->flow->de_state_m); /* see if we need to increment the inspect_id and reset the de_state */ } else if (alstate != NULL && alproto == ALPROTO_HTTP) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); SCLogDebug("getting de_state_status"); int de_state_status = DeStateUpdateInspectTransactionId(p->flow, (flags & STREAM_TOSERVER) ? STREAM_TOSERVER : STREAM_TOCLIENT); SCLogDebug("de_state_status %d", de_state_status); if (de_state_status == 2) { SCMutexLock(&p->flow->de_state_m); DetectEngineStateReset(p->flow->de_state); SCMutexUnlock(&p->flow->de_state_m); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); } if (((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) || ((p->flowflags & FLOW_PKT_TOCLIENT) && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) { SCLogDebug("testing against \"ip-only\" signatures"); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_IPONLY); IPOnlyMatchPacket(th_v, de_ctx, det_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_IPONLY); /* save in the flow that we scanned this direction... locking is * done in the FlowSetIPOnlyFlag function. */ FlowSetIPOnlyFlag(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0); } else if (((p->flowflags & FLOW_PKT_TOSERVER) && (p->flow->flags & FLOW_TOSERVER_IPONLY_SET)) || ((p->flowflags & FLOW_PKT_TOCLIENT) && (p->flow->flags & FLOW_TOCLIENT_IPONLY_SET))) { /* Get the result of the first IPOnlyMatch() */ if (p->flow->flags & FLOW_ACTION_PASS) { /* if it matched a "pass" rule, we have to let it go */ UPDATE_PACKET_ACTION(p, ACTION_PASS); } /* If we have a drop from IP only module, * we will drop the rest of the flow packets * This will apply only to inline/IPS */ if (p->flow->flags & FLOW_ACTION_DROP) { alert_flags = PACKET_ALERT_FLAG_DROP_FLOW; UPDATE_PACKET_ACTION(p, ACTION_DROP); } } if (!(sms_runflags & SMS_USE_FLOW_SGH)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_GETSGH); det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_GETSGH); } #ifdef DEBUG if (p->flow) { SCMutexLock(&p->flow->m); DebugInspectIds(p, p->flow, smsg); SCMutexUnlock(&p->flow->m); } #endif } else { /* p->flags & PKT_HAS_FLOW */ /* no flow */ /* Even without flow we should match the packet src/dst */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_IPONLY); IPOnlyMatchPacket(th_v, de_ctx, det_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_IPONLY); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_GETSGH); det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_GETSGH); } /* if we didn't get a sig group head, we * have nothing to do.... */ if (det_ctx->sgh == NULL) { SCLogDebug("no sgh for this packet, nothing to match against"); goto end; } /* run the mpm for each type */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flags, alproto, alstate, &sms_runflags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); /* stateful app layer detection */ if ((p->flags & PKT_HAS_FLOW) && alstate != NULL) { /* initialize to 0 (DE_STATE_MATCH_NOSTATE) */ memset(det_ctx->de_state_sig_array, 0x00, det_ctx->de_state_sig_array_len); /* if applicable, continue stateful detection */ int state = DeStateFlowHasState(p->flow, flags, alversion); if (state == 1 || (flags & STREAM_EOF)) { DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p->flow, flags, alstate, alproto, alversion); } else if (state == 2) { alstate = NULL; } } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); /* create our prefilter mask */ SignatureMask mask = 0; PacketCreateMask(p, &mask, alproto, alstate, smsg, app_decoder_events_cnt); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); /* build the match array */ SigMatchSignaturesBuildMatchArray(det_ctx, p, mask, alproto); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); /* inspect the sigs against the packet */ for (idx = 0; idx < det_ctx->match_array_cnt; idx++) { RULE_PROFILING_START; #ifdef PROFILING smatch = 0; #endif s = det_ctx->match_array[idx]; SCLogDebug("inspecting signature id %"PRIu32"", s->id); /* check if this signature has a requirement for flowvars of some type * and if so, if we actually have any in the flow. If not, the sig * can't match and we skip it. */ if ((p->flags & PKT_HAS_FLOW) && (s->flags & SIG_FLAG_REQUIRE_FLOWVAR)) { FLOWLOCK_RDLOCK(p->flow); int m = p->flow->flowvar ? 1 : 0; FLOWLOCK_UNLOCK(p->flow); /* no flowvars? skip this sig */ if (m == 0) { SCLogDebug("skipping sig as the flow has no flowvars and sig " "has SIG_FLAG_REQUIRE_FLOWVAR flag set."); goto next; } } if ((s->proto.flags & DETECT_PROTO_IPV4) && !PKT_IS_IPV4(p)) { SCLogDebug("ip version didn't match"); goto next; } if ((s->proto.flags & DETECT_PROTO_IPV6) && !PKT_IS_IPV6(p)) { SCLogDebug("ip version didn't match"); goto next; } if (DetectProtoContainsProto(&s->proto, IP_GET_IPPROTO(p)) == 0) { SCLogDebug("proto didn't match"); goto next; } /* check the source & dst port in the sig */ if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { if (!(s->flags & SIG_FLAG_DP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) goto next; DetectPort *dport = DetectPortLookupGroup(s->dp,p->dp); if (dport == NULL) { SCLogDebug("dport didn't match."); goto next; } } if (!(s->flags & SIG_FLAG_SP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) goto next; DetectPort *sport = DetectPortLookupGroup(s->sp,p->sp); if (sport == NULL) { SCLogDebug("sport didn't match."); goto next; } } } /* check the destination address */ if (!(s->flags & SIG_FLAG_DST_ANY)) { if (PKT_IS_IPV4(p)) { if (DetectAddressMatchIPv4(s->addr_dst_match4, s->addr_dst_match4_cnt, &p->dst) == 0) goto next; } else if (PKT_IS_IPV6(p)) { if (DetectAddressMatchIPv6(s->addr_dst_match6, s->addr_dst_match6_cnt, &p->dst) == 0) goto next; } } /* check the source address */ if (!(s->flags & SIG_FLAG_SRC_ANY)) { if (PKT_IS_IPV4(p)) { if (DetectAddressMatchIPv4(s->addr_src_match4, s->addr_src_match4_cnt, &p->src) == 0) goto next; } else if (PKT_IS_IPV6(p)) { if (DetectAddressMatchIPv6(s->addr_src_match6, s->addr_src_match6_cnt, &p->src) == 0) goto next; } } /* Check the payload keywords. If we are a MPM sig and we've made * to here, we've had at least one of the patterns match */ if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { /* if we have stream msgs, inspect against those first, * but not for a "dsize" signature */ if (s->flags & SIG_FLAG_REQUIRE_STREAM) { char pmatch = 0; if (smsg != NULL) { uint8_t pmq_idx = 0; StreamMsg *smsg_inspect = smsg; for ( ; smsg_inspect != NULL; smsg_inspect = smsg_inspect->next, pmq_idx++) { /* filter out sigs that want pattern matches, but * have no matches */ if ((s->flags & SIG_FLAG_MPM_STREAM) && !(s->flags & SIG_FLAG_MPM_STREAM_NEG) && !(det_ctx->smsg_pmq[pmq_idx].pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { SCLogDebug("no match in this smsg"); continue; } if (DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, p->flow, smsg_inspect->data.data, smsg_inspect->data.data_len) == 1) { SCLogDebug("match in smsg %p", smsg); pmatch = 1; det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH; /* Tell the engine that this reassembled stream can drop the * rest of the pkts with no further inspection */ if (s->action & ACTION_DROP) alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW; alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH; break; } } } /* if (smsg != NULL) */ /* no match? then inspect packet payload */ if (pmatch == 0) { SCLogDebug("no match in smsg, fall back to packet payload"); if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { if (p->flags & PKT_STREAM_ADD) goto next; } if (sms_runflags & SMS_USED_PM) { if ((s->flags & SIG_FLAG_MPM_PACKET) && !(s->flags & SIG_FLAG_MPM_PACKET_NEG) && !(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { goto next; } if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, flags, alstate, p) != 1) { goto next; } } else { if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, flags, alstate, p) != 1) { goto next; } } } } else { if (sms_runflags & SMS_USED_PM) { if ((s->flags & SIG_FLAG_MPM_PACKET) && !(s->flags & SIG_FLAG_MPM_PACKET_NEG) && !(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { goto next; } if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, flags, alstate, p) != 1) { goto next; } } else { if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, flags, alstate, p) != 1) goto next; } } } /* run the packet match functions */ if (s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { sm = s->sm_lists[DETECT_SM_LIST_MATCH]; SCLogDebug("running match functions, sm %p", sm); for ( ; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].Match(th_v, det_ctx, p, s, sm) <= 0) { goto next; } } } SCLogDebug("s->sm_lists[DETECT_SM_LIST_AMATCH] %p, " "s->sm_lists[DETECT_SM_LIST_UMATCH] %p, " "s->sm_lists[DETECT_SM_LIST_DMATCH] %p, " "s->sm_lists[DETECT_SM_LIST_HCDMATCH] %p", s->sm_lists[DETECT_SM_LIST_AMATCH], s->sm_lists[DETECT_SM_LIST_UMATCH], s->sm_lists[DETECT_SM_LIST_DMATCH], s->sm_lists[DETECT_SM_LIST_HCDMATCH]); /* consider stateful sig matches */ if (s->flags & SIG_FLAG_STATE_MATCH) { if (alstate == NULL) { SCLogDebug("state matches but no state, we can't match"); goto next; } if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NOSTATE) { SCLogDebug("stateful app layer match inspection starting"); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); int de_r = DeStateDetectStartDetection(th_v, de_ctx, det_ctx, s, p->flow, flags, alstate, alproto, alversion); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); if (de_r != 1) { goto next; } } else { SCLogDebug("already having a destate"); SCLogDebug("signature %"PRIu32" (%"PRIuMAX"): %s", s->id, (uintmax_t)s->num, DeStateMatchResultToString(det_ctx->de_state_sig_array[s->num])); if (det_ctx->de_state_sig_array[s->num] != DE_STATE_MATCH_NEW) { goto next; } } /* match */ if (s->action & ACTION_DROP) alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW; alert_flags |= PACKET_ALERT_FLAG_STATE_MATCH; } /* match! */ fmatch = 1; #ifdef PROFILING smatch = 1; #endif SigMatchSignaturesRunPostMatch(th_v, de_ctx, det_ctx, p, s); if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, alert_flags); } else { /* apply actions even if not alerting */ UPDATE_PACKET_ACTION(p, s->action); } next: DetectFlowvarCleanupList(det_ctx); DetectReplaceFree(det_ctx->replist); det_ctx->replist = NULL; RULE_PROFILING_END(det_ctx, s, smatch); det_ctx->flags = 0; continue; } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_RULES); end: /* see if we need to increment the inspect_id and reset the de_state */ if (alstate != NULL && alproto != ALPROTO_HTTP) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); SCLogDebug("getting de_state_status"); int de_state_status = DeStateUpdateInspectTransactionId(p->flow, (flags & STREAM_TOSERVER) ? STREAM_TOSERVER : STREAM_TOCLIENT); SCLogDebug("de_state_status %d", de_state_status); if (de_state_status == 2) { SCMutexLock(&p->flow->de_state_m); DetectEngineStateReset(p->flow->de_state); SCMutexUnlock(&p->flow->de_state_m); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); } /* so now let's iterate the alerts and remove the ones after a pass rule * matched (if any). This is done inside PacketAlertFinalize() */ /* PR: installed "tag" keywords are handled after the threshold inspection */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_ALERT); PacketAlertFinalize(de_ctx, det_ctx, p); if (p->alerts.cnt > 0) { SCPerfCounterAddUI64(det_ctx->counter_alerts, det_ctx->tv->sc_perf_pca, (uint64_t)p->alerts.cnt); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_ALERT); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_CLEANUP); /* cleanup pkt specific part of the patternmatcher */ PacketPatternCleanup(th_v, det_ctx); DetectEngineCleanHCBDBuffers(det_ctx); DetectEngineCleanHSBDBuffers(det_ctx); DetectEngineCleanHHDBuffers(det_ctx); /* store the found sgh (or NULL) in the flow to save us from looking it * up again for the next packet. Also return any stream chunk we processed * to the pool. */ if (p->flags & PKT_HAS_FLOW) { if (sms_runflags & SMS_USED_STREAM_PM) { StreamPatternCleanup(th_v, det_ctx, smsg); } FLOWLOCK_WRLOCK(p->flow); if (debuglog_enabled) { if (p->alerts.cnt > 0) { AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(p, de_ctx); } } if (!(sms_runflags & SMS_USE_FLOW_SGH)) { if ((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flow->flags & FLOW_SGH_TOSERVER)) { /* first time we see this toserver sgh, store it */ p->flow->sgh_toserver = det_ctx->sgh; p->flow->flags |= FLOW_SGH_TOSERVER; /* see if this sgh requires us to consider file storing */ if (p->flow->sgh_toserver == NULL || p->flow->sgh_toserver->filestore_cnt == 0) { FileDisableStoring(p->flow, STREAM_TOSERVER); } /* see if this sgh requires us to consider file magic */ if (!FileForceMagic() && (p->flow->sgh_toserver == NULL || !(p->flow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) { SCLogDebug("disabling magic for flow"); FileDisableMagic(p->flow, STREAM_TOSERVER); } /* see if this sgh requires us to consider file md5 */ if (!FileForceMd5() && (p->flow->sgh_toserver == NULL || !(p->flow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) { SCLogDebug("disabling md5 for flow"); FileDisableMd5(p->flow, STREAM_TOSERVER); } /* see if this sgh requires us to consider filesize */ if (p->flow->sgh_toserver == NULL || !(p->flow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) { SCLogDebug("disabling filesize for flow"); FileDisableFilesize(p->flow, STREAM_TOSERVER); } } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(p->flow->flags & FLOW_SGH_TOCLIENT)) { p->flow->sgh_toclient = det_ctx->sgh; p->flow->flags |= FLOW_SGH_TOCLIENT; if (p->flow->sgh_toclient == NULL || p->flow->sgh_toclient->filestore_cnt == 0) { FileDisableStoring(p->flow, STREAM_TOCLIENT); } /* check if this flow needs magic, if not disable it */ if (!FileForceMagic() && (p->flow->sgh_toclient == NULL || !(p->flow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) { SCLogDebug("disabling magic for flow"); FileDisableMagic(p->flow, STREAM_TOCLIENT); } /* check if this flow needs md5, if not disable it */ if (!FileForceMd5() && (p->flow->sgh_toclient == NULL || !(p->flow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) { SCLogDebug("disabling md5 for flow"); FileDisableMd5(p->flow, STREAM_TOCLIENT); } /* see if this sgh requires us to consider filesize */ if (p->flow->sgh_toclient == NULL || !(p->flow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) { SCLogDebug("disabling filesize for flow"); FileDisableFilesize(p->flow, STREAM_TOCLIENT); } } } /* if we had no alerts that involved the smsgs, * we can get rid of them now. */ StreamMsgReturnListToPool(smsg); FLOWLOCK_UNLOCK(p->flow); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_CLEANUP); SCReturnInt(fmatch); } /* tm module api functions */ /** \brief Detection engine thread wrapper. * \param tv thread vars * \param p packet to inspect * \param data thread specific data * \param pq packet queue * \retval TM_ECODE_FAILED error * \retval TM_ECODE_OK ok */ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { DEBUG_VALIDATE_PACKET(p); /* No need to perform any detection on this packet, if the the given flag is set.*/ if ((p->flags & PKT_NOPACKET_INSPECTION) || (PACKET_TEST_ACTION(p, ACTION_DROP))) return 0; DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; if (det_ctx == NULL) { printf("ERROR: Detect has no thread ctx\n"); goto error; } DetectEngineCtx *de_ctx = det_ctx->de_ctx; if (de_ctx == NULL) { printf("ERROR: Detect has no detection engine ctx\n"); goto error; } if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); SCLogDebug("Detect Engine using new det_ctx - %p and de_ctx - %p", det_ctx, de_ctx); } /* see if the packet matches one or more of the sigs */ int r = SigMatchSignatures(tv,de_ctx,det_ctx,p); if (r >= 0) { return TM_ECODE_OK; } error: return TM_ECODE_FAILED; } TmEcode DetectThreadInit(ThreadVars *t, void *initdata, void **data) { return DetectEngineThreadCtxInit(t,initdata,data); } TmEcode DetectThreadDeinit(ThreadVars *t, void *data) { return DetectEngineThreadCtxDeinit(t,data); } void SigCleanSignatures(DetectEngineCtx *de_ctx) { Signature *s = NULL, *ns; if (de_ctx == NULL) return; for (s = de_ctx->sig_list; s != NULL;) { ns = s->next; SigFree(s); s = ns; } de_ctx->sig_list = NULL; DetectEngineResetMaxSigId(de_ctx); de_ctx->sig_list = NULL; } /** \brief Find a specific signature by sid and gid * \param de_ctx detection engine ctx * \param sid the signature id * \param gid the signature group id * * \retval s sig found * \retval NULL sig not found */ Signature *SigFindSignatureBySidGid(DetectEngineCtx *de_ctx, uint32_t sid, uint32_t gid) { Signature *s = NULL; if (de_ctx == NULL) return NULL; for (s = de_ctx->sig_list; s != NULL; s = s->next) { if (s->id == sid && s->gid == gid) return s; } return NULL; } int SignatureIsAppLayer(DetectEngineCtx *de_ctx, Signature *s) { if (s->alproto != 0) return 1; return 0; } /** * \brief Check if a signature contains the filestore keyword. * * \param s signature * * \retval 0 no * \retval 1 yes */ int SignatureIsFilestoring(Signature *s) { if (s == NULL) return 0; if (s->flags & SIG_FLAG_FILESTORE) return 1; return 0; } /** * \brief Check if a signature contains the filemagic keyword. * * \param s signature * * \retval 0 no * \retval 1 yes */ int SignatureIsFilemagicInspecting(Signature *s) { if (s == NULL) return 0; if (s->file_flags & FILE_SIG_NEED_MAGIC) return 1; return 0; } /** * \brief Check if a signature contains the filemd5 keyword. * * \param s signature * * \retval 0 no * \retval 1 yes */ int SignatureIsFileMd5Inspecting(Signature *s) { if (s == NULL) return 0; if (s->file_flags & FILE_SIG_NEED_MD5) return 1; return 0; } /** * \brief Check if a signature contains the filesize keyword. * * \param s signature * * \retval 0 no * \retval 1 yes */ int SignatureIsFilesizeInspecting(Signature *s) { if (s == NULL) return 0; if (s->file_flags & FILE_SIG_NEED_SIZE) return 1; return 0; } /** \brief Test is a initialized signature is IP only * \param de_ctx detection engine ctx * \param s the signature * \retval 1 sig is ip only * \retval 0 sig is not ip only */ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) { if (s->alproto != ALPROTO_UNKNOWN) return 0; if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) return 0; if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) return 0; IPOnlyCIDRItem *cidr_item; cidr_item = s->CidrSrc; while (cidr_item != NULL) { if (cidr_item->negated) return 0; cidr_item = cidr_item->next; } cidr_item = s->CidrDst; while (cidr_item != NULL) { if (cidr_item->negated) return 0; cidr_item = cidr_item->next; } SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; if (sm == NULL) goto iponly; for ( ; sm != NULL; sm = sm->next) { if ( !(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)) return 0; /* we have enabled flowbits to be compatible with ip only sigs, as long * as the sig only has a "set" flowbits */ if (sm->type == DETECT_FLOWBITS && (((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET) ) { return 0; } } iponly: if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("IP-ONLY (%" PRIu32 "): source %s, dest %s", s->id, s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET", s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET"); } return 1; } /** * \internal * \brief Check if the initialized signature is inspecting the packet payload * \param de_ctx detection engine ctx * \param s the signature * \retval 1 sig is inspecting the payload * \retval 0 sig is not inspecting the payload */ static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, Signature *s) { if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { return 1; } #if 0 SigMatch *sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; if (sm == NULL) return 0; for (; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].flags & SIGMATCH_PAYLOAD) { if (!(de_ctx->flags & DE_QUIET)) SCLogDebug("Signature (%" PRIu32 "): is inspecting payload.", s->id); return 1; } } #endif return 0; } /** * \internal * \brief check if a signature is decoder event matching only * \param de_ctx detection engine * \param s the signature to test * \retval 0 not a DEOnly sig * \retval 1 DEOnly sig */ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) { if (s->alproto != ALPROTO_UNKNOWN) { SCReturnInt(0); } if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { SCReturnInt(0); } /* check for conflicting keywords */ SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; for ( ;sm != NULL; sm = sm->next) { if ( !(sigmatch_table[sm->type].flags & SIGMATCH_DEONLY_COMPAT)) SCReturnInt(0); } /* need at least one decode event keyword to be considered decode event. */ sm = s->sm_lists[DETECT_SM_LIST_MATCH]; for ( ;sm != NULL; sm = sm->next) { if (sm->type == DETECT_DECODE_EVENT) goto deonly; if (sm->type == DETECT_ENGINE_EVENT) goto deonly; if (sm->type == DETECT_STREAM_EVENT) goto deonly; } SCReturnInt(0); deonly: if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("DE-ONLY (%" PRIu32 "): source %s, dest %s", s->id, s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET", s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET"); } SCReturnInt(1); } #define MASK_TCP_INITDEINIT_FLAGS (TH_SYN|TH_RST|TH_FIN) #define MASK_TCP_UNUSUAL_FLAGS (TH_URG|TH_ECN|TH_CWR) /* Create mask for this packet + it's flow if it has one * * Sets SIG_MASK_REQUIRE_PAYLOAD, SIG_MASK_REQUIRE_FLOW, * SIG_MASK_REQUIRE_HTTP_STATE, SIG_MASK_REQUIRE_DCE_STATE */ static void PacketCreateMask(Packet *p, SignatureMask *mask, uint16_t alproto, void *alstate, StreamMsg *smsg, int app_decoder_events_cnt) { if (!(p->flags & PKT_NOPAYLOAD_INSPECTION) && (p->payload_len > 0 || smsg != NULL)) { SCLogDebug("packet has payload"); (*mask) |= SIG_MASK_REQUIRE_PAYLOAD; } else { SCLogDebug("packet has no payload"); (*mask) |= SIG_MASK_REQUIRE_NO_PAYLOAD; } if (p->events.cnt > 0 || app_decoder_events_cnt > 0) { SCLogDebug("packet/flow has events set"); (*mask) |= SIG_MASK_REQUIRE_ENGINE_EVENT; } if (PKT_IS_TCP(p)) { if ((p->tcph->th_flags & MASK_TCP_INITDEINIT_FLAGS) != 0) { (*mask) |= SIG_MASK_REQUIRE_FLAGS_INITDEINIT; } if ((p->tcph->th_flags & MASK_TCP_UNUSUAL_FLAGS) != 0) { (*mask) |= SIG_MASK_REQUIRE_FLAGS_UNUSUAL; } } if (p->flags & PKT_HAS_FLOW) { SCLogDebug("packet has flow"); (*mask) |= SIG_MASK_REQUIRE_FLOW; if (alstate != NULL) { switch(alproto) { case ALPROTO_HTTP: SCLogDebug("packet/flow has http state"); (*mask) |= SIG_MASK_REQUIRE_HTTP_STATE; break; case ALPROTO_SMB: case ALPROTO_SMB2: case ALPROTO_DCERPC: SCLogDebug("packet/flow has dce state"); (*mask) |= SIG_MASK_REQUIRE_DCE_STATE; break; default: SCLogDebug("packet/flow has other state"); break; } } else { SCLogDebug("no alstate"); } } } static int SignatureCreateMask(Signature *s) { SCEnter(); if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_PAYLOAD; SCLogDebug("sig requires payload"); } if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_DCE_STATE; SCLogDebug("sig requires dce state"); } if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http state"); } if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires http app state"); } SigMatch *sm; for (sm = s->sm_lists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { case DETECT_AL_URILEN: case DETECT_AL_HTTP_URI: s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; SCLogDebug("sig requires dce http state"); break; case DETECT_AL_APP_LAYER_EVENT: s->mask |= SIG_MASK_REQUIRE_ENGINE_EVENT; break; } } for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { switch(sm->type) { case DETECT_FLOWBITS: { /* figure out what flowbit action */ DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx; if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) { /* not a mask flag, but still set it here */ s->flags |= SIG_FLAG_REQUIRE_FLOWVAR; SCLogDebug("SIG_FLAG_REQUIRE_FLOWVAR set as sig has " "flowbit isset option."); } /* flow is required for any flowbit manipulation */ s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow to be able to manipulate " "flowbit(s)"); break; } case DETECT_FLAGS: { DetectFlagsData *fl = (DetectFlagsData *)sm->ctx; if (fl->flags & TH_SYN) { s->mask |= SIG_MASK_REQUIRE_FLAGS_INITDEINIT; SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_INITDEINIT"); } if (fl->flags & TH_RST) { s->mask |= SIG_MASK_REQUIRE_FLAGS_INITDEINIT; SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_INITDEINIT"); } if (fl->flags & TH_FIN) { s->mask |= SIG_MASK_REQUIRE_FLAGS_INITDEINIT; SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_INITDEINIT"); } if (fl->flags & TH_URG) { s->mask |= SIG_MASK_REQUIRE_FLAGS_UNUSUAL; SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_UNUSUAL"); } if (fl->flags & TH_ECN) { s->mask |= SIG_MASK_REQUIRE_FLAGS_UNUSUAL; SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_UNUSUAL"); } if (fl->flags & TH_CWR) { s->mask |= SIG_MASK_REQUIRE_FLAGS_UNUSUAL; SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_UNUSUAL"); } break; } case DETECT_DSIZE: { DetectDsizeData *ds = (DetectDsizeData *)sm->ctx; switch (ds->mode) { case DETECTDSIZE_LT: /* LT will include 0, so no payload. * if GT is used in the same rule the * flag will be set anyway. */ break; case DETECTDSIZE_RA: case DETECTDSIZE_GT: s->mask |= SIG_MASK_REQUIRE_PAYLOAD; SCLogDebug("sig requires payload"); break; case DETECTDSIZE_EQ: if (ds->dsize > 0) { s->mask |= SIG_MASK_REQUIRE_PAYLOAD; SCLogDebug("sig requires payload"); } else if (ds->dsize == 0) { s->mask |= SIG_MASK_REQUIRE_NO_PAYLOAD; SCLogDebug("sig requires no payload"); } break; } break; } case DETECT_ENGINE_EVENT: s->mask |= SIG_MASK_REQUIRE_ENGINE_EVENT; break; } } if ((s->mask & SIG_MASK_REQUIRE_DCE_STATE) || (s->mask & SIG_MASK_REQUIRE_HTTP_STATE)) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); } if (s->init_flags & SIG_FLAG_INIT_FLOW) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); } if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); } if (s->flags & SIG_FLAG_APPLAYER) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); } SCLogDebug("mask %02X", s->mask); SCReturnInt(0); } static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) { de_ctx->sgh_mpm_context_proto_tcp_packet = MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_tcp", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_proto_udp_packet = MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_udp", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_proto_other_packet = MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_other", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_uri = MpmFactoryRegisterMpmCtxProfile(de_ctx, "uri", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_stream = MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hcbd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hcbd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hhd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hhd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hrhd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrhd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hmd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hmd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hcd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hcd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hrud = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrud", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hsmd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hsmd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hscd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hscd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_huad = MpmFactoryRegisterMpmCtxProfile(de_ctx, "huad", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hhhd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hhhd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_hrhhd = MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrhhd", MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); de_ctx->sgh_mpm_context_app_proto_detect = MpmFactoryRegisterMpmCtxProfile(de_ctx, "app_proto_detect", 0); return; } /** \brief get max dsize "depth" * \param s signature to get dsize value from * \retval depth or negative value */ static int SigParseGetMaxDsize(Signature *s) { if (s->flags & SIG_FLAG_DSIZE && s->dsize_sm != NULL) { DetectDsizeData *dd = (DetectDsizeData *)s->dsize_sm->ctx; switch (dd->mode) { case DETECTDSIZE_LT: case DETECTDSIZE_EQ: return dd->dsize; case DETECTDSIZE_RA: return dd->dsize2; case DETECTDSIZE_GT: default: SCReturnInt(-2); } } SCReturnInt(-1); } /** \brief set prefilter dsize pair * \param s signature to get dsize value from */ static void SigParseSetDsizePair(Signature *s) { if (s->flags & SIG_FLAG_DSIZE && s->dsize_sm != NULL) { DetectDsizeData *dd = (DetectDsizeData *)s->dsize_sm->ctx; uint16_t low = 0; uint16_t high = 65535; switch (dd->mode) { case DETECTDSIZE_LT: low = 0; high = dd->dsize; break; case DETECTDSIZE_EQ: low = dd->dsize; high = dd->dsize; break; case DETECTDSIZE_RA: low = dd->dsize; high = dd->dsize2; break; case DETECTDSIZE_GT: low = dd->dsize; high = 65535; break; } s->dsize_low = low; s->dsize_high = high; SCLogDebug("low %u, high %u", low, high); } } /** * \brief Apply dsize as depth to content matches in the rule * \param s signature to get dsize value from */ static void SigParseApplyDsizeToContent(Signature *s) { SCEnter(); if (s->flags & SIG_FLAG_DSIZE) { SigParseSetDsizePair(s); int dsize = SigParseGetMaxDsize(s); if (dsize < 0) { /* nothing to do */ return; } SigMatch *sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; for ( ; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) { continue; } DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd == NULL) { continue; } if (cd->depth == 0 || cd->depth >= dsize) { cd->depth = (uint16_t)dsize; SCLogDebug("updated %u, content %u to have depth %u " "because of dsize.", s->id, cd->id, cd->depth); } } } } /** * \brief Add all signatures to their own source address group * * \param de_ctx Pointer to the Detection Engine Context * * \retval 0 on success * \retval -1 on failure */ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) { Signature *tmp_s = NULL; DetectAddress *gr = NULL; uint32_t cnt = 0, cnt_iponly = 0; uint32_t cnt_payload = 0; uint32_t cnt_applayer = 0; uint32_t cnt_deonly = 0; //DetectAddressPrintMemory(); //DetectSigGroupPrintMemory(); //DetectPortPrintMemory(); if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("building signature grouping structure, stage 1: " "adding signatures to signature source addresses..."); } #ifdef HAVE_LUAJIT /* run this before the mpm states are initialized */ if (DetectLuajitSetupStatesPool(de_ctx->detect_luajit_instances, rule_reload) != 0) { if (de_ctx->failure_fatal) return -1; } #endif de_ctx->sig_array_len = DetectEngineGetMaxSigId(de_ctx); de_ctx->sig_array_size = (de_ctx->sig_array_len * sizeof(Signature *)); de_ctx->sig_array = (Signature **)SCMalloc(de_ctx->sig_array_size); if (de_ctx->sig_array == NULL) goto error; memset(de_ctx->sig_array,0,de_ctx->sig_array_size); SCLogDebug("signature lookup array: %" PRIu32 " sigs, %" PRIu32 " bytes", de_ctx->sig_array_len, de_ctx->sig_array_size); /* now for every rule add the source group */ for (tmp_s = de_ctx->sig_list; tmp_s != NULL; tmp_s = tmp_s->next) { de_ctx->sig_array[tmp_s->num] = tmp_s; SCLogDebug("Signature %" PRIu32 ", internal id %" PRIu32 ", ptrs %p %p ", tmp_s->id, tmp_s->num, tmp_s, de_ctx->sig_array[tmp_s->num]); /* see if the sig is ip only */ if (SignatureIsIPOnly(de_ctx, tmp_s) == 1) { tmp_s->flags |= SIG_FLAG_IPONLY; cnt_iponly++; SCLogDebug("Signature %"PRIu32" is considered \"IP only\"", tmp_s->id); /* see if any sig is inspecting the packet payload */ } else if (SignatureIsInspectingPayload(de_ctx, tmp_s) == 1) { tmp_s->init_flags |= SIG_FLAG_INIT_PAYLOAD; cnt_payload++; SCLogDebug("Signature %"PRIu32" is considered \"Payload inspecting\"", tmp_s->id); } else if (SignatureIsDEOnly(de_ctx, tmp_s) == 1) { tmp_s->init_flags |= SIG_FLAG_INIT_DEONLY; SCLogDebug("Signature %"PRIu32" is considered \"Decoder Event only\"", tmp_s->id); cnt_deonly++; } if (tmp_s->flags & SIG_FLAG_APPLAYER) { SCLogDebug("Signature %"PRIu32" is considered \"Applayer inspecting\"", tmp_s->id); cnt_applayer++; } #ifdef DEBUG if (SCLogDebugEnabled()) { uint16_t colen = 0; char copresent = 0; SigMatch *sm; DetectContentData *co; for (sm = tmp_s->sm_lists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; copresent = 1; co = (DetectContentData *)sm->ctx; if (co->content_len > colen) colen = co->content_len; } if (copresent && colen == 1) { SCLogDebug("signature %8u content maxlen 1", tmp_s->id); int proto; for (proto = 0; proto < 256; proto++) { if (tmp_s->proto.proto[(proto/8)] & (1<<(proto%8))) SCLogDebug("=> proto %" PRId32 "", proto); } } } #endif /* DEBUG */ SignatureCreateMask(tmp_s); for (gr = tmp_s->src.ipv4_head; gr != NULL; gr = gr->next) { if (SigGroupHeadAppendSig(de_ctx, &gr->sh, tmp_s) < 0) { goto error; } cnt++; } for (gr = tmp_s->src.ipv6_head; gr != NULL; gr = gr->next) { if (SigGroupHeadAppendSig(de_ctx, &gr->sh, tmp_s) < 0) { goto error; } cnt++; } for (gr = tmp_s->src.any_head; gr != NULL; gr = gr->next) { if (SigGroupHeadAppendSig(de_ctx, &gr->sh, tmp_s) < 0) { goto error; } cnt++; } SigParseApplyDsizeToContent(tmp_s); de_ctx->sig_cnt++; } //DetectAddressPrintMemory(); //DetectSigGroupPrintMemory(); //DetectPortPrintMemory(); if (!(de_ctx->flags & DE_QUIET)) { SCLogInfo("%" PRIu32 " signatures processed. %" PRIu32 " are IP-only " "rules, %" PRIu32 " are inspecting packet payload, %"PRIu32 " inspect application layer, %"PRIu32" are decoder event only", de_ctx->sig_cnt, cnt_iponly, cnt_payload, cnt_applayer, cnt_deonly); SCLogInfo("building signature grouping structure, stage 1: " "adding signatures to signature source addresses... complete"); } return 0; error: return -1; } static int DetectEngineLookupBuildSourceAddressList(DetectEngineCtx *de_ctx, DetectEngineLookupFlow *flow_gh, Signature *s, int family) { DetectAddress *gr = NULL, *lookup_gr = NULL, *head = NULL; int proto; if (family == AF_INET) { head = s->src.ipv4_head; } else if (family == AF_INET6) { head = s->src.ipv6_head; } else { head = s->src.any_head; } /* for each source address group in the signature... */ for (gr = head; gr != NULL; gr = gr->next) { BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); /* ...and each protocol the signature matches on... */ for (proto = 0; proto < 256; proto++) { if ((s->proto.proto[(proto/8)] & (1<<(proto%8))) || (s->proto.flags & DETECT_PROTO_ANY)) { /* ...see if the group is in the tmp list, and if not add it. */ if (family == AF_INET) { lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->ipv4_head,gr); } else if (family == AF_INET6) { lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->ipv6_head,gr); } else { lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->any_head,gr); } if (lookup_gr == NULL) { DetectAddress *grtmp = DetectAddressCopy(gr); if (grtmp == NULL) { goto error; } SigGroupHeadAppendSig(de_ctx, &grtmp->sh, s); /* add to the lookup list */ if (family == AF_INET) { DetectAddressAdd(&flow_gh->tmp_gh[proto]->ipv4_head, grtmp); } else if (family == AF_INET6) { DetectAddressAdd(&flow_gh->tmp_gh[proto]->ipv6_head, grtmp); } else { DetectAddressAdd(&flow_gh->tmp_gh[proto]->any_head, grtmp); } } else { /* our group will only have one sig, this one. So add that. */ SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, s); lookup_gr->cnt++; } } } SCLogDebug("calling SigGroupHeadFree gr %p, gr->sh %p", gr, gr->sh); SigGroupHeadFree(gr->sh); gr->sh = NULL; } return 0; error: return -1; } /** * \brief add signature to the right flow group(s) */ static int DetectEngineLookupFlowAddSig(DetectEngineCtx *de_ctx, Signature *s, int family) { SCLogDebug("s->id %u", s->id); if (s->flags & SIG_FLAG_TOCLIENT) { SCLogDebug("s->id %u (toclient)", s->id); DetectEngineLookupBuildSourceAddressList(de_ctx, &de_ctx->flow_gh[0], s, family); } if (s->flags & SIG_FLAG_TOSERVER) { SCLogDebug("s->id %u (toserver)", s->id); DetectEngineLookupBuildSourceAddressList(de_ctx, &de_ctx->flow_gh[1], s, family); } return 0; } static DetectAddress *GetHeadPtr(DetectAddressHead *head, int family) { DetectAddress *grhead; if (head == NULL) return NULL; if (family == AF_INET) { grhead = head->ipv4_head; } else if (family == AF_INET6) { grhead = head->ipv6_head; } else { grhead = head->any_head; } return grhead; } //#define SMALL_MPM(c) 0 #define SMALL_MPM(c) ((c) == 1) // || (c) == 2) // || (c) == 3) int CreateGroupedAddrListCmpCnt(DetectAddress *a, DetectAddress *b) { if (a->cnt > b->cnt) return 1; return 0; } int CreateGroupedAddrListCmpMpmMaxlen(DetectAddress *a, DetectAddress *b) { if (a->sh == NULL || b->sh == NULL) return 0; if (SMALL_MPM(a->sh->mpm_content_maxlen)) return 1; if (a->sh->mpm_content_maxlen < b->sh->mpm_content_maxlen) return 1; return 0; } /* set unique_groups to 0 for no grouping. * * srchead is a ordered "inserted" list w/o internal overlap * */ int CreateGroupedAddrList(DetectEngineCtx *de_ctx, DetectAddress *srchead, int family, DetectAddressHead *newhead, uint32_t unique_groups, int (*CompareFunc)(DetectAddress *, DetectAddress *), uint32_t max_idx) { DetectAddress *tmplist = NULL, *tmplist2 = NULL, *joingr = NULL; char insert = 0; DetectAddress *gr, *next_gr; uint32_t groups = 0; /* insert the addresses into the tmplist, where it will * be sorted descending on 'cnt'. */ for (gr = srchead; gr != NULL; gr = gr->next) { BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); if (SMALL_MPM(gr->sh->mpm_content_maxlen) && unique_groups > 0) unique_groups++; groups++; /* alloc a copy */ DetectAddress *newtmp = DetectAddressCopy(gr); if (newtmp == NULL) { goto error; } SigGroupHeadCopySigs(de_ctx, gr->sh,&newtmp->sh); DetectPort *port = gr->port; for ( ; port != NULL; port = port->next) { DetectPortInsertCopy(de_ctx,&newtmp->port, port); newtmp->flags |= ADDRESS_HAVEPORT; } /* insert it */ DetectAddress *tmpgr = tmplist, *prevtmpgr = NULL; if (tmplist == NULL) { /* empty list, set head */ tmplist = newtmp; } else { /* look for the place to insert */ for ( ; tmpgr != NULL&&!insert; tmpgr = tmpgr->next) { if (CompareFunc(gr, tmpgr)) { if (tmpgr == tmplist) { newtmp->next = tmplist; tmplist = newtmp; } else { newtmp->next = prevtmpgr->next; prevtmpgr->next = newtmp; } insert = 1; } prevtmpgr = tmpgr; } if (insert == 0) { newtmp->next = NULL; prevtmpgr->next = newtmp; } insert = 0; } } uint32_t i = unique_groups; if (i == 0) i = groups; for (gr = tmplist; gr != NULL; ) { BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); if (i == 0) { if (joingr == NULL) { joingr = DetectAddressCopy(gr); if (joingr == NULL) { goto error; } SigGroupHeadCopySigs(de_ctx,gr->sh,&joingr->sh); DetectPort *port = gr->port; for ( ; port != NULL; port = port->next) { DetectPortInsertCopy(de_ctx,&joingr->port, port); joingr->flags |= ADDRESS_HAVEPORT; } } else { DetectAddressJoin(de_ctx, joingr, gr); } } else { DetectAddress *newtmp = DetectAddressCopy(gr); if (newtmp == NULL) { goto error; } SigGroupHeadCopySigs(de_ctx,gr->sh,&newtmp->sh); DetectPort *port = gr->port; for ( ; port != NULL; port = port->next) { DetectPortInsertCopy(de_ctx,&newtmp->port, port); newtmp->flags |= ADDRESS_HAVEPORT; } if (tmplist2 == NULL) { tmplist2 = newtmp; } else { newtmp->next = tmplist2; tmplist2 = newtmp; } } if (i)i--; next_gr = gr->next; DetectAddressFree(gr); gr = next_gr; } /* we now have a tmplist2 containing the 'unique' groups and * possibly a joingr that covers the rest. Now build the newhead * that we will pass back to the caller. * * Start with inserting the unique groups */ for (gr = tmplist2; gr != NULL; ) { BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); DetectAddress *newtmp = DetectAddressCopy(gr); if (newtmp == NULL) { goto error; } SigGroupHeadCopySigs(de_ctx, gr->sh,&newtmp->sh); DetectPort *port = gr->port; for ( ; port != NULL; port = port->next) { DetectPortInsertCopy(de_ctx, &newtmp->port, port); newtmp->flags |= ADDRESS_HAVEPORT; } DetectAddressInsert(de_ctx, newhead, newtmp); next_gr = gr->next; DetectAddressFree(gr); gr = next_gr; } /* if present, insert the joingr that covers the rest */ if (joingr != NULL) { DetectAddressInsert(de_ctx, newhead, joingr); } return 0; error: return -1; } int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) { if (a->cnt > b->cnt) return 1; return 0; } int CreateGroupedPortListCmpMpmMaxlen(DetectPort *a, DetectPort *b) { if (a->sh == NULL || b->sh == NULL) return 0; if (SMALL_MPM(a->sh->mpm_content_maxlen)) return 1; if (a->sh->mpm_content_maxlen < b->sh->mpm_content_maxlen) return 1; return 0; } static uint32_t g_groupportlist_maxgroups = 0; static uint32_t g_groupportlist_groupscnt = 0; static uint32_t g_groupportlist_totgroups = 0; int CreateGroupedPortList(DetectEngineCtx *de_ctx,HashListTable *port_hash, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx) { DetectPort *tmplist = NULL, *tmplist2 = NULL, *joingr = NULL; char insert = 0; DetectPort *gr, *next_gr; uint32_t groups = 0; HashListTableBucket *htb = HashListTableGetListHead(port_hash); /* insert the addresses into the tmplist, where it will * be sorted descending on 'cnt'. */ for ( ; htb != NULL; htb = HashListTableGetListNext(htb)) { gr = (DetectPort *)HashListTableGetListData(htb); SCLogDebug("hash list gr %p", gr); DetectPortPrint(gr); if (SMALL_MPM(gr->sh->mpm_content_maxlen) && unique_groups > 0) unique_groups++; groups++; /* alloc a copy */ DetectPort *newtmp = DetectPortCopySingle(de_ctx, gr); if (newtmp == NULL) { goto error; } /* insert it */ DetectPort *tmpgr = tmplist, *prevtmpgr = NULL; if (tmplist == NULL) { /* empty list, set head */ tmplist = newtmp; } else { /* look for the place to insert */ for ( ; tmpgr != NULL&&!insert; tmpgr = tmpgr->next) { if (CompareFunc(gr, tmpgr)) { if (tmpgr == tmplist) { newtmp->next = tmplist; tmplist = newtmp; } else { newtmp->next = prevtmpgr->next; prevtmpgr->next = newtmp; } insert = 1; } prevtmpgr = tmpgr; } if (insert == 0) { newtmp->next = NULL; prevtmpgr->next = newtmp; } insert = 0; } } uint32_t i = unique_groups; if (i == 0) i = groups; if (unique_groups > g_groupportlist_maxgroups) g_groupportlist_maxgroups = unique_groups; g_groupportlist_groupscnt++; g_groupportlist_totgroups += unique_groups; for (gr = tmplist; gr != NULL; ) { SCLogDebug("temp list gr %p", gr); DetectPortPrint(gr); if (i == 0) { if (joingr == NULL) { joingr = DetectPortCopySingle(de_ctx,gr); if (joingr == NULL) { goto error; } } else { DetectPortJoin(de_ctx,joingr, gr); } } else { DetectPort *newtmp = DetectPortCopySingle(de_ctx,gr); if (newtmp == NULL) { goto error; } if (tmplist2 == NULL) { tmplist2 = newtmp; } else { newtmp->next = tmplist2; tmplist2 = newtmp; } } if (i)i--; next_gr = gr->next; gr->next = NULL; DetectPortFree(gr); gr = next_gr; } /* we now have a tmplist2 containing the 'unique' groups and * possibly a joingr that covers the rest. Now build the newhead * that we will pass back to the caller. * * Start with inserting the unique groups */ for (gr = tmplist2; gr != NULL; ) { SCLogDebug("temp list2 gr %p", gr); DetectPortPrint(gr); DetectPort *newtmp = DetectPortCopySingle(de_ctx,gr); if (newtmp == NULL) { goto error; } int r = DetectPortInsert(de_ctx,newhead,newtmp); BUG_ON(r == -1); next_gr = gr->next; gr->next = NULL; DetectPortFree(gr); gr = next_gr; } DetectPortPrintList(*newhead); /* if present, insert the joingr that covers the rest */ if (joingr != NULL) { SCLogDebug("inserting joingr %p", joingr); DetectPortInsert(de_ctx,newhead,joingr); } else { SCLogDebug("no joingr"); } return 0; error: return -1; } /** * \internal * \brief add a decoder event signature to the detection engine ctx */ static void DetectEngineAddDecoderEventSig(DetectEngineCtx *de_ctx, Signature *s) { SCLogDebug("adding signature %"PRIu32" to the decoder event sgh", s->id); SigGroupHeadAppendSig(de_ctx, &de_ctx->decoder_event_sgh, s); } /** * \brief Fill the global src group head, with the sigs included * * \param de_ctx Pointer to the Detection Engine Context whose Signatures have * to be processed * * \retval 0 On success * \retval -1 On failure */ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) { Signature *tmp_s = NULL; uint32_t sigs = 0; if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("building signature grouping structure, stage 2: " "building source address lists..."); } IPOnlyInit(de_ctx, &de_ctx->io_ctx); int f, proto; for (f = 0; f < FLOW_STATES; f++) { for (proto = 0; proto < 256; proto++) { de_ctx->flow_gh[f].src_gh[proto] = DetectAddressHeadInit(); if (de_ctx->flow_gh[f].src_gh[proto] == NULL) { goto error; } de_ctx->flow_gh[f].tmp_gh[proto] = DetectAddressHeadInit(); if (de_ctx->flow_gh[f].tmp_gh[proto] == NULL) { goto error; } } } /* now for every rule add the source group to our temp lists */ for (tmp_s = de_ctx->sig_list; tmp_s != NULL; tmp_s = tmp_s->next) { SCLogDebug("tmp_s->id %"PRIu32, tmp_s->id); if (tmp_s->flags & SIG_FLAG_IPONLY) { IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, tmp_s); } else { DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_INET); DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_INET6); DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_UNSPEC); } if (tmp_s->init_flags & SIG_FLAG_INIT_DEONLY) { DetectEngineAddDecoderEventSig(de_ctx, tmp_s); } sigs++; } /* create the final src addr list based on the tmplist. */ for (f = 0; f < FLOW_STATES; f++) { for (proto = 0; proto < 256; proto++) { int groups = (f ? de_ctx->max_uniq_toserver_src_groups : de_ctx->max_uniq_toclient_src_groups); CreateGroupedAddrList(de_ctx, de_ctx->flow_gh[f].tmp_gh[proto]->ipv4_head, AF_INET, de_ctx->flow_gh[f].src_gh[proto], groups, CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); CreateGroupedAddrList(de_ctx, de_ctx->flow_gh[f].tmp_gh[proto]->ipv6_head, AF_INET6, de_ctx->flow_gh[f].src_gh[proto], groups, CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); CreateGroupedAddrList(de_ctx, de_ctx->flow_gh[f].tmp_gh[proto]->any_head, AF_UNSPEC, de_ctx->flow_gh[f].src_gh[proto], groups, CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); DetectAddressHeadFree(de_ctx->flow_gh[f].tmp_gh[proto]); de_ctx->flow_gh[f].tmp_gh[proto] = NULL; } } //DetectAddressPrintMemory(); //DetectSigGroupPrintMemory(); //printf("g_src_gh strt\n"); //DetectAddressPrintList(g_src_gh->ipv4_head); //printf("g_src_gh end\n"); IPOnlyPrepare(de_ctx); IPOnlyPrint(de_ctx, &de_ctx->io_ctx); #ifdef DEBUG DetectAddress *gr = NULL; if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("%" PRIu32 " total signatures:", sigs); } /* TCP */ uint32_t cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->any_head; gr != NULL; gr = gr->next) { cnt_any++; } } for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->ipv4_head; gr != NULL; gr = gr->next) { cnt_ipv4++; } } for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->ipv6_head; gr != NULL; gr = gr->next) { cnt_ipv6++; } } if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("TCP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); } cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; /* UDP */ for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->any_head; gr != NULL; gr = gr->next) { cnt_any++; } } for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->ipv4_head; gr != NULL; gr = gr->next) { cnt_ipv4++; } } for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->ipv6_head; gr != NULL; gr = gr->next) { cnt_ipv6++; } } if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("UDP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); } cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; /* SCTP */ for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->any_head; gr != NULL; gr = gr->next) { cnt_any++; } } for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->ipv4_head; gr != NULL; gr = gr->next) { cnt_ipv4++; } } for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->ipv6_head; gr != NULL; gr = gr->next) { cnt_ipv6++; } } if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("SCTP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); } /* ICMP */ cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[1]->any_head; gr != NULL; gr = gr->next) { cnt_any++; } } for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[1]->ipv4_head; gr != NULL; gr = gr->next) { cnt_ipv4++; } } for (f = 0; f < FLOW_STATES; f++) { for (gr = de_ctx->flow_gh[f].src_gh[1]->ipv6_head; gr != NULL; gr = gr->next) { cnt_ipv6++; } } if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("ICMP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); } #endif /* DEBUG */ if (!(de_ctx->flags & DE_QUIET)) { SCLogInfo("building signature grouping structure, stage 2: building source address list... complete"); } return 0; error: printf("SigAddressPrepareStage2 error\n"); return -1; } /** * \brief Build the destination address portion of the match tree */ int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, DetectAddressHead *head, int family, int flow) { Signature *tmp_s = NULL; DetectAddress *gr = NULL, *sgr = NULL, *lookup_gr = NULL; uint32_t max_idx = 0; DetectAddress *grhead = NULL, *grdsthead = NULL, *grsighead = NULL; /* based on the family, select the list we are using in the head */ grhead = GetHeadPtr(head, family); /* loop through the global source address list */ for (gr = grhead; gr != NULL; gr = gr->next) { //printf(" * Source group (BuildDestinationAddressHeads): "); DetectAddressPrint(gr); printf(" (%p)\n", gr); /* initialize the destination group head */ gr->dst_gh = DetectAddressHeadInit(); if (gr->dst_gh == NULL) { goto error; } /* use a tmp list for speeding up insertions */ DetectAddress *tmp_gr_list = NULL; /* loop through all signatures in this source address group * and build the temporary destination address list for it */ uint32_t sig; for (sig = 0; sig < de_ctx->sig_array_len; sig++) { if (!(gr->sh->init->sig_array[(sig/8)] & (1<<(sig%8)))) continue; tmp_s = de_ctx->sig_array[sig]; if (tmp_s == NULL) continue; //printf(" * (tmp) Signature %u (num %u)\n", tmp_s->id, tmp_s->num); max_idx = sig; /* build the temp list */ grsighead = GetHeadPtr(&tmp_s->dst, family); for (sgr = grsighead; sgr != NULL; sgr = sgr->next) { //printf(" * (tmp) dst group: "); DetectAddressPrint(sgr); printf(" (%p)\n", sgr); if ((lookup_gr = DetectAddressLookupInList(tmp_gr_list, sgr)) == NULL) { DetectAddress *grtmp = DetectAddressCopy(sgr); if (grtmp == NULL) { goto error; } SigGroupHeadAppendSig(de_ctx,&grtmp->sh,tmp_s); DetectAddressAdd(&tmp_gr_list,grtmp); } else { /* our group will only have one sig, this one. So add that. */ SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, tmp_s); lookup_gr->cnt++; } } } /* Create the destination address list, keeping in * mind the limits we use. */ int groups = (flow ? de_ctx->max_uniq_toserver_dst_groups : de_ctx->max_uniq_toclient_dst_groups); CreateGroupedAddrList(de_ctx, tmp_gr_list, family, gr->dst_gh, groups, CreateGroupedAddrListCmpMpmMaxlen, max_idx); /* see if the sig group head of each address group is the * same as an earlier one. If it is, free our head and use * a pointer to the earlier one. This saves _a lot_ of memory. */ grdsthead = GetHeadPtr(gr->dst_gh, family); for (sgr = grdsthead; sgr != NULL; sgr = sgr->next) { //printf(" * Destination group: "); DetectAddressPrint(sgr); printf("\n"); /* Because a pattern matcher context uses quite some * memory, we first check if we can reuse it from * another group head. */ SigGroupHead *sgh = SigGroupHeadHashLookup(de_ctx, sgr->sh); if (sgh == NULL) { /* put the contents in our sig group head */ SigGroupHeadSetSigCnt(sgr->sh, max_idx); SigGroupHeadBuildMatchArray(de_ctx, sgr->sh, max_idx); /* init the pattern matcher, this will respect the copy * setting */ if (PatternMatchPrepareGroup(de_ctx, sgr->sh) < 0) { printf("PatternMatchPrepareGroup failed\n"); goto error; } if (sgr->sh->mpm_proto_tcp_ctx_ts != NULL) { if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt) de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; } if (sgr->sh->mpm_proto_tcp_ctx_tc != NULL) { if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt) de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; } if (sgr->sh->mpm_proto_udp_ctx_ts != NULL) { if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt) de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt; de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt; } if (sgr->sh->mpm_proto_udp_ctx_tc != NULL) { if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt) de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt; de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt; } if (sgr->sh->mpm_proto_other_ctx != NULL) { if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_other_ctx->pattern_cnt) de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_other_ctx->pattern_cnt; de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_other_ctx->pattern_cnt; } if (sgr->sh->mpm_uri_ctx_ts != NULL) { if (de_ctx->mpm_uri_max_patcnt < sgr->sh->mpm_uri_ctx_ts->pattern_cnt) de_ctx->mpm_uri_max_patcnt = sgr->sh->mpm_uri_ctx_ts->pattern_cnt; de_ctx->mpm_uri_tot_patcnt += sgr->sh->mpm_uri_ctx_ts->pattern_cnt; } if (sgr->sh->mpm_uri_ctx_tc != NULL) { if (de_ctx->mpm_uri_max_patcnt < sgr->sh->mpm_uri_ctx_tc->pattern_cnt) de_ctx->mpm_uri_max_patcnt = sgr->sh->mpm_uri_ctx_tc->pattern_cnt; de_ctx->mpm_uri_tot_patcnt += sgr->sh->mpm_uri_ctx_tc->pattern_cnt; } /* dbg */ if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_tcp_ctx_ts) { de_ctx->mpm_memory_size += sgr->sh->mpm_proto_tcp_ctx_ts->memory_size; } if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_tcp_ctx_tc) { de_ctx->mpm_memory_size += sgr->sh->mpm_proto_tcp_ctx_tc->memory_size; } if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_udp_ctx_ts) { de_ctx->mpm_memory_size += sgr->sh->mpm_proto_udp_ctx_ts->memory_size; } if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_udp_ctx_tc) { de_ctx->mpm_memory_size += sgr->sh->mpm_proto_udp_ctx_tc->memory_size; } if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_other_ctx) { de_ctx->mpm_memory_size += sgr->sh->mpm_proto_other_ctx->memory_size; } if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY) && sgr->sh->mpm_uri_ctx_ts) { de_ctx->mpm_memory_size += sgr->sh->mpm_uri_ctx_ts->memory_size; } if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY) && sgr->sh->mpm_uri_ctx_tc) { de_ctx->mpm_memory_size += sgr->sh->mpm_uri_ctx_tc->memory_size; } SigGroupHeadHashAdd(de_ctx, sgr->sh); SigGroupHeadStore(de_ctx, sgr->sh); de_ctx->gh_unique++; } else { SCLogDebug("calling SigGroupHeadFree sgr %p, sgr->sh %p", sgr, sgr->sh); SigGroupHeadFree(sgr->sh); sgr->sh = sgh; de_ctx->gh_reuse++; sgr->flags |= ADDRESS_SIGGROUPHEAD_COPY; sgr->sh->flags |= SIG_GROUP_HEAD_REFERENCED; } } /* free the temp list */ DetectAddressCleanupList(tmp_gr_list); /* clear now unneeded sig group head */ SCLogDebug("calling SigGroupHeadFree gr %p, gr->sh %p", gr, gr->sh); SigGroupHeadFree(gr->sh); gr->sh = NULL; } return 0; error: return -1; } //static int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, DetectAddressHead *head, int family, int flow) { Signature *tmp_s = NULL; DetectAddress *src_gr = NULL, *dst_gr = NULL, *sig_gr = NULL, *lookup_gr = NULL; DetectAddress *src_gr_head = NULL, *dst_gr_head = NULL, *sig_gr_head = NULL; uint32_t max_idx = 0; /* loop through the global source address list */ src_gr_head = GetHeadPtr(head,family); for (src_gr = src_gr_head; src_gr != NULL; src_gr = src_gr->next) { //printf(" * Source group: "); DetectAddressPrint(src_gr); printf("\n"); /* initialize the destination group head */ src_gr->dst_gh = DetectAddressHeadInit(); if (src_gr->dst_gh == NULL) { goto error; } /* use a tmp list for speeding up insertions */ DetectAddress *tmp_gr_list = NULL; /* loop through all signatures in this source address group * and build the temporary destination address list for it */ uint32_t sig; for (sig = 0; sig < de_ctx->sig_array_len; sig++) { if (!(src_gr->sh->init->sig_array[(sig/8)] & (1<<(sig%8)))) continue; tmp_s = de_ctx->sig_array[sig]; if (tmp_s == NULL) continue; //printf(" * Source group: "); DetectAddressPrint(src_gr); printf("\n"); max_idx = sig; /* build the temp list */ sig_gr_head = GetHeadPtr(&tmp_s->dst,family); for (sig_gr = sig_gr_head; sig_gr != NULL; sig_gr = sig_gr->next) { //printf(" * Sig dst addr: "); DetectAddressPrint(sig_gr); printf("\n"); if ((lookup_gr = DetectAddressLookupInList(tmp_gr_list, sig_gr)) == NULL) { DetectAddress *grtmp = DetectAddressCopy(sig_gr); if (grtmp == NULL) { goto error; } SigGroupHeadAppendSig(de_ctx, &grtmp->sh, tmp_s); DetectAddressAdd(&tmp_gr_list,grtmp); } else { /* our group will only have one sig, this one. So add that. */ SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, tmp_s); lookup_gr->cnt++; } SCLogDebug("calling SigGroupHeadFree sig_gr %p, sig_gr->sh %p", sig_gr, sig_gr->sh); SigGroupHeadFree(sig_gr->sh); sig_gr->sh = NULL; } } /* Create the destination address list, keeping in * mind the limits we use. */ int groups = (flow ? de_ctx->max_uniq_toserver_dst_groups : de_ctx->max_uniq_toclient_dst_groups); CreateGroupedAddrList(de_ctx, tmp_gr_list, family, src_gr->dst_gh, groups, CreateGroupedAddrListCmpMpmMaxlen, max_idx); /* add the ports to the dst address groups and the sigs * to the ports */ dst_gr_head = GetHeadPtr(src_gr->dst_gh,family); for (dst_gr = dst_gr_head; dst_gr != NULL; dst_gr = dst_gr->next) { //printf(" * Destination group: "); DetectAddressPrint(dst_gr); printf("\n"); dst_gr->flags |= ADDRESS_HAVEPORT; if (dst_gr->sh == NULL) continue; /* we will reuse address sig group heads at this points, * because if the sigs are the same, the ports will be * the same. Saves memory and a lot of init time. */ SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, dst_gr->sh); if (lookup_sgh == NULL) { DetectPortSpHashReset(de_ctx); uint32_t sig2; for (sig2 = 0; sig2 < max_idx+1; sig2++) { if (!(dst_gr->sh->init->sig_array[(sig2/8)] & (1<<(sig2%8)))) continue; Signature *s = de_ctx->sig_array[sig2]; if (s == NULL) continue; //printf(" + Destination group (grouped): "); DetectAddressPrint(dst_gr); printf("\n"); DetectPort *sdp = s->sp; for ( ; sdp != NULL; sdp = sdp->next) { DetectPort *lookup_port = DetectPortSpHashLookup(de_ctx, sdp); if (lookup_port == NULL) { DetectPort *port = DetectPortCopySingle(de_ctx,sdp); if (port == NULL) goto error; SigGroupHeadAppendSig(de_ctx, &port->sh, s); DetectPortSpHashAdd(de_ctx, port); port->cnt = 1; } else { SigGroupHeadAppendSig(de_ctx, &lookup_port->sh, s); lookup_port->cnt++; } } } int spgroups = (flow ? de_ctx->max_uniq_toserver_sp_groups : de_ctx->max_uniq_toclient_sp_groups); CreateGroupedPortList(de_ctx, de_ctx->sport_hash_table, &dst_gr->port, spgroups, CreateGroupedPortListCmpMpmMaxlen, max_idx); SCLogDebug("adding sgh %p to the hash", dst_gr->sh); SigGroupHeadHashAdd(de_ctx, dst_gr->sh); dst_gr->sh->init->port = dst_gr->port; /* mark this head for deletion once we no longer need * the hash. We're only using the port ptr, so no problem * when we remove this after initialization is done */ dst_gr->sh->flags |= SIG_GROUP_HEAD_FREE; /* for each destination port we setup the siggrouphead here */ DetectPort *sp = dst_gr->port; for ( ; sp != NULL; sp = sp->next) { //printf(" * Src Port(range): "); DetectPortPrint(sp); printf("\n"); if (sp->sh == NULL) continue; /* we will reuse address sig group heads at this points, * because if the sigs are the same, the ports will be * the same. Saves memory and a lot of init time. */ SigGroupHead *lookup_sp_sgh = SigGroupHeadSPortHashLookup(de_ctx, sp->sh); if (lookup_sp_sgh == NULL) { DetectPortDpHashReset(de_ctx); uint32_t sig2; for (sig2 = 0; sig2 < max_idx+1; sig2++) { if (!(sp->sh->init->sig_array[(sig2/8)] & (1<<(sig2%8)))) continue; Signature *s = de_ctx->sig_array[sig2]; if (s == NULL) continue; DetectPort *sdp = s->dp; for ( ; sdp != NULL; sdp = sdp->next) { DetectPort *lookup_port = DetectPortDpHashLookup(de_ctx,sdp); if (lookup_port == NULL) { DetectPort *port = DetectPortCopySingle(de_ctx,sdp); if (port == NULL) goto error; SigGroupHeadAppendSig(de_ctx, &port->sh, s); DetectPortDpHashAdd(de_ctx,port); port->cnt = 1; } else { SigGroupHeadAppendSig(de_ctx, &lookup_port->sh, s); lookup_port->cnt++; } } } int dpgroups = (flow ? de_ctx->max_uniq_toserver_dp_groups : de_ctx->max_uniq_toclient_dp_groups); CreateGroupedPortList(de_ctx, de_ctx->dport_hash_table, &sp->dst_ph, dpgroups, CreateGroupedPortListCmpMpmMaxlen, max_idx); SigGroupHeadSPortHashAdd(de_ctx, sp->sh); sp->sh->init->port = sp->dst_ph; /* mark this head for deletion once we no longer need * the hash. We're only using the port ptr, so no problem * when we remove this after initialization is done */ sp->sh->flags |= SIG_GROUP_HEAD_FREE; /* for each destination port we setup the siggrouphead here */ DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { if (dp->sh == NULL) continue; /* Because a pattern matcher context uses quite some * memory, we first check if we can reuse it from * another group head. */ SigGroupHead *lookup_dp_sgh = SigGroupHeadDPortHashLookup(de_ctx, dp->sh); if (lookup_dp_sgh == NULL) { SCLogDebug("dp %p dp->sh %p is the original (sp %p, dst_gr %p, src_gr %p)", dp, dp->sh, sp, dst_gr, src_gr); SigGroupHeadSetSigCnt(dp->sh, max_idx); SigGroupHeadBuildMatchArray(de_ctx,dp->sh, max_idx); /* init the pattern matcher, this will respect the copy * setting */ if (PatternMatchPrepareGroup(de_ctx, dp->sh) < 0) { printf("PatternMatchPrepareGroup failed\n"); goto error; } if (dp->sh->mpm_proto_tcp_ctx_ts != NULL) { if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt) de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; } if (dp->sh->mpm_proto_tcp_ctx_tc != NULL) { if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt) de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; } if (dp->sh->mpm_proto_udp_ctx_ts != NULL) { if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt) de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt; de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt; } if (dp->sh->mpm_proto_udp_ctx_tc != NULL) { if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt) de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt; de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt; } if (dp->sh->mpm_proto_other_ctx != NULL) { if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_other_ctx->pattern_cnt) de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_other_ctx->pattern_cnt; de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_other_ctx->pattern_cnt; } if (dp->sh->mpm_uri_ctx_ts != NULL) { if (de_ctx->mpm_uri_max_patcnt < dp->sh->mpm_uri_ctx_ts->pattern_cnt) de_ctx->mpm_uri_max_patcnt = dp->sh->mpm_uri_ctx_ts->pattern_cnt; de_ctx->mpm_uri_tot_patcnt += dp->sh->mpm_uri_ctx_ts->pattern_cnt; } if (dp->sh->mpm_uri_ctx_tc != NULL) { if (de_ctx->mpm_uri_max_patcnt < dp->sh->mpm_uri_ctx_tc->pattern_cnt) de_ctx->mpm_uri_max_patcnt = dp->sh->mpm_uri_ctx_tc->pattern_cnt; de_ctx->mpm_uri_tot_patcnt += dp->sh->mpm_uri_ctx_tc->pattern_cnt; } /* dbg */ if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_tcp_ctx_ts) { de_ctx->mpm_memory_size += dp->sh->mpm_proto_tcp_ctx_ts->memory_size; } if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_tcp_ctx_tc) { de_ctx->mpm_memory_size += dp->sh->mpm_proto_tcp_ctx_tc->memory_size; } if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_udp_ctx_ts) { de_ctx->mpm_memory_size += dp->sh->mpm_proto_udp_ctx_ts->memory_size; } if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_udp_ctx_tc) { de_ctx->mpm_memory_size += dp->sh->mpm_proto_udp_ctx_tc->memory_size; } if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_other_ctx) { de_ctx->mpm_memory_size += dp->sh->mpm_proto_other_ctx->memory_size; } if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY) && dp->sh->mpm_uri_ctx_ts) { de_ctx->mpm_memory_size += dp->sh->mpm_uri_ctx_ts->memory_size; } if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY) && dp->sh->mpm_uri_ctx_tc) { de_ctx->mpm_memory_size += dp->sh->mpm_uri_ctx_tc->memory_size; } SigGroupHeadDPortHashAdd(de_ctx, dp->sh); SigGroupHeadStore(de_ctx, dp->sh); de_ctx->gh_unique++; } else { SCLogDebug("dp %p dp->sh %p is a copy", dp, dp->sh); SigGroupHeadFree(dp->sh); dp->sh = lookup_dp_sgh; dp->flags |= PORT_SIGGROUPHEAD_COPY; dp->sh->flags |= SIG_GROUP_HEAD_REFERENCED; de_ctx->gh_reuse++; } } /* sig group head found in hash, free it and use the hashed one */ } else { SigGroupHeadFree(sp->sh); sp->sh = lookup_sp_sgh; sp->flags |= PORT_SIGGROUPHEAD_COPY; sp->sh->flags |= SIG_GROUP_HEAD_REFERENCED; SCLogDebug("replacing sp->dst_ph %p with lookup_sp_sgh->init->port %p", sp->dst_ph, lookup_sp_sgh->init->port); DetectPortCleanupList(sp->dst_ph); sp->dst_ph = lookup_sp_sgh->init->port; sp->flags |= PORT_GROUP_PORTS_COPY; de_ctx->gh_reuse++; } } } else { SigGroupHeadFree(dst_gr->sh); dst_gr->sh = lookup_sgh; dst_gr->flags |= ADDRESS_SIGGROUPHEAD_COPY; dst_gr->sh->flags |= SIG_GROUP_HEAD_REFERENCED; SCLogDebug("replacing dst_gr->port %p with lookup_sgh->init->port %p", dst_gr->port, lookup_sgh->init->port); DetectPortCleanupList(dst_gr->port); dst_gr->port = lookup_sgh->init->port; dst_gr->flags |= ADDRESS_PORTS_COPY; de_ctx->gh_reuse++; } } /* free the temp list */ DetectAddressCleanupList(tmp_gr_list); /* clear now unneeded sig group head */ SigGroupHeadFree(src_gr->sh); src_gr->sh = NULL; /* free dst addr sgh's */ dst_gr_head = GetHeadPtr(src_gr->dst_gh,family); for (dst_gr = dst_gr_head; dst_gr != NULL; dst_gr = dst_gr->next) { if (!(dst_gr->flags & ADDRESS_SIGGROUPHEAD_COPY)) { if (!(dst_gr->sh->flags & SIG_GROUP_HEAD_REFERENCED)) { SCLogDebug("removing sgh %p from hash", dst_gr->sh); int r = SigGroupHeadHashRemove(de_ctx,dst_gr->sh); BUG_ON(r == -1); if (r == 0) { SCLogDebug("removed sgh %p from hash", dst_gr->sh); SigGroupHeadFree(dst_gr->sh); dst_gr->sh = NULL; } } } } } return 0; error: return -1; } static void DetectEngineBuildDecoderEventSgh(DetectEngineCtx *de_ctx) { if (de_ctx->decoder_event_sgh == NULL) return; uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx); SigGroupHeadSetSigCnt(de_ctx->decoder_event_sgh, max_idx); SigGroupHeadBuildMatchArray(de_ctx, de_ctx->decoder_event_sgh, max_idx); } int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) { int r; if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("building signature grouping structure, stage 3: " "building destination address lists..."); } //DetectAddressPrintMemory(); //DetectSigGroupPrintMemory(); //DetectPortPrintMemory(); int f = 0; int proto; for (f = 0; f < FLOW_STATES; f++) { r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); goto error; } r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); goto error; } r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); goto error; } r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET6,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); goto error; } r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET6,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); goto error; } r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET6,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); goto error; } r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_UNSPEC,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); goto error; } r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_UNSPEC,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); goto error; } r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_UNSPEC,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); goto error; } for (proto = 0; proto < 256; proto++) { if (proto == IPPROTO_TCP || proto == IPPROTO_UDP || proto == IPPROTO_SCTP) continue; r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_INET) failed\n", proto); goto error; } r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET6,f); if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_INET6) failed\n", proto); goto error; } r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_UNSPEC,f); /* for any */ if (r < 0) { printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_UNSPEC) failed\n", proto); goto error; } } } /* prepare the decoder event sgh */ DetectEngineBuildDecoderEventSgh(de_ctx); /* cleanup group head (uri)content_array's */ SigGroupHeadFreeMpmArrays(de_ctx); /* cleanup group head sig arrays */ SigGroupHeadFreeSigArrays(de_ctx); /* cleanup the hashes now since we won't need them * after the initialization phase. */ SigGroupHeadHashFree(de_ctx); SigGroupHeadDPortHashFree(de_ctx); SigGroupHeadSPortHashFree(de_ctx); SigGroupHeadMpmHashFree(de_ctx); SigGroupHeadMpmUriHashFree(de_ctx); DetectPortDpHashFree(de_ctx); DetectPortSpHashFree(de_ctx); if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("MPM memory %" PRIuMAX " (dynamic %" PRIu32 ", ctxs %" PRIuMAX ", avg per ctx %" PRIu32 ")", de_ctx->mpm_memory_size + ((de_ctx->mpm_unique + de_ctx->mpm_uri_unique) * (uintmax_t)sizeof(MpmCtx)), de_ctx->mpm_memory_size, ((de_ctx->mpm_unique + de_ctx->mpm_uri_unique) * (uintmax_t)sizeof(MpmCtx)), de_ctx->mpm_unique ? de_ctx->mpm_memory_size / de_ctx->mpm_unique: 0); SCLogDebug("max sig id %" PRIu32 ", array size %" PRIu32 "", DetectEngineGetMaxSigId(de_ctx), DetectEngineGetMaxSigId(de_ctx) / 8 + 1); SCLogDebug("signature group heads: unique %" PRIu32 ", copies %" PRIu32 ".", de_ctx->gh_unique, de_ctx->gh_reuse); SCLogDebug("MPM instances: %" PRIu32 " unique, copies %" PRIu32 " (none %" PRIu32 ").", de_ctx->mpm_unique, de_ctx->mpm_reuse, de_ctx->mpm_none); SCLogDebug("MPM (URI) instances: %" PRIu32 " unique, copies %" PRIu32 " (none %" PRIu32 ").", de_ctx->mpm_uri_unique, de_ctx->mpm_uri_reuse, de_ctx->mpm_uri_none); SCLogDebug("MPM max patcnt %" PRIu32 ", avg %" PRIu32 "", de_ctx->mpm_max_patcnt, de_ctx->mpm_unique?de_ctx->mpm_tot_patcnt/de_ctx->mpm_unique:0); if (de_ctx->mpm_uri_tot_patcnt && de_ctx->mpm_uri_unique) SCLogDebug("MPM (URI) max patcnt %" PRIu32 ", avg %" PRIu32 " (%" PRIu32 "/%" PRIu32 ")", de_ctx->mpm_uri_max_patcnt, de_ctx->mpm_uri_tot_patcnt/de_ctx->mpm_uri_unique, de_ctx->mpm_uri_tot_patcnt, de_ctx->mpm_uri_unique); SCLogDebug("port maxgroups: %" PRIu32 ", avg %" PRIu32 ", tot %" PRIu32 "", g_groupportlist_maxgroups, g_groupportlist_groupscnt ? g_groupportlist_totgroups/g_groupportlist_groupscnt : 0, g_groupportlist_totgroups); SCLogInfo("building signature grouping structure, stage 3: building destination address lists... complete"); } return 0; error: printf("SigAddressPrepareStage3 error\n"); return -1; } int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) { BUG_ON(de_ctx == NULL); if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("cleaning up signature grouping structure..."); } int f, proto; for (f = 0; f < FLOW_STATES; f++) { for (proto = 0; proto < 256; proto++) { /* XXX fix this */ DetectAddressHeadFree(de_ctx->flow_gh[f].src_gh[proto]); de_ctx->flow_gh[f].src_gh[proto] = NULL; } } IPOnlyDeinit(de_ctx, &de_ctx->io_ctx); if (!(de_ctx->flags & DE_QUIET)) { SCLogInfo("cleaning up signature grouping structure... complete"); } return 0; } void DbgPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { if (sgh == NULL) { printf("\n"); return; } uint32_t sig; for (sig = 0; sig < sgh->sig_cnt; sig++) { printf("%" PRIu32 " ", sgh->match_array[sig]->id); } printf("\n"); } void DbgPrintSigs2(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { if (sgh == NULL || sgh->init == NULL) { printf("\n"); return; } uint32_t sig; for (sig = 0; sig < DetectEngineGetMaxSigId(de_ctx); sig++) { if (sgh->init->sig_array[(sig/8)] & (1<<(sig%8))) { printf("%" PRIu32 " ", de_ctx->sig_array[sig]->id); } } printf("\n"); } void DbgSghContainsSig(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid) { if (sgh == NULL || sgh->init == NULL) { printf("\n"); return; } uint32_t sig; for (sig = 0; sig < DetectEngineGetMaxSigId(de_ctx); sig++) { if (!(sgh->init->sig_array[(sig/8)] & (1<<(sig%8)))) continue; Signature *s = de_ctx->sig_array[sig]; if (s == NULL) continue; if (sid == s->id) { printf("%" PRIu32 " ", de_ctx->sig_array[sig]->id); } } printf("\n"); } /** \brief finalize preparing sgh's */ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) { SCEnter(); //SCLogInfo("sgh's %"PRIu32, de_ctx->sgh_array_cnt); uint32_t idx = 0; for (idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { SigGroupHead *sgh = de_ctx->sgh_array[idx]; if (sgh == NULL) continue; SigGroupHeadBuildHeadArray(de_ctx, sgh); SigGroupHeadSetFilemagicFlag(de_ctx, sgh); SigGroupHeadSetFileMd5Flag(de_ctx, sgh); SigGroupHeadSetFilesizeFlag(de_ctx, sgh); SigGroupHeadSetFilestoreCount(de_ctx, sgh); SCLogDebug("filestore count %u", sgh->filestore_cnt); } if (de_ctx->decoder_event_sgh != NULL) { SigGroupHeadBuildHeadArray(de_ctx, de_ctx->decoder_event_sgh); /* no need to set filestore count here as that would make a * signature not decode event only. */ } SCFree(de_ctx->sgh_array); de_ctx->sgh_array_cnt = 0; de_ctx->sgh_array_size = 0; SCReturnInt(0); } /* shortcut for debugging. If enabled Stage5 will * print sigid's for all groups */ #define PRINTSIGS /* just printing */ int SigAddressPrepareStage5(DetectEngineCtx *de_ctx) { DetectAddressHead *global_dst_gh = NULL; DetectAddress *global_src_gr = NULL, *global_dst_gr = NULL; uint32_t u; printf("* Building signature grouping structure, stage 5: print...\n"); int f, proto; printf("\n"); for (f = 0; f < FLOW_STATES; f++) { printf("\n"); for (proto = 0; proto < 256; proto++) { if (proto != IPPROTO_TCP) continue; for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->ipv4_head; global_src_gr != NULL; global_src_gr = global_src_gr->next) { printf("1 Src Addr: "); DetectAddressPrint(global_src_gr); printf(" (sh %p)\n", global_src_gr->sh); //printf("\n"); #ifdef PRINTSIGS SigGroupHeadPrintSigs(de_ctx, global_src_gr->sh); if (global_src_gr->sh != NULL) { printf(" - "); for (u = 0; u < global_src_gr->sh->sig_cnt; u++) { Signature *s = global_src_gr->sh->match_array[u]; printf("%" PRIu32 " ", s->id); } printf("\n"); } #endif global_dst_gh = global_src_gr->dst_gh; if (global_dst_gh == NULL) continue; for (global_dst_gr = global_dst_gh->ipv4_head; global_dst_gr != NULL; global_dst_gr = global_dst_gr->next) { printf(" 2 Dst Addr: "); DetectAddressPrint(global_dst_gr); //printf(" (sh %p) ", global_dst_gr->sh); if (global_dst_gr->sh) { if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { printf(" (COPY): "); } else { printf(" (ORIGINAL): "); } } else { printf(" "); } #ifdef PRINTSIGS if (global_dst_gr->sh != NULL) { printf(" - "); for (u = 0; u < global_dst_gr->sh->sig_cnt; u++) { Signature *s = global_dst_gr->sh->match_array[u]; printf("%" PRIu32 " ", s->id); } printf("\n"); } #endif DetectPort *sp = global_dst_gr->port; for ( ; sp != NULL; sp = sp->next) { printf(" 3 Src port(range): "); DetectPortPrint(sp); //printf(" (sh %p)", sp->sh); printf("\n"); DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { printf(" 4 Dst port(range): "); DetectPortPrint(dp); printf(" (sigs %" PRIu32 ", sgh %p, maxlen %" PRIu32 ")", dp->sh->sig_cnt, dp->sh, dp->sh->mpm_content_maxlen); #ifdef PRINTSIGS printf(" - "); for (u = 0; u < dp->sh->sig_cnt; u++) { Signature *s = dp->sh->match_array[u]; printf("%" PRIu32 " ", s->id); } #endif printf("\n"); } } } for (global_dst_gr = global_dst_gh->any_head; global_dst_gr != NULL; global_dst_gr = global_dst_gr->next) { printf(" - "); DetectAddressPrint(global_dst_gr); //printf(" (sh %p) ", global_dst_gr->sh); if (global_dst_gr->sh) { if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { printf("(COPY)\n"); } else { printf("\n"); } } DetectPort *sp = global_dst_gr->port; for ( ; sp != NULL; sp = sp->next) { printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { printf(" * Dst port(range): "); DetectPortPrint(dp); printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); #ifdef PRINTSIGS printf(" - "); for (u = 0; u < dp->sh->sig_cnt; u++) { Signature *s = dp->sh->match_array[u]; printf("%" PRIu32 " ", s->id); } #endif printf("\n"); } } } } #if 0 for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->ipv6_head; global_src_gr != NULL; global_src_gr = global_src_gr->next) { printf("- "); DetectAddressPrint(global_src_gr); //printf(" (sh %p)\n", global_src_gr->sh); global_dst_gh = global_src_gr->dst_gh; if (global_dst_gh == NULL) continue; for (global_dst_gr = global_dst_gh->ipv6_head; global_dst_gr != NULL; global_dst_gr = global_dst_gr->next) { printf(" - "); DetectAddressPrint(global_dst_gr); //printf(" (sh %p) ", global_dst_gr->sh); if (global_dst_gr->sh) { if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { printf("(COPY)\n"); } else { printf("\n"); } } DetectPort *sp = global_dst_gr->port; for ( ; sp != NULL; sp = sp->next) { printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { printf(" * Dst port(range): "); DetectPortPrint(dp); printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); #ifdef PRINTSIGS printf(" - "); for (u = 0; u < dp->sh->sig_cnt; u++) { Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; printf("%" PRIu32 " ", s->id); } #endif printf("\n"); } } } for (global_dst_gr = global_dst_gh->any_head; global_dst_gr != NULL; global_dst_gr = global_dst_gr->next) { printf(" - "); DetectAddressPrint(global_dst_gr); //printf(" (sh %p) ", global_dst_gr->sh); if (global_dst_gr->sh) { if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { printf("(COPY)\n"); } else { printf("\n"); } } DetectPort *sp = global_dst_gr->port; for ( ; sp != NULL; sp = sp->next) { printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { printf(" * Dst port(range): "); DetectPortPrint(dp); printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); #ifdef PRINTSIGS printf(" - "); for (u = 0; u < dp->sh->sig_cnt; u++) { Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; printf("%" PRIu32 " ", s->id); } #endif printf("\n"); } } } } for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->any_head; global_src_gr != NULL; global_src_gr = global_src_gr->next) { printf("- "); DetectAddressPrint(global_src_gr); //printf(" (sh %p)\n", global_src_gr->sh); global_dst_gh = global_src_gr->dst_gh; if (global_dst_gh == NULL) continue; for (global_dst_gr = global_dst_gh->any_head; global_dst_gr != NULL; global_dst_gr = global_dst_gr->next) { printf(" - "); DetectAddressPrint(global_dst_gr); //printf(" (sh %p) ", global_dst_gr->sh); if (global_dst_gr->sh) { if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { printf("(COPY)\n"); } else { printf("\n"); } } DetectPort *sp = global_dst_gr->port; for ( ; sp != NULL; sp = sp->next) { printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { printf(" * Dst port(range): "); DetectPortPrint(dp); printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); #ifdef PRINTSIGS printf(" - "); for (u = 0; u < dp->sh->sig_cnt; u++) { Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; printf("%" PRIu32 " ", s->id); } #endif printf("\n"); } } } for (global_dst_gr = global_dst_gh->ipv4_head; global_dst_gr != NULL; global_dst_gr = global_dst_gr->next) { printf(" - "); DetectAddressPrint(global_dst_gr); //printf(" (sh %p) ", global_dst_gr->sh); if (global_dst_gr->sh) { if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { printf("(COPY)\n"); } else { printf("\n"); } } DetectPort *sp = global_dst_gr->port; for ( ; sp != NULL; sp = sp->next) { printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { printf(" * Dst port(range): "); DetectPortPrint(dp); printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); #ifdef PRINTSIGS printf(" - "); for (u = 0; u < dp->sh->sig_cnt; u++) { Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; printf("%" PRIu32 " ", s->id); } #endif printf("\n"); } } } for (global_dst_gr = global_dst_gh->ipv6_head; global_dst_gr != NULL; global_dst_gr = global_dst_gr->next) { printf(" - "); DetectAddressPrint(global_dst_gr); //printf(" (sh %p) ", global_dst_gr->sh); if (global_dst_gr->sh) { if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { printf("(COPY)\n"); } else { printf("\n"); } } DetectPort *sp = global_dst_gr->port; for ( ; sp != NULL; sp = sp->next) { printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); DetectPort *dp = sp->dst_ph; for ( ; dp != NULL; dp = dp->next) { printf(" * Dst port(range): "); DetectPortPrint(dp); printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); #ifdef PRINTSIGS printf(" - "); for (u = 0; u < dp->sh->sig_cnt; u++) { Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; printf("%" PRIu32 " ", s->id); } #endif printf("\n"); } } } } #endif } } printf("* Building signature grouping structure, stage 5: print... done\n"); return 0; } /** * \brief Convert the signature list into the runtime match structure. * * \param de_ctx Pointer to the Detection Engine Context whose Signatures have * to be processed * * \retval 0 Always */ int SigGroupBuild (DetectEngineCtx *de_ctx) { Signature *s = de_ctx->sig_list; /* Assign the unique order id of signatures after sorting, * so the IP Only engine process them in order too. Also * reset the old signums and assign new signums. We would * have experienced Sig reordering by now, hence the new * signums. */ de_ctx->signum = 0; while (s != NULL) { s->num = de_ctx->signum++; s = s->next; } /* if we are using single sgh_mpm_context then let us init the standard mpm * contexts using the mpm_ctx factory */ if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { SigInitStandardMpmFactoryContexts(de_ctx); } if (SigAddressPrepareStage1(de_ctx) != 0) { SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); exit(EXIT_FAILURE); } if (SigAddressPrepareStage2(de_ctx) != 0) { SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); exit(EXIT_FAILURE); } #ifdef __SC_CUDA_SUPPORT__ unsigned int cuda_total = 0; unsigned int cuda_free_before_alloc = 0; /* we register a module that would require cuda handler service. This * module would hold the context for all the patterns in the rules */ de_ctx->cuda_rc_mod_handle = SCCudaHlRegisterModule("SC_RULES_CONTENT_B2G_CUDA"); if (de_ctx->mpm_matcher == MPM_B2G_CUDA) { CUcontext dummy_context; if (SCCudaHlGetCudaContext(&dummy_context, "mpm", de_ctx->cuda_rc_mod_handle) == -1) { SCLogError(SC_ERR_B2G_CUDA_ERROR, "Error getting a cuda context for the " "module SC_RULES_CONTENT_B2G_CUDA"); } SCCudaCtxPushCurrent(dummy_context); if (SCCudaMemGetInfo(&cuda_free_before_alloc, &cuda_total) == 0) { SCLogInfo("Total Memory available in the CUDA context used for mpm " "with b2g: %.2f MB", cuda_total/(1024.0 * 1024.0)); SCLogInfo("Free Memory available in the CUDA context used for b2g " "mpm before any allocation is made on the GPU for the " "context: %.2f MB", cuda_free_before_alloc/(1024.0 * 1024.0)); } } #endif if (SigAddressPrepareStage3(de_ctx) != 0) { SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); exit(EXIT_FAILURE); } if (SigAddressPrepareStage4(de_ctx) != 0) { SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); exit(EXIT_FAILURE); } #ifdef __SC_CUDA_SUPPORT__ unsigned int cuda_free_after_alloc = 0; /* if a user has selected some other mpm algo other than b2g_cuda, inspite of * enabling cuda support, then no cuda contexts or cuda vars would be created. * Pop the cuda context, only on confirming that the MPM algo selected is the * CUDA mpm algo */ if (de_ctx->mpm_matcher == MPM_B2G_CUDA) { if (SCCudaMemGetInfo(&cuda_free_after_alloc, &cuda_total) == 0) { SCLogInfo("Free Memory available in the CUDA context used for b2g mpm " "after allocation is made on the GPU for the context: %.2f MB", cuda_free_after_alloc/(1024.0 * 1024.0)); SCLogInfo("Total memory consumed by the CUDA context for the b2g mpm: " "%.2f MB", (cuda_free_before_alloc/(1024.0 * 1024.0)) - (cuda_free_after_alloc/(1024.0 * 1024.0))); } /* the AddressPrepareStage3 actually handles the creation of device * pointers on the gpu. The cuda context that stage3 used would still be * attached to this host thread. We need to pop this cuda context so that * the dispatcher thread that we are going to create for the above module * we registered can attach to this cuda context */ CUcontext context; if (SCCudaCtxPopCurrent(&context) == -1) exit(EXIT_FAILURE); } #endif if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { MpmCtx *mpm_ctx = NULL; mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("packet- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("packet- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("packet- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("uri- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hcbd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hhd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hrhd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hmd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hcd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hrud- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("stream- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hsmd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hsmd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hscd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hscd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("huad- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("huad- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hhhd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hhhd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hrhhd- %d\n", mpm_ctx->pattern_cnt); mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } //printf("hrhhd- %d\n", mpm_ctx->pattern_cnt); } // SigAddressPrepareStage5(de_ctx); // DetectAddressPrintMemory(); // DetectSigGroupPrintMemory(); // DetectPortPrintMemory(); #ifdef PROFILING SCProfilingRuleInitCounters(de_ctx); #endif return 0; } int SigGroupCleanup (DetectEngineCtx *de_ctx) { SigAddressCleanupStage1(de_ctx); return 0; } static inline void PrintFeatureList(int flags, char sep) { int prev = 0; if (flags & SIGMATCH_NOOPT) { printf("No option"); prev = 1; } if (flags & SIGMATCH_IPONLY_COMPAT) { if (prev == 1) printf("%c", sep); printf("compatible with IP only rule"); prev = 1; } if (flags & SIGMATCH_DEONLY_COMPAT) { if (prev == 1) printf("%c", sep); printf("compatible with decoder event only rule"); prev = 1; } if (flags & SIGMATCH_PAYLOAD) { if (prev == 1) printf("%c", sep); printf("payload inspecting keyword"); prev = 1; } if (prev == 0) { printf("none"); } } static inline void SigMultilinePrint(int i, char *prefix) { if (sigmatch_table[i].desc) { printf("%sDescription: %s\n", prefix, sigmatch_table[i].desc); } printf("%sProtocol: %s\n", prefix, AppLayerGetProtoString(sigmatch_table[i].alproto)); printf("%sFeatures: ", prefix); PrintFeatureList(sigmatch_table[i].flags, ','); if (sigmatch_table[i].url) { printf("\n%sDocumentation: %s", prefix, sigmatch_table[i].url); } printf("\n"); } void SigTableList(const char *keyword) { size_t size = sizeof(sigmatch_table) / sizeof(SigTableElmt); size_t i; if (keyword == NULL) { printf("=====Supported keywords=====\n"); for (i = 0; i < size; i++) { if (sigmatch_table[i].name != NULL) { if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { printf("- %s (not built-in)\n", sigmatch_table[i].name); } else { printf("- %s\n", sigmatch_table[i].name); } } } } else if (!strcmp("csv", keyword)) { printf("name;description;app layer;features;documentation\n"); for (i = 0; i < size; i++) { if (sigmatch_table[i].name != NULL) { if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { continue; } printf("%s;", sigmatch_table[i].name); if (sigmatch_table[i].desc) { printf("%s", sigmatch_table[i].desc); } /* Build feature */ printf(";%s;", AppLayerGetProtoString(sigmatch_table[i].alproto)); PrintFeatureList(sigmatch_table[i].flags, ':'); printf(";"); if (sigmatch_table[i].url) { printf("%s", sigmatch_table[i].url); } printf(";"); printf("\n"); } } } else if (!strcmp("all", keyword)) { for (i = 0; i < size; i++) { printf("%s:\n", sigmatch_table[i].name); SigMultilinePrint(i, "\t"); } } else { for (i = 0; i < size; i++) { if ((sigmatch_table[i].name != NULL) && !strcmp(sigmatch_table[i].name, keyword)) { printf("= %s =\n", sigmatch_table[i].name); if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { printf("Not built-in\n"); return; } SigMultilinePrint(i, ""); return; } } } return; } void SigTableSetup(void) { memset(sigmatch_table, 0, sizeof(sigmatch_table)); DetectSidRegister(); DetectPriorityRegister(); DetectRevRegister(); DetectClasstypeRegister(); DetectReferenceRegister(); DetectTagRegister(); DetectThresholdRegister(); DetectMetadataRegister(); DetectMsgRegister(); DetectAckRegister(); DetectSeqRegister(); DetectContentRegister(); DetectUricontentRegister(); DetectPcreRegister(); DetectDepthRegister(); DetectNocaseRegister(); DetectRawbytesRegister(); DetectBytetestRegister(); DetectBytejumpRegister(); DetectSameipRegister(); DetectGeoipRegister(); DetectL3ProtoRegister(); DetectIPProtoRegister(); DetectWithinRegister(); DetectDistanceRegister(); DetectOffsetRegister(); DetectReplaceRegister(); DetectFlowRegister(); DetectWindowRegister(); DetectRpcRegister(); DetectFtpbounceRegister(); DetectIsdataatRegister(); DetectIdRegister(); DetectDsizeRegister(); DetectFlowvarRegister(); DetectFlowintRegister(); DetectPktvarRegister(); DetectNoalertRegister(); DetectFlowbitsRegister(); DetectEngineEventRegister(); DetectIpOptsRegister(); DetectFlagsRegister(); DetectFragBitsRegister(); DetectFragOffsetRegister(); DetectGidRegister(); DetectMarkRegister(); DetectCsumRegister(); DetectStreamSizeRegister(); DetectTtlRegister(); DetectTosRegister(); DetectFastPatternRegister(); DetectITypeRegister(); DetectICodeRegister(); DetectIcmpIdRegister(); DetectIcmpSeqRegister(); DetectDceIfaceRegister(); DetectDceOpnumRegister(); DetectDceStubDataRegister(); DetectHttpCookieRegister(); DetectHttpMethodRegister(); DetectHttpStatMsgRegister(); DetectTlsRegister(); DetectTlsVersionRegister(); DetectUrilenRegister(); DetectDetectionFilterRegister(); DetectHttpHeaderRegister(); DetectHttpRawHeaderRegister(); DetectHttpClientBodyRegister(); DetectHttpServerBodyRegister(); DetectHttpUriRegister(); DetectHttpRawUriRegister(); DetectAsn1Register(); DetectSshVersionRegister(); DetectSslStateRegister(); DetectSshSoftwareVersionRegister(); DetectHttpStatCodeRegister(); DetectSslVersionRegister(); DetectByteExtractRegister(); DetectFiledataRegister(); DetectPktDataRegister(); DetectFilenameRegister(); DetectFileextRegister(); DetectFilestoreRegister(); DetectFilemagicRegister(); DetectFileMd5Register(); DetectFilesizeRegister(); DetectAppLayerEventRegister(); DetectHttpUARegister(); DetectHttpHHRegister(); DetectHttpHRHRegister(); DetectLuajitRegister(); DetectIPRepRegister(); uint8_t i = 0; for (i = 0; i < DETECT_TBLSIZE; i++) { if (sigmatch_table[i].RegisterTests == NULL) { SCLogDebug("detection plugin %s has no unittest " "registration function.", sigmatch_table[i].name); } } } void SigTableRegisterTests(void) { /* register the tests */ uint8_t i = 0; for (i = 0; i < DETECT_TBLSIZE; i++) { if (sigmatch_table[i].RegisterTests != NULL) { sigmatch_table[i].RegisterTests(); } } } /* * TESTS */ #ifdef UNITTESTS #include "flow-util.h" #include "stream-tcp-reassemble.h" #include "util-var-name.h" static const char *dummy_conf_string = "%YAML 1.1\n" "---\n" "\n" "default-log-dir: /var/log/suricata\n" "\n" "logging:\n" "\n" " default-log-level: debug\n" "\n" " default-format: \"<%t> - <%l>\"\n" "\n" " default-startup-message: Your IDS has started.\n" "\n" " default-output-filter:\n" "\n" " output:\n" "\n" " - interface: console\n" " log-level: info\n" "\n" " - interface: file\n" " filename: /var/log/suricata.log\n" "\n" " - interface: syslog\n" " facility: local5\n" " format: \"%l\"\n" "\n" "pfring:\n" "\n" " interface: eth0\n" "\n" " clusterid: 99\n" "\n" "vars:\n" "\n" " address-groups:\n" "\n" " HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:" "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n" "\n" " EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n" "\n" " HTTP_SERVERS: \"!192.168.0.0/16\"\n" "\n" " SMTP_SERVERS: \"!192.168.0.0/16\"\n" "\n" " SQL_SERVERS: \"!192.168.0.0/16\"\n" "\n" " DNS_SERVERS: any\n" "\n" " TELNET_SERVERS: any\n" "\n" " AIM_SERVERS: any\n" "\n" " port-groups:\n" "\n" " HTTP_PORTS: \"80:81,88\"\n" "\n" " SHELLCODE_PORTS: 80\n" "\n" " ORACLE_PORTS: 1521\n" "\n" " SSH_PORTS: 22\n" "\n"; static int SigTest01Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, mpm_type) == 0) { result = 0; goto end; } #if 0 //printf("URI0 \"%s\", len %" PRIu32 "\n", p.http_uri.raw[0], p.http_uri.raw_size[0]); //printf("URI1 \"%s\", len %" PRIu32 "\n", p.http_uri.raw[1], p.http_uri.raw_size[1]); if (p->http_uri.raw_size[0] == 5 && memcmp(p->http_uri.raw[0], "/one/", 5) == 0 && p->http_uri.raw_size[1] == 5 && memcmp(p->http_uri.raw[1], "/two/", 5) == 0) { result = 1; } #endif result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } static int SigTest01B2g (void) { return SigTest01Real(MPM_B2G); } static int SigTest01B3g (void) { return SigTest01Real(MPM_B3G); } static int SigTest01Wm (void) { return SigTest01Real(MPM_WUMANBER); } static int SigTest02Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); char sig[] = "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:41; sid:1;)"; int ret = UTHPacketMatchSigMpm(p, sig, mpm_type); UTHFreePacket(p); return ret; } static int SigTest02B2g (void) { return SigTest02Real(MPM_B2G); } static int SigTest02B3g (void) { return SigTest02Real(MPM_B3G); } static int SigTest02Wm (void) { return SigTest02Real(MPM_WUMANBER); } static int SigTest03Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:39; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTest03B2g (void) { return SigTest03Real(MPM_B2G); } static int SigTest03B3g (void) { return SigTest03Real(MPM_B3G); } static int SigTest03Wm (void) { return SigTest03Real(MPM_WUMANBER); } static int SigTest04Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20*/ "Host: one.example.org\r\n" /* 23, post "Host:" 18 */ "\r\n\r\n" /* 4 */ "GET /two/ HTTP/1.1\r\n" /* 20 */ "Host: two.example.org\r\n" /* 23 */ "\r\n\r\n"; /* 4 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:42; within:47; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTest04B2g (void) { return SigTest04Real(MPM_B2G); } static int SigTest04B3g (void) { return SigTest04Real(MPM_B3G); } static int SigTest04Wm (void) { return SigTest04Real(MPM_WUMANBER); } static int SigTest05Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20 */ "Host: one.example.org\r\n" /* 23, 43 */ "\r\n\r\n" /* 4, 47 */ "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ "Host: two.example.org\r\n" /* 23, 90 */ "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:48; within:52; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { result = 1; } else { printf("sig matched but shouldn't have: "); } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTest05B2g (void) { return SigTest05Real(MPM_B2G); } static int SigTest05B3g (void) { return SigTest05Real(MPM_B3G); } static int SigTest05Wm (void) { return SigTest05Real(MPM_WUMANBER); } static int SigTest06Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20 */ "Host: one.example.org\r\n" /* 23, 43 */ "\r\n\r\n" /* 4, 47 */ "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ "Host: two.example.org\r\n" /* 23, 90 */ "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; Flow f; TcpSession ssn; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 1; else printf("sid:1 %s, sid:2 %s: ", PacketAlertCheck(p, 1) ? "OK" : "FAIL", PacketAlertCheck(p, 2) ? "OK" : "FAIL"); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } static int SigTest06B2g (void) { return SigTest06Real(MPM_B2G); } static int SigTest06B3g (void) { return SigTest06Real(MPM_B3G); } static int SigTest06Wm (void) { return SigTest06Real(MPM_WUMANBER); } static int SigTest07Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20 */ "Host: one.example.org\r\n" /* 23, 43 */ "\r\n\r\n" /* 4, 47 */ "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ "Host: two.example.org\r\n" /* 23, 90 */ "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; TcpSession ssn; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"three\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 0; else result = 1; end: UTHFreePackets(&p, 1); StreamTcpFreeConfig(TRUE); AppLayerParserCleanupState(&f); FLOW_DESTROY(&f); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); return result; } static int SigTest07B2g (void) { return SigTest07Real(MPM_B2G); } static int SigTest07B3g (void) { return SigTest07Real(MPM_B3G); } static int SigTest07Wm (void) { return SigTest07Real(MPM_WUMANBER); } static int SigTest08Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.0\r\n" /* 20 */ "Host: one.example.org\r\n" /* 23, 43 */ "\r\n\r\n" /* 4, 47 */ "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ "Host: two.example.org\r\n" /* 23, 90 */ "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; Flow f; TcpSession ssn; int result = 0; memset(&f, 0, sizeof(Flow)); memset(&th_v, 0, sizeof(th_v)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"one\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ( (PacketAlertCheck(p, 1) || FlowAlertSidIsset(&f, 1)) && PacketAlertCheck(p, 2)) result = 1; else printf("sid:1 %s, sid:2 %s: ", PacketAlertCheck(p, 1) ? "OK" : "FAIL", PacketAlertCheck(p, 2) ? "OK" : "FAIL"); AppLayerParserCleanupState(&f); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } static int SigTest08B2g (void) { return SigTest08Real(MPM_B2G); } static int SigTest08B3g (void) { return SigTest08Real(MPM_B3G); } static int SigTest08Wm (void) { return SigTest08Real(MPM_WUMANBER); } static int SigTest09Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.0\r\n" /* 20 */ "Host: one.example.org\r\n" /* 23, 43 */ "\r\n\r\n" /* 4, 47 */ "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ "Host: two.example.org\r\n" /* 23, 90 */ "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; Flow f; TcpSession ssn; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 1; else result = 0; AppLayerParserCleanupState(&f); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } static int SigTest09B2g (void) { return SigTest09Real(MPM_B2G); } static int SigTest09B3g (void) { return SigTest09Real(MPM_B3G); } static int SigTest09Wm (void) { return SigTest09Real(MPM_WUMANBER); } static int SigTest10Real (int mpm_type) { uint8_t *buf = (uint8_t *) "ABC"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; Flow f; TcpSession ssn; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (1)\"; content:\"ABCD\"; depth:4; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (2)\"; content:\"VWXYZ\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 0; else result = 1; AppLayerParserCleanupState(&f); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } static int SigTest10B2g (void) { return SigTest10Real(MPM_B2G); } static int SigTest10B3g (void) { return SigTest10Real(MPM_B3G); } static int SigTest10Wm (void) { return SigTest10Real(MPM_WUMANBER); } static int SigTest11Real (int mpm_type) { uint8_t *buf = (uint8_t *) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; Flow f; TcpSession ssn; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (content:\"VWXYZabcde\"; content:\"5678\"; content:\"89\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 1; AppLayerParserCleanupState(&f); SigGroupCleanup(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } static int SigTest11B2g (void) { return SigTest11Real(MPM_B2G); } static int SigTest11B3g (void) { return SigTest11Real(MPM_B3G); } static int SigTest11Wm (void) { return SigTest11Real(MPM_WUMANBER); } static int SigTest12Real (int mpm_type) { uint8_t *buf = (uint8_t *) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); Flow f; memset(&f, 0, sizeof(Flow)); FLOW_INITIALIZE(&f); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; else result = 0; if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: UTHFreePackets(&p, 1); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } FLOW_DESTROY(&f); return result; } static int SigTest12B2g (void) { return SigTest12Real(MPM_B2G); } static int SigTest12B3g (void) { return SigTest12Real(MPM_B3G); } static int SigTest12Wm (void) { return SigTest12Real(MPM_WUMANBER); } static int SigTest13Real (int mpm_type) { uint8_t *buf = (uint8_t *) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); Flow f; memset(&f, 0, sizeof(Flow)); FLOW_INITIALIZE(&f); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; else result = 0; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); FLOW_DESTROY(&f); return result; } static int SigTest13B2g (void) { return SigTest13Real(MPM_B2G); } static int SigTest13B3g (void) { return SigTest13Real(MPM_B3G); } static int SigTest13Wm (void) { return SigTest13Real(MPM_WUMANBER); } static int SigTest14Real (int mpm_type) { uint8_t *buf = (uint8_t *) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; distance:0; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 0; else result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTest14B2g (void) { return SigTest14Real(MPM_B2G); } static int SigTest14B3g (void) { return SigTest14Real(MPM_B3G); } static int SigTest14Wm (void) { return SigTest14Real(MPM_WUMANBER); } static int SigTest15Real (int mpm_type) { uint8_t *buf = (uint8_t *) "CONNECT 213.92.8.7:31204 HTTP/1.1"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; p->dp = 80; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 2008284)) result = 0; else result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return result; } static int SigTest15B2g (void) { return SigTest15Real(MPM_B2G); } static int SigTest15B3g (void) { return SigTest15Real(MPM_B3G); } static int SigTest15Wm (void) { return SigTest15Real(MPM_WUMANBER); } static int SigTest16Real (int mpm_type) { uint8_t *buf = (uint8_t *) "CONNECT 213.92.8.7:31204 HTTP/1.1"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); p = UTHBuildPacketSrcDstPorts((uint8_t *)buf, buflen, IPPROTO_TCP, 12345, 1234); ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 2008284)) result = 1; else printf("sid:2008284 %s: ", PacketAlertCheck(p, 2008284) ? "OK" : "FAIL"); SigGroupCleanup(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: ConfDeInit(); ConfRestoreContextBackup(); UTHFreePackets(&p, 1); return result; } static int SigTest16B2g (void) { return SigTest16Real(MPM_B2G); } static int SigTest16B3g (void) { return SigTest16Real(MPM_B3G); } static int SigTest16Wm (void) { return SigTest16Real(MPM_WUMANBER); } static int SigTest17Real (int mpm_type) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" /* 20 */ "Host: one.example.org\r\n" /* 23, 43 */ "\r\n\r\n" /* 4, 47 */ "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ "Host: two.example.org\r\n" /* 23, 90 */ "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacketSrcDstPorts((uint8_t *)buf, buflen, IPPROTO_TCP, 12345, 80); ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any $HTTP_PORTS (msg:\"HTTP host cap\"; content:\"Host:\"; pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); PktVar *pv_hn = PktVarGet(p, "http_host"); if (pv_hn != NULL) { if (memcmp(pv_hn->value, "one.example.org", pv_hn->value_len < 15 ? pv_hn->value_len : 15) == 0) result = 1; else { printf("\""); PrintRawUriFp(stdout, pv_hn->value, pv_hn->value_len); printf("\" != \"one.example.org\": "); } PktVarFree(pv_hn); } else { printf("Pkt var http_host not captured: "); } end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } ConfDeInit(); ConfRestoreContextBackup(); UTHFreePackets(&p, 1); return result; } static int SigTest17B2g (void) { return SigTest17Real(MPM_B2G); } static int SigTest17B3g (void) { return SigTest17Real(MPM_B3G); } static int SigTest17Wm (void) { return SigTest17Real(MPM_WUMANBER); } static int SigTest18Real (int mpm_type) { uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; p->dp = 34260; p->sp = 21; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 2003055)) result = 1; else printf("signature shouldn't match, but did: "); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p); return result; } static int SigTest18B2g (void) { return SigTest18Real(MPM_B2G); } static int SigTest18B3g (void) { return SigTest18Real(MPM_B3G); } static int SigTest18Wm (void) { return SigTest18Real(MPM_WUMANBER); } int SigTest19Real (int mpm_type) { uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; p->dp = 34260; p->sp = 21; p->flowflags |= FLOW_PKT_TOSERVER; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> 1.2.3.4 any (msg:\"IP-ONLY test (1)\"; sid:999; rev:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 999)) result = 1; else printf("signature didn't match, but should have: "); SigGroupCleanup(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return result; } static int SigTest19B2g (void) { return SigTest19Real(MPM_B2G); } static int SigTest19B3g (void) { return SigTest19Real(MPM_B3G); } static int SigTest19Wm (void) { return SigTest19Real(MPM_WUMANBER); } static int SigTest20Real (int mpm_type) { uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; p->dp = 34260; p->sp = 21; p->flowflags |= FLOW_PKT_TOSERVER; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> [99.99.99.99,1.2.3.0/24,1.1.1.1,3.0.0.0/8] any (msg:\"IP-ONLY test (2)\"; sid:999; rev:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); //DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 999)) result = 1; else printf("signature didn't match, but should have: "); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: ConfDeInit(); ConfRestoreContextBackup(); SCFree(p); return result; } static int SigTest20B2g (void) { return SigTest20Real(MPM_B2G); } static int SigTest20B3g (void) { return SigTest20Real(MPM_B3G); } static int SigTest20Wm (void) { return SigTest20Real(MPM_WUMANBER); } static int SigTest21Real (int mpm_type) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx = NULL; int result = 0; Flow f; memset(&f, 0, sizeof(f)); FLOW_INITIALIZE(&f); /* packet 1 */ uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buf1len = strlen((char *)buf1); Packet *p1 = NULL; /* packet 2 */ uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buf2len = strlen((char *)buf2); Packet *p2 = NULL; p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); p1->flow = &f; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); p2->flow = &f; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 alerted, but shouldn't: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 2))) { printf("sid 2 didn't alert, but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } } DetectEngineCtxFree(de_ctx); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); FLOW_DESTROY(&f); return result; } static int SigTest21B2g (void) { return SigTest21Real(MPM_B2G); } static int SigTest21B3g (void) { return SigTest21Real(MPM_B3G); } static int SigTest21Wm (void) { return SigTest21Real(MPM_WUMANBER); } static int SigTest22Real (int mpm_type) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx; int result = 0; Flow f; memset(&f, 0, sizeof(f)); FLOW_INITIALIZE(&f); /* packet 1 */ uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buf1len = strlen((char *)buf1); Packet *p1 = NULL; p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); p1->flow = &f; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; /* packet 2 */ uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buf2len = strlen((char *)buf2); Packet *p2 = NULL; p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); p2->flow = &f; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.abc; sid:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 alerted, but shouldn't: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 2))) result = 1; else printf("sid 2 alerted, but shouldn't: "); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); FLOW_DESTROY(&f); return result; } static int SigTest22B2g (void) { return SigTest22Real(MPM_B2G); } static int SigTest22B3g (void) { return SigTest22Real(MPM_B3G); } static int SigTest22Wm (void) { return SigTest22Real(MPM_WUMANBER); } static int SigTest23Real (int mpm_type) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx; int result = 0; Flow f; memset(&f, 0, sizeof(f)); FLOW_INITIALIZE(&f); /* packet 1 */ uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buf1len = strlen((char *)buf1); Packet *p1 = NULL; p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); p1->flow = &f; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; /* packet 2 */ uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buf2len = strlen((char *)buf2); Packet *p2 = NULL; p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); p2->flow = &f; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:toggle,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 alerted, but shouldn't: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result = 1; else printf("sid 2 didn't alert, but should have: "); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); FLOW_DESTROY(&f); return result; } static int SigTest23B2g (void) { return SigTest23Real(MPM_B2G); } static int SigTest23B3g (void) { return SigTest23Real(MPM_B3G); } static int SigTest23Wm (void) { return SigTest23Real(MPM_WUMANBER); } int SigTest24IPV4Keyword(void) { uint8_t valid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x03}; uint8_t invalid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x06}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->ip4vars.comp_csum = -1; p2->ip4vars.comp_csum = -1; p1->ip4h = (IPV4Hdr *)valid_raw_ipv4; p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = buflen; p1->proto = IPPROTO_TCP; p2->ip4h = (IPV4Hdr *)invalid_raw_ipv4; p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = buflen; p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " "(content:\"/one/\"; ipv4-csum:valid; " "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig 1 parse: "); goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " "(content:\"/one/\"; ipv4-csum:invalid; " "msg:\"ipv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { printf("sig 2 parse: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("signature 1 didn't match, but should have: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!((PacketAlertCheck(p2, 2)))) { printf("signature 2 didn't match, but should have: "); goto end; } result = 1; end: if (det_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } SCFree(p1); SCFree(p2); return result; } int SigTest25NegativeIPV4Keyword(void) { uint8_t valid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x03}; uint8_t invalid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x06}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->ip4vars.comp_csum = -1; p2->ip4vars.comp_csum = -1; p1->ip4h = (IPV4Hdr *)valid_raw_ipv4; p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = buflen; p1->proto = IPPROTO_TCP; p2->ip4h = (IPV4Hdr *)invalid_raw_ipv4; p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = buflen; p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " "(content:\"/one/\"; ipv4-csum:invalid; " "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " "(content:\"/one/\"; ipv4-csum:valid; " "msg:\"ipv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 0; else result &= 1; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result &= 0; else result &= 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest26TCPV4Keyword(void) { uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; uint8_t valid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0x4A, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; uint8_t invalid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); p1->tcpvars.comp_csum = -1; p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20; p1->payload_len = 20; p1->proto = IPPROTO_TCP; p2->tcpvars.comp_csum = -1; p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20; p2->payload_len = 20; p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " "msg:\"tcpv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sig 1 didn't match: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 2))) { printf("sig 2 didn't match: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); SCFree(p1); SCFree(p2); return result; } static int SigTest27NegativeTCPV4Keyword(void) { uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; uint8_t valid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; uint8_t invalid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); p1->tcpvars.comp_csum = -1; p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20; p1->payload_len = 20; p1->proto = IPPROTO_TCP; p2->tcpvars.comp_csum = -1; p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20; p2->payload_len = 20; p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; dsize:20; " "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " "msg:\"tcpv4-csum keyword check(2)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!PacketAlertCheck(p1, 1)) { printf("sig 1 didn't match on p1: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) { printf("sig 2 matched on p2: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); SCFree(p1); SCFree(p2); return result; } int SigTest28TCPV6Keyword(void) { static uint8_t valid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, 0xf2, 0xf1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x27}; static uint8_t invalid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, 0xc2, 0xf1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x28}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->tcpvars.comp_csum = -1; p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); p1->tcph = (TCPHdr *) (valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = valid_raw_ipv6 + 54 + 20; p1->payload_len = 12; p1->proto = IPPROTO_TCP; if (TCP_GET_HLEN(p1) != 20) { BUG_ON(1); } p2->tcpvars.comp_csum = -1; p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); p2->tcph = (TCPHdr *) (invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = invalid_raw_ipv6 + 54 + 20;; p2->payload_len = 12; p2->proto = IPPROTO_TCP; if (TCP_GET_HLEN(p2) != 20) { BUG_ON(1); } DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " "msg:\"tcpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " "msg:\"tcpv6-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match on p1: "); goto end; } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 2))) { printf("sid 2 didn't match on p2: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); SCFree(p1); SCFree(p2); return result; } int SigTest29NegativeTCPV6Keyword(void) { static uint8_t valid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, 0xf2, 0xf1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x27}; static uint8_t invalid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, 0xc2, 0xf1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x28}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->tcpvars.comp_csum = -1; p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); p1->tcph = (TCPHdr *) (valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = valid_raw_ipv6 + 54 + 20; p1->payload_len = 12; p1->proto = IPPROTO_TCP; if (TCP_GET_HLEN(p1) != 20) { BUG_ON(1); } p2->tcpvars.comp_csum = -1; p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); p2->tcph = (TCPHdr *) (invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = invalid_raw_ipv6 + 54 + 20;; p2->payload_len = 12; p2->proto = IPPROTO_TCP; if (TCP_GET_HLEN(p2) != 20) { BUG_ON(1); } DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " "msg:\"tcpv6-csum keyword check(1)\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " "msg:\"tcpv6-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) goto end; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); SCFree(p1); SCFree(p2); return result; } int SigTest30UDPV4Keyword(void) { uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x03}; uint8_t valid_raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x26}; uint8_t invalid_raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x27}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->udpvars.comp_csum = -1; p1->ip4h = (IPV4Hdr *)raw_ipv4; p1->udph = (UDPHdr *)valid_raw_udp; p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = sizeof(valid_raw_udp) - UDP_HEADER_LEN; p1->proto = IPPROTO_UDP; p2->udpvars.comp_csum = -1; p2->ip4h = (IPV4Hdr *)raw_ipv4; p2->udph = (UDPHdr *)invalid_raw_udp; p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = sizeof(invalid_raw_udp) - UDP_HEADER_LEN; p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv4-csum:valid; " "msg:\"udpv4-csum keyword check(1)\"; " "sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv4-csum:invalid; " "msg:\"udpv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 1; else result &= 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result &= 1; else result &= 0; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest31NegativeUDPV4Keyword(void) { uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x03}; uint8_t valid_raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x26}; uint8_t invalid_raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x27}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->udpvars.comp_csum = -1; p1->ip4h = (IPV4Hdr *)raw_ipv4; p1->udph = (UDPHdr *)valid_raw_udp; p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = sizeof(valid_raw_udp) - UDP_HEADER_LEN; p1->proto = IPPROTO_UDP; p2->udpvars.comp_csum = -1; p2->ip4h = (IPV4Hdr *)raw_ipv4; p2->udph = (UDPHdr *)invalid_raw_udp; p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = sizeof(invalid_raw_udp) - UDP_HEADER_LEN; p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv4-csum:invalid; " "msg:\"udpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv4-csum:valid; " "msg:\"udpv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 0; else result &= 1; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) { result &= 0; } else result &= 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest32UDPV6Keyword(void) { static uint8_t valid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x00}; static uint8_t invalid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x01}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" "\r\n\r\n"; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->udpvars.comp_csum = -1; p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); p1->udph = (UDPHdr *) (valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = IPV6_GET_PLEN((p1)) - UDP_HEADER_LEN; p1->proto = IPPROTO_UDP; p2->udpvars.comp_csum = -1; p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); p2->udph = (UDPHdr *) (invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = IPV6_GET_PLEN((p2)) - UDP_HEADER_LEN; p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv6-csum:valid; " "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv6-csum:invalid; " "msg:\"udpv6-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 1; else result &= 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result &= 1; else result &= 0; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest33NegativeUDPV6Keyword(void) { static uint8_t valid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x00}; static uint8_t invalid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x01}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" "\r\n\r\n"; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->udpvars.comp_csum = -1; p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); p1->udph = (UDPHdr *) (valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = IPV6_GET_PLEN((p1)) - UDP_HEADER_LEN; p1->proto = IPPROTO_UDP; p2->udpvars.comp_csum = -1; p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); p2->udph = (UDPHdr *) (invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = IPV6_GET_PLEN((p2)) - UDP_HEADER_LEN; p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv6-csum:invalid; " "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " "(content:\"/one/\"; udpv6-csum:valid; " "msg:\"udpv6-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 0; else result &= 1; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result &= 0; else result &= 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest34ICMPV4Keyword(void) { uint8_t valid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; uint8_t invalid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->icmpv4vars.comp_csum = -1; p1->ip4h = (IPV4Hdr *)(valid_raw_ipv4); p1->ip4h->ip_verhl = 69; p1->icmpv4h = (ICMPV4Hdr *) (valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = buflen; p1->proto = IPPROTO_ICMP; p2->icmpv4vars.comp_csum = -1; p2->ip4h = (IPV4Hdr *)(invalid_raw_ipv4); p2->ip4h->ip_verhl = 69; p2->icmpv4h = (ICMPV4Hdr *) (invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = buflen; p2->proto = IPPROTO_ICMP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; icmpv4-csum:valid; " "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; icmpv4-csum:invalid; " "msg:\"icmpv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 1; else result &= 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result &= 1; else result &= 0; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest35NegativeICMPV4Keyword(void) { uint8_t valid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; uint8_t invalid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->icmpv4vars.comp_csum = -1; p1->ip4h = (IPV4Hdr *)(valid_raw_ipv4); p1->ip4h->ip_verhl = 69; p1->icmpv4h = (ICMPV4Hdr *) (valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = buflen; p1->proto = IPPROTO_ICMP; p2->icmpv4vars.comp_csum = -1; p2->ip4h = (IPV4Hdr *)(invalid_raw_ipv4); p2->ip4h->ip_verhl = 69; p2->icmpv4h = (ICMPV4Hdr *) (invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = buflen; p2->proto = IPPROTO_ICMP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; icmpv4-csum:invalid; " "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert icmp any any -> any any " "(content:\"/one/\"; icmpv4-csum:valid; " "msg:\"icmpv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 0; else result &= 1; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result &= 0; else { result &= 1; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest36ICMPV6Keyword(void) { uint8_t valid_raw_ipv6[] = { 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, 0x08, 0x00}; uint8_t invalid_raw_ipv6[] = { 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, 0x08, 0x01}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->icmpv6vars.comp_csum = -1; p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); p1->icmpv6h = (ICMPV6Hdr *) (valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = buflen; p1->proto = IPPROTO_ICMPV6; p2->icmpv6vars.comp_csum = -1; p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); p2->icmpv6h = (ICMPV6Hdr *) (invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = buflen; p2->proto = IPPROTO_ICMPV6; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmpv6 any any -> any any " "(content:\"/one/\"; icmpv6-csum:valid; " "msg:\"icmpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert icmpv6 any any -> any any " "(content:\"/one/\"; icmpv6-csum:invalid; " "msg:\"icmpv6-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 1; else result &= 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result &= 1; else result &= 0; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest37NegativeICMPV6Keyword(void) { uint8_t valid_raw_ipv6[] = { 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, 0x08, 0x00}; uint8_t invalid_raw_ipv6[] = { 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, 0x08, 0x01}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); p1->icmpv6vars.comp_csum = -1; p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); p1->icmpv6h = (ICMPV6Hdr *) (valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; p1->payload_len = buflen; p1->proto = IPPROTO_ICMPV6; p2->icmpv6vars.comp_csum = -1; p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); p2->icmpv6h = (ICMPV6Hdr *) (invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; p2->payload_len = buflen; p2->proto = IPPROTO_ICMPV6; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert icmpv6 any any -> any any " "(content:\"/one/\"; icmpv6-csum:invalid; " "msg:\"icmpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert icmpv6 any any -> any any " "(content:\"/one/\"; icmpv6-csum:valid; " "msg:\"icmpv6-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) result &= 0; else result &= 1; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) result &= 0; else result &= 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); SCFree(p2); return result; } int SigTest38Real(int mpm_type) { Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t raw_eth[] = { 0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 }; uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x7d, 0xd8, 0xf3, 0x40, 0x00, 0x40, 0x06, 0x63, 0x85, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01 }; uint8_t raw_tcp[] = { 0xad, 0x22, 0x04, 0x00, 0x16, 0x39, 0x72, 0xe2, 0x16, 0x1f, 0x79, 0x84, 0x80, 0x18, 0x01, 0x01, 0xfe, 0x71, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x22, 0xaa, 0x10, 0x00, 0x22, 0xaa, 0x10 }; uint8_t buf[] = { 0x00, 0x00, 0x00, 0x08, 0x62, 0x6f, 0x6f, 0x65, 0x65, 0x6b, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x31, 0x20, 0x38, 0x0d, 0x0a, 0x66, 0x6f, 0x30, 0x30, /* LEN1|20| ends at 17 */ 0x30, 0x38, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x32, /* "0008" at offset 5 */ 0x20, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x0d, 0x0a, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a }; uint16_t ethlen = sizeof(raw_eth); uint16_t ipv4len = sizeof(raw_ipv4); uint16_t tcplen = sizeof(raw_tcp); uint16_t buflen = sizeof(buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); /* Copy raw data into packet */ if (PacketCopyData(p1, raw_eth, ethlen) == -1) { SCFree(p1); return 1; } if (PacketCopyDataOffset(p1, ethlen, raw_ipv4, ipv4len) == -1) { SCFree(p1); return 1; } if (PacketCopyDataOffset(p1, ethlen + ipv4len, raw_tcp, tcplen) == -1) { SCFree(p1); return 1; } if (PacketCopyDataOffset(p1, ethlen + ipv4len + tcplen, buf, buflen) == -1) { SCFree(p1); return 1; } SET_PKT_LEN(p1, ethlen + ipv4len + tcplen + buflen); p1->tcpvars.comp_csum = -1; p1->ethh = (EthernetHdr *)raw_eth; p1->ip4h = (IPV4Hdr *)raw_ipv4; p1->tcph = (TCPHdr *)raw_tcp; p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = GET_PKT_DATA(p1) + ethlen + ipv4len + tcplen; p1->payload_len = buflen; p1->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"LEN1|20|\"; " "byte_test:4,=,8,0; " "msg:\"byte_test keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"LEN1|20|\"; " "byte_test:4,=,8,5,relative,string,dec; " "msg:\"byte_test keyword check(2)\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { result = 1; } else { result = 0; printf("sid 1 didn't alert, but should have: "); goto cleanup; } if (PacketAlertCheck(p1, 2)) { result = 1; } else { result = 0; printf("sid 2 didn't alert, but should have: "); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); return result; } static int SigTest38B2g (void) { return SigTest38Real(MPM_B2G); } static int SigTest38B3g (void) { return SigTest38Real(MPM_B3G); } static int SigTest38Wm (void) { return SigTest38Real(MPM_WUMANBER); } int SigTest39Real(int mpm_type) { Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; uint8_t raw_eth[] = { 0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 }; uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x7d, 0xd8, 0xf3, 0x40, 0x00, 0x40, 0x06, 0x63, 0x85, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01 }; uint8_t raw_tcp[] = { 0xad, 0x22, 0x04, 0x00, 0x16, 0x39, 0x72, 0xe2, 0x16, 0x1f, 0x79, 0x84, 0x80, 0x18, 0x01, 0x01, 0xfe, 0x71, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x22, 0xaa, 0x10, 0x00, 0x22, 0xaa, 0x10 }; uint8_t buf[] = { 0x00, 0x00, 0x00, 0x08, 0x62, 0x6f, 0x6f, 0x65, 0x65, 0x6b, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x31, 0x20, 0x38, 0x0d, 0x0a, 0x66, 0x30, 0x30, 0x30, 0x38, 0x72, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x32, 0x20, 0x39, 0x39, 0x4c, 0x45, 0x4e, 0x32, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x0d, 0x0a, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a }; uint16_t ethlen = sizeof(raw_eth); uint16_t ipv4len = sizeof(raw_ipv4); uint16_t tcplen = sizeof(raw_tcp); uint16_t buflen = sizeof(buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); /* Copy raw data into packet */ if (PacketCopyData(p1, raw_eth, ethlen) == -1) { SCFree(p1); return 1; } if (PacketCopyDataOffset(p1, ethlen, raw_ipv4, ipv4len) == -1) { SCFree(p1); return 1; } if (PacketCopyDataOffset(p1, ethlen + ipv4len, raw_tcp, tcplen) == -1) { SCFree(p1); return 1; } if (PacketCopyDataOffset(p1, ethlen + ipv4len + tcplen, buf, buflen) == -1) { SCFree(p1); return 1; } SET_PKT_LEN(p1, ethlen + ipv4len + tcplen + buflen); p1->tcpvars.comp_csum = -1; p1->ethh = (EthernetHdr *)raw_eth; p1->ip4h = (IPV4Hdr *)raw_ipv4; p1->tcph = (TCPHdr *)raw_tcp; p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = GET_PKT_DATA(p1) + ethlen + ipv4len + tcplen; p1->payload_len = buflen; p1->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"LEN1|20|\"; " "byte_test:4,=,8,0; " "byte_jump:4,0; " "byte_test:6,=,0x4c454e312038,0,relative; " "msg:\"byte_jump keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } // XXX TODO de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"LEN1|20|\"; " "byte_test:4,=,8,4,relative,string,dec; " "byte_jump:4,4,relative,string,dec,post_offset 2; " "byte_test:4,=,0x4c454e32,0,relative; " "msg:\"byte_jump keyword check(2)\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { result = 1; } else { result = 0; printf("sid 1 didn't alert, but should have: "); goto cleanup; } if (PacketAlertCheck(p1, 2)) { result = 1; } else { result = 0; printf("sid 2 didn't alert, but should have: "); goto cleanup; } cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); return result; } static int SigTest39B2g (void) { return SigTest39Real(MPM_B2G); } static int SigTest39B3g (void) { return SigTest39Real(MPM_B3G); } static int SigTest39Wm (void) { return SigTest39Real(MPM_WUMANBER); } /** * \test SigTest36ContentAndIsdataatKeywords01 is a test to check window with constructed packets, * \brief expecting to match a size */ int SigTest36ContentAndIsdataatKeywords01Real (int mpm_type) { int result = 0; // Buid and decode the packet uint8_t raw_eth [] = { 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth), NULL); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest36ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:404, relative; sid:101;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 101) == 0) { result = 0; goto end; } else { result=1; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; end: if(de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if(det_ctx) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); //PatternMatchDestroy(mpm_ctx); if(de_ctx) DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; } /** * \test SigTest37ContentAndIsdataatKeywords02 is a test to check window with constructed packets, * \brief not expecting to match a size */ int SigTest37ContentAndIsdataatKeywords02Real (int mpm_type) { int result = 0; // Buid and decode the packet uint8_t raw_eth [] = { 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth), NULL); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; Signature *s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest37ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:500, relative; sid:101;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); result = 0; goto end; } if (s->sm_lists[DETECT_SM_LIST_PMATCH]->type != DETECT_CONTENT) { printf("type not content: "); goto end; } /* if (s->sm_lists[DETECT_SM_LIST_PMATCH]->next == NULL) { printf("s->sm_lists[DETECT_SM_LIST_PMATCH]->next == NULL: "); goto end; } if (s->sm_lists[DETECT_SM_LIST_PMATCH]->next->type != DETECT_ISDATAAT) { printf("type not isdataat: "); goto end; } */ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 101) == 0) { result = 1; goto end; } else { printf("sig matched, but should not have: "); result=0; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; end: if(de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if(det_ctx) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if(de_ctx) DetectEngineCtxFree(de_ctx); FlowShutdown(); SCFree(p); return result; } // Wrapper functions to pass the mpm_type static int SigTest36ContentAndIsdataatKeywords01B2g (void) { return SigTest36ContentAndIsdataatKeywords01Real(MPM_B2G); } static int SigTest36ContentAndIsdataatKeywords01B3g (void) { return SigTest36ContentAndIsdataatKeywords01Real(MPM_B3G); } static int SigTest36ContentAndIsdataatKeywords01Wm (void) { return SigTest36ContentAndIsdataatKeywords01Real(MPM_WUMANBER); } static int SigTest37ContentAndIsdataatKeywords02B2g (void) { return SigTest37ContentAndIsdataatKeywords02Real(MPM_B2G); } static int SigTest37ContentAndIsdataatKeywords02B3g (void) { return SigTest37ContentAndIsdataatKeywords02Real(MPM_B3G); } static int SigTest37ContentAndIsdataatKeywords02Wm (void) { return SigTest37ContentAndIsdataatKeywords02Real(MPM_WUMANBER); } /** * \test SigTest41NoPacketInspection is a test to check that when PKT_NOPACKET_INSPECTION * flag is set, we don't need to inspect the packet protocol header or its contents. */ int SigTest40NoPacketInspection01(void) { uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); TCPHdr tcphdr; if (unlikely(p == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; PacketQueue pq; Flow f; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&pq, 0, sizeof(pq)); memset(&f, 0, sizeof(f)); memset(&tcphdr, 0, sizeof(tcphdr)); p->src.family = AF_INET; p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; p->dp = 34260; p->sp = 21; p->flowflags |= FLOW_PKT_TOSERVER; p->flags |= PKT_NOPACKET_INSPECTION; p->tcph = &tcphdr; p->flow = &f; FLOW_INITIALIZE(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> 1.2.3.4 any (msg:\"No Packet Inspection Test\"; flow:to_server; sid:2; rev:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); det_ctx->de_ctx = de_ctx; Detect(&th_v, p, det_ctx, &pq, NULL); if (PacketAlertCheck(p, 2)) result = 0; else result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p); return result; } /** * \test SigTest42NoPayloadInspection is a test to check that when PKT_NOPAYLOAD_INSPECTION * flasg is set, we don't need to inspect the packet contents. */ int SigTest40NoPayloadInspection02(void) { uint8_t *buf = (uint8_t *) "220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 1; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; p->flags |= PKT_NOPAYLOAD_INSPECTION; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { result = 0; goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"No Payload TEST\"; content:\"220 (vsFTPd 2.0.5)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); if (!(de_ctx->sig_list->init_flags & SIG_FLAG_INIT_PAYLOAD)) result = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result &= 0; else result &= 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p); return result; } static int SigTestMemory01 (void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n\r\n" "GET /two/ HTTP/1.1\r\n" "Host: two.example.org\r\n" "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); printf("@pre cleanup\n\n"); DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); SigGroupCleanup(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); result = 1; end: SCFree(p); return result; } static int SigTestMemory02 (void) { ThreadVars th_v; int result = 0; memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); printf("@cleanup\n\n"); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); printf("@exit\n\n"); DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); result = 1; end: return result; } static int SigTestMemory03 (void) { ThreadVars th_v; int result = 0; memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> 1.2.3.4 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> 1.2.3.3-1.2.3.6 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> !1.2.3.5 1:990 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:3;)"); if (de_ctx->sig_list->next->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); printf("@cleanup\n\n"); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); printf("@exit\n\n"); DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); DetectPortPrintMemory(); result = 1; end: return result; } static int SigTestSgh01 (void) { ThreadVars th_v; int result = 0; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); Packet *p = NULL; p = UTHBuildPacketSrcDstPorts((uint8_t *)"a", 1, IPPROTO_TCP, 12345, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"1\"; content:\"one\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (de_ctx->sig_list->num != 0) { printf("internal id != 0: "); goto end; } if (de_ctx->sig_list->mpm_content_maxlen != 3) { printf("de_ctx->sig_list->mpm_content_maxlen %u, expected 3: ", de_ctx->sig_list->mpm_content_maxlen); goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 81 (msg:\"2\"; content:\"two\"; content:\"abcd\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } if (de_ctx->sig_list->next->num != 1) { printf("internal id != 1: "); goto end; } if (de_ctx->sig_list->next->mpm_content_maxlen != 4) { printf("de_ctx->sig_list->mpm_content_maxlen %u, expected 4: ", de_ctx->sig_list->next->mpm_content_maxlen); goto end; } de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"3\"; content:\"three\"; sid:3;)"); if (de_ctx->sig_list->next->next == NULL) { result = 0; goto end; } if (de_ctx->sig_list->next->next->num != 2) { printf("internal id != 2: "); goto end; } if (de_ctx->sig_list->next->next->mpm_content_maxlen != 5) { printf("de_ctx->sig_list->next->next->mpm_content_maxlen %u, expected 5: ", de_ctx->sig_list->next->next->mpm_content_maxlen); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } #if 0 printf("-\n"); printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); #endif if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->match_array == NULL) { printf("sgh->match_array == NULL: "); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); goto end; } if (sgh->match_array[1] != de_ctx->sig_list->next->next) { printf("sgh doesn't contain sid 3, should have: "); goto end; } p->dp = 81; SigGroupHead *sgh2 = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh2 == NULL) { printf("no sgh2: "); goto end; } #if 0 if (!(SigGroupHeadContainsSigId(de_ctx, sgh2, 1))) { printf("sgh2 doesn't have sid 1: "); goto end; } #endif if (sgh2->sig_cnt != 1) { printf("expected one sig, got %u in sgh2: ", sgh2->sig_cnt); goto end; } if (sgh2->match_array[0] != de_ctx->sig_list->next) { printf("sgh doesn't contain sid 2, should have (sgh2->match_array[0] %p, expected %p): ", sgh2->match_array[0], de_ctx->sig_list->next); goto end; } #if 0 printf("-\n"); printf("sgh2->mpm_content_maxlen %u\n", sgh2->mpm_content_maxlen); printf("sgh2->mpm_uricontent_maxlen %u\n", sgh2->mpm_uricontent_maxlen); printf("sgh2->sig_cnt %u\n", sgh2->sig_cnt); printf("sgh2->sig_size %u\n", sgh2->sig_size); #endif if (sgh2->mpm_content_maxlen != 4) { printf("sgh2->mpm_content_maxlen %u, expected 4: ", sgh2->mpm_content_maxlen); goto end; } if (sgh2->match_array[0] != de_ctx->sig_list->next) { printf("sgh2 doesn't contain sid 2, should have: "); goto end; } DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); result = 1; end: return result; } static int SigTestSgh02 (void) { ThreadVars th_v; int result = 0; DetectEngineThreadCtx *det_ctx; Packet *p = NULL; p = UTHBuildPacketSrcDstPorts((uint8_t *)"a", 1, IPPROTO_TCP, 12345, 80); memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80:82 (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (de_ctx->sig_list->num != 0) { printf("internal id != 0: "); goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 81 (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } if (de_ctx->sig_list->next->num != 1) { printf("internal id != 1: "); goto end; } de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> any 80:81 (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); if (de_ctx->sig_list->next->next == NULL) { result = 0; goto end; } if (de_ctx->sig_list->next->next->num != 2) { printf("internal id != 2: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->match_array == NULL) { printf("sgh->match_array == NULL: "); goto end; } if (sgh->sig_cnt != 2) { printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); goto end; } if (sgh->match_array[1] != de_ctx->sig_list->next->next) { printf("sgh doesn't contain sid 3, should have: "); goto end; } #if 0 printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif p->dp = 81; sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->sig_cnt != 3) { printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have: "); goto end; } if (sgh->match_array[1] != de_ctx->sig_list->next) { printf("sgh doesn't contain sid 2, should have: "); goto end; } if (sgh->match_array[2] != de_ctx->sig_list->next->next) { printf("sgh doesn't contain sid 3, should have: "); goto end; } #if 0 printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif p->dp = 82; sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->sig_cnt != 1) { printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have: "); goto end; } #if 0 printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif p->src.family = AF_INET6; p->dst.family = AF_INET6; sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->sig_cnt != 1) { printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have: "); goto end; } #if 0 printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); result = 1; end: return result; } static int SigTestSgh03 (void) { ThreadVars th_v; int result = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload_len = 1; p->proto = IPPROTO_TCP; p->dp = 80; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (de_ctx->sig_list->num != 0) { printf("internal id != 0: "); goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.5 any (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } if (de_ctx->sig_list->next->num != 1) { printf("internal id != 1: "); goto end; } de_ctx->sig_list->next->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.5 any (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); if (de_ctx->sig_list->next->next == NULL) { result = 0; goto end; } if (de_ctx->sig_list->next->next->num != 2) { printf("internal id != 2: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } #if 0 printf("-\n"); printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->match_array == NULL) { printf("sgh->match_array == NULL: "); goto end; } if (sgh->sig_cnt != 2) { printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); goto end; } if (sgh->match_array[1] != de_ctx->sig_list->next->next) { printf("sgh doesn't contain sid 3, should have: "); goto end; } p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.5"); sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } #if 0 printf("-\n"); printf("sgh %p\n", sgh); printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif if (sgh->sig_cnt != 3) { printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have: "); goto end; } if (sgh->match_array[1] != de_ctx->sig_list->next) { printf("sgh doesn't contain sid 1, should have: "); goto end; } if (sgh->match_array[2] != de_ctx->sig_list->next->next) { printf("sgh doesn't contain sid 1, should have: "); goto end; } if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3 (%x): ", sgh->mpm_content_maxlen, p->dst.addr_data32[0]); goto end; } p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.6"); sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } #if 0 printf("-\n"); printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->sig_cnt != 1) { printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have: "); goto end; } DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); result = 1; end: SCFree(p); return result; } static int SigTestSgh04 (void) { ThreadVars th_v; int result = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload_len = 1; p->proto = IPPROTO_TCP; p->dp = 80; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } if (de_ctx->sig_list->num != 0) { printf("internal id != 0: "); goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.5 any (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } if (de_ctx->sig_list->next->num != 1) { printf("internal id != 1: "); goto end; } de_ctx->sig_list->next->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.5 any (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); if (de_ctx->sig_list->next->next == NULL) { result = 0; goto end; } if (de_ctx->sig_list->next->next->num != 2) { printf("internal id != 2: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->match_array == NULL) { printf("sgh->match_array == NULL: "); goto end; } if (sgh->sig_cnt != 2) { printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); goto end; } if (sgh->match_array[1] != de_ctx->sig_list->next->next) { printf("sgh doesn't contain sid 3, should have: "); goto end; } #if 0 printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.5"); sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->sig_cnt != 3) { printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have: "); goto end; } if (sgh->match_array[1] != de_ctx->sig_list->next) { printf("sgh doesn't contain sid 2, should have: "); goto end; } if (sgh->match_array[2] != de_ctx->sig_list->next->next) { printf("sgh doesn't contain sid 3, should have: "); goto end; } #if 0 printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.6"); sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->sig_cnt != 1) { printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have: "); goto end; } #if 0 printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif p->proto = IPPROTO_GRE; sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } #if 0 printf("-\n"); printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); printf("sgh->sig_cnt %u\n", sgh->sig_cnt); printf("sgh->sig_size %u\n", sgh->sig_size); printf("sgh->refcnt %u\n", sgh->refcnt); #endif if (sgh->mpm_content_maxlen != 3) { printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); goto end; } if (sgh->match_array[0] != de_ctx->sig_list) { printf("sgh doesn't contain sid 1, should have: "); goto end; } DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); result = 1; end: SCFree(p); return result; } /** \test setting of mpm type */ static int SigTestSgh05 (void) { ThreadVars th_v; int result = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DetectEngineThreadCtx *det_ctx; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload_len = 1; p->proto = IPPROTO_TCP; p->dp = 80; p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->mpm_matcher = MPM_WUMANBER; de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); if (sgh == NULL) { printf("no sgh: "); goto end; } if (sgh->mpm_proto_tcp_ctx_ts != NULL || sgh->mpm_proto_tcp_ctx_tc != NULL || sgh->mpm_proto_udp_ctx_ts != NULL || sgh->mpm_proto_udp_ctx_tc != NULL || sgh->mpm_proto_other_ctx != NULL) { printf("sgh->mpm_proto_tcp_ctx_ts != NULL || sgh->mpm_proto_tcp_ctx_tc != NULL" "sgh->mpm_proto_udp_ctx_ts != NULL || sgh->mpm_proto_udp_ctx_tc != NULL" "sgh->mpm_proto_other_ctx != NULL: "); goto end; } if (sgh->mpm_stream_ctx_ts == NULL || sgh->mpm_stream_ctx_tc == NULL) { printf("sgh->mpm_stream_ctx == NULL || sgh->mpm_stream_ctx_tc == NULL: "); goto end; } if (sgh->mpm_stream_ctx_ts->mpm_type != MPM_WUMANBER) { printf("sgh->mpm_type != MPM_WUMANBER, expected %d, got %d: ", MPM_WUMANBER, sgh->mpm_stream_ctx_ts->mpm_type); goto end; } DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); result = 1; end: SCFree(p); return result; } static int SigTestContent01Real (int mpm_type) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); Packet *p = NULL; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; else printf("sig 1 didn't match: "); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTestContent01B2g (void) { return SigTestContent01Real(MPM_B2G); } static int SigTestContent01B3g (void) { return SigTestContent01Real(MPM_B3G); } static int SigTestContent01Wm (void) { return SigTestContent01Real(MPM_WUMANBER); } static int SigTestContent02Real (int mpm_type) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); Packet *p = NULL; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 31\"; content:\"0123456789012345678901234567890\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { if (PacketAlertCheck(p, 2)) { result = 1; } else printf("sig 2 didn't match: "); } else printf("sig 1 didn't match: "); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTestContent02B2g (void) { return SigTestContent02Real(MPM_B2G); } static int SigTestContent02B3g (void) { return SigTestContent02Real(MPM_B3G); } static int SigTestContent02Wm (void) { return SigTestContent02Real(MPM_WUMANBER); } static int SigTestContent03Real (int mpm_type) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); Packet *p = NULL; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; else printf("sig 1 didn't match: "); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTestContent03B2g (void) { return SigTestContent03Real(MPM_B2G); } static int SigTestContent03B3g (void) { return SigTestContent03Real(MPM_B3G); } static int SigTestContent03Wm (void) { return SigTestContent03Real(MPM_WUMANBER); } static int SigTestContent04Real (int mpm_type) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); Packet *p = NULL; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; else printf("sig 1 didn't match: "); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTestContent04B2g (void) { return SigTestContent04Real(MPM_B2G); } static int SigTestContent04B3g (void) { return SigTestContent04Real(MPM_B3G); } static int SigTestContent04Wm (void) { return SigTestContent04Real(MPM_WUMANBER); } /** \test sigs with patterns at the limit of the pm's size limit */ static int SigTestContent05Real (int mpm_type) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901PADabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); Packet *p = NULL; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { printf("de_ctx == NULL: "); goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig1 parse failed: "); goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:1; within:32; sid:2;)"); if (de_ctx->sig_list->next == NULL) { printf("sig2 parse failed: "); goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sig 2 matched but shouldn't: "); goto end; } result = 1; end: UTHFreePackets(&p, 1); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } return result; } static int SigTestContent05B2g (void) { return SigTestContent05Real(MPM_B2G); } static int SigTestContent05B3g (void) { return SigTestContent05Real(MPM_B3G); } static int SigTestContent05Wm (void) { return SigTestContent05Real(MPM_WUMANBER); } static int SigTestContent06Real (int mpm_type) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); Packet *p = NULL; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Test 32 sig1\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Test 32 sig2\"; content:\"01234567890123456789012345678901\"; content:\"abcdefg\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)){ //printf("sig 1 matched :"); }else{ printf("sig 1 didn't match: "); goto end; } if (PacketAlertCheck(p, 2)){ result = 1; }else{ printf("sig 2 didn't match: "); goto end; } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTestContent06B2g (void) { return SigTestContent06Real(MPM_B2G); } static int SigTestContent06B3g (void) { return SigTestContent06Real(MPM_B3G); } static int SigTestContent06Wm (void) { return SigTestContent06Real(MPM_WUMANBER); } static int SigTestWithinReal01 (int mpm_type) { DecodeThreadVars dtv; ThreadVars th_v; int result = 0; Packet *p1 = NULL; Packet *p2 = NULL; Packet *p3 = NULL; Packet *p4 = NULL; uint8_t rawpkt1[] = { 0x00,0x04,0x76,0xd3,0xd8,0x6a,0x00,0x24, 0xe8,0x29,0xfa,0x4f,0x08,0x00,0x45,0x00, 0x00,0x8c,0x95,0x50,0x00,0x00,0x40,0x06, 0x2d,0x45,0xc0,0xa8,0x02,0x03,0xd0,0x45, 0x24,0xe6,0x06,0xcc,0x03,0x09,0x18,0x72, 0xd0,0xe3,0x1a,0xab,0x7c,0x98,0x50,0x00, 0x02,0x00,0x46,0xa0,0x00,0x00,0x48,0x69, 0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69, 0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20, 0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20, 0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f, 0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61, 0x74,0x63,0x68,0x65,0x73,0x0a,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00 }; /* end rawpkt1 */ uint8_t rawpkt2[] = { 0x00,0x04,0x76,0xd3,0xd8,0x6a,0x00,0x24, 0xe8,0x29,0xfa,0x4f,0x08,0x00,0x45,0x00, 0x00,0x8c,0x30,0x87,0x00,0x00,0x40,0x06, 0x92,0x0e,0xc0,0xa8,0x02,0x03,0xd0,0x45, 0x24,0xe6,0x06,0xcd,0x03,0x09,0x73,0xec, 0xd5,0x35,0x14,0x7d,0x7c,0x12,0x50,0x00, 0x02,0x00,0xed,0x86,0x00,0x00,0x48,0x69, 0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69, 0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20, 0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20, 0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f, 0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61, 0x74,0x63,0x68,0x65,0x73,0x0a,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00 }; /* end rawpkt2 */ uint8_t rawpkt3[] = { 0x00,0x04,0x76,0xd3,0xd8,0x6a,0x00,0x24, 0xe8,0x29,0xfa,0x4f,0x08,0x00,0x45,0x00, 0x00,0x8c,0x57,0xd8,0x00,0x00,0x40,0x06, 0x6a,0xbd,0xc0,0xa8,0x02,0x03,0xd0,0x45, 0x24,0xe6,0x06,0xce,0x03,0x09,0x06,0x3d, 0x02,0x22,0x2f,0x9b,0x6f,0x8f,0x50,0x00, 0x02,0x00,0x1f,0xae,0x00,0x00,0x48,0x69, 0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69, 0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20, 0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20, 0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f, 0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61, 0x74,0x63,0x68,0x65,0x73,0x0a,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00 }; /* end rawpkt3 */ uint8_t rawpkt4[] = { 0x00,0x04,0x76,0xd3,0xd8,0x6a,0x00,0x24, 0xe8,0x29,0xfa,0x4f,0x08,0x00,0x45,0x00, 0x00,0x8c,0xa7,0x2e,0x00,0x00,0x40,0x06, 0x1b,0x67,0xc0,0xa8,0x02,0x03,0xd0,0x45, 0x24,0xe6,0x06,0xcf,0x03,0x09,0x00,0x0e, 0xdf,0x72,0x3d,0xc2,0x21,0xce,0x50,0x00, 0x02,0x00,0x88,0x25,0x00,0x00,0x48,0x69, 0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69, 0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20, 0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20, 0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f, 0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61, 0x74,0x63,0x68,0x65,0x73,0x0a,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00 }; /* end rawpkt4 */ memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx = NULL; FlowInitConfig(FLOW_QUIET); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"within test\"; content:\"Hi, this is a big test to check \"; content:\"content matches\"; distance:0; within:15; sid:556;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* packet 1 */ p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; memset(p1, 0, SIZE_OF_PACKET); p1->pkt = (uint8_t *)(p1 + 1); DecodeEthernet(&th_v, &dtv, p1, rawpkt1, sizeof(rawpkt1), NULL); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 556))) { printf("failed to match on packet 1: "); goto end; } /* packet 2 */ p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) return 0; memset(p2, 0, SIZE_OF_PACKET); p2->pkt = (uint8_t *)(p2 + 1); DecodeEthernet(&th_v, &dtv, p2, rawpkt2, sizeof(rawpkt2), NULL); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 556))) { printf("failed to match on packet 2: "); goto end; } /* packet 3 */ p3 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p3 == NULL)) return 0; memset(p3, 0, SIZE_OF_PACKET); p3->pkt = (uint8_t *)(p3 + 1); DecodeEthernet(&th_v, &dtv, p3, rawpkt3, sizeof(rawpkt3), NULL); SigMatchSignatures(&th_v, de_ctx, det_ctx, p3); if (!(PacketAlertCheck(p3, 556))) { printf("failed to match on packet 3: "); goto end; } /* packet 4 */ p4 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p4 == NULL)) return 0; memset(p4, 0, SIZE_OF_PACKET); p4->pkt = (uint8_t *)(p4 + 1); DecodeEthernet(&th_v, &dtv, p4, rawpkt4, sizeof(rawpkt4), NULL); SigMatchSignatures(&th_v, de_ctx, det_ctx, p4); if (!(PacketAlertCheck(p4, 556))) { printf("failed to match on packet 4: "); goto end; } /* packet 5 */ uint8_t *p5buf = (uint8_t *)"Hi, this is a big test to check content matches"; uint16_t p5buflen = strlen((char *)p5buf); Packet *p5 = UTHBuildPacket(p5buf, p5buflen, IPPROTO_TCP); SigMatchSignatures(&th_v, de_ctx, det_ctx, p5); if (!(PacketAlertCheck(p5, 556))) { printf("failed to match on packet 5: "); goto end; } UTHFreePackets(&p5, 1); result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); FlowShutdown(); if (p1 != NULL) SCFree(p1); if (p2 != NULL) SCFree(p2); if (p3 != NULL) SCFree(p3); if (p4 != NULL) SCFree(p4); return result; } static int SigTestWithinReal01B2g (void) { return SigTestWithinReal01(MPM_B2G); } static int SigTestWithinReal01B3g (void) { return SigTestWithinReal01(MPM_B3G); } static int SigTestWithinReal01Wm (void) { return SigTestWithinReal01(MPM_WUMANBER); } static int SigTestDepthOffset01Real (int mpm_type) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"depth offset\"; content:\"456\"; offset:4; depth:3; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } static int SigTestDepthOffset01B2g (void) { return SigTestDepthOffset01Real(MPM_B2G); } static int SigTestDepthOffset01B3g (void) { return SigTestDepthOffset01Real(MPM_B3G); } static int SigTestDepthOffset01Wm (void) { return SigTestDepthOffset01Real(MPM_WUMANBER); } static int SigTestDetectAlertCounter(void) { Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&tv, 0, sizeof(tv)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test counter\"; " "content:\"boo\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); tv.name = "detect_test"; DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); p = UTHBuildPacket((uint8_t *)"boo", strlen("boo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); result = (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 1); Detect(&tv, p, det_ctx, NULL, NULL); result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"roo", strlen("roo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"laboosa", strlen("laboosa"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 3); UTHFreePackets(&p, 1); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); return result; } /** \test test if the engine set flag to drop pkts of a flow that * triggered a drop action on IPS mode */ static int SigTestDropFlow01(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop http any any -> any any " "(msg:\"Test proto match\"; " "sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should: "); goto end; } if ( !(p->flow->flags & FLOW_ACTION_DROP)) { printf("sig 1 alerted but flow was not flagged correctly: "); goto end; } /* Ok, now we know that the flag is set for proto http */ result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test test if the engine set flag to drop pkts of a flow that * triggered a drop action on IPS mode */ static int SigTestDropFlow02(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " "(msg:\"Test proto match\"; uricontent:\"one\";" "sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 didn't alert, but it should: "); goto end; } if ( !(p->flow->flags & FLOW_ACTION_DROP)) { printf("sig 1 alerted but flow was not flagged correctly: "); goto end; } /* Ok, now we know that the flag is set for app layer sigs * (ex: inspecting uricontent) */ result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test test if the engine set flag to drop pkts of a flow that * triggered a drop action on IPS mode, and it doesn't inspect * any other packet of the stream */ static int SigTestDropFlow03(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /two HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf1) - 1; /* Set the engine mode to IPS */ SET_ENGINE_MODE_IPS(engine_mode); TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " "(msg:\"Test proto match\"; uricontent:\"one\";" "sid:1;)"); if (s == NULL) { goto end; } /* the no inspection flag should be set after the first sig gets triggered, * so the second packet should not match the next sig (because of no inspection) */ s = de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any 80 " "(msg:\"Test proto match\"; uricontent:\"two\";" "sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p1); if (!PacketAlertCheck(p1, 1)) { printf("sig 1 didn't alert on p1, but it should: "); goto end; } if ( !(p1->flow->flags & FLOW_ACTION_DROP)) { printf("sig 1 alerted but flow was not flagged correctly: "); goto end; } /* Second part.. Let's feed with another packet */ if (StreamTcpCheckFlowDrops(p2) == 1) { SCLogDebug("This flow/stream triggered a drop rule"); FlowSetNoPacketInspectionFlag(p2->flow); DecodeSetNoPacketInspectionFlag(p2); FlowSetSessionNoApplayerInspectionFlag(p2->flow); p2->action |= ACTION_DROP; /* return the segments to the pool */ StreamTcpSessionPktFree(p2); } if ( !(p2->flags & PKT_NOPACKET_INSPECTION)) { printf("The packet was not flagged with no-inspection: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sig 1 alerted, but it should not since the no pkt inspection should be set: "); goto end; } if (PacketAlertCheck(p2, 2)) { printf("sig 2 alerted, but it should not since the no pkt inspection should be set: "); goto end; } if ( !(PACKET_TEST_ACTION(p2, ACTION_DROP))) { printf("A \"drop\" action should be set from the flow to the packet: "); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); /* Restore mode to IDS */ SET_ENGINE_MODE_IDS(engine_mode); return result; } /** \test test if the engine set flag to drop pkts of a flow that * triggered a drop action on IDS mode, but continue the inspection * as usual (instead of on IPS mode) */ static int SigTestDropFlow04(void) { int result = 0; Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /two HTTP/1.0\r\n" "User-Agent: Mozilla/1.0\r\n" "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; Signature *s = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " "(msg:\"Test proto match\"; uricontent:\"one\";" "sid:1;)"); if (s == NULL) { goto end; } /* the no inspection flag should be set after the first sig gets triggered, * so the second packet should not match the next sig (because of no inspection) */ s = de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any 80 " "(msg:\"Test proto match\"; uricontent:\"two\";" "sid:2;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p1); if (!PacketAlertCheck(p1, 1)) { printf("sig 1 didn't alert on p1, but it should: "); goto end; } if (PacketAlertCheck(p1, 2)) { printf("sig 2 alerted on p1, but it should not: "); goto end; } if ( !(p1->flow->flags & FLOW_ACTION_DROP)) { printf("sig 1 alerted but flow was not flagged correctly: "); goto end; } if (!(PACKET_TEST_ACTION(p1, ACTION_DROP))) { printf("A \"drop\" action was set from the flow to the packet " "which is right, but setting the flag shouldn't disable " "inspection on the packet in IDS mode"); goto end; } /* Second part.. Let's feed with another packet */ if (StreamTcpCheckFlowDrops(p2) == 1) { FlowSetNoPacketInspectionFlag(p2->flow); DecodeSetNoPacketInspectionFlag(p2); FlowSetSessionNoApplayerInspectionFlag(p2->flow); p2->action |= ACTION_DROP; /* return the segments to the pool */ StreamTcpSessionPktFree(p2); } if ( (p2->flags & PKT_NOPACKET_INSPECTION)) { printf("The packet was flagged with no-inspection but we are not on IPS mode: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sig 1 alerted, but it should not: "); goto end; } if (!PacketAlertCheck(p2, 2)) { printf("sig 2 didn't alert, but it should, since we are not on IPS mode: "); goto end; } if (!(PACKET_TEST_ACTION(p2, ACTION_DROP))) { printf("A \"drop\" action was set from the flow to the packet " "which is right, but setting the flag shouldn't disable " "inspection on the packet in IDS mode"); goto end; } result = 1; end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } /// SCLogInfo("%s %u %u %u %u", #v, (v).dw[0], (v).dw[1], (v).dw[2], (v).dw[3]); #define VECTOR_SCLogInfo(v) { \ SCLogInfo("%s %08X %08X %08X %08X", #v, (v).dw[0], (v).dw[1], (v).dw[2], (v).dw[3]); \ } /** * \test Test 32 bit SIMD code. */ int SigTestSIMDMask01(void) { #if defined (__SSE3__) Vector pm, sm, r1, r2; uint32_t bm = 0; uint8_t *mask = SCMallocAligned(32, 16); memset(mask, 0xEF, 32); mask[31] = 0xFF; printf("\n"); pm.v = _mm_set1_epi8(0xEF); VECTOR_SCLogInfo(pm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[0]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm = ((uint32_t) _mm_movemask_epi8(r2.v)); SCLogInfo("bm %08x", bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[16]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm |= ((uint32_t) _mm_movemask_epi8(r2.v)) << 16; SCLogInfo("bm %08x", bm); int b = 0; for ( ; b < 32; b++){ if (bm & (1 << b)) { SCLogInfo("b %02d, set", b); } else { SCLogInfo("b %02d, not set", b); } } if (!(bm & (1 << 31))) { return 1; } return 0; #else return 1; #endif } /** * \test Test 32 bit SIMD code. */ int SigTestSIMDMask02(void) { #if defined (__SSE3__) Vector pm, sm, r1, r2; uint32_t bm = 0; uint8_t *mask = SCMallocAligned(32, 16); memset(mask, 0x01, 32); mask[31] = 0; pm.v = _mm_set1_epi8(0x02); VECTOR_SCLogInfo(pm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[0]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm = ((uint32_t) _mm_movemask_epi8(r2.v)); SCLogInfo("bm %08x", bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[16]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm |= ((uint32_t) _mm_movemask_epi8(r2.v)) << 16; SCLogInfo("bm %08x", bm); int b = 0; for ( ; b < 32; b++){ if (bm & (1 << b)) { SCLogInfo("b %02d, set", b); } else { SCLogInfo("b %02d, not set", b); } } if (bm & (1 << 31)) { return 1; } return 0; #else return 1; #endif } /** * \test Test 64 bit SIMD code. */ int SigTestSIMDMask03(void) { #if defined (__SSE3__) Vector pm, sm, r1, r2; uint64_t bm = 0; uint8_t *mask = SCMallocAligned(64, 16); memset(mask, 0xEF, 64); mask[31] = 0xFF; mask[62] = 0xFF; printf("\n"); pm.v = _mm_set1_epi8(0xEF); VECTOR_SCLogInfo(pm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[0]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm = ((uint64_t) _mm_movemask_epi8(r2.v)); SCLogInfo("bm1 %"PRIxMAX, (uintmax_t)bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[16]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; SCLogInfo("bm2 %"PRIxMAX, (uintmax_t)bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[32]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; SCLogInfo("bm3 %"PRIxMAX, (uintmax_t)bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[48]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 48; SCLogInfo("bm4 %"PRIxMAX, (uintmax_t)bm); int b = 0; for ( ; b < 64; b++){ if (bm & ((uint64_t)1 << b)) { SCLogInfo("b %02d, set", b); } else { SCLogInfo("b %02d, not set", b); } } if (!(bm & ((uint64_t)1 << 31)) && !(bm & ((uint64_t)1 << 62))) { return 1; } return 0; #else return 1; #endif } /** * \test Test 64 bit SIMD code. */ int SigTestSIMDMask04(void) { #if defined (__SSE3__) Vector pm, sm, r1, r2; uint64_t bm = 0; uint8_t *mask = SCMallocAligned(64, 16); memset(mask, 0x01, 64); mask[31] = 0; mask[62] = 0; pm.v = _mm_set1_epi8(0x02); VECTOR_SCLogInfo(pm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[0]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm = ((uint64_t) _mm_movemask_epi8(r2.v)); SCLogInfo("bm1 %"PRIxMAX, (uintmax_t)bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[16]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; SCLogInfo("bm2 %"PRIxMAX, (uintmax_t)bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[32]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; SCLogInfo("bm3 %"PRIxMAX, (uintmax_t)bm); /* load a batch of masks */ sm.v = _mm_load_si128((const __m128i *)&mask[48]); VECTOR_SCLogInfo(sm); /* logical AND them with the packet's mask */ r1.v = _mm_and_si128(pm.v, sm.v); VECTOR_SCLogInfo(r1); /* compare the result with the original mask */ r2.v = _mm_cmpeq_epi8(sm.v, r1.v); VECTOR_SCLogInfo(r2); /* convert into a bitarray */ bm |= (((uint64_t) _mm_movemask_epi8(r2.v)) << 48); SCLogInfo("bm4-total %"PRIxMAX, (uintmax_t)bm); int b = 0; for ( ; b < 64; b++){ if (bm & ((uint64_t)1 << b)) { SCLogInfo("b %02d, set", b); } else { SCLogInfo("b %02d, not set", b); } } if ((bm & ((uint64_t)1 << 31)) && (bm & ((uint64_t)1 << 62))) { return 1; } return 0; #else return 1; #endif } #endif /* UNITTESTS */ void SigRegisterTests(void) { #ifdef UNITTESTS SigParseRegisterTests(); IPOnlyRegisterTests(); UtRegisterTest("SigTest01B2g -- HTTP URI cap", SigTest01B2g, 1); UtRegisterTest("SigTest01B3g -- HTTP URI cap", SigTest01B3g, 1); UtRegisterTest("SigTest01Wm -- HTTP URI cap", SigTest01Wm, 1); UtRegisterTest("SigTest02B2g -- Offset/Depth match", SigTest02B2g, 1); UtRegisterTest("SigTest02B3g -- Offset/Depth match", SigTest02B3g, 1); UtRegisterTest("SigTest02Wm -- Offset/Depth match", SigTest02Wm, 1); UtRegisterTest("SigTest03B2g -- offset/depth mismatch", SigTest03B2g, 1); UtRegisterTest("SigTest03B3g -- offset/depth mismatch", SigTest03B3g, 1); UtRegisterTest("SigTest03Wm -- offset/depth mismatch", SigTest03Wm, 1); UtRegisterTest("SigTest04B2g -- distance/within match", SigTest04B2g, 1); UtRegisterTest("SigTest04B3g -- distance/within match", SigTest04B3g, 1); UtRegisterTest("SigTest04Wm -- distance/within match", SigTest04Wm, 1); UtRegisterTest("SigTest05B2g -- distance/within mismatch", SigTest05B2g, 1); UtRegisterTest("SigTest05B3g -- distance/within mismatch", SigTest05B3g, 1); UtRegisterTest("SigTest05Wm -- distance/within mismatch", SigTest05Wm, 1); UtRegisterTest("SigTest06B2g -- uricontent HTTP/1.1 match test", SigTest06B2g, 1); UtRegisterTest("SigTest06B3g -- uricontent HTTP/1.1 match test", SigTest06B3g, 1); UtRegisterTest("SigTest06wm -- uricontent HTTP/1.1 match test", SigTest06Wm, 1); UtRegisterTest("SigTest07B2g -- uricontent HTTP/1.1 mismatch test", SigTest07B2g, 1); UtRegisterTest("SigTest07B3g -- uricontent HTTP/1.1 mismatch test", SigTest07B3g, 1); UtRegisterTest("SigTest07Wm -- uricontent HTTP/1.1 mismatch test", SigTest07Wm, 1); UtRegisterTest("SigTest08B2g -- uricontent HTTP/1.0 match test", SigTest08B2g, 1); UtRegisterTest("SigTest08B3g -- uricontent HTTP/1.0 match test", SigTest08B3g, 1); UtRegisterTest("SigTest08Wm -- uricontent HTTP/1.0 match test", SigTest08Wm, 1); UtRegisterTest("SigTest09B2g -- uricontent HTTP/1.0 mismatch test", SigTest09B2g, 1); UtRegisterTest("SigTest09B3g -- uricontent HTTP/1.0 mismatch test", SigTest09B3g, 1); UtRegisterTest("SigTest09Wm -- uricontent HTTP/1.0 mismatch test", SigTest09Wm, 1); UtRegisterTest("SigTest10B2g -- long content match, longer than pkt", SigTest10B2g, 1); UtRegisterTest("SigTest10B3g -- long content match, longer than pkt", SigTest10B3g, 1); UtRegisterTest("SigTest10Wm -- long content match, longer than pkt", SigTest10Wm, 1); UtRegisterTest("SigTest11B2g -- mpm searching", SigTest11B2g, 1); UtRegisterTest("SigTest11B3g -- mpm searching", SigTest11B3g, 1); UtRegisterTest("SigTest11Wm -- mpm searching", SigTest11Wm, 1); UtRegisterTest("SigTest12B2g -- content order matching, normal", SigTest12B2g, 1); UtRegisterTest("SigTest12B3g -- content order matching, normal", SigTest12B3g, 1); UtRegisterTest("SigTest12Wm -- content order matching, normal", SigTest12Wm, 1); UtRegisterTest("SigTest13B2g -- content order matching, diff order", SigTest13B2g, 1); UtRegisterTest("SigTest13B3g -- content order matching, diff order", SigTest13B3g, 1); UtRegisterTest("SigTest13Wm -- content order matching, diff order", SigTest13Wm, 1); UtRegisterTest("SigTest14B2g -- content order matching, distance 0", SigTest14B2g, 1); UtRegisterTest("SigTest14B3g -- content order matching, distance 0", SigTest14B3g, 1); UtRegisterTest("SigTest14Wm -- content order matching, distance 0", SigTest14Wm, 1); UtRegisterTest("SigTest15B2g -- port negation sig (no match)", SigTest15B2g, 1); UtRegisterTest("SigTest15B3g -- port negation sig (no match)", SigTest15B3g, 1); UtRegisterTest("SigTest15Wm -- port negation sig (no match)", SigTest15Wm, 1); UtRegisterTest("SigTest16B2g -- port negation sig (match)", SigTest16B2g, 1); UtRegisterTest("SigTest16B3g -- port negation sig (match)", SigTest16B3g, 1); UtRegisterTest("SigTest16Wm -- port negation sig (match)", SigTest16Wm, 1); UtRegisterTest("SigTest17B2g -- HTTP Host Pkt var capture", SigTest17B2g, 1); UtRegisterTest("SigTest17B3g -- HTTP Host Pkt var capture", SigTest17B3g, 1); UtRegisterTest("SigTest17Wm -- HTTP Host Pkt var capture", SigTest17Wm, 1); UtRegisterTest("SigTest18B2g -- Ftp negation sig test", SigTest18B2g, 1); UtRegisterTest("SigTest18B3g -- Ftp negation sig test", SigTest18B3g, 1); UtRegisterTest("SigTest18Wm -- Ftp negation sig test", SigTest18Wm, 1); UtRegisterTest("SigTest19B2g -- IP-ONLY test (1)", SigTest19B2g, 1); UtRegisterTest("SigTest19B3g -- IP-ONLY test (1)", SigTest19B3g, 1); UtRegisterTest("SigTest19Wm -- IP-ONLY test (1)", SigTest19Wm, 1); UtRegisterTest("SigTest20B2g -- IP-ONLY test (2)", SigTest20B2g, 1); UtRegisterTest("SigTest20B3g -- IP-ONLY test (2)", SigTest20B3g, 1); UtRegisterTest("SigTest20Wm -- IP-ONLY test (2)", SigTest20Wm, 1); UtRegisterTest("SigTest21B2g -- FLOWBIT test (1)", SigTest21B2g, 1); UtRegisterTest("SigTest21B3g -- FLOWBIT test (1)", SigTest21B3g, 1); UtRegisterTest("SigTest21Wm -- FLOWBIT test (1)", SigTest21Wm, 1); UtRegisterTest("SigTest22B2g -- FLOWBIT test (2)", SigTest22B2g, 1); UtRegisterTest("SigTest22B3g -- FLOWBIT test (2)", SigTest22B3g, 1); UtRegisterTest("SigTest22Wm -- FLOWBIT test (2)", SigTest22Wm, 1); UtRegisterTest("SigTest23B2g -- FLOWBIT test (3)", SigTest23B2g, 1); UtRegisterTest("SigTest23B3g -- FLOWBIT test (3)", SigTest23B3g, 1); UtRegisterTest("SigTest23Wm -- FLOWBIT test (3)", SigTest23Wm, 1); UtRegisterTest("SigTest24IPV4Keyword", SigTest24IPV4Keyword, 1); UtRegisterTest("SigTest25NegativeIPV4Keyword", SigTest25NegativeIPV4Keyword, 1); UtRegisterTest("SigTest26TCPV4Keyword", SigTest26TCPV4Keyword, 1); UtRegisterTest("SigTest27NegativeTCPV4Keyword", SigTest27NegativeTCPV4Keyword, 1); UtRegisterTest("SigTest28TCPV6Keyword", SigTest28TCPV6Keyword, 1); UtRegisterTest("SigTest29NegativeTCPV6Keyword", SigTest29NegativeTCPV6Keyword, 1); UtRegisterTest("SigTest30UDPV4Keyword", SigTest30UDPV4Keyword, 1); UtRegisterTest("SigTest31NegativeUDPV4Keyword", SigTest31NegativeUDPV4Keyword, 1); UtRegisterTest("SigTest32UDPV6Keyword", SigTest32UDPV6Keyword, 1); UtRegisterTest("SigTest33NegativeUDPV6Keyword", SigTest33NegativeUDPV6Keyword, 1); UtRegisterTest("SigTest34ICMPV4Keyword", SigTest34ICMPV4Keyword, 1); UtRegisterTest("SigTest35NegativeICMPV4Keyword", SigTest35NegativeICMPV4Keyword, 1); /* The following tests check content options with isdataat options relative to that content match */ UtRegisterTest("SigTest36ContentAndIsdataatKeywords01B2g", SigTest36ContentAndIsdataatKeywords01B2g, 1); UtRegisterTest("SigTest36ContentAndIsdataatKeywords01B3g", SigTest36ContentAndIsdataatKeywords01B3g, 1); UtRegisterTest("SigTest36ContentAndIsdataatKeywords01Wm" , SigTest36ContentAndIsdataatKeywords01Wm, 1); UtRegisterTest("SigTest37ContentAndIsdataatKeywords02B2g", SigTest37ContentAndIsdataatKeywords02B2g, 1); UtRegisterTest("SigTest37ContentAndIsdataatKeywords02B3g", SigTest37ContentAndIsdataatKeywords02B3g, 1); UtRegisterTest("SigTest37ContentAndIsdataatKeywords02Wm" , SigTest37ContentAndIsdataatKeywords02Wm, 1); /* We need to enable these tests, as soon as we add the ICMPv6 protocol support in our rules engine */ //UtRegisterTest("SigTest36ICMPV6Keyword", SigTest36ICMPV6Keyword, 1); //UtRegisterTest("SigTest37NegativeICMPV6Keyword", // SigTest37NegativeICMPV6Keyword, 1); UtRegisterTest("SigTest38B2g -- byte_test test (1)", SigTest38B2g, 1); UtRegisterTest("SigTest38B3g -- byte_test test (1)", SigTest38B3g, 1); UtRegisterTest("SigTest38Wm -- byte_test test (1)", SigTest38Wm, 1); UtRegisterTest("SigTest39B2g -- byte_jump test (2)", SigTest39B2g, 1); UtRegisterTest("SigTest39B3g -- byte_jump test (2)", SigTest39B3g, 1); UtRegisterTest("SigTest39Wm -- byte_jump test (2)", SigTest39Wm, 1); UtRegisterTest("SigTest40NoPacketInspection01", SigTest40NoPacketInspection01, 1); UtRegisterTest("SigTest40NoPayloadInspection02", SigTest40NoPayloadInspection02, 1); UtRegisterTest("SigTestMemory01", SigTestMemory01, 1); UtRegisterTest("SigTestMemory02", SigTestMemory02, 1); UtRegisterTest("SigTestMemory03", SigTestMemory03, 1); UtRegisterTest("SigTestSgh01", SigTestSgh01, 1); UtRegisterTest("SigTestSgh02", SigTestSgh02, 1); UtRegisterTest("SigTestSgh03", SigTestSgh03, 1); UtRegisterTest("SigTestSgh04", SigTestSgh04, 1); UtRegisterTest("SigTestSgh05", SigTestSgh05, 1); UtRegisterTest("SigTestContent01B2g -- 32 byte pattern", SigTestContent01B2g, 1); UtRegisterTest("SigTestContent01B3g -- 32 byte pattern", SigTestContent01B3g, 1); UtRegisterTest("SigTestContent01Wm -- 32 byte pattern", SigTestContent01Wm, 1); UtRegisterTest("SigTestContent02B2g -- 32+31 byte pattern", SigTestContent02B2g, 1); UtRegisterTest("SigTestContent02B3g -- 32+31 byte pattern", SigTestContent02B3g, 1); UtRegisterTest("SigTestContent02Wm -- 32+31 byte pattern", SigTestContent02Wm, 1); UtRegisterTest("SigTestContent03B2g -- 32 byte pattern, x2 + distance", SigTestContent03B2g, 1); UtRegisterTest("SigTestContent03B3g -- 32 byte pattern, x2 + distance", SigTestContent03B3g, 1); UtRegisterTest("SigTestContent03Wm -- 32 byte pattern, x2 + distance", SigTestContent03Wm, 1); UtRegisterTest("SigTestContent04B2g -- 32 byte pattern, x2 + distance/within", SigTestContent04B2g, 1); UtRegisterTest("SigTestContent04B3g -- 32 byte pattern, x2 + distance/within", SigTestContent04B3g, 1); UtRegisterTest("SigTestContent04Wm -- 32 byte pattern, x2 + distance/within", SigTestContent04Wm, 1); UtRegisterTest("SigTestContent05B2g -- distance/within", SigTestContent05B2g, 1); UtRegisterTest("SigTestContent05B3g -- distance/within", SigTestContent05B3g, 1); UtRegisterTest("SigTestContent05Wm -- distance/within", SigTestContent05Wm, 1); UtRegisterTest("SigTestContent06B2g -- distance/within ip only", SigTestContent06B2g, 1); UtRegisterTest("SigTestContent06B3g -- distance/within ip only", SigTestContent06B3g, 1); UtRegisterTest("SigTestContent06Wm -- distance/within ip only", SigTestContent06Wm, 1); UtRegisterTest("SigTestWithinReal01B2g", SigTestWithinReal01B2g, 1); UtRegisterTest("SigTestWithinReal01B3g", SigTestWithinReal01B3g, 1); UtRegisterTest("SigTestWithinReal01Wm", SigTestWithinReal01Wm, 1); UtRegisterTest("SigTestDepthOffset01B2g", SigTestDepthOffset01B2g, 1); UtRegisterTest("SigTestDepthOffset01B3g", SigTestDepthOffset01B3g, 1); UtRegisterTest("SigTestDepthOffset01Wm", SigTestDepthOffset01Wm, 1); UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter, 1); UtRegisterTest("SigTestDropFlow01", SigTestDropFlow01, 1); UtRegisterTest("SigTestDropFlow02", SigTestDropFlow02, 1); UtRegisterTest("SigTestDropFlow03", SigTestDropFlow03, 1); UtRegisterTest("SigTestDropFlow04", SigTestDropFlow04, 1); UtRegisterTest("SigTestSIMDMask01", SigTestSIMDMask01, 1); UtRegisterTest("SigTestSIMDMask02", SigTestSIMDMask02, 1); UtRegisterTest("SigTestSIMDMask03", SigTestSIMDMask03, 1); UtRegisterTest("SigTestSIMDMask04", SigTestSIMDMask04, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-flowvar.c0000644000000000000000000002552512253546156014130 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Simple flowvar content match part of the detection engine. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-content.h" #include "threads.h" #include "flow.h" #include "flow-var.h" #include "detect-flowvar.h" #include "util-spm.h" #include "util-var-name.h" #include "util-debug.h" #define PARSE_REGEX "(.*),(.*)" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectFlowvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectFlowvarSetup (DetectEngineCtx *, Signature *, char *); static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm); static void DetectFlowvarDataFree(void *ptr); 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 = DetectFlowvarDataFree; sigmatch_table[DETECT_FLOWVAR].RegisterTests = NULL; /* post-match for flowvar storage */ sigmatch_table[DETECT_FLOWVAR_POSTMATCH].name = "__flowvar__postmatch__"; sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Match = DetectFlowvarPostMatch; sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Setup = NULL; sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Free = DetectFlowvarDataFree; sigmatch_table[DETECT_FLOWVAR_POSTMATCH].RegisterTests = NULL; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief this function will SCFree memory associated with DetectFlowvarData * * \param cd pointer to DetectCotentData */ static void DetectFlowvarDataFree(void *ptr) { if (ptr == NULL) SCReturn; DetectFlowvarData *fd = (DetectFlowvarData *)ptr; if (fd->name) SCFree(fd->name); if (fd->content) SCFree(fd->content); SCFree(fd); } /* * returns 0: no match * 1: match * -1: error */ int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { int ret = 0; DetectFlowvarData *fd = (DetectFlowvarData *)m->ctx; /* we need a lock */ FLOWLOCK_RDLOCK(p->flow); FlowVar *fv = FlowVarGet(p->flow, fd->idx); if (fv != NULL) { uint8_t *ptr = SpmSearch(fv->data.fv_str.value, fv->data.fv_str.value_len, fd->content, fd->content_len); if (ptr != NULL) ret = 1; } FLOWLOCK_UNLOCK(p->flow); return ret; } static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectFlowvarData *cd = NULL; SigMatch *sm = NULL; char *str = rawstr; char dubbed = 0; uint16_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 != 3) { SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowvar.", rawstr); return -1; } const char *str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } varname = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } varcontent = (char *)str_ptr; } if (varcontent[0] == '\"' && varcontent[strlen(varcontent)-1] == '\"') { str = SCStrdup(varcontent+1); if (unlikely(str == NULL)) { return -1; } str[strlen(varcontent)-2] = '\0'; dubbed = 1; } len = strlen(str); if (len == 0) { if (dubbed) SCFree(str); return -1; } cd = SCMalloc(sizeof(DetectFlowvarData)); if (unlikely(cd == NULL)) goto error; char converted = 0; { uint16_t i, x; uint8_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((unsigned char)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) { uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF; 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 if (SCLogDebugEnabled()) { for (i = 0; i < x; i++) { if (isprint((unsigned char)str[i])) printf("%c", str[i]); else printf("\\x%02u", str[i]); } printf("\n"); } #endif if (converted) len = x; } cd->content = SCMalloc(len); if (cd->content == NULL) { if (dubbed) SCFree(str); SCFree(cd); return -1; } cd->name = SCStrdup(varname); cd->idx = VariableNameGetIdx(de_ctx, varname, DETECT_FLOWVAR); 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; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); if (cd) SCFree(cd); if (sm) SCFree(sm); return -1; } /** \brief Store flowvar in det_ctx so we can exec it post-match */ int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint16_t idx, uint8_t *buffer, uint16_t len) { DetectFlowvarList *fs = det_ctx->flowvarlist; /* first check if we have had a previous match for this idx */ for ( ; fs != NULL; fs = fs->next) { if (fs->idx == idx) { /* we're replacing the older store */ SCFree(fs->buffer); fs->buffer = NULL; break; } } if (fs == NULL) { fs = SCMalloc(sizeof(*fs)); if (unlikely(fs == NULL)) return -1; fs->idx = idx; fs->next = det_ctx->flowvarlist; det_ctx->flowvarlist = fs; } fs->len = len; fs->buffer = buffer; return 0; } /** \brief Setup a post-match for flowvar storage * We're piggyback riding the DetectFlowvarData struct */ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) { SigMatch *sm = NULL; DetectFlowvarData *fv = NULL; fv = SCMalloc(sizeof(DetectFlowvarData)); if (unlikely(fv == NULL)) goto error; memset(fv, 0x00, sizeof(*fv)); /* we only need the idx */ fv->idx = idx; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_FLOWVAR_POSTMATCH; sm->ctx = (void *)fv; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); return 0; error: return -1; } /** \internal * \brief post-match func to store flowvars in the flow * \param sm sigmatch containing the idx to store * \retval 1 or -1 in case of error */ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) { DetectFlowvarList *fs, *prev; DetectFlowvarData *fd; if (det_ctx->flowvarlist == NULL || p->flow == NULL) return 1; fd = (DetectFlowvarData *)sm->ctx; prev = NULL; fs = det_ctx->flowvarlist; while (fs != NULL) { if (fd->idx == fs->idx) { FlowVarAddStr(p->flow, fs->idx, fs->buffer, fs->len); /* memory at fs->buffer is now the responsibility of * the flowvar code. */ if (fs == det_ctx->flowvarlist) { det_ctx->flowvarlist = fs->next; SCFree(fs); fs = det_ctx->flowvarlist; } else { prev->next = fs->next; SCFree(fs); fs = prev->next; } } else { prev = fs; fs = fs->next; } } return 1; } /** \brief Clean flowvar candidate list in det_ctx */ void DetectFlowvarCleanupList(DetectEngineThreadCtx *det_ctx) { DetectFlowvarList *fs, *next; if (det_ctx->flowvarlist != NULL) { fs = det_ctx->flowvarlist; while (fs != NULL) { next = fs->next; SCFree(fs->buffer); SCFree(fs); fs = next; } det_ctx->flowvarlist = NULL; } } suricata-1.4.7/src/flow-alert-sid.h0000644000000000000000000000275512253546156014040 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __FLOW_ALERT_SID_H__ #define __FLOW_ALERT_SID_H__ #include "flow.h" #include "util-var.h" typedef struct FlowAlertSid_ { uint8_t type; /* type, DETECT_FLOWALERTSID in this case */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ uint32_t sid; /* sid */ } FlowAlertSid; void FlowAlertSidFree(FlowAlertSid *); void FlowAlertSidRegisterTests(void); void FlowAlertSidSet(Flow *, uint32_t); void FlowAlertSidUnset(Flow *, uint32_t); void FlowAlertSidToggle(Flow *, uint32_t); int FlowAlertSidIsset(Flow *, uint32_t); int FlowAlertSidIsnotset(Flow *, uint32_t); #endif /* __FLOW_ALERT_SID_H__ */ suricata-1.4.7/src/util-mpm-b2gc.c0000644000000000000000000042137712253546156013566 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implementation of the SBNDMq pattern matching algorithm that tries * to be very limiting memory use and CPU cache efficient. * * Things to try: * - 1 byte pattern checks use lowercase *buf for hash, limiting the hash * - lookup array with pminlen and pminlenb like in B2gm */ //#define PRINTMATCH #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "util-mpm-b2gc.h" #include "util-print.h" #include "util-bloomfilter.h" #include "util-debug.h" #include "util-unittest.h" #include "util-hashlist.h" #include "util-optimize.h" #include "util-memcmp.h" #include "conf.h" #ifdef B2GC_COUNTERS #define COUNT(counter) \ (counter) #else #define COUNT(counter) #endif /* B2GC_COUNTERS */ /* Hash table used at ctx initialization to keep and ordered list of * patterns. The ordered list is used to build the ordered lookup * array. */ static uint32_t b2gc_hash_size = 0; static int8_t b2gc_hash_shift = 0; static uint32_t b2gc_bloom_size = 0; static void *b2g_func; #define B2GC_HASH16(a,b) (((a) << b2gc_hash_shift) | (b)) #define B2GC_PMINLEN_MAX 8 /* align pattern storage to these bytes. 1 disables. */ #define B2GC_ALIGN_PATTERNS 2 void B2gcInitCtx (MpmCtx *, int); void B2gcThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void B2gcDestroyCtx(MpmCtx *); void B2gcThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); int B2gcAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B2gcAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); int B2gcPreparePatterns(MpmCtx *mpm_ctx); uint32_t B2gcSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); #ifdef B2GC_SEARCH2 uint32_t B2gcSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); #endif uint32_t B2gcSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); void B2gcPrintInfo(MpmCtx *mpm_ctx); void B2gcPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void B2gcRegisterTests(void); void MpmB2gcRegister (void) { mpm_table[MPM_B2GC].name = "b2gc"; mpm_table[MPM_B2GC].max_pattern_length = B2GC_WORD_SIZE; mpm_table[MPM_B2GC].InitCtx = B2gcInitCtx; mpm_table[MPM_B2GC].InitThreadCtx = B2gcThreadInitCtx; mpm_table[MPM_B2GC].DestroyCtx = B2gcDestroyCtx; mpm_table[MPM_B2GC].DestroyThreadCtx = B2gcThreadDestroyCtx; mpm_table[MPM_B2GC].AddPattern = B2gcAddPatternCS; mpm_table[MPM_B2GC].AddPatternNocase = B2gcAddPatternCI; mpm_table[MPM_B2GC].Prepare = B2gcPreparePatterns; mpm_table[MPM_B2GC].Search = B2gcSearchWrap; mpm_table[MPM_B2GC].Cleanup = NULL; mpm_table[MPM_B2GC].PrintCtx = B2gcPrintInfo; mpm_table[MPM_B2GC].PrintThreadCtx = B2gcPrintSearchStats; mpm_table[MPM_B2GC].RegisterUnittests = B2gcRegisterTests; } #ifdef PRINTMATCH static void prt (uint8_t *buf, uint16_t buflen) { uint16_t i; for (i = 0; i < buflen; i++) { if (isprint(buf[i])) printf("%c", buf[i]); else printf("\\x%02X", buf[i]); } //printf("\n"); } #endif void B2gcPrintInfo(MpmCtx *mpm_ctx) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; printf("MPM B2gc Information:\n"); printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); printf(" Sizeofs:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" B2gcCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gcCtx)); printf(" B2gcPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gcPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Hash size: %" PRIu32 "\n", ctx->hash_size); printf("\n"); } static inline int memcmp_lowercase(const uint8_t *s1, const uint8_t *s2, const uint16_t n) { size_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ for (i = n - 1; i; i--) { //if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) if (s1[i] != u8_tolower(*(s2+i))) return 1; } return 0; } static inline int memcmp_lowercase2(uint8_t *s1, uint8_t *s2, uint16_t n) { size_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ for (i = n - 1; i; i--) { //if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) if (u8_tolower(s1[i]) != u8_tolower(*(s2+i))) return 1; } return 0; } static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) { d[i] = u8_tolower(s[i]); } } static inline B2gcPattern *B2gcAllocPattern(MpmCtx *mpm_ctx) { B2gcPattern *p = SCMalloc(sizeof(B2gcPattern)); if (unlikely(p == NULL)) return NULL; memset(p,0,sizeof(B2gcPattern)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gcPattern); return p; } /** \internal * \brief Free a init hash pattern */ static void B2gcFreePattern(MpmCtx *mpm_ctx, B2gcPattern *p) { if (p != NULL) { if (p->pat != NULL) { SCFree(p->pat); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gcPattern); } } /** \internal * \brief add a pattern to the mpm/b2g context * * \param pat ptr to the pattern * \param patlen length of the pattern * \param pid pattern id * \param sid signature id (internal id) * \param flags pattern MPM_PATTERN_* flags */ static int B2gcAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); if (patlen == 0) return 0; /* detect duplicate pattern adds */ B2gcPattern lookup_p = { patlen, flags, 0, pid, pat }; /* get a memory piece */ B2gcPattern *p = HashListTableLookup(ctx->b2gc_init_hash, (void *)&lookup_p, sizeof(B2gcPattern)); if (p == NULL) { SCLogDebug("allocing new pattern"); p = B2gcAllocPattern(mpm_ctx); if (p == NULL) goto error; p->len = patlen; p->flags = flags; p->id = pid; p->pat = SCMalloc(patlen); if (p->pat == NULL) goto error; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += patlen; memcpy(p->pat, pat, patlen); /* put in the pattern hash */ HashListTableAdd(ctx->b2gc_init_hash, (void *)p, sizeof(B2gcPattern)); if (mpm_ctx->pattern_cnt == 65535) { printf("Max search words reached\n"); exit(1); } mpm_ctx->pattern_cnt++; if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } return 0; error: B2gcFreePattern(mpm_ctx, p); return -1; } int B2gcAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; return B2gcAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } int B2gcAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { return B2gcAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } static inline uint32_t B2gcBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint16_t i; uint32_t hash = (uint32_t)u8_tolower(*d); for (i = 1; i < datalen; i++) { d++; hash += (u8_tolower(*d)) ^ i; } hash <<= (iter+1); hash %= hash_size; return hash; } static uint32_t B2gcHashPatternInitHash(HashListTable *ht, void *pattern, uint16_t len) { BUG_ON(len != sizeof(B2gcPattern)); BUG_ON(pattern == NULL); B2gcPattern *p = (B2gcPattern *)pattern; uint32_t hash = 0; uint32_t u; for (u = 0; u < p->len; u++) { hash += (u8_tolower(p->pat[u])); } return hash % ht->array_size; } #define B2GC_SORTHASH_MODE_LL 0 #define B2GC_SORTHASH_MODE_LU 1 #define B2GC_SORTHASH_MODE_UL 2 #define B2GC_SORTHASH_MODE_UU 3 #define B2GC_SORTHASH_MODE_CS 4 /* copy of ctx->m for use in B2gcHashPatternSortHash */ static B2GC_TYPE m; static int b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LL; static uint32_t B2gcHashPatternSortHash(HashListTable *ht, void *pattern, uint16_t len) { BUG_ON(len != sizeof(B2gcPattern)); BUG_ON(pattern == NULL); B2gcPattern *p = (B2gcPattern *)pattern; uint32_t hash = 0; if (b2gc_sorthash_mode == B2GC_SORTHASH_MODE_LL) { hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); } else if(b2gc_sorthash_mode == B2GC_SORTHASH_MODE_LU) { hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), toupper(p->pat[m - 1])); } else if(b2gc_sorthash_mode == B2GC_SORTHASH_MODE_UL) { hash = B2GC_HASH16(toupper(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); } else if (b2gc_sorthash_mode == B2GC_SORTHASH_MODE_UU) { hash = B2GC_HASH16(toupper(p->pat[m - 2]), toupper(p->pat[m - 1])); } else { hash = B2GC_HASH16(p->pat[m - 2], p->pat[m - 1]); } SCReturnUInt(hash); } static uint32_t B2gcHashPatternSortHash1(HashListTable *ht, void *pattern, uint16_t len) { BUG_ON(len != sizeof(B2gcPattern)); BUG_ON(pattern == NULL); B2gcPattern *p = (B2gcPattern *)pattern; return (uint32_t)u8_tolower(p->pat[0]); } static char B2gcHashPatternCompare(void *pattern1, uint16_t len1, void *pattern2, uint16_t len2) { BUG_ON(len1 != sizeof(B2gcPattern)); BUG_ON(len2 != sizeof(B2gcPattern)); B2gcPattern *p1 = (B2gcPattern *)pattern1; B2gcPattern *p2 = (B2gcPattern *)pattern2; if (p1->id != p2->id) { return 0; } return 1; } static void B2gcHashPatternFree(void *pattern) { B2gcPattern *p = (B2gcPattern *)pattern; SCFree(p->pat); SCFree(pattern); } static void B2gcAddToMatchArray(MpmCtx *mpm_ctx, B2gcPattern *p, int j) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* u, u */ uint16_t uuidx = B2GC_HASH16(toupper(p->pat[j]), toupper(p->pat[j + 1])); ctx->B2GC[uuidx] = ctx->B2GC[uuidx] | (1 << (ctx->m - j)); /* l, l */ uint16_t llidx = B2GC_HASH16(u8_tolower(p->pat[j]), u8_tolower(p->pat[j + 1])); if (llidx != uuidx) { ctx->B2GC[llidx] = ctx->B2GC[llidx] | (1 << (ctx->m - j)); } /* u, l */ uint16_t ulidx = B2GC_HASH16(toupper(p->pat[j]), u8_tolower(p->pat[j + 1])); if (ulidx != llidx && ulidx != uuidx) { ctx->B2GC[ulidx] = ctx->B2GC[ulidx] | (1 << (ctx->m - j)); } /* l, u */ uint16_t luidx = B2GC_HASH16(u8_tolower(p->pat[j]), toupper(p->pat[j + 1])); if (luidx != ulidx && luidx != llidx && luidx != uuidx) { ctx->B2GC[luidx] = ctx->B2GC[luidx] | (1 << (ctx->m - j)); } SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); } } int B2gcBuildMatchArray(MpmCtx *mpm_ctx, HashListTable *b2gc_sort_hash) { SCEnter(); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; ctx->B2GC = SCMalloc(sizeof(B2GC_TYPE) * ctx->hash_size); if (ctx->B2GC == NULL) return -1; mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(B2GC_TYPE) * ctx->hash_size); memset(ctx->B2GC, 0x00, (b2gc_hash_size * sizeof(B2GC_TYPE))); uint32_t j; /* fill the match array */ for (j = 0; j <= (ctx->m - B2GC_Q); j++) { HashListTableBucket *next = NULL; HashListTableBucket *buck = HashListTableGetListHead(b2gc_sort_hash); while (buck != NULL) { /* get the next before we free "buck" */ next = HashListTableGetListNext(buck); B2gcPattern *p = (B2gcPattern *) HashListTableGetListData(buck); BUG_ON(p == NULL); if (p->len < ctx->m) goto next; uint16_t h; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { B2gcAddToMatchArray(mpm_ctx, p, j); } else { h = B2GC_HASH16(p->pat[j],p->pat[j+1]); ctx->B2GC[h] = ctx->B2GC[h] | (1 << (ctx->m - j)); SCLogDebug("h %"PRIu16", ctx->B2GC[h] %"PRIu32" (cs)", h, ctx->B2GC[h]); } next: buck = next; } } SCReturnInt(0); } static void B2gcAddCopyToHash(MpmCtx *mpm_ctx, HashListTable *ht, B2gcPattern *p) { B2gcPattern *pcopy = B2gcAllocPattern(mpm_ctx); BUG_ON(pcopy == NULL); pcopy->id = p->id; pcopy->flags = p->flags; pcopy->len = p->len; pcopy->pat = SCMalloc(pcopy->len); BUG_ON(pcopy->pat == NULL); memcpy(pcopy->pat, p->pat, pcopy->len); HashListTableAdd(ht, (void *)pcopy, sizeof(B2gcPattern)); } static int B2gcAddToHash(MpmCtx *mpm_ctx, HashListTable *b2gc_sort_hash, B2gcPattern *p) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; int added = 0; //printf("%c.%c\n", p->pat[ctx->m - 2], p->pat[ctx->m - 1]); if (p->flags & MPM_PATTERN_FLAG_NOCASE) { /* u, u */ uint16_t uuidx = B2GC_HASH16(toupper(p->pat[ctx->m - 2]), toupper(p->pat[ctx->m - 1])); b2gc_sorthash_mode = B2GC_SORTHASH_MODE_UU; HashListTableAdd(b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); added++; /* l, l */ uint16_t llidx = B2GC_HASH16(u8_tolower(p->pat[ctx->m - 2]), u8_tolower(p->pat[ctx->m - 1])); if (llidx != uuidx) { b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LL; B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); added++; } /* u, l */ uint16_t ulidx = B2GC_HASH16(toupper(p->pat[ctx->m - 2]), u8_tolower(p->pat[ctx->m - 1])); if (ulidx != llidx && ulidx != uuidx) { b2gc_sorthash_mode = B2GC_SORTHASH_MODE_UL; B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); added++; } /* l, u */ uint16_t luidx = B2GC_HASH16(u8_tolower(p->pat[ctx->m - 2]), toupper(p->pat[ctx->m - 1])); if (luidx != ulidx && luidx != llidx && luidx != uuidx) { b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LU; B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); added++; } SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); } return added; } static void B2gcPrepareHash(MpmCtx *mpm_ctx) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; HashListTable *b2gc_sort_hash = NULL; HashListTable *b2gc_sort_hash1 = NULL; /* make sure ctx->m is set */ BUG_ON(ctx->m == 0); m = ctx->m; /* convert b2gc_init_hash to b2gc_sort_hash and count size */ uint32_t size = B2GC_ALIGN_PATTERNS; uint16_t size1 = 1; /* only used at init */ b2gc_sort_hash = HashListTableInit(b2gc_hash_size, B2gcHashPatternSortHash, B2gcHashPatternCompare, B2gcHashPatternFree); if (b2gc_sort_hash == NULL) { exit(EXIT_FAILURE); } b2gc_sort_hash1 = HashListTableInit(256, B2gcHashPatternSortHash1, B2gcHashPatternCompare, B2gcHashPatternFree); if (b2gc_sort_hash1 == NULL) { exit(EXIT_FAILURE); } HashListTableBucket *next = NULL; HashListTableBucket *buck = HashListTableGetListHead(ctx->b2gc_init_hash); while (buck != NULL) { /* get the next before we free "buck" */ next = HashListTableGetListNext(buck); B2gcPattern *p = (B2gcPattern *) HashListTableGetListData(buck); BUG_ON(p == NULL); //printf("init_hash: "); prt(p->pat,p->len);printf("\n"); if (p->len > 1) { uint32_t psize; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { //prt(p->pat, p->len);printf(" (m %u)\n", m); int added = B2gcAddToHash(mpm_ctx, b2gc_sort_hash, p); SCLogDebug("nocase pattern was added under different hash values %d times", added); uint32_t one = sizeof(B2gcPatternHdr) + ((p->len + (p->len % B2GC_ALIGN_PATTERNS))); //uint32_t one = sizeof(B2gcPatternHdr) + ((p->len + (p->len % B2GC_ALIGN_PATTERNS)) * 2); psize = one * added; } else { b2gc_sorthash_mode = B2GC_SORTHASH_MODE_CS; HashListTableAdd(b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); psize = (sizeof(B2gcPatternHdr) + p->len + (p->len % B2GC_ALIGN_PATTERNS)); } size += psize; } else { HashListTableAdd(b2gc_sort_hash1, (void *)p, sizeof(B2gcPattern)); size1 += (sizeof(B2gcPattern1)); } buck = next; } HashListTableFree(ctx->b2gc_init_hash); ctx->b2gc_init_hash = NULL; SCLogDebug("size %u", size); /* alloc buf of size */ ctx->patterns = SCMalloc(size); BUG_ON(ctx->patterns == NULL); memset(ctx->patterns, 0x00, size); ctx->patterns1 = SCMalloc(size1); BUG_ON(ctx->patterns1 == NULL); memset(ctx->patterns1, 0x00, size1); /* loop through sort list and copy to buf */ /* skip the first byte of the buffer */ uint32_t offset = B2GC_ALIGN_PATTERNS; /* the hashlist is not sorted, it's in the order of insertion. * We need it to be sorted by hash, so here we do something * unclean: we bypass the hashlist api. */ uint32_t a = 0; for (a = 0; a < b2gc_sort_hash->array_size; a++) { if ((buck = b2gc_sort_hash->array[a]) != NULL) { while (buck != NULL) { if (buck->data != NULL) { uint32_t prev_offset = offset; B2gcPattern *p = (B2gcPattern *) (buck->data); BUG_ON(p == NULL); BUG_ON(p->len == 1); uint16_t hash = a;//= B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); if (ctx->pminlen[hash] == 0) { ctx->pminlen[hash] = p->len; } else if (p->len < ctx->pminlen[hash]) { ctx->pminlen[hash] = p->len; } if (ctx->ha[hash] == 0) ctx->ha[hash] = offset; /* copy */ B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; h->id = p->id; h->len = p->len; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { h->flags |= B2GC_FLAG_NOCASE; } offset += sizeof(B2gcPatternHdr); if (p->flags & MPM_PATTERN_FLAG_NOCASE) { memcpy_tolower(&ctx->patterns[offset], p->pat, p->len); } else { memcpy(&ctx->patterns[offset], p->pat, p->len); } offset += (p->len + (p->len % B2GC_ALIGN_PATTERNS)); h->np_offset = offset - prev_offset; SCLogDebug("h->offset %u", offset); ctx->pat_x_cnt++; } buck = buck->bucknext; } } } /* build the hash containing idx' to the pattern array */ for (a = 0; a < b2gc_hash_size; a++) { uint32_t offset = ctx->ha[a]; uint32_t next_offset = 0; if (offset > 0) { uint32_t b = a + 1; while (b < b2gc_hash_size) { if (ctx->ha[b] > 0) { next_offset = ctx->ha[b]; break; } b++; } } while (offset > 0) { B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; BUG_ON(h == NULL); BUG_ON(h->len <= 1); uint8_t *pattern = (uint8_t *)&ctx->patterns[offset + sizeof(B2gcPatternHdr)]; BUG_ON(pattern == NULL); //printf("hash %u (offset %u, h %u) sort_hash: ", a, offset, ctx->ha[a]);prt(pattern,h->len);printf("\n"); uint16_t hash = a; SCLogDebug("hash %u, offset %u", hash, offset); if (ctx->bloom[hash] == NULL) { ctx->bloom[hash] = BloomFilterInit(b2gc_bloom_size, 2, B2gcBloomHash); SCLogDebug("bloom created for hash %u", hash); BUG_ON(ctx->bloom[hash] == NULL); mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[hash]); mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[hash]); } if (ctx->pminlen[hash] > B2GC_PMINLEN_MAX) ctx->pminlen[hash] = B2GC_PMINLEN_MAX; BloomFilterAdd(ctx->bloom[hash], pattern, ctx->pminlen[hash]); offset += h->np_offset; /* last item in the pattern storage is "final" too */ if (offset == size) { SCLogDebug("final pattern in the array"); h->flags |= B2GC_FLAG_FINAL; break; } /* next_offset points to next hash */ if (next_offset > 0 && offset == next_offset) { SCLogDebug("last pattern for this hash"); h->flags |= B2GC_FLAG_FINAL; break; } } } /* skip the first byte of the buffer */ uint16_t offset1 = 1; for (a = 0; a < b2gc_sort_hash1->array_size; a++) { buck = b2gc_sort_hash1->array[a]; if (buck != NULL) { while (buck != NULL) { if (buck->data != NULL) { B2gcPattern *p = (B2gcPattern *) (buck->data); BUG_ON(p == NULL); BUG_ON(p->len != 1); B2gcPattern1 *h = (B2gcPattern1 *)&ctx->patterns1[offset1]; h->id = p->id; h->pat = p->pat[0]; if (p->flags & MPM_PATTERN_FLAG_NOCASE) { h->flags |= B2GC_FLAG_NOCASE; } offset1 += (sizeof(B2gcPattern1)); ctx->pat_1_cnt++; } buck = buck->bucknext; } } } /* build the hash containing idx' to the pattern array */ offset1 = 1; B2gcPattern1 *ph1 = NULL; uint8_t prevhash1 = 0; while (offset1 < size1) { B2gcPattern1 *h = (B2gcPattern1 *)&ctx->patterns1[offset1]; if (ctx->ha1[u8_tolower(h->pat)] == 0) ctx->ha1[u8_tolower(h->pat)] = offset1; /* check the prev pattern for setting the final flag */ if (ph1 != NULL) { if (h->pat != prevhash1) { SCLogDebug("setting final flag on %p", ph1); ph1->flags |= B2GC_FLAG_FINAL; } } prevhash1 = u8_tolower(h->pat); ph1 = h; offset1 += (sizeof(B2gcPattern1)); /* last item is "final" too */ if (offset1 == size1) { SCLogDebug("final pattern in the array"); h->flags |= B2GC_FLAG_FINAL; } } B2gcBuildMatchArray(mpm_ctx, b2gc_sort_hash); /* free the hashes only used at init */ HashListTableFree(b2gc_sort_hash); b2gc_sort_hash = NULL; HashListTableFree(b2gc_sort_hash1); b2gc_sort_hash1 = NULL; } int B2gcPreparePatterns(MpmCtx *mpm_ctx) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; /* set 'm' to the smallest pattern size */ ctx->m = mpm_ctx->minlen; /* make sure 'm' stays in bounds m can be max WORD_SIZE - 1 */ if (ctx->m >= B2GC_WORD_SIZE) { ctx->m = B2GC_WORD_SIZE - 1; } if (ctx->m < 2) ctx->m = 2; ctx->hash_size = b2gc_hash_size; /* alloc the hashes */ ctx->ha = SCMalloc(b2gc_hash_size * sizeof(uint32_t)); BUG_ON(ctx->ha == NULL); memset(ctx->ha, 0x00, b2gc_hash_size * sizeof(uint32_t)); ctx->ha1 = SCMalloc(256 * sizeof(uint16_t)); BUG_ON(ctx->ha1 == NULL); memset(ctx->ha1, 0x00, 256 * sizeof(uint16_t)); /* alloc the bloom array */ ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); if (ctx->bloom == NULL) exit(EXIT_FAILURE); memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); /* alloc the pminlen array */ ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); if (ctx->pminlen == NULL) exit(EXIT_FAILURE); memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); B2gcPrepareHash(mpm_ctx); SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); if (ctx->pat_1_cnt) { ctx->Search = B2gcSearch1; ctx->MBSearch = b2g_func; } return 0; } void B2gcPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { #ifdef B2GC_COUNTERS B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; printf("B2gc Thread Search stats (tctx %p)\n", tctx); printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); #endif /* B2GC_COUNTERS */ } /** * \brief Function to get the user defined values for b2g algorithm from the * config file 'suricata.yaml' */ static void B2gcGetConfig() { ConfNode *b2g_conf; const char *hash_val = NULL; const char *bloom_val = NULL; const char *algo = NULL; /* init defaults */ b2gc_hash_size = HASHSIZE_LOW; b2gc_hash_shift = B2GC_HASHSHIFT_LOW; b2gc_bloom_size = BLOOMSIZE_MEDIUM; b2g_func = B2GC_SEARCHFUNC; ConfNode *pm = ConfGetNode("pattern-matcher"); if (pm != NULL) { TAILQ_FOREACH(b2g_conf, &pm->head, next) { if (strncmp(b2g_conf->val, "b2gc", 4) == 0) { algo = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "algo"); hash_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "hash_size"); bloom_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "bf_size"); if (algo != NULL) { if (strcmp(algo, "B2gcSearch") == 0) { b2g_func = B2gcSearch; } else if (strcmp(algo, "B2gcSearchBNDMq") == 0) { b2g_func = B2gcSearchBNDMq; } } if (hash_val != NULL) { b2gc_hash_size = MpmGetHashSize(hash_val); switch (b2gc_hash_size) { case HASHSIZE_LOWEST: b2gc_hash_shift = B2GC_HASHSHIFT_LOWEST; break; case HASHSIZE_LOW: b2gc_hash_shift = B2GC_HASHSHIFT_LOW; break; case HASHSIZE_MEDIUM: b2gc_hash_shift = B2GC_HASHSHIFT_MEDIUM; break; case HASHSIZE_HIGH: b2gc_hash_shift = B2GC_HASHSHIFT_HIGH; break; case HASHSIZE_HIGHER: b2gc_hash_shift = B2GC_HASHSHIFT_HIGHER; break; case HASHSIZE_MAX: b2gc_hash_shift = B2GC_HASHSHIFT_MAX; break; } } if (bloom_val != NULL) b2gc_bloom_size = MpmGetBloomSize(bloom_val); SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", b2gc_hash_size, b2gc_bloom_size); } } } } void B2gcInitCtx (MpmCtx *mpm_ctx, int module_handle) { SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); if (mpm_ctx->ctx != NULL) return; //BUG_ON(mpm_ctx->ctx != NULL); mpm_ctx->ctx = SCMalloc(sizeof(B2gcCtx)); if (mpm_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_ctx->ctx, 0, sizeof(B2gcCtx)); mpm_ctx->memory_cnt++; mpm_ctx->memory_size += sizeof(B2gcCtx); /* Initialize the defaults value from the config file. The given check make sure that we query config file only once for config values */ if (b2gc_hash_size == 0) B2gcGetConfig(); /* initialize the hash we use to speed up pattern insertions */ B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; ctx->b2gc_init_hash = HashListTableInit(4096, B2gcHashPatternInitHash, B2gcHashPatternCompare, NULL); if (ctx->b2gc_init_hash == NULL) { exit(EXIT_FAILURE); } /* init defaults search functions */ ctx->Search = b2g_func; SCReturn; } void B2gcDestroyCtx(MpmCtx *mpm_ctx) { SCLogDebug("mpm_ctx %p", mpm_ctx); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; if (ctx == NULL) return; if (ctx->b2gc_init_hash != NULL) { HashListTableFree(ctx->b2gc_init_hash); } if (ctx->B2GC != NULL) { SCFree(ctx->B2GC); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(B2GC_TYPE) * ctx->hash_size); } if (ctx->ha != NULL) { SCFree(ctx->ha); } if (ctx->ha1 != NULL) { SCFree(ctx->ha1); } if (ctx->patterns != NULL) { SCFree(ctx->patterns); } if (ctx->patterns1 != NULL) { SCFree(ctx->patterns1); } if (ctx->bloom) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { if (ctx->bloom[h] == NULL) continue; mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); BloomFilterFree(ctx->bloom[h]); } SCFree(ctx->bloom); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); } if (ctx->pminlen) { SCFree(ctx->pminlen); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gcCtx); } void B2gcThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); if (sizeof(B2gcThreadCtx) > 0) { /* size can be null when optimized */ mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gcThreadCtx)); if (mpm_thread_ctx->ctx == NULL) { exit(EXIT_FAILURE); } memset(mpm_thread_ctx->ctx, 0, sizeof(B2gcThreadCtx)); mpm_thread_ctx->memory_cnt++; mpm_thread_ctx->memory_size += sizeof(B2gcThreadCtx); } } void B2gcThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { B2gcThreadCtx *ctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; B2gcPrintSearchStats(mpm_thread_ctx); if (ctx != NULL) { /* can be NULL if B2gcThreadCtx is optimized to 0 */ mpm_thread_ctx->memory_cnt--; mpm_thread_ctx->memory_size -= sizeof(B2gcThreadCtx); SCFree(mpm_thread_ctx->ctx); } } uint32_t B2gcSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; } uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; #ifdef B2GC_COUNTERS B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = ctx->m - B2GC_Q + 1, matches = 0; B2GC_TYPE d; //printf("\n"); //PrintRawDataFp(stdout, buf, buflen); SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32, buflen, ctx->m, pos); COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (uint32_t)(buflen - B2GC_Q + 1)) { //uint16_t h = B2GC_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); uint16_t h = B2GC_HASH16(buf[pos - 1], buf[pos]); d = ctx->B2GC[h]; if (d != 0) { COUNT(tctx->stat_d0++); uint32_t j = pos; uint32_t first = pos - (ctx->m - B2GC_Q + 1); do { j = j - 1; if (d >= (uint32_t)(1 << (ctx->m - 1))) { if (j > first) pos = j; else { /* get our patterns from the hash */ h = B2GC_HASH16(buf[j + ctx->m - 2], buf[j + ctx->m - 1]); if (ctx->pminlen[h] > 0 && (buflen - j) >= ctx->pminlen[h] && BloomFilterTest(ctx->bloom[h], buf+pos-1, ctx->pminlen[h]) == 1) { uint32_t offset = ctx->ha[h]; SCLogDebug("offset %u, hash %u", offset, h); do { B2gcPatternHdr *hdr = (B2gcPatternHdr *)&ctx->patterns[offset]; //BUG_ON(hdr->len <= 1); offset += hdr->np_offset; SCLogDebug("next offset %u", offset); if (hdr->len <= (buflen - j)) { if (hdr->flags & B2GC_FLAG_NOCASE) { uint8_t *pattern = (uint8_t *)hdr + sizeof(B2gcPatternHdr); //uint8_t *pattern = (uint8_t *)hdr + hdr->nc_offset; SCLogDebug("nocase compare"); #ifdef PRINTMATCH prt(pattern, hdr->len);printf("\n"); prt(buf+pos-1, hdr->len);printf("\n"); #endif if (SCMemcmpLowercase(pattern, buf+pos-1, hdr->len) == 0) { matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); } } else { uint8_t *pattern = (uint8_t *)hdr + sizeof(B2gcPatternHdr); SCLogDebug("case sensitive compare"); #ifdef PRINTMATCH prt(pattern, hdr->len);printf("\n"); prt(buf+pos-1, hdr->len);printf("\n"); #endif if (SCMemcmp(pattern, buf+pos-1, hdr->len) == 0) { matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); } } } if (hdr->flags & B2GC_FLAG_FINAL) { SCLogDebug("final flag set, done matching"); break; } } while(1); } } } if (j == 0) { break; } h = B2GC_HASH16(buf[j - 1], buf[j]); d = (d << 1) & ctx->B2GC[h]; } while (d != 0); } COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (ctx->m - B2GC_Q + 1)); pos = pos + ctx->m - B2GC_Q + 1; SCLogDebug("pos %"PRIu32"", pos); } SCLogDebug("matches %"PRIu32"", matches); return matches; } uint32_t B2gcSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; #ifdef B2GC_COUNTERS B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; #endif uint32_t pos = 0, matches = 0; B2GC_TYPE d; uint32_t j; COUNT(tctx->stat_calls++); COUNT(tctx->stat_m_total+=ctx->m); if (buflen < ctx->m) return 0; while (pos <= (buflen - ctx->m)) { j = ctx->m - 1; d = ~0; do { uint16_t h = B2GC_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); d = ((d << 1) & ctx->B2GC[h]); j = j - 1; } while (d != 0 && j != 0); /* (partial) match, move on to verification */ if (d != 0) { COUNT(tctx->stat_d0++); //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); #if 0 /* get our patterns from the hash */ uint16_t h = B2GC_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); B2gcPattern *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->next) { COUNT(tctx->stat_d0_hashloop++); //B2gcPattern *p = ctx->parray[thi->idx]; if (buflen - pos < thi->len) continue; if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { if (memcmp_lowercase(thi->ci, buf+pos, thi->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } else { if (memcmp(thi->cs, buf+pos, thi->len) == 0) { COUNT(tctx->stat_loop_match++); matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); } else { COUNT(tctx->stat_loop_no_match++); } } } skip_loop: //pos = pos + ctx->s0; pos = pos + 1; #endif } else { COUNT(tctx->stat_num_shift++); COUNT(tctx->stat_total_shift += (j + 1)); pos = pos + j + 1; } } //printf("Total matches %" PRIu32 "\n", matches); return matches; } uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { SCEnter(); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; if (buflen == 0) SCReturnUInt(0); //printf("BUF "); prt(buf,buflen); printf("\n"); while (buf <= bufend) { uint8_t h = u8_tolower(*buf); uint16_t offset = ctx->ha1[h]; SCLogDebug("offset %u, h %02X, buf %02X", offset, h, *buf); if (offset > 0) { do { B2gcPattern1 *hdr = (B2gcPattern1 *)&ctx->patterns1[offset]; offset += (sizeof(B2gcPattern1)); SCLogDebug("hdr flags %02x, id %u, pat %02X", hdr->flags, hdr->id, hdr->pat); if (hdr->flags & B2GC_FLAG_NOCASE) { SCLogDebug("nocase compare, %02X", *buf); cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); } else { SCLogDebug("case sensitive compare, %02X", *buf); if (*buf == hdr->pat) { cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); } } if (hdr->flags & B2GC_FLAG_FINAL) break; } while(1); } buf += 1; } //printf("B2gcSearch1: after 1byte cnt %" PRIu32 "\n", cnt); if (ctx->pat_x_cnt) { cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); } SCReturnUInt(cnt); } /* * TESTS */ #ifdef UNITTESTS static int B2gcTestMacro01 (void) { int result = 1; B2gcPatternHdr a; B2gcPatternHdr *b = &a; memset(&a, 0xff, sizeof(a)); printf("ID %u\n", B2GC_GET_ID(b)); printf("FLAGS %u\n", B2GC_GET_FLAGS(b)); printf("LEN %u\n", B2GC_GET_LEN(b)); return result; } static int B2gcTestInit01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); if (ctx->m == 4) result = 1; else printf("4 != %" PRIu32 " ", ctx->m); B2gcDestroyCtx(&mpm_ctx); return result; } #if 0 static int B2gcTestS0Init01 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); if (ctx->s0 == 4) result = 1; else printf("4 != %" PRIu32 " ", ctx->s0); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestS0Init02 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); if (ctx->s0 == 2) result = 1; else printf("2 != %" PRIu32 " ", ctx->s0); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestS0Init03 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); if (ctx->s0 == 1) result = 1; else printf("1 != %" PRIu32 " ", ctx->s0); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestS0Init04 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); if (ctx->s0 == 2) result = 1; else printf("2 != %" PRIu32 " ", ctx->s0); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestS0Init05 (void) { int result = 0; MpmCtx mpm_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); if (ctx->s0 == 3) result = 1; else printf("3 != %" PRIu32 " ", ctx->s0); B2gcDestroyCtx(&mpm_ctx); return result; } #endif static int B2gcTestSearch01 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch02 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch03 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } /* test patterns longer than 'm'. M is 4 here. */ static int B2gcTestSearch04 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } /* case insensitive test patterns longer than 'm'. M is 4 here. */ static int B2gcTestSearch05 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 3) result = 1; else printf("3 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch05a (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 5) result = 1; else printf("5 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch05b (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 2, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 3, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 4, 0, 0); /* 1 match */ B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abXD", 4, 0, 0, 5, 0, 0); /* 0 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); if (cnt == 5) result = 1; else printf("5 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch05c (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch05d (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 1, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ABCD", 4); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch06 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch06a (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch07 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ /* total matches: 135 */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); uint32_t cnt; int i; for (i = 0; i<100000;i++) cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; else printf("135 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch07a (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 6 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 30) result = 1; else printf("30 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch08 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); if (cnt == 0) result = 1; else printf("0 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch09 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch10 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); char *buf = "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "abcdefgh" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789"; uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch11 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch12 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); if (cnt == 2) result = 1; else printf("2 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch13 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch14 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch15 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch16 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch17 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch18 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch19 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch20 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ //B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } static int B2gcTestSearch21 (void) { int result = 0; MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); if (cnt == 1) result = 1; else printf("1 != %" PRIu32 " ",cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); return result; } #endif /* UNITTESTS */ #if 0 static int B2gcTestSearchXX (void) { MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); MpmThreadCtx mpm_thread_ctx; MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; FILE *fp = fopen("/usr/share/dict/words", "r"); if (fp == NULL) exit(1); char *word; char line[128]; int w = 0; int w_max = 4000; while((word = fgets(line, sizeof(line), fp)) != NULL) { word[strlen(word) - 1] = '\0'; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); w++; if (w_max == w) break; } B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "we're adding a lot more text lines etc." "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; uint32_t len = strlen(text) - 1; int i; uint32_t cnt; for (i = 0; i < 100; i++) { cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); } printf("cnt %u ", cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); fclose(fp); return 1; } #endif void B2gcRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("B2gcTestMacro01", B2gcTestMacro01, 1); UtRegisterTest("B2gcTestInit01", B2gcTestInit01, 1); /* UtRegisterTest("B2gcTestS0Init01", B2gcTestS0Init01, 1); UtRegisterTest("B2gcTestS0Init02", B2gcTestS0Init02, 1); UtRegisterTest("B2gcTestS0Init03", B2gcTestS0Init03, 1); UtRegisterTest("B2gcTestS0Init04", B2gcTestS0Init04, 1); UtRegisterTest("B2gcTestS0Init05", B2gcTestS0Init05, 1); */ UtRegisterTest("B2gcTestSearch01", B2gcTestSearch01, 1); UtRegisterTest("B2gcTestSearch02", B2gcTestSearch02, 1); UtRegisterTest("B2gcTestSearch03", B2gcTestSearch03, 1); UtRegisterTest("B2gcTestSearch04", B2gcTestSearch04, 1); UtRegisterTest("B2gcTestSearch05", B2gcTestSearch05, 1); UtRegisterTest("B2gcTestSearch05a", B2gcTestSearch05a, 1); UtRegisterTest("B2gcTestSearch05b", B2gcTestSearch05b, 1); UtRegisterTest("B2gcTestSearch05c", B2gcTestSearch05c, 1); UtRegisterTest("B2gcTestSearch05d", B2gcTestSearch05d, 1); UtRegisterTest("B2gcTestSearch06", B2gcTestSearch06, 1); UtRegisterTest("B2gcTestSearch06a", B2gcTestSearch06a, 1); UtRegisterTest("B2gcTestSearch07", B2gcTestSearch07, 1); UtRegisterTest("B2gcTestSearch07a", B2gcTestSearch07a, 1); UtRegisterTest("B2gcTestSearch08", B2gcTestSearch08, 1); UtRegisterTest("B2gcTestSearch09", B2gcTestSearch09, 1); UtRegisterTest("B2gcTestSearch10", B2gcTestSearch10, 1); UtRegisterTest("B2gcTestSearch11", B2gcTestSearch11, 1); UtRegisterTest("B2gcTestSearch12", B2gcTestSearch12, 1); UtRegisterTest("B2gcTestSearch13", B2gcTestSearch13, 1); UtRegisterTest("B2gcTestSearch14", B2gcTestSearch14, 1); UtRegisterTest("B2gcTestSearch15", B2gcTestSearch15, 1); UtRegisterTest("B2gcTestSearch16", B2gcTestSearch16, 1); UtRegisterTest("B2gcTestSearch17", B2gcTestSearch17, 1); UtRegisterTest("B2gcTestSearch18", B2gcTestSearch18, 1); UtRegisterTest("B2gcTestSearch19", B2gcTestSearch19, 1); UtRegisterTest("B2gcTestSearch20", B2gcTestSearch20, 1); UtRegisterTest("B2gcTestSearch21", B2gcTestSearch21, 1); /* UtRegisterTest("B2gcTestSearchXX", B2gcTestSearchXX, 1); */ #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-ssh-proto-version.c0000644000000000000000000004612112253546156016064 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * * Implements the ssh.protoversion keyword * You can specify a concrete version like ssh.protoversion: 1.66 * or search for protoversion 2 compat (1.99 is considered as 2) like * ssh.protoversion:2_compat * or just the beginning of the string like ssh.protoversion:"1." */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-ssh.h" #include "detect-ssh-proto-version.h" #include "stream-tcp.h" /** * \brief Regex for parsing the protoversion string */ #define PARSE_REGEX "^\\s*\"?\\s*([0-9]+([\\.\\-0-9]+)?|2_compat)\\s*\"?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectSshVersionSetup (DetectEngineCtx *, Signature *, char *); void DetectSshVersionRegisterTests(void); void DetectSshVersionFree(void *); /** * \brief Registration function for keyword: ssh.protoversion */ void DetectSshVersionRegister(void) { sigmatch_table[DETECT_AL_SSH_PROTOVERSION].name = "ssh.protoversion"; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Match = NULL; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerMatch = DetectSshVersionMatch; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].alproto = ALPROTO_SSH; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests; const char *eb; int eo; int opts = 0; SCLogDebug("registering ssh.protoversion rule option"); parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief match the specified version on a ssh session * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectSshVersionData * * \retval 0 no match * \retval 1 match */ int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); DetectSshVersionData *ssh = (DetectSshVersionData *)m->ctx; SshState *ssh_state = (SshState *)state; if (ssh_state == NULL) { SCLogDebug("no ssh state, no match"); SCReturnInt(0); } int ret = 0; FLOWLOCK_RDLOCK(f); if ((flags & STREAM_TOCLIENT) && (ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) { SCLogDebug("looking for ssh server protoversion 2 compat"); if (strncmp((char *) ssh_state->server_proto_version, "2", 1) == 0 || strncmp((char *) ssh_state->server_proto_version, "2.", 2) == 0 || strncmp((char *) ssh_state->server_proto_version, "1.99", 4) == 0) ret = 1; } else { SCLogDebug("looking for ssh server protoversion %s length %"PRIu16"", ssh->ver, ssh->len); ret = (strncmp((char *) ssh_state->server_proto_version, (char *) ssh->ver, ssh->len) == 0)? 1 : 0; } } else if ((flags & STREAM_TOSERVER) && (ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) { SCLogDebug("looking for client ssh client protoversion 2 compat"); if (strncmp((char *) ssh_state->client_proto_version, "2", 1) == 0 || strncmp((char *) ssh_state->client_proto_version, "2.", 2) == 0 || strncmp((char *) ssh_state->client_proto_version, "1.99", 4) == 0) ret = 1; } else { SCLogDebug("looking for ssh client protoversion %s length %"PRIu16"", ssh->ver, ssh->len); ret = (strncmp((char *) ssh_state->client_proto_version, (char *) ssh->ver, ssh->len) == 0)? 1 : 0; } } FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" * * \param idstr Pointer to the user provided id option * * \retval id_d pointer to DetectSshVersionData on success * \retval NULL on failure */ DetectSshVersionData *DetectSshVersionParse (char *str) { DetectSshVersionData *ssh = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 3) { SCLogError(SC_ERR_PCRE_MATCH, "invalid ssh.protoversion option"); goto error; } if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* We have a correct id option */ ssh = SCMalloc(sizeof(DetectSshVersionData)); if (unlikely(ssh == NULL)) goto error; memset(ssh, 0x00, sizeof(DetectSshVersionData)); /* If we expect a protocol version 2 or 1.99 (considered 2, we * will compare it with both strings) */ if (strcmp("2_compat", str_ptr) == 0) { ssh->flags |= SSH_FLAG_PROTOVERSION_2_COMPAT; SCLogDebug("will look for ssh protocol version 2 (2, 2.0, 1.99 that's considered as 2"); return ssh; } ssh->ver = (uint8_t *)SCStrdup((char*)str_ptr); if (ssh->ver == NULL) { goto error; } ssh->len = strlen((char *) ssh->ver); SCLogDebug("will look for ssh %s", ssh->ver); } return ssh; error: if (ssh != NULL) DetectSshVersionFree(ssh); return NULL; } /** * \brief this function is used to add the parsed "id" option * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param idstr pointer to the user provided "id" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectSshVersionData *ssh = NULL; SigMatch *sm = NULL; ssh = DetectSshVersionParse(str); if (ssh == 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_AL_SSH_PROTOVERSION; sm->ctx = (void *)ssh; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_SSH; return 0; error: if (ssh != NULL) DetectSshVersionFree(ssh); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectSshVersionData * * \param id_d pointer to DetectSshVersionData */ void DetectSshVersionFree(void *ptr) { DetectSshVersionData *id_d = (DetectSshVersionData *)ptr; SCFree(id_d); } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectSshVersionTestParse01 is a test to make sure that we parse * a proto version correctly */ int DetectSshVersionTestParse01 (void) { DetectSshVersionData *ssh = NULL; ssh = DetectSshVersionParse("1.0"); if (ssh != NULL && strncmp((char *) ssh->ver, "1.0", 3) == 0) { DetectSshVersionFree(ssh); return 1; } return 0; } /** * \test DetectSshVersionTestParse02 is a test to make sure that we parse * the proto version (compatible with proto version 2) correctly */ int DetectSshVersionTestParse02 (void) { DetectSshVersionData *ssh = NULL; ssh = DetectSshVersionParse("2_compat"); if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) { DetectSshVersionFree(ssh); return 1; } return 0; } /** * \test DetectSshVersionTestParse03 is a test to make sure that we * don't return a ssh_data with an invalid value specified */ int DetectSshVersionTestParse03 (void) { DetectSshVersionData *ssh = NULL; ssh = DetectSshVersionParse("2_com"); if (ssh != NULL) { DetectSshVersionFree(ssh); return 0; } ssh = DetectSshVersionParse(""); if (ssh != NULL) { DetectSshVersionFree(ssh); return 0; } ssh = DetectSshVersionParse(".1"); if (ssh != NULL) { DetectSshVersionFree(ssh); return 0; } ssh = DetectSshVersionParse("lalala"); if (ssh != NULL) { DetectSshVersionFree(ssh); return 0; } return 1; } #include "stream-tcp-reassemble.h" /** \test Send a get request in three chunks + more data. */ static int DetectSshVersionTestDetect01(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "SSH-1."; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "10-PuTTY_2.123" ; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = "\n"; uint32_t sshlen3 = sizeof(sshbuf3) - 1; uint8_t sshbuf4[] = "whatever..."; uint32_t sshlen4 = sizeof(sshbuf4) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:1.10; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ( !(PacketAlertCheck(p, 1))) { printf("Error, the sig should match: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Send a get request in three chunks + more data. */ static int DetectSshVersionTestDetect02(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "SSH-1."; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "99-PuTTY_2.123" ; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = "\n"; uint32_t sshlen3 = sizeof(sshbuf3) - 1; uint8_t sshbuf4[] = "whatever..."; uint32_t sshlen4 = sizeof(sshbuf4) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if ( !(PacketAlertCheck(p, 1))) { printf("Error, the sig should match: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** \test Send a get request in three chunks + more data. */ static int DetectSshVersionTestDetect03(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "SSH-1."; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "7-PuTTY_2.123" ; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = "\n"; uint32_t sshlen3 = sizeof(sshbuf3) - 1; uint8_t sshbuf4[] = "whatever..."; uint32_t sshlen4 = sizeof(sshbuf4) - 1; TcpSession ssn; Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("Error, 1.7 version is not 2 compat, so the sig should not match: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectSshVersion */ void DetectSshVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01, 1); UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02, 1); UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03, 1); UtRegisterTest("DetectSshVersionTestDetect01", DetectSshVersionTestDetect01, 1); UtRegisterTest("DetectSshVersionTestDetect02", DetectSshVersionTestDetect02, 1); UtRegisterTest("DetectSshVersionTestDetect03", DetectSshVersionTestDetect03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-threshold.h0000644000000000000000000000551012253546156014441 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DETECT_THRESHOLD_H__ #define __DETECT_THRESHOLD_H__ #include "decode-events.h" #include "decode-ipv4.h" #include "decode-tcp.h" #define TYPE_LIMIT 1 #define TYPE_BOTH 2 #define TYPE_THRESHOLD 3 #define TYPE_DETECTION 4 #define TYPE_RATE 5 #define TYPE_SUPPRESS 6 #define TRACK_DST 1 #define TRACK_SRC 2 #define TRACK_RULE 3 /* Get the new action to take */ #define TH_ACTION_ALERT 0x01 #define TH_ACTION_DROP 0x02 #define TH_ACTION_PASS 0x04 #define TH_ACTION_LOG 0x08 #define TH_ACTION_SDROP 0x10 #define TH_ACTION_REJECT 0x20 /** * \typedef DetectThresholdData * A typedef for DetectThresholdData_ */ typedef struct DetectThresholdData_ { uint32_t count; /**< Event count */ uint32_t seconds; /**< Event seconds */ uint8_t type; /**< Threshold type : limit , threshold, both, detection_filter */ uint8_t track; /**< Track type: by_src, by_dst */ uint8_t new_action; /**< new_action alert|drop|pass|log|sdrop|reject */ uint32_t timeout; /**< timeout */ uint32_t flags; /**< flags used to set option */ DetectAddress* addr; /**< address group used by suppress keyword */ } DetectThresholdData; typedef struct DetectThresholdEntry_ { uint32_t sid; /**< Signature id */ uint32_t gid; /**< Signature group id */ uint32_t tv_timeout; /**< Timeout for new_action (for rate_filter) its not "seconds", that define the time interval */ uint32_t seconds; /**< Event seconds */ uint32_t tv_sec1; /**< Var for time control */ uint32_t tv_usec1; /**< Var for time control */ uint32_t current_count; /**< Var for count control */ int track; /**< Track type: by_src, by_src */ struct DetectThresholdEntry_ *next; } DetectThresholdEntry; /** * Registration function for threshold: keyword */ void DetectThresholdRegister (void); /** * This function registers unit tests for Threshold */ void ThresholdRegisterTests(void); #endif /*__DETECT_THRESHOLD_H__ */ suricata-1.4.7/src/defrag.c0000644000000000000000000015612112253546156012427 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited, Jason Ish * * Defragmentation module. * References: * - RFC 815 * - OpenBSD PF's IP normalizaton (pf_norm.c) * * \todo pool for frag packet storage * \todo policy bsd-right * \todo profile hash function * \todo log anomalies */ #include "suricata-common.h" #include "queue.h" #include "suricata.h" #include "threads.h" #include "conf.h" #include "decode-ipv6.h" #include "util-hashlist.h" #include "util-pool.h" #include "util-time.h" #include "util-print.h" #include "util-debug.h" #include "util-fix_checksum.h" #include "util-random.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "util-host-os-info.h" #include "defrag.h" #include "defrag-hash.h" #include "defrag-queue.h" #ifdef UNITTESTS #include "util-unittest.h" #endif #define DEFAULT_DEFRAG_HASH_SIZE 0xffff #define DEFAULT_DEFRAG_POOL_SIZE 0xffff /** * Default timeout (in seconds) before a defragmentation tracker will * be released. */ #define TIMEOUT_DEFAULT 60 /** * Maximum allowed timeout, 24 hours. */ #define TIMEOUT_MAX (60 * 60 * 24) /** * Minimum allowed timeout, 1 second. */ #define TIMEOUT_MIN 1 /** Fragment reassembly policies. */ enum defrag_policies { DEFRAG_POLICY_FIRST = 1, DEFRAG_POLICY_LAST, DEFRAG_POLICY_BSD, DEFRAG_POLICY_BSD_RIGHT, DEFRAG_POLICY_LINUX, DEFRAG_POLICY_WINDOWS, DEFRAG_POLICY_SOLARIS, DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD, }; static int default_policy = DEFRAG_POLICY_BSD; /** The global DefragContext so all threads operate from the same * context. */ static DefragContext *defrag_context; /** * Utility/debugging function to dump the frags associated with a * tracker. Only enable when unit tests are enabled. */ #if 0 #ifdef UNITTESTS static void DumpFrags(DefragTracker *tracker) { Frag *frag; printf("Dumping frags for packet: ID=%d\n", tracker->id); TAILQ_FOREACH(frag, &tracker->frags, next) { printf("-> Frag: frag_offset=%d, frag_len=%d, data_len=%d, ltrim=%d, skip=%d\n", frag->offset, frag->len, frag->data_len, frag->ltrim, frag->skip); PrintRawDataFp(stdout, frag->pkt, frag->len); } } #endif /* UNITTESTS */ #endif /** * \brief Reset a frag for reuse in a pool. */ static void DefragFragReset(Frag *frag) { if (frag->pkt != NULL) SCFree(frag->pkt); memset(frag, 0, sizeof(*frag)); } /** * \brief Allocate a new frag for use in a pool. */ static int DefragFragInit(void *data, void *initdata) { Frag *frag = data; memset(frag, 0, sizeof(*frag)); return 1; } /** * \brief Free all frags associated with a tracker. */ void DefragTrackerFreeFrags(DefragTracker *tracker) { Frag *frag; /* Lock the frag pool as we'll be return items to it. */ SCMutexLock(&defrag_context->frag_pool_lock); while ((frag = TAILQ_FIRST(&tracker->frags)) != NULL) { TAILQ_REMOVE(&tracker->frags, frag, next); /* Don't SCFree the frag, just give it back to its pool. */ DefragFragReset(frag); PoolReturn(defrag_context->frag_pool, frag); } SCMutexUnlock(&defrag_context->frag_pool_lock); } /** * \brief Create a new DefragContext. * * \retval On success a return an initialized DefragContext, otherwise * NULL will be returned. */ static DefragContext * DefragContextNew(void) { DefragContext *dc; dc = SCCalloc(1, sizeof(*dc)); if (unlikely(dc == NULL)) return NULL; /* Initialize the pool of trackers. */ intmax_t tracker_pool_size; if (!ConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) { tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE; } /* Initialize the pool of frags. */ intmax_t frag_pool_size; if (!ConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0) { frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE; } intmax_t frag_pool_prealloc = frag_pool_size / 2; dc->frag_pool = PoolInit(frag_pool_size, frag_pool_prealloc, sizeof(Frag), NULL, DefragFragInit, dc, NULL, NULL); if (dc->frag_pool == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Defrag: Failed to initialize fragment pool."); exit(EXIT_FAILURE); } if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) { SCLogError(SC_ERR_MUTEX, "Defrag: Failed to initialize frag pool mutex."); exit(EXIT_FAILURE); } /* Set the default timeout. */ intmax_t timeout; if (!ConfGetInt("defrag.timeout", &timeout)) { dc->timeout = TIMEOUT_DEFAULT; } else { if (timeout < TIMEOUT_MIN) { SCLogError(SC_ERR_INVALID_ARGUMENT, "defrag: Timeout less than minimum allowed value."); exit(EXIT_FAILURE); } else if (timeout > TIMEOUT_MAX) { SCLogError(SC_ERR_INVALID_ARGUMENT, "defrag: Tiemout greater than maximum allowed value."); exit(EXIT_FAILURE); } dc->timeout = timeout; } SCLogDebug("Defrag Initialized:"); SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout); SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size); SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size); SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size); SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc); return dc; } static void DefragContextDestroy(DefragContext *dc) { if (dc == NULL) return; PoolFree(dc->frag_pool); SCFree(dc); } /** * Attempt to re-assemble a packet. * * \param tracker The defragmentation tracker to reassemble from. */ static Packet * Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) { Packet *rp = NULL; /* Should not be here unless we have seen the last fragment. */ if (!tracker->seen_last) return NULL; /* Check that we have all the data. Relies on the fact that * fragments are inserted if frag_offset order. */ Frag *frag; int len = 0; TAILQ_FOREACH(frag, &tracker->frags, next) { if (frag->skip) continue; if (frag == TAILQ_FIRST(&tracker->frags)) { if (frag->offset != 0) { goto done; } len = frag->data_len; } else { if (frag->offset > len) { /* This fragment starts after the end of the previous * fragment. We have a hole. */ goto done; } else { len += frag->data_len; } } } /* Allocate a Packet for the reassembled packet. On failure we * SCFree all the resources held by this tracker. */ rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_IPPROTO(p)); if (rp == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for " "fragmentation re-assembly, dumping fragments."); goto remove_tracker; } PKT_SET_SRC(rp, PKT_SRC_DEFRAG); rp->recursion_level = p->recursion_level; int fragmentable_offset = 0; int fragmentable_len = 0; int hlen = 0; int ip_hdr_offset = 0; TAILQ_FOREACH(frag, &tracker->frags, next) { SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64, frag, frag->data_len, frag->offset, frag->pcap_cnt); if (frag->skip) continue; if (frag->data_len - frag->ltrim <= 0) continue; if (frag->offset == 0) { if (PacketCopyData(rp, frag->pkt, frag->len) == -1) goto remove_tracker; hlen = frag->hlen; ip_hdr_offset = frag->ip_hdr_offset; /* This is the start of the fragmentable portion of the * first packet. All fragment offsets are relative to * this. */ fragmentable_offset = frag->ip_hdr_offset + frag->hlen; fragmentable_len = frag->data_len; } else { int pkt_end = fragmentable_offset + frag->offset + frag->data_len; if (pkt_end > (int)MAX_PAYLOAD_SIZE) { SCLogWarning(SC_ERR_REASSEMBLY, "Failed re-assemble " "fragmented packet, exceeds size of packet buffer."); goto remove_tracker; } if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, frag->pkt + frag->data_offset + frag->ltrim, frag->data_len - frag->ltrim) == -1) { goto remove_tracker; } if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; } } SCLogDebug("ip_hdr_offset %u, hlen %u, fragmentable_len %u", ip_hdr_offset, hlen, fragmentable_len); rp->ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset); int old = rp->ip4h->ip_len + rp->ip4h->ip_off; rp->ip4h->ip_len = htons(fragmentable_len + hlen); rp->ip4h->ip_off = 0; rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum, old, rp->ip4h->ip_len + rp->ip4h->ip_off); SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len); remove_tracker: /** \todo check locking */ tracker->remove = 1; DefragTrackerFreeFrags(tracker); done: return rp; } /** * Attempt to re-assemble a packet. * * \param tracker The defragmentation tracker to reassemble from. */ static Packet * Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) { Packet *rp = NULL; /* Should not be here unless we have seen the last fragment. */ if (!tracker->seen_last) return NULL; /* Check that we have all the data. Relies on the fact that * fragments are inserted if frag_offset order. */ Frag *frag; int len = 0; TAILQ_FOREACH(frag, &tracker->frags, next) { if (frag->skip) continue; if (frag == TAILQ_FIRST(&tracker->frags)) { if (frag->offset != 0) { goto done; } len = frag->data_len; } else { if (frag->offset > len) { /* This fragment starts after the end of the previous * fragment. We have a hole. */ goto done; } else { len += frag->data_len; } } } /* Allocate a Packet for the reassembled packet. On failure we * SCFree all the resources held by this tracker. */ rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h, IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0); if (rp == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for " "fragmentation re-assembly, dumping fragments."); goto remove_tracker; } PKT_SET_SRC(rp, PKT_SRC_DEFRAG); int fragmentable_offset = 0; int fragmentable_len = 0; int ip_hdr_offset = 0; uint8_t next_hdr = 0; TAILQ_FOREACH(frag, &tracker->frags, next) { if (frag->skip) continue; if (frag->data_len - frag->ltrim <= 0) continue; if (frag->offset == 0) { IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt + frag->frag_hdr_offset); next_hdr = frag_hdr->ip6fh_nxt; /* This is the first packet, we use this packets link and * IPv6 headers. We also copy in its data, but remove the * fragmentation header. */ if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1) goto remove_tracker; if (PacketCopyDataOffset(rp, frag->frag_hdr_offset, frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr), frag->data_len) == -1) goto remove_tracker; ip_hdr_offset = frag->ip_hdr_offset; /* This is the start of the fragmentable portion of the * first packet. All fragment offsets are relative to * this. */ fragmentable_offset = frag->frag_hdr_offset; fragmentable_len = frag->data_len; } else { if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, frag->pkt + frag->data_offset + frag->ltrim, frag->data_len - frag->ltrim) == -1) goto remove_tracker; if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; } } rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset); rp->ip6h->s_ip6_plen = htons(fragmentable_len); rp->ip6h->s_ip6_nxt = next_hdr; SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) + fragmentable_len); remove_tracker: /** \todo check locking */ tracker->remove = 1; DefragTrackerFreeFrags(tracker); done: return rp; } /** * Insert a new IPv4/IPv6 fragment into a tracker. * * \todo Allocate packet buffers from a pool. */ static Packet * DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p) { Packet *r = NULL; int ltrim = 0; uint8_t more_frags; uint16_t frag_offset; /* IPv4 header length - IPv4 only. */ uint16_t hlen = 0; /* This is the offset of the start of the data in the packet that * falls after the IP header. */ uint16_t data_offset; /* The length of the (fragmented) data. This is the length of the * data that falls after the IP header. */ uint16_t data_len; /* Where the fragment ends. */ uint16_t frag_end; /* Offset in the packet to the IPv6 header. */ uint16_t ip_hdr_offset; /* Offset in the packet to the IPv6 frag header. IPv6 only. */ uint16_t frag_hdr_offset = 0; /* Address family */ int af = tracker->af; #ifdef DEBUG uint64_t pcap_cnt = p->pcap_cnt; #endif if (tracker->af == AF_INET) { more_frags = IPV4_GET_MF(p); frag_offset = IPV4_GET_IPOFFSET(p) << 3; hlen = IPV4_GET_HLEN(p); data_offset = (uint8_t *)p->ip4h + hlen - GET_PKT_DATA(p); data_len = IPV4_GET_IPLEN(p) - hlen; frag_end = frag_offset + data_len; ip_hdr_offset = (uint8_t *)p->ip4h - GET_PKT_DATA(p); /* Ignore fragment if the end of packet extends past the * maximum size of a packet. */ if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) { ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE); return NULL; } } else if (tracker->af == AF_INET6) { more_frags = IPV6_EXTHDR_GET_FH_FLAG(p); frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p); data_offset = (uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr) - GET_PKT_DATA(p); data_len = IPV6_GET_PLEN(p) - ( ((uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr)) - ((uint8_t *)p->ip6h + sizeof(IPV6Hdr))); frag_end = frag_offset + data_len; ip_hdr_offset = (uint8_t *)p->ip6h - GET_PKT_DATA(p); frag_hdr_offset = (uint8_t *)p->ip6eh.ip6fh - GET_PKT_DATA(p); /* Ignore fragment if the end of packet extends past the * maximum size of a packet. */ if (frag_offset + data_len > IPV6_MAXPACKET) { ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE); return NULL; } } else { /* Abort - should not happen. */ SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid address family, aborting."); return NULL; } /* Update timeout. */ tracker->timeout = p->ts.tv_sec + defrag_context->timeout; Frag *prev = NULL, *next; int overlap = 0; if (!TAILQ_EMPTY(&tracker->frags)) { TAILQ_FOREACH(prev, &tracker->frags, next) { ltrim = 0; next = TAILQ_NEXT(prev, next); switch (tracker->policy) { case DEFRAG_POLICY_BSD: if (frag_offset < prev->offset + prev->data_len) { if (frag_offset >= prev->offset) { ltrim = prev->offset + prev->data_len - frag_offset; overlap++; } if ((next != NULL) && (frag_end > next->offset)) { next->ltrim = frag_end - next->offset; overlap++; } if ((frag_offset < prev->offset) && (frag_end >= prev->offset + prev->data_len)) { prev->skip = 1; overlap++; } goto insert; } break; case DEFRAG_POLICY_LINUX: if (frag_offset < prev->offset + prev->data_len) { if (frag_offset > prev->offset) { ltrim = prev->offset + prev->data_len - frag_offset; overlap++; } if ((next != NULL) && (frag_end > next->offset)) { next->ltrim = frag_end - next->offset; overlap++; } if ((frag_offset < prev->offset) && (frag_end >= prev->offset + prev->data_len)) { prev->skip = 1; overlap++; } goto insert; } break; case DEFRAG_POLICY_WINDOWS: if (frag_offset < prev->offset + prev->data_len) { if (frag_offset >= prev->offset) { ltrim = prev->offset + prev->data_len - frag_offset; overlap++; } if ((frag_offset < prev->offset) && (frag_end > prev->offset + prev->data_len)) { prev->skip = 1; overlap++; } goto insert; } break; case DEFRAG_POLICY_SOLARIS: if (frag_offset < prev->offset + prev->data_len) { if (frag_offset >= prev->offset) { ltrim = prev->offset + prev->data_len - frag_offset; overlap++; } if ((frag_offset < prev->offset) && (frag_end >= prev->offset + prev->data_len)) { prev->skip = 1; overlap++; } goto insert; } break; case DEFRAG_POLICY_FIRST: if ((frag_offset >= prev->offset) && (frag_end <= prev->offset + prev->data_len)) { overlap++; goto done; } if (frag_offset < prev->offset) { goto insert; } if (frag_offset < prev->offset + prev->data_len) { ltrim = prev->offset + prev->data_len - frag_offset; overlap++; goto insert; } break; case DEFRAG_POLICY_LAST: if (frag_offset <= prev->offset) { if (frag_end > prev->offset) { prev->ltrim = frag_end - prev->offset; overlap++; } goto insert; } break; default: break; } } } insert: if (data_len - ltrim <= 0) { if (af == AF_INET) { ENGINE_SET_EVENT(p, IPV4_FRAG_TOO_LARGE); } else { ENGINE_SET_EVENT(p, IPV6_FRAG_TOO_LARGE); } goto done; } /* Allocate fragment and insert. */ SCMutexLock(&defrag_context->frag_pool_lock); Frag *new = PoolGet(defrag_context->frag_pool); SCMutexUnlock(&defrag_context->frag_pool_lock); if (new == NULL) { if (af == AF_INET) { ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED); } else { ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED); } goto done; } new->pkt = SCMalloc(GET_PKT_LEN(p)); if (new->pkt == NULL) { SCMutexLock(&defrag_context->frag_pool_lock); PoolReturn(defrag_context->frag_pool, new); SCMutexUnlock(&defrag_context->frag_pool_lock); if (af == AF_INET) { ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED); } else { ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED); } goto done; } memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim); new->len = GET_PKT_LEN(p) - ltrim; new->hlen = hlen; new->offset = frag_offset + ltrim; new->data_offset = data_offset; new->data_len = data_len - ltrim; new->ip_hdr_offset = ip_hdr_offset; new->frag_hdr_offset = frag_hdr_offset; #ifdef DEBUG new->pcap_cnt = pcap_cnt; #endif Frag *frag; TAILQ_FOREACH(frag, &tracker->frags, next) { if (frag_offset < frag->offset) break; } if (frag == NULL) { TAILQ_INSERT_TAIL(&tracker->frags, new, next); } else { TAILQ_INSERT_BEFORE(frag, new, next); } if (!more_frags) { tracker->seen_last = 1; } if (tracker->seen_last) { if (tracker->af == AF_INET) { r = Defrag4Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { SCPerfCounterIncr(dtv->counter_defrag_ipv4_reassembled, tv->sc_perf_pca); } } else if (tracker->af == AF_INET6) { r = Defrag6Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { SCPerfCounterIncr(dtv->counter_defrag_ipv6_reassembled, tv->sc_perf_pca); } } } done: if (overlap) { if (af == AF_INET) { ENGINE_SET_EVENT(p, IPV4_FRAG_OVERLAP); } else { ENGINE_SET_EVENT(p, IPV6_FRAG_OVERLAP); } } return r; } /** * \brief Get the defrag policy based on the destination address of * the packet. * * \param p The packet used to get the destination address. * * \retval The defrag policy to use. */ uint8_t DefragGetOsPolicy(Packet *p) { int policy = -1; if (PKT_IS_IPV4(p)) { policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p)); } else if (PKT_IS_IPV6(p)) { policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p)); } if (policy == -1) { return default_policy; } /* Map the OS policies returned from the configured host info to * defrag specific policies. */ switch (policy) { /* BSD. */ case OS_POLICY_BSD: case OS_POLICY_HPUX10: case OS_POLICY_IRIX: return DEFRAG_POLICY_BSD; /* BSD-Right. */ case OS_POLICY_BSD_RIGHT: return DEFRAG_POLICY_BSD_RIGHT; /* Linux. */ case OS_POLICY_OLD_LINUX: case OS_POLICY_LINUX: return DEFRAG_POLICY_LINUX; /* First. */ case OS_POLICY_OLD_SOLARIS: case OS_POLICY_HPUX11: case OS_POLICY_MACOS: case OS_POLICY_FIRST: return DEFRAG_POLICY_FIRST; /* Solaris. */ case OS_POLICY_SOLARIS: return DEFRAG_POLICY_SOLARIS; /* Windows. */ case OS_POLICY_WINDOWS: case OS_POLICY_VISTA: case OS_POLICY_WINDOWS2K3: return DEFRAG_POLICY_WINDOWS; /* Last. */ case OS_POLICY_LAST: return DEFRAG_POLICY_LAST; default: return default_policy; } } /** \internal * * \retval NULL or a *LOCKED* tracker */ static DefragTracker * DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { return DefragGetTrackerFromHash(p); } /** * \brief Entry point for IPv4 and IPv6 fragments. * * \param tv ThreadVars for the calling decoder. * \param p The packet fragment. * * \retval A new Packet resembling the re-assembled packet if the most * recent fragment allowed the packet to be re-assembled, otherwise * NULL is returned. */ Packet * Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { uint16_t frag_offset; uint8_t more_frags; DefragTracker *tracker; int af; if (PKT_IS_IPV4(p)) { af = AF_INET; more_frags = IPV4_GET_MF(p); frag_offset = IPV4_GET_IPOFFSET(p); } else if (PKT_IS_IPV6(p)) { af = AF_INET6; frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p); more_frags = IPV6_EXTHDR_GET_FH_FLAG(p); } else { return NULL; } if (frag_offset == 0 && more_frags == 0) { return NULL; } if (tv != NULL && dtv != NULL) { if (af == AF_INET) { SCPerfCounterIncr(dtv->counter_defrag_ipv4_fragments, tv->sc_perf_pca); } else if (af == AF_INET6) { SCPerfCounterIncr(dtv->counter_defrag_ipv6_fragments, tv->sc_perf_pca); } } /* return a locked tracker or NULL */ tracker = DefragGetTracker(tv, dtv, p); if (tracker == NULL) return NULL; Packet *rp = DefragInsertFrag(tv, dtv, tracker, p); DefragTrackerRelease(tracker); return rp; } void DefragInit(void) { intmax_t tracker_pool_size; if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) { tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE; } /* Allocate the DefragContext. */ defrag_context = DefragContextNew(); if (defrag_context == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for the Defrag module."); exit(EXIT_FAILURE); } DefragInitConfig(FALSE); } void DefragDestroy(void) { DefragHashShutdown(); DefragContextDestroy(defrag_context); defrag_context = NULL; } #ifdef UNITTESTS #define IP_MF 0x2000 /** * Allocate a test packet. Nothing to fancy, just a simple IP packet * with some payload of no particular protocol. */ static Packet * BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, int content_len) { Packet *p = NULL; int hlen = 20; int ttl = 64; uint8_t *pcontent; IPV4Hdr ip4h; p = SCCalloc(1, sizeof(*p) + default_packet_size); if (unlikely(p == NULL)) return NULL; PACKET_INITIALIZE(p); gettimeofday(&p->ts, NULL); //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); ip4h.ip_verhl = 4 << 4; ip4h.ip_verhl |= hlen >> 2; ip4h.ip_len = htons(hlen + content_len); ip4h.ip_id = htons(id); ip4h.ip_off = htons(off); if (mf) ip4h.ip_off = htons(IP_MF | off); else ip4h.ip_off = htons(off); ip4h.ip_ttl = ttl; ip4h.ip_proto = IPPROTO_ICMP; ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */ ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */ /* copy content_len crap, we need full length */ PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h)); p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); SET_IPV4_SRC_ADDR(p, &p->src); SET_IPV4_DST_ADDR(p, &p->dst); pcontent = SCCalloc(1, content_len); if (unlikely(pcontent == NULL)) return NULL; memset(pcontent, content, content_len); PacketCopyDataOffset(p, hlen, pcontent, content_len); SET_PKT_LEN(p, hlen + content_len); SCFree(pcontent); p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)GET_PKT_DATA(p), hlen); /* Self test. */ if (IPV4_GET_VER(p) != 4) goto error; if (IPV4_GET_HLEN(p) != hlen) goto error; if (IPV4_GET_IPLEN(p) != hlen + content_len) goto error; if (IPV4_GET_IPID(p) != id) goto error; if (IPV4_GET_IPOFFSET(p) != off) goto error; if (IPV4_GET_MF(p) != mf) goto error; if (IPV4_GET_IPTTL(p) != ttl) goto error; if (IPV4_GET_IPPROTO(p) != IPPROTO_ICMP) goto error; return p; error: if (p != NULL) SCFree(p); return NULL; } static Packet * IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, int content_len) { Packet *p = NULL; uint8_t *pcontent; IPV6Hdr ip6h; p = SCCalloc(1, sizeof(*p) + default_packet_size); if (unlikely(p == NULL)) return NULL; PACKET_INITIALIZE(p); gettimeofday(&p->ts, NULL); ip6h.s_ip6_nxt = 44; ip6h.s_ip6_hlim = 2; /* Source and dest address - very bogus addresses. */ ip6h.s_ip6_src[0] = 0x01010101; ip6h.s_ip6_src[1] = 0x01010101; ip6h.s_ip6_src[2] = 0x01010101; ip6h.s_ip6_src[3] = 0x01010101; ip6h.s_ip6_dst[0] = 0x02020202; ip6h.s_ip6_dst[1] = 0x02020202; ip6h.s_ip6_dst[2] = 0x02020202; ip6h.s_ip6_dst[3] = 0x02020202; /* copy content_len crap, we need full length */ PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr)); p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p); IPV6_SET_RAW_VER(p->ip6h, 6); /* Fragmentation header. */ p->ip6eh.ip6fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr)); p->ip6eh.ip6fh->ip6fh_nxt = IPPROTO_ICMP; p->ip6eh.ip6fh->ip6fh_ident = htonl(id); p->ip6eh.ip6fh->ip6fh_offlg = htons((off << 3) | mf); pcontent = SCCalloc(1, content_len); if (unlikely(pcontent == NULL)) return NULL; memset(pcontent, content, content_len); PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len); SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len); SCFree(pcontent); p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len); SET_IPV6_SRC_ADDR(p, &p->src); SET_IPV6_DST_ADDR(p, &p->dst); /* Self test. */ if (IPV6_GET_VER(p) != 6) goto error; if (IPV6_GET_NH(p) != 44) goto error; if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len) goto error; return p; error: fprintf(stderr, "Error building test packet.\n"); if (p != NULL) SCFree(p); return NULL; } /** * Test the simplest possible re-assembly scenario. All packet in * order and no overlaps. */ static int DefragInOrderSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; int ret = 0; DefragInit(); p1 = BuildTestPacket(id, 0, 1, 'A', 8); if (p1 == NULL) goto end; p2 = BuildTestPacket(id, 1, 1, 'B', 8); if (p2 == NULL) goto end; p3 = BuildTestPacket(id, 2, 0, 'C', 3); if (p3 == NULL) goto end; if (Defrag(NULL, NULL, p1) != NULL) goto end; if (Defrag(NULL, NULL, p2) != NULL) goto end; reassembled = Defrag(NULL, NULL, p3); if (reassembled == NULL) { goto end; } if (IPV4_GET_HLEN(reassembled) != 20) { goto end; } if (IPV4_GET_IPLEN(reassembled) != 39) { goto end; } /* 20 bytes in we should find 8 bytes of A. */ for (i = 20; i < 20 + 8; i++) { if (GET_PKT_DATA(reassembled)[i] != 'A') { goto end; } } /* 28 bytes in we should find 8 bytes of B. */ for (i = 28; i < 28 + 8; i++) { if (GET_PKT_DATA(reassembled)[i] != 'B') { goto end; } } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 36; i < 36 + 3; i++) { if (GET_PKT_DATA(reassembled)[i] != 'C') goto end; } ret = 1; end: if (p1 != NULL) SCFree(p1); if (p2 != NULL) SCFree(p2); if (p3 != NULL) SCFree(p3); if (reassembled != NULL) SCFree(reassembled); DefragDestroy(); return ret; } /** * Simple fragmented packet in reverse order. */ static int DefragReverseSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; int ret = 0; DefragInit(); p1 = BuildTestPacket(id, 0, 1, 'A', 8); if (p1 == NULL) goto end; p2 = BuildTestPacket(id, 1, 1, 'B', 8); if (p2 == NULL) goto end; p3 = BuildTestPacket(id, 2, 0, 'C', 3); if (p3 == NULL) goto end; if (Defrag(NULL, NULL, p3) != NULL) goto end; if (Defrag(NULL, NULL, p2) != NULL) goto end; reassembled = Defrag(NULL, NULL, p1); if (reassembled == NULL) goto end; if (IPV4_GET_HLEN(reassembled) != 20) goto end; if (IPV4_GET_IPLEN(reassembled) != 39) goto end; /* 20 bytes in we should find 8 bytes of A. */ for (i = 20; i < 20 + 8; i++) { if (GET_PKT_DATA(reassembled)[i] != 'A') goto end; } /* 28 bytes in we should find 8 bytes of B. */ for (i = 28; i < 28 + 8; i++) { if (GET_PKT_DATA(reassembled)[i] != 'B') goto end; } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 36; i < 36 + 3; i++) { if (GET_PKT_DATA(reassembled)[i] != 'C') goto end; } ret = 1; end: if (p1 != NULL) SCFree(p1); if (p2 != NULL) SCFree(p2); if (p3 != NULL) SCFree(p3); if (reassembled != NULL) SCFree(reassembled); DefragDestroy(); return ret; } /** * Test the simplest possible re-assembly scenario. All packet in * order and no overlaps. */ static int IPV6DefragInOrderSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; int ret = 0; DefragInit(); p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8); if (p1 == NULL) goto end; p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8); if (p2 == NULL) goto end; p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3); if (p3 == NULL) goto end; if (Defrag(NULL, NULL, p1) != NULL) goto end; if (Defrag(NULL, NULL, p2) != NULL) goto end; reassembled = Defrag(NULL, NULL, p3); if (reassembled == NULL) goto end; if (IPV6_GET_PLEN(reassembled) != 19) goto end; /* 40 bytes in we should find 8 bytes of A. */ for (i = 40; i < 40 + 8; i++) { if (GET_PKT_DATA(reassembled)[i] != 'A') goto end; } /* 28 bytes in we should find 8 bytes of B. */ for (i = 48; i < 48 + 8; i++) { if (GET_PKT_DATA(reassembled)[i] != 'B') goto end; } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 56; i < 56 + 3; i++) { if (GET_PKT_DATA(reassembled)[i] != 'C') goto end; } ret = 1; end: if (p1 != NULL) SCFree(p1); if (p2 != NULL) SCFree(p2); if (p3 != NULL) SCFree(p3); if (reassembled != NULL) SCFree(reassembled); DefragDestroy(); return ret; } static int IPV6DefragReverseSimpleTest(void) { DefragContext *dc = NULL; Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; int ret = 0; DefragInit(); dc = DefragContextNew(); if (dc == NULL) goto end; p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8); if (p1 == NULL) goto end; p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8); if (p2 == NULL) goto end; p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3); if (p3 == NULL) goto end; if (Defrag(NULL, NULL, p3) != NULL) goto end; if (Defrag(NULL, NULL, p2) != NULL) goto end; reassembled = Defrag(NULL, NULL, p1); if (reassembled == NULL) goto end; /* 40 bytes in we should find 8 bytes of A. */ for (i = 40; i < 40 + 8; i++) { if (GET_PKT_DATA(reassembled)[i] != 'A') goto end; } /* 28 bytes in we should find 8 bytes of B. */ for (i = 48; i < 48 + 8; i++) { if (GET_PKT_DATA(reassembled)[i] != 'B') goto end; } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 56; i < 56 + 3; i++) { if (GET_PKT_DATA(reassembled)[i] != 'C') goto end; } ret = 1; end: if (dc != NULL) DefragContextDestroy(dc); if (p1 != NULL) SCFree(p1); if (p2 != NULL) SCFree(p2); if (p3 != NULL) SCFree(p3); if (reassembled != NULL) SCFree(reassembled); DefragDestroy(); return ret; } static int DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) { int i; int ret = 0; DefragInit(); /* * Build the packets. */ int id = 1; Packet *packets[17]; memset(packets, 0x00, sizeof(packets)); /* * Original fragments. */ /* A*24 at 0. */ packets[0] = BuildTestPacket(id, 0, 1, 'A', 24); /* B*15 at 32. */ packets[1] = BuildTestPacket(id, 32 >> 3, 1, 'B', 16); /* C*24 at 48. */ packets[2] = BuildTestPacket(id, 48 >> 3, 1, 'C', 24); /* D*8 at 80. */ packets[3] = BuildTestPacket(id, 80 >> 3, 1, 'D', 8); /* E*16 at 104. */ packets[4] = BuildTestPacket(id, 104 >> 3, 1, 'E', 16); /* F*24 at 120. */ packets[5] = BuildTestPacket(id, 120 >> 3, 1, 'F', 24); /* G*16 at 144. */ packets[6] = BuildTestPacket(id, 144 >> 3, 1, 'G', 16); /* H*16 at 160. */ packets[7] = BuildTestPacket(id, 160 >> 3, 1, 'H', 16); /* I*8 at 176. */ packets[8] = BuildTestPacket(id, 176 >> 3, 1, 'I', 8); /* * Overlapping subsequent fragments. */ /* J*32 at 8. */ packets[9] = BuildTestPacket(id, 8 >> 3, 1, 'J', 32); /* K*24 at 48. */ packets[10] = BuildTestPacket(id, 48 >> 3, 1, 'K', 24); /* L*24 at 72. */ packets[11] = BuildTestPacket(id, 72 >> 3, 1, 'L', 24); /* M*24 at 96. */ packets[12] = BuildTestPacket(id, 96 >> 3, 1, 'M', 24); /* N*8 at 128. */ packets[13] = BuildTestPacket(id, 128 >> 3, 1, 'N', 8); /* O*8 at 152. */ packets[14] = BuildTestPacket(id, 152 >> 3, 1, 'O', 8); /* P*8 at 160. */ packets[15] = BuildTestPacket(id, 160 >> 3, 1, 'P', 8); /* Q*16 at 176. */ packets[16] = BuildTestPacket(id, 176 >> 3, 0, 'Q', 16); default_policy = policy; /* Send all but the last. */ for (i = 0; i < 9; i++) { Packet *tp = Defrag(NULL, NULL, packets[i]); if (tp != NULL) { SCFree(tp); goto end; } if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) { goto end; } } int overlap = 0; for (; i < 16; i++) { Packet *tp = Defrag(NULL, NULL, packets[i]); if (tp != NULL) { SCFree(tp); goto end; } if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) { overlap++; } } if (!overlap) { goto end; } /* And now the last one. */ Packet *reassembled = Defrag(NULL, NULL, packets[16]); if (reassembled == NULL) { goto end; } if (IPV4_GET_HLEN(reassembled) != 20) { goto end; } if (IPV4_GET_IPLEN(reassembled) != 20 + 192) { goto end; } if (memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0) { goto end; } SCFree(reassembled); /* Make sure all frags were returned back to the pool. */ if (defrag_context->frag_pool->outstanding != 0) { goto end; } ret = 1; end: for (i = 0; i < 17; i++) { SCFree(packets[i]); } DefragDestroy(); return ret; } static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) { int i; int ret = 0; DefragInit(); /* * Build the packets. */ int id = 1; Packet *packets[17]; memset(packets, 0x00, sizeof(packets)); /* * Original fragments. */ /* A*24 at 0. */ packets[0] = IPV6BuildTestPacket(id, 0, 1, 'A', 24); /* B*15 at 32. */ packets[1] = IPV6BuildTestPacket(id, 32 >> 3, 1, 'B', 16); /* C*24 at 48. */ packets[2] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'C', 24); /* D*8 at 80. */ packets[3] = IPV6BuildTestPacket(id, 80 >> 3, 1, 'D', 8); /* E*16 at 104. */ packets[4] = IPV6BuildTestPacket(id, 104 >> 3, 1, 'E', 16); /* F*24 at 120. */ packets[5] = IPV6BuildTestPacket(id, 120 >> 3, 1, 'F', 24); /* G*16 at 144. */ packets[6] = IPV6BuildTestPacket(id, 144 >> 3, 1, 'G', 16); /* H*16 at 160. */ packets[7] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'H', 16); /* I*8 at 176. */ packets[8] = IPV6BuildTestPacket(id, 176 >> 3, 1, 'I', 8); /* * Overlapping subsequent fragments. */ /* J*32 at 8. */ packets[9] = IPV6BuildTestPacket(id, 8 >> 3, 1, 'J', 32); /* K*24 at 48. */ packets[10] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'K', 24); /* L*24 at 72. */ packets[11] = IPV6BuildTestPacket(id, 72 >> 3, 1, 'L', 24); /* M*24 at 96. */ packets[12] = IPV6BuildTestPacket(id, 96 >> 3, 1, 'M', 24); /* N*8 at 128. */ packets[13] = IPV6BuildTestPacket(id, 128 >> 3, 1, 'N', 8); /* O*8 at 152. */ packets[14] = IPV6BuildTestPacket(id, 152 >> 3, 1, 'O', 8); /* P*8 at 160. */ packets[15] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'P', 8); /* Q*16 at 176. */ packets[16] = IPV6BuildTestPacket(id, 176 >> 3, 0, 'Q', 16); default_policy = policy; /* Send all but the last. */ for (i = 0; i < 9; i++) { Packet *tp = Defrag(NULL, NULL, packets[i]); if (tp != NULL) { SCFree(tp); goto end; } if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) { goto end; } } int overlap = 0; for (; i < 16; i++) { Packet *tp = Defrag(NULL, NULL, packets[i]); if (tp != NULL) { SCFree(tp); goto end; } if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) { overlap++; } } if (!overlap) goto end; /* And now the last one. */ Packet *reassembled = Defrag(NULL, NULL, packets[16]); if (reassembled == NULL) goto end; if (memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0) goto end; if (IPV6_GET_PLEN(reassembled) != 192) goto end; SCFree(reassembled); /* Make sure all frags were returned to the pool. */ if (defrag_context->frag_pool->outstanding != 0) { printf("defrag_context->frag_pool->outstanding %u: ", defrag_context->frag_pool->outstanding); goto end; } ret = 1; end: for (i = 0; i < 17; i++) { SCFree(packets[i]); } DefragDestroy(); return ret; } static int DefragSturgesNovakBsdTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "JJJJJJJJ" "BBBBBBBB" "CCCCCCCC" "CCCCCCCC" "CCCCCCCC" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "MMMMMMMM" "MMMMMMMM" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "HHHHHHHH" "HHHHHHHH" "IIIIIIII" "QQQQQQQQ" }; return DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected)); } static int IPV6DefragSturgesNovakBsdTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "JJJJJJJJ" "BBBBBBBB" "CCCCCCCC" "CCCCCCCC" "CCCCCCCC" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "MMMMMMMM" "MMMMMMMM" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "HHHHHHHH" "HHHHHHHH" "IIIIIIII" "QQQQQQQQ" }; return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected)); } static int DefragSturgesNovakLinuxTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "JJJJJJJJ" "BBBBBBBB" "KKKKKKKK" "KKKKKKKK" "KKKKKKKK" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "MMMMMMMM" "MMMMMMMM" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "PPPPPPPP" "HHHHHHHH" "QQQQQQQQ" "QQQQQQQQ" }; return DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, sizeof(expected)); } static int IPV6DefragSturgesNovakLinuxTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "JJJJJJJJ" "BBBBBBBB" "KKKKKKKK" "KKKKKKKK" "KKKKKKKK" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "MMMMMMMM" "MMMMMMMM" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "PPPPPPPP" "HHHHHHHH" "QQQQQQQQ" "QQQQQQQQ" }; return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, sizeof(expected)); } static int DefragSturgesNovakWindowsTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "BBBBBBBB" "BBBBBBBB" "CCCCCCCC" "CCCCCCCC" "CCCCCCCC" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "EEEEEEEE" "EEEEEEEE" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "HHHHHHHH" "HHHHHHHH" "IIIIIIII" "QQQQQQQQ" }; return DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)); } static int IPV6DefragSturgesNovakWindowsTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "BBBBBBBB" "BBBBBBBB" "CCCCCCCC" "CCCCCCCC" "CCCCCCCC" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "EEEEEEEE" "EEEEEEEE" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "HHHHHHHH" "HHHHHHHH" "IIIIIIII" "QQQQQQQQ" }; return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)); } static int DefragSturgesNovakSolarisTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "BBBBBBBB" "BBBBBBBB" "CCCCCCCC" "CCCCCCCC" "CCCCCCCC" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "MMMMMMMM" "MMMMMMMM" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "HHHHHHHH" "HHHHHHHH" "IIIIIIII" "QQQQQQQQ" }; return DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)); } static int IPV6DefragSturgesNovakSolarisTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "BBBBBBBB" "BBBBBBBB" "CCCCCCCC" "CCCCCCCC" "CCCCCCCC" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "MMMMMMMM" "MMMMMMMM" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "HHHHHHHH" "HHHHHHHH" "IIIIIIII" "QQQQQQQQ" }; return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)); } static int DefragSturgesNovakFirstTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "BBBBBBBB" "BBBBBBBB" "CCCCCCCC" "CCCCCCCC" "CCCCCCCC" "LLLLLLLL" "DDDDDDDD" "LLLLLLLL" "MMMMMMMM" "EEEEEEEE" "EEEEEEEE" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "HHHHHHHH" "HHHHHHHH" "IIIIIIII" "QQQQQQQQ" }; return DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, sizeof(expected)); } static int IPV6DefragSturgesNovakFirstTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "AAAAAAAA" "AAAAAAAA" "JJJJJJJJ" "BBBBBBBB" "BBBBBBBB" "CCCCCCCC" "CCCCCCCC" "CCCCCCCC" "LLLLLLLL" "DDDDDDDD" "LLLLLLLL" "MMMMMMMM" "EEEEEEEE" "EEEEEEEE" "FFFFFFFF" "FFFFFFFF" "FFFFFFFF" "GGGGGGGG" "GGGGGGGG" "HHHHHHHH" "HHHHHHHH" "IIIIIIII" "QQQQQQQQ" }; return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, sizeof(expected)); } static int DefragSturgesNovakLastTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "JJJJJJJJ" "JJJJJJJJ" "JJJJJJJJ" "JJJJJJJJ" "BBBBBBBB" "KKKKKKKK" "KKKKKKKK" "KKKKKKKK" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "MMMMMMMM" "MMMMMMMM" "FFFFFFFF" "NNNNNNNN" "FFFFFFFF" "GGGGGGGG" "OOOOOOOO" "PPPPPPPP" "HHHHHHHH" "QQQQQQQQ" "QQQQQQQQ" }; return DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, sizeof(expected)); } static int IPV6DefragSturgesNovakLastTest(void) { /* Expected data. */ u_char expected[] = { "AAAAAAAA" "JJJJJJJJ" "JJJJJJJJ" "JJJJJJJJ" "JJJJJJJJ" "BBBBBBBB" "KKKKKKKK" "KKKKKKKK" "KKKKKKKK" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "MMMMMMMM" "MMMMMMMM" "MMMMMMMM" "FFFFFFFF" "NNNNNNNN" "FFFFFFFF" "GGGGGGGG" "OOOOOOOO" "PPPPPPPP" "HHHHHHHH" "QQQQQQQQ" "QQQQQQQQ" }; return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, sizeof(expected)); } static int DefragTimeoutTest(void) { int i; int ret = 0; /* Setup a small numberr of trackers. */ if (ConfSet("defrag.trackers", "16", 1) != 1) { printf("ConfSet failed: "); goto end; } DefragInit(); /* Load in 16 packets. */ for (i = 0; i < 16; i++) { Packet *p = BuildTestPacket(i, 0, 1, 'A' + i, 16); if (p == NULL) goto end; Packet *tp = Defrag(NULL, NULL, p); SCFree(p); if (tp != NULL) { SCFree(tp); goto end; } } /* Build a new packet but push the timestamp out by our timeout. * This should force our previous fragments to be timed out. */ Packet *p = BuildTestPacket(99, 0, 1, 'A' + i, 16); if (p == NULL) goto end; p->ts.tv_sec += (defrag_context->timeout + 1); Packet *tp = Defrag(NULL, NULL, p); if (tp != NULL) { SCFree(tp); goto end; } DefragTracker *tracker = DefragLookupTrackerFromHash(p); if (tracker == NULL) goto end; if (tracker->id != 99) goto end; SCFree(p); ret = 1; end: DefragDestroy(); return ret; } /** * QA found that if you send a packet where more frags is 0, offset is * > 0 and there is no data in the packet that the re-assembler will * fail. The fix was simple, but this unit test is just to make sure * its not introduced. */ static int DefragIPv4NoDataTest(void) { DefragContext *dc = NULL; Packet *p = NULL; int id = 12; int ret = 0; DefragInit(); dc = DefragContextNew(); if (dc == NULL) goto end; /* This packet has an offset > 0, more frags set to 0 and no data. */ p = BuildTestPacket(id, 1, 0, 'A', 0); if (p == NULL) goto end; /* We do not expect a packet returned. */ if (Defrag(NULL, NULL, p) != NULL) goto end; /* The fragment should have been ignored so no fragments should * have been allocated from the pool. */ if (dc->frag_pool->outstanding != 0) return 0; ret = 1; end: if (dc != NULL) DefragContextDestroy(dc); if (p != NULL) SCFree(p); DefragDestroy(); return ret; } static int DefragIPv4TooLargeTest(void) { DefragContext *dc = NULL; Packet *p = NULL; int ret = 0; DefragInit(); dc = DefragContextNew(); if (dc == NULL) goto end; /* Create a fragment that would extend past the max allowable size * for an IPv4 packet. */ p = BuildTestPacket(1, 8183, 0, 'A', 71); if (p == NULL) goto end; /* We do not expect a packet returned. */ if (Defrag(NULL, NULL, p) != NULL) goto end; if (!ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE)) goto end; /* The fragment should have been ignored so no fragments should have * been allocated from the pool. */ if (dc->frag_pool->outstanding != 0) return 0; ret = 1; end: if (dc != NULL) DefragContextDestroy(dc); if (p != NULL) SCFree(p); DefragDestroy(); return ret; } #endif /* UNITTESTS */ void DefragRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest, 1); UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest, 1); UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest, 1); UtRegisterTest("DefragSturgesNovakLinuxTest", DefragSturgesNovakLinuxTest, 1); UtRegisterTest("DefragSturgesNovakWindowsTest", DefragSturgesNovakWindowsTest, 1); UtRegisterTest("DefragSturgesNovakSolarisTest", DefragSturgesNovakSolarisTest, 1); UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest, 1); UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest, 1); UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest, 1); UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest, 1); UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest, 1); UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest, 1); UtRegisterTest("IPV6DefragSturgesNovakBsdTest", IPV6DefragSturgesNovakBsdTest, 1); UtRegisterTest("IPV6DefragSturgesNovakLinuxTest", IPV6DefragSturgesNovakLinuxTest, 1); UtRegisterTest("IPV6DefragSturgesNovakWindowsTest", IPV6DefragSturgesNovakWindowsTest, 1); UtRegisterTest("IPV6DefragSturgesNovakSolarisTest", IPV6DefragSturgesNovakSolarisTest, 1); UtRegisterTest("IPV6DefragSturgesNovakFirstTest", IPV6DefragSturgesNovakFirstTest, 1); UtRegisterTest("IPV6DefragSturgesNovakLastTest", IPV6DefragSturgesNovakLastTest, 1); UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-proto-name.h0000644000000000000000000000235512253546156014237 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh */ #ifndef __UTIL_PROTO_NAME_H__ #define __UTIL_PROTO_NAME_H__ #ifndef OS_WIN32 #define PROTO_FILE "/etc/protocols" #else #define PROTO_FILE "C:\\Windows\\system32\\drivers\\etc\\protocol" #endif /* OS_WIN32 */ /** Lookup array to hold the information related to known protocol * in /etc/protocols */ char *known_proto[256]; uint8_t SCProtoNameValid(uint16_t); void SCProtoNameInit(void); void SCProtoNameDeInit(void); #endif /* __UTIL_PROTO_NAME_H__ */ suricata-1.4.7/src/util-misc.h0000644000000000000000000000215312253546156013105 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_MISC_H__ #define __UTIL_MISC_H__ /* size string parsing API */ int ParseSizeStringU8(const char *, uint8_t *); int ParseSizeStringU16(const char *, uint16_t *); int ParseSizeStringU32(const char *, uint32_t *); int ParseSizeStringU64(const char *, uint64_t *); void UtilMiscRegisterTests(void); #endif /* __UTIL_MISC_H__ */ suricata-1.4.7/src/detect-dce-iface.c0000644000000000000000000015051112253546156014242 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implements dce_iface keyword. */ #include "suricata-common.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-dce-iface.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "app-layer.h" #include "app-layer-dcerpc.h" #include "queue.h" #include "stream-tcp-reassemble.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "stream-tcp.h" #define DETECT_DCE_IFACE_PCRE_PARSE_ARGS "^\\s*([0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12})(?:\\s*,(<|>|=|!)([0-9]{1,5}))?(?:\\s*,(any_frag))?\\s*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectDceIfaceSetup(DetectEngineCtx *, Signature *, char *); void DetectDceIfaceFree(void *); /** * \brief Registers the keyword handlers for the "dce_iface" keyword. */ void DetectDceIfaceRegister(void) { const char *eb; int eo; int opts = 0; sigmatch_table[DETECT_DCE_IFACE].name = "dce_iface"; sigmatch_table[DETECT_DCE_IFACE].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_IFACE].Match = NULL; sigmatch_table[DETECT_DCE_IFACE].AppLayerMatch = DetectDceIfaceMatch; sigmatch_table[DETECT_DCE_IFACE].Setup = DetectDceIfaceSetup; sigmatch_table[DETECT_DCE_IFACE].Free = DetectDceIfaceFree; sigmatch_table[DETECT_DCE_IFACE].RegisterTests = DetectDceIfaceRegisterTests; sigmatch_table[DETECT_DCE_IFACE].flags |= SIGMATCH_PAYLOAD; parse_regex = pcre_compile(DETECT_DCE_IFACE_PCRE_PARSE_ARGS, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", DETECT_DCE_IFACE_PCRE_PARSE_ARGS, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogDebug("pcre study failed: %s", eb); goto error; } return; error: /* we need to handle error?! */ return; } /** * \internal * \brief Parses the argument sent along with the "dce_iface" keyword. * * \param arg Pointer to the string containing the argument to be parsed. * * \retval did Pointer to a DetectDceIfaceData instance that holds the data * from the parsed arg. */ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) { DetectDceIfaceData *did = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; uint8_t hex_value; const char *pcre_sub_str = NULL; int i = 0, j = 0; int len = 0; char temp_str[3]; int version; ret = pcre_exec(parse_regex, parse_regex_study, arg, strlen(arg), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, arg); goto error; } if ( (did = SCMalloc(sizeof(DetectDceIfaceData))) == NULL) goto error; memset(did, 0, sizeof(DetectDceIfaceData)); /* retrieve the iface uuid string. iface uuid is a compulsion in the keyword */ res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 1, &pcre_sub_str); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } /* parse the iface uuid string */ len = strlen(pcre_sub_str); j = 0; temp_str[2] = '\0'; for (i = 0; i < len; ) { if (pcre_sub_str[i] == '-') { i++; continue; } temp_str[0] = pcre_sub_str[i]; temp_str[1] = pcre_sub_str[i + 1]; hex_value = strtol(temp_str, NULL, 16); did->uuid[j] = hex_value; i += 2; j++; } /* if the regex has 3 or 5, any_frag option is present in the signature */ if (ret == 3 || ret == 5) did->any_frag = 1; /* if the regex has 4 or 5, version/operator is present in the signature */ if (ret == 4 || ret == 5) { /* first handle the version number, so that we can do some additional * validations of the version number, wrt. the operator */ res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 3, &pcre_sub_str); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } version = atoi(pcre_sub_str); if (version > UINT16_MAX) { SCLogError(SC_ERR_INVALID_SIGNATURE, "DCE_IFACE interface version " "invalid: %d\n", version); goto error; } did->version = version; /* free the substring */ pcre_free_substring(pcre_sub_str); /* now let us handle the operator supplied with the version number */ res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 2, &pcre_sub_str); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } switch (pcre_sub_str[0]) { case '<': if (version == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "DCE_IFACE interface " "version invalid: %d. Version can't be less" "than 0, with \"<\" operator", version); goto error; } did->op = DETECT_DCE_IFACE_OP_LT; break; case '>': if (version == UINT16_MAX) { SCLogError(SC_ERR_INVALID_SIGNATURE, "DCE_IFACE interface " "version invalid: %d. Version can't be greater" "than %d, with \">\" operator", version, UINT16_MAX); goto error; } did->op = DETECT_DCE_IFACE_OP_GT; break; case '=': did->op = DETECT_DCE_IFACE_OP_EQ; break; case '!': did->op = DETECT_DCE_IFACE_OP_NE; break; } /* free the substring */ pcre_free_substring(pcre_sub_str); } return did; error: if (did != NULL) SCFree(did); return NULL; } /** * \internal * \brief Internal function that compares the dce interface version for this * flow, to the signature's interface version specified using the * dce_iface keyword. * * \param version The dce interface version for this flow. * \param dce_data Pointer to the Signature's dce_iface keyword * state(DetectDceIfaceData *). */ static inline int DetectDceIfaceMatchIfaceVersion(uint16_t version, DetectDceIfaceData *dce_data) { switch (dce_data->op) { case DETECT_DCE_IFACE_OP_LT: return (version < dce_data->version); case DETECT_DCE_IFACE_OP_GT: return (version > dce_data->version); case DETECT_DCE_IFACE_OP_EQ: return (version == dce_data->version); case DETECT_DCE_IFACE_OP_NE: return (version != dce_data->version); default: return 1; } } /** * \brief App layer match function for the "dce_iface" keyword. * * \param t Pointer to the ThreadVars instance. * \param det_ctx Pointer to the DetectEngineThreadCtx. * \param f Pointer to the flow. * \param flags Pointer to the flags indicating the flow direction. * \param state Pointer to the app layer state data. * \param s Pointer to the Signature instance. * \param m Pointer to the SigMatch. * * \retval 1 On Match. * \retval 0 On no match. */ int DetectDceIfaceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; DCERPCUuidEntry *item = NULL; int i = 0; DetectDceIfaceData *dce_data = (DetectDceIfaceData *)m->ctx; DCERPCState *dcerpc_state = (DCERPCState *)state; if (dcerpc_state == NULL) { SCLogDebug("No DCERPCState for the flow"); SCReturnInt(0); } FLOWLOCK_RDLOCK(f); /* we still haven't seen a request */ if (!dcerpc_state->dcerpc.dcerpcrequest.first_request_seen) goto end; if (!(dcerpc_state->dcerpc.dcerpchdr.type == REQUEST)) goto end; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { SCLogDebug("item %p", item); ret = 1; /* if any_frag is not enabled, we need to match only against the first * fragment */ if (!dce_data->any_frag && !(item->flags & DCERPC_UUID_ENTRY_FLAG_FF)) continue; /* if the uuid has been rejected(item->result == 1), we skip to the * next uuid */ if (item->result != 0) continue; /* check the interface uuid */ for (i = 0; i < 16; i++) { if (dce_data->uuid[i] != item->uuid[i]) { ret = 0; break; } } ret &= (item->ctxid == dcerpc_state->dcerpc.dcerpcrequest.ctxid); if (ret == 0) continue; /* check the interface version */ if (dce_data->op != DETECT_DCE_IFACE_OP_NONE && !DetectDceIfaceMatchIfaceVersion(item->version, dce_data)) { ret &= 0; } /* we have a match. Time to leave with a match */ if (ret == 1) goto end; } end: FLOWLOCK_UNLOCK(f); SCReturnInt(ret); } /** * \brief Creates a SigMatch for the "dce_iface" keyword being sent as argument, * and appends it to the Signature(s). * * \param de_ctx Pointer to the detection engine context. * \param s Pointer to signature for the current Signature being parsed * from the rules. * \param arg Pointer to the string holding the keyword value. * * \retval 0 on success, -1 on failure. */ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectDceIfaceData *did = NULL; SigMatch *sm = NULL; did = DetectDceIfaceArgParse(arg); if (did == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Error parsing dec_iface option in " "signature"); goto error; } sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_DCE_IFACE; sm->ctx = (void *)did; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_DCERPC; /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; return 0; error: DetectDceIfaceFree(did); if (sm != NULL) SCFree(sm); return -1; } void DetectDceIfaceFree(void *ptr) { SCFree(ptr); return; } /************************************Unittests*********************************/ #ifdef UNITTESTS static int DetectDceIfaceTestParse01(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 0); result &= (did->op == 0); result &= (did->any_frag == 0); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse02(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>1") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 1); result &= (did->op == DETECT_DCE_IFACE_OP_GT); result &= (did->any_frag == 0); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse03(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,<10") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 10); result &= (did->op == DETECT_DCE_IFACE_OP_LT); result &= (did->any_frag == 0); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse04(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,!10") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 10); result &= (did->op == DETECT_DCE_IFACE_OP_NE); result &= (did->any_frag == 0); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse05(void) { SCEnter(); Signature *s = SigAlloc(); int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,=10") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 10); result &= (did->op == DETECT_DCE_IFACE_OP_EQ); result &= (did->any_frag == 0); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse06(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,any_frag") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 0); result &= (did->op == 0); result &= (did->any_frag == 1); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse07(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>1,any_frag") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 1); result &= (did->op == DETECT_DCE_IFACE_OP_GT); result &= (did->any_frag == 1); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse08(void) { Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,<1,any_frag") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 1); result &= (did->op == DETECT_DCE_IFACE_OP_LT); result &= (did->any_frag == 1); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse09(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,=1,any_frag") == 0); temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 1); result &= (did->op == DETECT_DCE_IFACE_OP_EQ); result &= (did->any_frag == 1); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse10(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 0; DetectDceIfaceData *did = NULL; uint8_t test_uuid[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; SigMatch *temp = NULL; int i = 0; result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,!1,any_frag") == 0); if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { SCReturnInt(0); } temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; did = temp->ctx; if (did == NULL) { SCReturnInt(0); } result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { result = 0; break; } } result &= (did->version == 1); result &= (did->op == DETECT_DCE_IFACE_OP_NE); result &= (did->any_frag == 1); SigFree(s); SCReturnInt(result); } static int DetectDceIfaceTestParse11(void) { SCEnter(); Signature *s = SigAlloc(); if (s == NULL) return 0; int result = 1; result &= (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>1,ay_frag") == -1); result &= (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-12345679ABC,>1,any_frag") == -1); result &= (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-134-123456789ABC,>1,any_frag") == -1); result &= (DetectDceIfaceSetup(NULL, s, "12345678-123-124-1234-123456789ABC,>1,any_frag") == -1); result &= (DetectDceIfaceSetup(NULL, s, "1234568-1234-1234-1234-123456789ABC,>1,any_frag") == -1); result &= (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>65536,any_frag") == -1); result &= (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>=1,any_frag") == -1); result &= (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,<0,any_frag") == -1); result &= (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>65535,any_frag") == -1); SigFree(s); return result; } /** * \test Test a valid dce_iface entry for a bind and bind_ack */ static int DetectDceIfaceTestParse12(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x26, 0x3d, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint8_t dcerpc_request[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint32_t dcerpc_request_len = sizeof(dcerpc_request); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5,=0,any_frag; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCLogDebug("handling to_server chunk"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 didn't match (1): "); goto end; } SCLogDebug("handling to_client chunk"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched, but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 matched, but shouldn't have: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_iface entry with a bind, bind_ack and 3 request/responses. */ static int DetectDceIfaceTestParse13(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xd0, 0x8c, 0x33, 0x44, 0x22, 0xf1, 0x31, 0xaa, 0xaa, 0x90, 0x00, 0x38, 0x00, 0x10, 0x03, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x65, 0x8e, 0x00, 0x00, 0x0d, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x77, 0x69, 0x6e, 0x72, 0x65, 0x67, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x5c, 0x00, 0x5c, 0x00, 0xa8, 0xb9, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x54, 0x00, 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x0c, 0x00, 0x0c, 0x00, 0x98, 0xda, 0x14, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x73, 0x00, 0x61, 0x00, 0x33, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x41, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); uint32_t dcerpc_request2_len = sizeof(dcerpc_request2); uint32_t dcerpc_response2_len = sizeof(dcerpc_response2); uint32_t dcerpc_request3_len = sizeof(dcerpc_request3); uint32_t dcerpc_response3_len = sizeof(dcerpc_response3); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any " "(msg:\"DCERPC\"; dce_iface:338cd001-2244-31f1-aaaa-900038001003,=1,any_frag; sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCLogDebug("chunk 1, bind"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 didn't match after bind request: "); goto end; } SCLogDebug("chunk 2, bind_ack"); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched again after bind ack: "); goto end; } SCLogDebug("chunk 3, request 1"); /* request1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't match after request1: "); goto end; } SCLogDebug("sending response1"); /* response1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched after response1, but shouldn't: "); goto end; } SCLogDebug("sending request2"); /* request2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't match after request2: "); goto end; } /* response2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched after response2, but shouldn't have: "); goto end; } /* request3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sig 1 didn't match after request3: "); goto end; } /* response3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched after response3, but shouldn't have: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_iface entry for a bind and bind_ack */ static int DetectDceIfaceTestParse14(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x26, 0x3d, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint8_t dcerpc_request[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint32_t dcerpc_request_len = sizeof(dcerpc_request); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5,=0; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't have: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_iface entry for a bind and bind_ack */ static int DetectDceIfaceTestParse15(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0xfd, 0x2c, 0x34, 0x6c, 0x3c, 0xce, 0x11, 0xa8, 0x93, 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x7d, 0xd8, 0x00, 0x00, 0x0d, 0x00, 0x5c, 0x70, 0x69, 0x70, 0x65, 0x5c, 0x6c, 0x6c, 0x73, 0x72, 0x70, 0x63, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint8_t dcerpc_alter_context[] = { 0x05, 0x00, 0x0e, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xd0, 0x4c, 0x67, 0x57, 0x00, 0x52, 0xce, 0x11, 0xa8, 0x97, 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t dcerpc_alter_context_len = sizeof(dcerpc_alter_context); uint8_t dcerpc_alter_context_resp[] = { 0x05, 0x00, 0x0f, 0x03, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x7d, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t dcerpc_alter_context_resp_len = sizeof(dcerpc_alter_context_resp); uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xdd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x66, 0xbf, 0x54, 0xc4, 0xdb, 0xdb, 0x4f, 0xa0, 0x01, 0x6d, 0xf4, 0xf6, 0xa8, 0x44, 0xb3, 0x00, 0x00, 0x00, 0x00 }; uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x9f, 0x13, 0xd9, }; uint32_t dcerpc_request2_len = sizeof(dcerpc_request2); memset(&th_v, 0, sizeof(th_v)); memset(&p, 0, sizeof(p)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_iface:57674cd0-5200-11ce-a897-08002b2e9c6d; " "sid:1;)"); if (s == NULL) goto end; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_iface:342cfd40-3c6c-11ce-a893-08002b2e9c6d; " "sid:2;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; if (PacketAlertCheck(p, 2)) goto end; r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sig 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_alter_context, dcerpc_alter_context_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sig 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_alter_context_resp, dcerpc_alter_context_resp_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sig 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sig 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't have: "); goto end; } if (PacketAlertCheck(p, 2)) { printf("sig 1 matched but shouldn't have: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 matched but shouldn't have: "); goto end; } if (!PacketAlertCheck(p, 2)) { printf("sig 1 matched but shouldn't have: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif void DetectDceIfaceRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDceIfaceTestParse01", DetectDceIfaceTestParse01, 1); UtRegisterTest("DetectDceIfaceTestParse02", DetectDceIfaceTestParse02, 1); UtRegisterTest("DetectDceIfaceTestParse03", DetectDceIfaceTestParse03, 1); UtRegisterTest("DetectDceIfaceTestParse04", DetectDceIfaceTestParse04, 1); UtRegisterTest("DetectDceIfaceTestParse05", DetectDceIfaceTestParse05, 1); UtRegisterTest("DetectDceIfaceTestParse06", DetectDceIfaceTestParse06, 1); UtRegisterTest("DetectDceIfaceTestParse07", DetectDceIfaceTestParse07, 1); UtRegisterTest("DetectDceIfaceTestParse08", DetectDceIfaceTestParse08, 1); UtRegisterTest("DetectDceIfaceTestParse09", DetectDceIfaceTestParse09, 1); UtRegisterTest("DetectDceIfaceTestParse10", DetectDceIfaceTestParse10, 1); UtRegisterTest("DetectDceIfaceTestParse11", DetectDceIfaceTestParse11, 1); UtRegisterTest("DetectDceIfaceTestParse12", DetectDceIfaceTestParse12, 1); UtRegisterTest("DetectDceIfaceTestParse13", DetectDceIfaceTestParse13, 1); UtRegisterTest("DetectDceIfaceTestParse14", DetectDceIfaceTestParse14, 1); UtRegisterTest("DetectDceIfaceTestParse15", DetectDceIfaceTestParse15, 1); #endif return; } suricata-1.4.7/src/util-cpu.h0000644000000000000000000000216612253546156012745 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo */ #ifndef __UTIL_CPU_H__ #define __UTIL_CPU_H__ /* Processors configured: */ uint16_t UtilCpuGetNumProcessorsConfigured(); /* Processors online: */ uint16_t UtilCpuGetNumProcessorsOnline(); /* Only on Solaris */ uint16_t UtilCpuGetNumProcessorsMax(); void UtilCpuPrintSummary(); uint64_t UtilCpuGetTicks(void); #endif /* __UTIL_CPU_H__ */ suricata-1.4.7/src/runmodes.h0000644000000000000000000000372512253546156013041 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien */ #ifndef __RUNMODES_H__ #define __RUNMODES_H__ /* Run mode */ enum { RUNMODE_UNKNOWN = 0, RUNMODE_PCAP_DEV, RUNMODE_PCAP_FILE, RUNMODE_PFRING, RUNMODE_NFQ, RUNMODE_IPFW, RUNMODE_ERF_FILE, RUNMODE_DAG, RUNMODE_AFP_DEV, RUNMODE_UNITTEST, RUNMODE_NAPATECH, RUNMODE_UNIX_SOCKET, RUNMODE_MAX, }; char *RunmodeGetActive(void); const char *RunModeGetMainMode(void); void RunModeListRunmodes(void); void RunModeDispatch(int, const char *, DetectEngineCtx *); void RunModeRegisterRunModes(void); void RunModeRegisterNewRunMode(int, const char *, const char *, int (*RunModeFunc)(DetectEngineCtx *)); void RunModeInitialize(void); void RunModeInitializeOutputs(void); void SetupOutputs(ThreadVars *); void RunModeShutDown(void); #include "runmode-pcap.h" #include "runmode-pcap-file.h" #include "runmode-pfring.h" #include "runmode-nfq.h" #include "runmode-ipfw.h" #include "runmode-erf-file.h" #include "runmode-erf-dag.h" #include "runmode-napatech.h" #include "runmode-af-packet.h" #include "runmode-unix-socket.h" int threading_set_cpu_affinity; extern float threading_detect_ratio; extern int debuglog_enabled; #endif /* __RUNMODES_H__ */ suricata-1.4.7/src/detect-engine-hrhhd.h0000644000000000000000000000234212253546156015005 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Anoop Saldanha */ #ifndef __DETECT_ENGINE_HRHHD_H__ #define __DETECT_ENGINE_HRHHD_H__ #include "app-layer-htp.h" int DetectEngineInspectHttpHRH(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, int); int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *, Flow *, HtpState *, uint8_t); void DetectEngineHttpHRHRegisterTests(void); #endif /* __DETECT_ENGINE_HRHHD_H__ */ suricata-1.4.7/src/cuda-packet-batcher.h0000644000000000000000000001342212253546156014767 00000000000000/** * Copyright (c) 2010 Open Information Security Foundation. * * \author Anoop Saldanha */ #ifndef __CUDA_PACKET_BATCHER_H__ #define __CUDA_PACKET_BATCHER_H__ #include "suricata-common.h" /* compile in, only if we have a CUDA enabled on this machine */ #ifdef __SC_CUDA_SUPPORT__ #include "util-cuda.h" /* The min no of packets that we allot the buffer for. We will make * this user configurable(yaml) based on the traffic they expect. Either ways * for a low/medium traffic network with occasional sgh matches, we shouldn't * be enabling cuda. We will only end up screwing performance */ #define SC_CUDA_PB_MIN_NO_OF_PACKETS 4000 /* the maximum payload size we're sending to the card (defined in decode.h) */ #define SC_CUDA_PB_MAX_PAYLOAD_SIZE CUDA_MAX_PAYLOAD_SIZE /** * \brief Implement the template SCDQGenericQData to transfer the cuda * packet buffer from the cuda batcher thread to the dispatcher * thread using the queue SCDQDataQueue. */ typedef struct SCCudaPBPacketsBuffer_ { /* these members from the template SCDQGenericQData that have to be * compulsarily implemented */ struct SCDQGenericQData_ *next; struct SCDQGenericQData_ *prev; /* if we want to consider this pointer as the head of a list, this var * holds the no of elements in the list */ //uint16_t len; /* in case this data instance is the head of a list, we can refer the * bottomost instance directly using this var */ //struct SCDQGenericaQData *bot; /* our own members from here on*/ /* current count of packets held in packets_buffer. nop = no of packets */ uint32_t nop_in_buffer; /* the packets buffer. We will assign buffer for SC_CUDA_PB_MIN_NO_OF_PACKETS * packets. Basically the size of this buffer would be * SC_CUDA_PB_MIN_NO_OF_PACKETS * sizeof(SCCudaPBPacketDataForGPU), so that * we can hold mininum SC_CUDA_PB_MIN_NO_OF_PACKETS */ uint8_t *packets_buffer; /* length of data buffered so far in packets_buffer, which would be sent * to the GPU. We will need this to copy the buffered data from the * packets_buffer here on the host, to the buffer on the GPU */ uint32_t packets_buffer_len; /* packet offset within the packets_buffer. Each packet would be stored in * packets buffer at a particular offset. This buffer would indicate the * offset of a packet inside the packet buffer. We will allot space to hold * offsets for SC_CUDA_PB_MIN_NO_OF_PACKETS packets * \todo change it to holds offsets for more than SC_CUDA_PB_MIN_NO_OF_PACKETS * when we use the buffer to hold packets based on the remaining size in the * buffer rather than on a fixed limit like SC_CUDA_PB_MIN_NO_OF_PACKETS */ uint32_t *packets_offset_buffer; /* the total packet payload lengths buffered so far. We will need this to * transfer the total length of the results buffer that has to be transferred * back from the gpu */ uint32_t packets_total_payload_len; /* the payload offsets for the different payload lengths buffered in. For * example if we buffer 4 packets of lengths 3, 4, 5, 6, we will store four * offsets in the buffer {0, 3, 7, 12, 18} */ uint32_t *packets_payload_offset_buffer; /* packet addresses for all the packets buffered in the packets_buffer. We * will allot space to hold packet addresses for SC_CUDA_PB_MIN_NO_OF_PACKETS. * We will need this, so that the cuda mpm b2g dispatcher thread can inform * and store the b2g cuda mpm results for the packet*/ Packet **packets_address_buffer; } SCCudaPBPacketsBuffer; /** * \brief Structure for each packet that is being batched to the GPU. */ typedef struct SCCudaPBPacketDataForGPU_ { /* holds B2gCudaCtx->m */ unsigned int m; /* holds B2gCudaCtx->cuda_B2g */ CUdeviceptr table; /* holds the length of the payload */ unsigned int payload_len; /* holds the payload. While we actually store the payload in the buffer, * we may not end up using the entire 1480 bytes if the payload is smaller */ uint8_t payload[SC_CUDA_PB_MAX_PAYLOAD_SIZE]; } SCCudaPBPacketDataForGPU; /** * \brief Same as struct SCCudaPBPacketDataForGPU_ except for the payload part. * We will need this for calculating the size of the non-payload part * of the packet data to be buffered. */ typedef struct SCCudaPBPacketDataForGPUNonPayload_ { /* holds B2gCudaCtx->m */ unsigned int m; /* holds B2gCudaCtx->cuda_B2g */ CUdeviceptr table; /* holds the length of the payload */ unsigned int payload_len; } SCCudaPBPacketDataForGPUNonPayload; /** * \brief The cuda packet batcher threading context. */ typedef struct SCCudaPBThreadCtx_ { /* we need the detection engine context to retrieve the sgh while we start * receiving and batching the packets */ DetectEngineCtx *de_ctx; /* packets buffer currently in use inside the cuda batcher thread */ SCCudaPBPacketsBuffer *curr_pb; } SCCudaPBThreadCtx; SCCudaPBPacketsBuffer *SCCudaPBAllocSCCudaPBPacketsBuffer(void); void SCCudaPBDeAllocSCCudaPBPacketsBuffer(SCCudaPBPacketsBuffer *); void SCCudaPBSetBufferPacketThreshhold(uint32_t); void SCCudaPBCleanUpQueuesAndBuffers(void); void SCCudaPBSetUpQueuesAndBuffers(void); void SCCudaPBKillBatchingPackets(void); TmEcode SCCudaPBBatchPackets(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode SCCudaPBThreadInit(ThreadVars *, void *, void **); TmEcode SCCudaPBThreadDeInit(ThreadVars *, void *); void SCCudaPBThreadExitStats(ThreadVars *, void *); void SCCudaPBRegisterTests(void); void TmModuleCudaPacketBatcherRegister(void); void *SCCudaPBTmThreadsSlot1(void *); void SCCudaPBRunningTests(int); void SCCudaPBSetProfile(char *); #endif /* __SC_CUDA_SUPPORT__ */ #endif /* __CUDA_PACKET_BATCHER_H__ */ suricata-1.4.7/src/defrag-timeout.h0000644000000000000000000000171612253546156014117 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DEFRAG_TIMEOUT_H__ #define __DEFRAG_TIMEOUT_H__ uint32_t DefragTimeoutHash(struct timeval *ts); uint32_t DefragGetSpareCount(void); uint32_t DefragGetActiveCount(void); #endif suricata-1.4.7/src/tm-modules.h0000644000000000000000000000657412253546156013300 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __TM_MODULES_H__ #define __TM_MODULES_H__ #include "tm-threads-common.h" #include "threadvars.h" /* thread flags */ #define TM_FLAG_RECEIVE_TM 0x01 #define TM_FLAG_DECODE_TM 0x02 #define TM_FLAG_STREAM_TM 0x04 #define TM_FLAG_DETECT_TM 0x08 typedef struct TmModule_ { char *name; /** thread handling */ TmEcode (*ThreadInit)(ThreadVars *, void *, void **); void (*ThreadExitPrintStats)(ThreadVars *, void *); TmEcode (*ThreadDeinit)(ThreadVars *, void *); /** the packet processing function */ TmEcode (*Func)(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode (*PktAcqLoop)(ThreadVars *, void *, void *); /** global Init/DeInit */ TmEcode (*Init)(void); TmEcode (*DeInit)(void); void (*RegisterTests)(void); uint8_t cap_flags; /**< Flags to indicate the capability requierment of the given TmModule */ /* Other flags used by the module */ uint8_t flags; } TmModule; TmModule tmm_modules[TMM_SIZE]; /** Global structure for Output Context */ typedef struct LogFileCtx_ { FILE *fp; /** It will be locked if the log/alert * record cannot be written to the file in one call */ SCMutex fp_mutex; /** The name of the file */ char *filename; /**< Used by some alert loggers like the unified ones that append * the date onto the end of files. */ char *prefix; /** Generic size_limit and size_current * They must be common to the threads accesing the same file */ uint64_t size_limit; /**< file size limit */ uint64_t size_current; /**< file current size */ /* Alerts on the module (not on the file) */ uint64_t alerts; /* flag to avoid multiple threads printing the same stats */ uint8_t flags; } LogFileCtx; /* flags for LogFileCtx */ #define LOGFILE_HEADER_WRITTEN 0x01 #define LOGFILE_ALERTS_PRINTED 0x02 /** * Structure that output modules use to maintain private data. */ typedef struct OutputCtx_ { /** Pointer to data private to the output. */ void *data; /** Pointer to a cleanup function. */ void (*DeInit)(struct OutputCtx_ *); } OutputCtx; LogFileCtx *LogFileNewCtx(); int LogFileFreeCtx(LogFileCtx *); TmModule *TmModuleGetByName(char *name); TmModule *TmModuleGetById(int id); int TmModuleGetIDForTM(TmModule *tm); TmEcode TmModuleRegister(char *name, int (*module_func)(ThreadVars *, Packet *, void *)); void TmModuleDebugList(void); void TmModuleRegisterTests(void); const char * TmModuleTmmIdToString(TmmId id); void TmModuleRunInit(void); void TmModuleRunDeInit(void); #endif /* __TM_MODULES_H__ */ suricata-1.4.7/src/detect-ssl-version.h0000644000000000000000000000251512253546156014733 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file detect-ssl-version.h * * \author Gurvinder Singh * */ #ifndef DETECT_SSL_VERSION_H #define DETECT_SSL_VERSION_H #define DETECT_SSL_VERSION_NEGATED 0x01 enum { SSLv2 = 0, SSLv3 = 1, TLS10 = 2, TLS11 = 3, TLS12 = 4, TLS_SIZE = 5, TLS_UNKNOWN = 6, }; typedef struct SSLVersionData_ { uint16_t ver; /** ssl version to match */ uint8_t flags; } SSLVersionData; typedef struct DetectSslVersionData_ { SSLVersionData data[TLS_SIZE]; } DetectSslVersionData; /* prototypes */ void DetectSslVersionRegister (void); #endif /* DETECT_SSL_VERSION_H */ suricata-1.4.7/src/tm-queuehandlers.c0000644000000000000000000000311612253546156014455 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Master Queue Handler */ #include "suricata-common.h" #include "packet-queue.h" #include "decode.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tmqh-simple.h" #include "tmqh-nfq.h" #include "tmqh-packetpool.h" #include "tmqh-flow.h" #include "tmqh-ringbuffer.h" void TmqhSetup (void) { memset(&tmqh_table, 0, sizeof(tmqh_table)); TmqhSimpleRegister(); TmqhNfqRegister(); TmqhPacketpoolRegister(); TmqhFlowRegister(); TmqhRingBufferRegister(); } /** \brief Clean up registration time allocs */ void TmqhCleanup(void) { TmqhRingBufferDestroy(); } Tmqh* TmqhGetQueueHandlerByName(char *name) { int i; for (i = 0; i < TMQH_SIZE; i++) { if (strcmp(name, tmqh_table[i].name) == 0) return &tmqh_table[i]; } return NULL; } suricata-1.4.7/src/detect-priority.c0000644000000000000000000001410312253546156014317 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * * Implements the priority keyword */ #include "suricata-common.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" #define DETECT_PRIORITY_REGEX "^\\s*(\\d+|\"\\d+\")\\s*$" static pcre *regex = NULL; static pcre_extra *regex_study = NULL; static int DetectPrioritySetup (DetectEngineCtx *, Signature *, char *); void SCPriorityRegisterTests(void); /** * \brief Registers the handler functions for the "priority" keyword */ void DetectPriorityRegister (void) { const char *eb = NULL; int eo; int opts = 0; sigmatch_table[DETECT_PRIORITY].name = "priority"; sigmatch_table[DETECT_PRIORITY].desc = "rules with a higher priority will be examined first"; sigmatch_table[DETECT_PRIORITY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Priority"; sigmatch_table[DETECT_PRIORITY].Match = NULL; sigmatch_table[DETECT_PRIORITY].Setup = DetectPrioritySetup; sigmatch_table[DETECT_PRIORITY].Free = NULL; sigmatch_table[DETECT_PRIORITY].RegisterTests = SCPriorityRegisterTests; regex = pcre_compile(DETECT_PRIORITY_REGEX, opts, &eb, &eo, NULL); if (regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", DETECT_PRIORITY_REGEX, eo, eb); goto end; } regex_study = pcre_study(regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto end; } end: return; } static int DetectPrioritySetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { const char *prio_str = NULL; #define MAX_SUBSTRINGS 30 int ret = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30); if (ret < 0) { SCLogError(SC_ERR_PCRE_MATCH, "Invalid Priority in Signature " "- %s", rawstr); return -1; } ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &prio_str); if (ret < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } long prio = 0; char *endptr = NULL; prio = strtol(rawstr, &endptr, 10); if (endptr == NULL || *endptr != '\0') { SCLogError(SC_ERR_INVALID_SIGNATURE, "Saw an invalid character as arg " "to priority keyword"); goto error; } /* if we have reached here, we have had a valid priority. Assign it */ s->prio = prio; return 0; error: return -1; } /*------------------------------Unittests-------------------------------------*/ #ifdef UNITTESTS int DetectPriorityTest01() { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Priority test\"; priority:2; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; DetectEngineCtxFree(de_ctx); end: return result; } int DetectPriorityTest02() { int result = 0; Signature *last = NULL; Signature *sig = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Priority test\"; priority:1; sid:1;)"); de_ctx->sig_list = last = sig; if (sig == NULL) { result = 0; } else { result = 1; result &= (sig->prio == 1); } sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Priority test\"; priority:boo; sid:1;)"); if (last != NULL) last->next = sig; result &= (sig == NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Priority test\"; priority:10boo; sid:1;)"); if (last != NULL) last->next = sig; result &= (sig == NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Priority test\"; priority:b10oo; sid:1;)"); if (last != NULL) last->next = sig; result &= (sig == NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Priority test\"; priority:boo10; sid:1;)"); if (last != NULL) last->next = sig; result &= (sig == NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Priority test\"; priority:-1; sid:1;)"); if (last != NULL) last->next = sig; result &= (sig == NULL); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Priority test\"; sid:1;)"); if (last != NULL) last->next = sig; if (sig == NULL) { result &= 0; } else { result &= (sig->prio == 3); } SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); end: return result; } #endif /* UNITTESTS */ /** * \brief This function registers unit tests for Classification Config API. */ void SCPriorityRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectPriorityTest01", DetectPriorityTest01, 1); UtRegisterTest("DetectPriorityTest02", DetectPriorityTest02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-seq.c0000644000000000000000000001461312253546156013234 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus * * Implements the seq keyword. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-seq.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" static int DetectSeqSetup(DetectEngineCtx *, Signature *, char *); static int DetectSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static void DetectSeqRegisterTests(void); static void DetectSeqFree(void *); void DetectSeqRegister(void) { sigmatch_table[DETECT_SEQ].name = "seq"; sigmatch_table[DETECT_SEQ].desc = "check for a specific TCP sequence number"; sigmatch_table[DETECT_SEQ].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#seq"; sigmatch_table[DETECT_SEQ].Match = DetectSeqMatch; sigmatch_table[DETECT_SEQ].Setup = DetectSeqSetup; sigmatch_table[DETECT_SEQ].Free = DetectSeqFree; sigmatch_table[DETECT_SEQ].RegisterTests = DetectSeqRegisterTests; } /** * \internal * \brief This function is used to match packets with a given Seq number * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectSeqData * * \retval 0 no match * \retval 1 match */ static int DetectSeqMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectSeqData *data = (DetectSeqData *)m->ctx; /* This is only needed on TCP packets */ if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { return 0; } return (data->seq == TCP_GET_SEQ(p)) ? 1 : 0; } /** * \internal * \brief this function is used to add the seq option into the signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param optstr pointer to the user provided options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, char *optstr) { DetectSeqData *data; SigMatch *sm = NULL; data = SCMalloc(sizeof(DetectSeqData)); if (unlikely(data == NULL)) goto error; sm = SigMatchAlloc(); if (sm == NULL) { goto error; } sm->type = DETECT_SEQ; if (-1 == ByteExtractStringUint32(&data->seq, 10, 0, optstr)) { goto error; } sm->ctx = data; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (data) SCFree(data); return -1; } /** * \internal * \brief this function will free memory associated with seq option * * \param data pointer to seq configuration data */ static void DetectSeqFree(void *ptr) { DetectSeqData *data = (DetectSeqData *)ptr; SCFree(data); } #ifdef UNITTESTS /** * \test DetectSeqSigTest01 tests parses */ static int DetectSeqSigTest01(void) { int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; /* These three are crammed in here as there is no Parse */ if (SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing seq\";seq:foo;sid:1;)") != NULL) { printf("invalid seq accepted: "); goto cleanup; } if (SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing seq\";seq:9999999999;sid:1;)") != NULL) { printf("overflowing seq accepted: "); goto cleanup; } if (SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing seq\";seq:-100;sid:1;)") != NULL) { printf("negative seq accepted: "); goto cleanup; } result = 1; cleanup: if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } end: return result; } /** * \test DetectSeqSigTest02 tests seq keyword */ static int DetectSeqSigTest02(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; /* TCP w/seq=42 */ p[0]->tcph->th_seq = htonl(42); /* TCP w/seq=100 */ p[1]->tcph->th_seq = htonl(100); char *sigs[2]; sigs[0]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:41; sid:1;)"; sigs[1]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:42; sid:2;)"; uint32_t sid[2] = {1, 2}; uint32_t results[3][2] = { /* packet 0 match sid 1 but should not match sid 2 */ {0, 1}, /* packet 1 should not match */ {0, 0}, /* packet 2 should not match */ {0, 0} }; result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2); UTHFreePackets(p, 3); end: return result; } #endif /* UNITTESTS */ /** * \internal * \brief This function registers unit tests for DetectSeq */ static void DetectSeqRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01, 1); UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/flow-queue.c0000644000000000000000000000702212253546156013263 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Flow queue handler functions */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "flow-private.h" #include "flow-queue.h" #include "flow-util.h" #include "util-error.h" #include "util-debug.h" #include "util-print.h" FlowQueue *FlowQueueNew() { FlowQueue *q = (FlowQueue *)SCMalloc(sizeof(FlowQueue)); if (q == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in FlowQueueNew. Exiting..."); exit(EXIT_SUCCESS); } q = FlowQueueInit(q); return q; } FlowQueue *FlowQueueInit (FlowQueue *q) { if (q != NULL) { memset(q, 0, sizeof(FlowQueue)); FQLOCK_INIT(q); } return q; } /** * \brief Destroy a flow queue * * \param q the flow queue to destroy */ void FlowQueueDestroy (FlowQueue *q) { FQLOCK_DESTROY(q); } /** * \brief add a flow to a queue * * \param q queue * \param f flow */ void FlowEnqueue (FlowQueue *q, Flow *f) { #ifdef DEBUG BUG_ON(q == NULL || f == NULL); #endif FQLOCK_LOCK(q); /* more flows in queue */ if (q->top != NULL) { f->lnext = q->top; q->top->lprev = f; q->top = f; /* only flow */ } 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 */ FQLOCK_UNLOCK(q); } /** * \brief remove a flow from the queue * * \param q queue * * \retval f flow or NULL if empty list. */ Flow *FlowDequeue (FlowQueue *q) { FQLOCK_LOCK(q); Flow *f = q->bot; if (f == NULL) { FQLOCK_UNLOCK(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; } #ifdef DEBUG BUG_ON(q->len == 0); #endif if (q->len > 0) q->len--; f->lnext = NULL; f->lprev = NULL; FQLOCK_UNLOCK(q); return f; } /** * \brief Transfer a flow from a queue to the spare queue * * \param f the flow to be transfered * \param q the source queue, where the flow will be removed. This queue is locked. * * \note spare queue needs locking */ void FlowMoveToSpare(Flow *f) { /* now put it in spare */ FQLOCK_LOCK(&flow_spare_q); /* add to new queue (append) */ f->lprev = flow_spare_q.bot; if (f->lprev != NULL) f->lprev->lnext = f; f->lnext = NULL; flow_spare_q.bot = f; if (flow_spare_q.top == NULL) flow_spare_q.top = f; flow_spare_q.len++; #ifdef DBG_PERF if (flow_spare_q.len > flow_spare_q.dbg_maxlen) flow_spare_q.dbg_maxlen = flow_spare_q.len; #endif /* DBG_PERF */ FQLOCK_UNLOCK(&flow_spare_q); } suricata-1.4.7/src/detect-isdataat.c0000644000000000000000000011710012253546156014231 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * * Implements isdataat keyword */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "app-layer.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "detect-isdataat.h" #include "detect-content.h" #include "detect-uricontent.h" #include "flow.h" #include "flow-var.h" #include "util-debug.h" #include "util-byte.h" #include "detect-pcre.h" #include "detect-bytejump.h" #include "detect-byte-extract.h" /** * \brief Regex for parsing our isdataat options */ #define PARSE_REGEX "^\\s*!?([^\\s,]+)\\s*(,\\s*relative)?\\s*(,\\s*rawbytes\\s*)?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectIsdataatMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectIsdataatSetup (DetectEngineCtx *, Signature *, char *); void DetectIsdataatRegisterTests(void); void DetectIsdataatFree(void *); /** * \brief Registration function for isdataat: keyword */ void DetectIsdataatRegister (void) { sigmatch_table[DETECT_ISDATAAT].name = "isdataat"; sigmatch_table[DETECT_ISDATAAT].desc = "check if there is still data at a specific part of the payload"; sigmatch_table[DETECT_ISDATAAT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Isadataat"; sigmatch_table[DETECT_ISDATAAT].Match = DetectIsdataatMatch; sigmatch_table[DETECT_ISDATAAT].Setup = DetectIsdataatSetup; sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree; sigmatch_table[DETECT_ISDATAAT].RegisterTests = DetectIsdataatRegisterTests; sigmatch_table[DETECT_ISDATAAT].flags |= SIGMATCH_PAYLOAD; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: /* XXX */ return; } /** * \brief This function is used to match isdataat on a packet * \todo We need to add support for rawbytes * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectIsdataatData * * \retval 0 no match * \retval 1 match */ int DetectIsdataatMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectIsdataatData *idad = (DetectIsdataatData *)m->ctx; SCLogDebug("payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); /* Relative to the last matched content is not performed here, returning match (content should take care of this)*/ if (idad->flags & ISDATAAT_RELATIVE) return 1; /* its not relative and we have more data in the packet than the offset of isdataat */ if (p->payload_len >= idad->dataat) { SCLogDebug("matched with payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); return 1; } return 0; } /** * \brief This function is used to parse isdataat options passed via isdataat: keyword * * \param isdataatstr Pointer to the user provided isdataat options * * \retval idad pointer to DetectIsdataatData on success * \retval NULL on failure */ DetectIsdataatData *DetectIsdataatParse (char *isdataatstr, char **offset) { DetectIsdataatData *idad = NULL; char *args[3] = {NULL,NULL,NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int i=0; ret = pcre_exec(parse_regex, parse_regex_study, isdataatstr, strlen(isdataatstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, isdataatstr); goto error; } if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)isdataatstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[0] = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)isdataatstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[1] = (char *)str_ptr; } if (ret > 3) { res = pcre_get_substring((char *)isdataatstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[2] = (char *)str_ptr; } idad = SCMalloc(sizeof(DetectIsdataatData)); if (unlikely(idad == NULL)) goto error; idad->flags = 0; idad->dataat = 0; if (args[0][0] != '-' && isalpha((unsigned char)args[0][0])) { if (offset == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "isdataat supplied with " "var name for offset. \"offset\" argument supplied to " "this function has to be non-NULL"); goto error; } *offset = SCStrdup(args[0]); if (*offset == NULL) goto error; } else { if (ByteExtractStringUint16(&idad->dataat, 10, strlen(args[0]), args[0]) < 0 ) { SCLogError(SC_ERR_INVALID_VALUE, "isdataat out of range"); SCFree(idad); idad = NULL; goto error; } } if (args[1] !=NULL) { idad->flags |= ISDATAAT_RELATIVE; if(args[2] !=NULL) idad->flags |= ISDATAAT_RAWBYTES; } if (isdataatstr[0] == '!') { idad->flags |= ISDATAAT_NEGATED; } for (i = 0; i < (ret -1); i++) { if (args[i] != NULL) SCFree(args[i]); } return idad; } error: for (i = 0; i < (ret -1) && i < 3; i++){ if (args[i] != NULL) SCFree(args[i]); } if (idad != NULL) DetectIsdataatFree(idad); return NULL; } /** * \brief This function is used to add the parsed isdataatdata into the current * signature. * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param isdataatstr pointer to the user provided isdataat options * * \retval 0 on Success * \retval -1 on Failure */ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatstr) { DetectIsdataatData *idad = NULL; SigMatch *sm = NULL; SigMatch *dm = NULL; SigMatch *pm = NULL; SigMatch *prev_pm = NULL; char *offset = NULL; idad = DetectIsdataatParse(isdataatstr, &offset); if (idad == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ISDATAAT; sm->ctx = (void *)idad; if (s->alproto == ALPROTO_DCERPC && (idad->flags & ISDATAAT_RELATIVE)) { pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); dm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_DMATCH]); if (pm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (dm == NULL) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } else if (pm->idx > dm->idx) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); } else { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_DMATCH); } prev_pm = SigMatchGetLastSMFromLists(s, 6, DETECT_CONTENT, sm->prev, DETECT_BYTEJUMP, sm->prev, DETECT_PCRE, sm->prev); if (prev_pm == NULL) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is a dce alproto sig."); if (offset != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in isdataat - %s", offset); goto error; } return 0; } } else if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { if (idad->flags & ISDATAAT_RELATIVE) { pm = SigMatchGetLastSMFromLists(s, 10, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); if (pm == NULL) { idad->flags &= ~ISDATAAT_RELATIVE; } s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } else { s->flags |= SIG_FLAG_APPLAYER; AppLayerHtpEnableResponseBodyCallback(); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); } if (pm == NULL) { SCLogDebug("No preceding content or pcre keyword. Possible " "since this is a file_data sig."); if (offset != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in isdataat - %s", offset); goto error; } return 0; } prev_pm = pm; } else { if (!(idad->flags & ISDATAAT_RELATIVE)) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); if (offset != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, SigMatchListSMBelongsTo(s, sm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in isdataat - %s\n", offset); goto error; } DetectIsdataatData *isdd = sm->ctx; isdd->dataat = ((DetectByteExtractData *)bed_sm->ctx)->local_id; isdd->flags |= ISDATAAT_OFFSET_BE; SCFree(offset); } return 0; } pm = SigMatchGetLastSMFromLists(s, 66, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH]); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "isdataat relative seen " "without a previous content uricontent, " "http_client_body, http_header, http_raw_header, " "http_method, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code, byte_test, " "byte_extract, byte_jump, http_user_agent, " "http_host or http_raw_host keyword"); goto error; } else { int list_type = SigMatchListSMBelongsTo(s, pm); if (list_type == -1) { goto error; } SigMatchAppendSMToList(s, sm, list_type); } /* else - if (pm == NULL) */ prev_pm = pm; } if (offset != NULL) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(offset, s, SigMatchListSMBelongsTo(s, sm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown byte_extract var " "seen in isdataat - %s\n", offset); goto error; } DetectIsdataatData *isdd = sm->ctx; isdd->dataat = ((DetectByteExtractData *)bed_sm->ctx)->local_id; isdd->flags |= ISDATAAT_OFFSET_BE; SCFree(offset); } DetectContentData *cd = NULL; DetectPcreData *pe = NULL; switch (prev_pm->type) { case DETECT_CONTENT: /* Set the relative next flag on the prev sigmatch */ cd = (DetectContentData *)prev_pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; break; case DETECT_PCRE: pe = (DetectPcreData *)prev_pm->ctx; if (pe == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } pe->flags |= DETECT_PCRE_RELATIVE_NEXT; break; case DETECT_BYTEJUMP: case DETECT_BYTETEST: case DETECT_BYTE_EXTRACT: SCLogDebug("Do nothing for byte_jump, byte_test, byte_extract"); break; default: /* this will never hit */ SCLogError(SC_ERR_INVALID_SIGNATURE, "Unknown previous-" "previous keyword!"); return -1; } /* switch */ return 0; error: return -1; } /** * \brief this function will free memory associated with DetectIsdataatData * * \param idad pointer to DetectIsdataatData */ void DetectIsdataatFree(void *ptr) { DetectIsdataatData *idad = (DetectIsdataatData *)ptr; SCFree(idad); } #ifdef UNITTESTS /** * \test DetectIsdataatTestParse01 is a test to make sure that we return a correct IsdataatData structure * when given valid isdataat opt */ int DetectIsdataatTestParse01 (void) { int result = 0; DetectIsdataatData *idad = NULL; idad = DetectIsdataatParse("30 ", NULL); if (idad != NULL) { DetectIsdataatFree(idad); result = 1; } return result; } /** * \test DetectIsdataatTestParse02 is a test to make sure that we return a correct IsdataatData structure * when given valid isdataat opt */ int DetectIsdataatTestParse02 (void) { int result = 0; DetectIsdataatData *idad = NULL; idad = DetectIsdataatParse("30 , relative", NULL); if (idad != NULL && idad->flags & ISDATAAT_RELATIVE && !(idad->flags & ISDATAAT_RAWBYTES)) { DetectIsdataatFree(idad); result = 1; } return result; } /** * \test DetectIsdataatTestParse03 is a test to make sure that we return a correct IsdataatData structure * when given valid isdataat opt */ int DetectIsdataatTestParse03 (void) { int result = 0; DetectIsdataatData *idad = NULL; idad = DetectIsdataatParse("30,relative, rawbytes ", NULL); if (idad != NULL && idad->flags & ISDATAAT_RELATIVE && idad->flags & ISDATAAT_RAWBYTES) { DetectIsdataatFree(idad); result = 1; } return result; } /** * \test Test isdataat option for dce sig. */ int DetectIsdataatTestParse04(void) { Signature *s = SigAlloc(); int result = 1; s->alproto = ALPROTO_DCERPC; result &= (DetectIsdataatSetup(NULL, s, "30") == 0); result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); s = SigAlloc(); s->alproto = ALPROTO_DCERPC; /* failure since we have no preceding content/pcre/bytejump */ result &= (DetectIsdataatSetup(NULL, s, "30,relative") == 0); result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); SigFree(s); return result; } /** * \test Test isdataat option for dce sig. */ int DetectIsdataatTestParse05(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "isdataat:4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) ) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "isdataat:4,relative; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) ) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "isdataat:4,relative,rawbytes; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || !(data->flags & ISDATAAT_RAWBYTES) ) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; isdataat:4,relative,rawbytes; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectIsdataatTestParse06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { goto end; } result = 1; result &= (s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectIsdataatTestParse07(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "uricontent:\"one\"; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { goto end; } result = 1; result &= (s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectIsdataatTestParse08(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; http_uri; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { goto end; } result = 1; result &= (s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectIsdataatTestParse09(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; http_client_body; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL) { goto end; } result = 1; result &= (s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectIsdataatTestParse10(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; http_header; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL) { goto end; } result = 1; result &= (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectIsdataatTestParse11(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "flow:to_server; content:\"one\"; http_raw_header; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL) { goto end; } result = 1; result &= (s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectIsdataatTestParse12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; http_method; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL) { goto end; } result = 1; result &= (s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectIsdataatTestParse13(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; http_cookie; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] == NULL) { goto end; } result = 1; result &= (s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->type == DETECT_ISDATAAT); data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } static int DetectIsdataatTestParse14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing file_data and isdataat\"; " "file_data; content:\"one\"; " "isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("server body list empty: "); goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_ISDATAAT) { printf("last server body sm not isdataat: "); goto end; } data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test file_data with isdataat relative to it */ static int DetectIsdataatTestParse15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; Signature *s = NULL; DetectIsdataatData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing file_data and isdataat\"; " "file_data; isdataat:!4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse: "); goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("server body list empty: "); goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_ISDATAAT) { printf("last server body sm not isdataat: "); goto end; } data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; if ( (data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) || !(data->flags & ISDATAAT_NEGATED) ) { goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test DetectIsdataatTestPacket01 is a test to check matches of * isdataat, and isdataat relative */ int DetectIsdataatTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p[3]; p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_UDP); p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; char *sigs[5]; sigs[0]= "alert ip any any -> any any (msg:\"Testing window 1\"; isdataat:6; sid:1;)"; sigs[1]= "alert ip any any -> any any (msg:\"Testing window 2\"; content:\"all\"; isdataat:1, relative; isdataat:6; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"Testing window 3\"; isdataat:8; sid:3;)"; sigs[3]= "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:5, relative; sid:4;)"; sigs[4]= "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:6, relative; sid:5;)"; uint32_t sid[5] = {1, 2, 3, 4, 5}; uint32_t results[3][5] = { /* packet 0 match sid 1 but should not match sid 2 */ {1, 1, 0, 1, 0}, /* packet 1 should not match */ {1, 1, 0, 1, 0}, /* packet 2 should not match */ {1, 1, 0, 1, 0} }; result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 5); UTHFreePackets(p, 3); end: return result; } /** * \test DetectIsdataatTestPacket02 is a test to check matches of * isdataat, and isdataat relative works if the previous keyword is pcre * (bug 144) */ int DetectIsdataatTestPacket02 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" "User-Agent: Wget/1.11.4" "Accept: */*" "Host: www.google.com" "Connection: Keep-Alive" "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"pcre with" " isdataat + relative\"; pcre:\"/A(ll|pp)WorkAndNoPlayMakesWillA" "DullBoy/\"; isdataat:96,relative; sid:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } /** * \test DetectIsdataatTestPacket03 is a test to check matches of * isdataat, and isdataat relative works if the previous keyword is byte_jump * (bug 146) */ int DetectIsdataatTestPacket03 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" "User-Agent: Wget/1.11.4" "Accept: */*" "Host: www.google.com" "Connection: Keep-Alive" "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; char sig[] = "alert tcp any any -> any any (msg:\"byte_jump match = 0 " "with distance content HTTP/1. relative against HTTP/1.0\"; byte_jump:1," "46,string,dec; isdataat:87,relative; sid:109; rev:1;)"; result = UTHPacketMatchSig(p, sig); UTHFreePacket(p); end: return result; } #endif /** * \brief this function registers unit tests for DetectIsdataat */ void DetectIsdataatRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectIsdataatTestParse01", DetectIsdataatTestParse01, 1); UtRegisterTest("DetectIsdataatTestParse02", DetectIsdataatTestParse02, 1); UtRegisterTest("DetectIsdataatTestParse03", DetectIsdataatTestParse03, 1); UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04, 1); UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05, 1); UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06, 1); UtRegisterTest("DetectIsdataatTestParse07", DetectIsdataatTestParse07, 1); UtRegisterTest("DetectIsdataatTestParse08", DetectIsdataatTestParse08, 1); UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09, 1); UtRegisterTest("DetectIsdataatTestParse10", DetectIsdataatTestParse10, 1); UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11, 1); UtRegisterTest("DetectIsdataatTestParse12", DetectIsdataatTestParse12, 1); UtRegisterTest("DetectIsdataatTestParse13", DetectIsdataatTestParse13, 1); UtRegisterTest("DetectIsdataatTestParse14", DetectIsdataatTestParse14, 1); UtRegisterTest("DetectIsdataatTestParse15", DetectIsdataatTestParse15, 1); UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01, 1); UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02, 1); UtRegisterTest("DetectIsdataatTestPacket03", DetectIsdataatTestPacket03, 1); #endif } suricata-1.4.7/src/stream-tcp-util.c0000644000000000000000000001415412253546156014230 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Helper functions for the stream engine. */ #include "suricata-common.h" #include "stream-tcp-reassemble.h" #include "stream-tcp-inline.h" #include "stream-tcp.h" #include "stream-tcp-util.h" #include "util-memcmp.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" #ifdef UNITTESTS /* unittest helper functions */ void StreamTcpUTInit(TcpReassemblyThreadCtx **ra_ctx) { StreamTcpInitConfig(TRUE); *ra_ctx = StreamTcpReassembleInitThreadCtx(); } void StreamTcpUTDeinit(TcpReassemblyThreadCtx *ra_ctx) { StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); } void StreamTcpUTSetupSession(TcpSession *ssn) { memset(ssn, 0x00, sizeof(TcpSession)); } void StreamTcpUTClearSession(TcpSession *ssn) { StreamTcpUTClearStream(&ssn->client); StreamTcpUTClearStream(&ssn->server); } void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn) { memset(s, 0x00, sizeof(TcpStream)); s->isn = isn; STREAMTCP_SET_RA_BASE_SEQ(s, isn); } void StreamTcpUTClearStream(TcpStream *s) { StreamTcpReturnStreamSegments(s); } int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len) { TcpSegment *s = StreamTcpGetSegment(tv, ra_ctx, len); if (s == NULL) { return -1; } s->seq = seq; s->payload_len = len; memcpy(s->payload, payload, len); Packet *p = UTHBuildPacketReal(s->payload, s->payload_len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { return -1; } p->tcph->th_seq = htonl(seq); if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p) < 0) return -1; UTHFreePacket(p); return 0; } int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t byte, uint16_t len) { TcpSegment *s = StreamTcpGetSegment(tv, ra_ctx, len); if (s == NULL) { return -1; } s->seq = seq; s->payload_len = len; memset(s->payload, byte, len); Packet *p = UTHBuildPacketReal(s->payload, s->payload_len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { return -1; } p->tcph->th_seq = htonl(seq); if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p) < 0) return -1; UTHFreePacket(p); return 0; } /* tests */ int StreamTcpUtilTest01(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; StreamTcpUTInit(&ra_ctx); if (ra_ctx == NULL) { printf("ra_ctx is NULL: "); goto end; } ret = 1; end: StreamTcpUTDeinit(ra_ctx); return ret; } int StreamTcpUtilStreamTest01(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpStream stream; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupStream(&stream, 1); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } TcpSegment *seg = stream.seg_list; if (seg->seq != 2) { printf("first seg in the list should have seq 2: "); goto end; } seg = seg->next; if (seg->seq != 7) { printf("first seg in the list should have seq 7: "); goto end; } seg = seg->next; if (seg->seq != 12) { printf("first seg in the list should have seq 12: "); goto end; } ret = 1; end: StreamTcpUTClearStream(&stream); StreamTcpUTDeinit(ra_ctx); return ret; } int StreamTcpUtilStreamTest02(void) { int ret = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; ThreadVars tv; TcpStream stream; memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupStream(&stream, 1); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); goto end; } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } TcpSegment *seg = stream.seg_list; if (seg->seq != 2) { printf("first seg in the list should have seq 2: "); goto end; } seg = seg->next; if (seg->seq != 7) { printf("first seg in the list should have seq 7: "); goto end; } seg = seg->next; if (seg->seq != 12) { printf("first seg in the list should have seq 12: "); goto end; } ret = 1; end: StreamTcpUTClearStream(&stream); StreamTcpUTDeinit(ra_ctx); return ret; } #endif void StreamTcpUtilRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("StreamTcpUtilTest01", StreamTcpUtilTest01, 1); UtRegisterTest("StreamTcpUtilStreamTest01", StreamTcpUtilStreamTest01, 1); UtRegisterTest("StreamTcpUtilStreamTest02", StreamTcpUtilStreamTest02, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-engine-address.c0000644000000000000000000042071712253546156015342 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Address part of the detection engine. * * \todo Move this out of the detection plugin structure * rename to detect-engine-address.c */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "flow-var.h" #include "util-cidr.h" #include "util-unittest.h" #include "util-rule-vars.h" #include "conf.h" #include "conf-yaml-loader.h" #include "detect-engine-siggroup.h" #include "detect-engine-address.h" #include "detect-engine-address-ipv4.h" #include "detect-engine-address-ipv6.h" #include "detect-engine-port.h" #include "util-debug.h" #include "util-print.h" /* prototypes */ void DetectAddressPrint(DetectAddress *); static int DetectAddressCutNot(DetectAddress *, DetectAddress **); static int DetectAddressCut(DetectEngineCtx *, DetectAddress *, DetectAddress *, DetectAddress **); /** memory usage counters * \todo not MT safe */ #ifdef DEBUG static uint32_t detect_address_group_memory = 0; static uint32_t detect_address_group_init_cnt = 0; static uint32_t detect_address_group_free_cnt = 0; static uint32_t detect_address_group_head_memory = 0; static uint32_t detect_address_group_head_init_cnt = 0; static uint32_t detect_address_group_head_free_cnt = 0; #endif /** * \brief Creates and returns a new instance of a DetectAddress. * * \retval ag Pointer to the newly created DetectAddress on success; * NULL on failure. */ DetectAddress *DetectAddressInit(void) { DetectAddress *ag = SCMalloc(sizeof(DetectAddress)); if (unlikely(ag == NULL)) return NULL; memset(ag, 0, sizeof(DetectAddress)); #ifdef DEBUG detect_address_group_memory += sizeof(DetectAddress); detect_address_group_init_cnt++; #endif return ag; } /** * \brief Frees a DetectAddress instance. * * \param ag Pointer to the DetectAddress instance to be freed. */ void DetectAddressFree(DetectAddress *ag) { if (ag == NULL) return; SCLogDebug("ag %p, sh %p", ag, ag->sh); /* only free the head if we have the original */ if (ag->sh != NULL && !(ag->flags & ADDRESS_SIGGROUPHEAD_COPY)) { SCLogDebug("- ag %p, sh %p not a copy, so call SigGroupHeadFree", ag, ag->sh); SigGroupHeadFree(ag->sh); } ag->sh = NULL; if (!(ag->flags & ADDRESS_HAVEPORT)) { SCLogDebug("- ag %p dst_gh %p", ag, ag->dst_gh); if (ag->dst_gh != NULL) DetectAddressHeadFree(ag->dst_gh); ag->dst_gh = NULL; } else { SCLogDebug("- ag %p port %p", ag, ag->port); if (ag->port != NULL && !(ag->flags & ADDRESS_PORTS_COPY)) { SCLogDebug("- ag %p port %p, not a copy so call DetectPortCleanupList", ag, ag->port); DetectPortCleanupList(ag->port); } ag->port = NULL; } #ifdef DEBUG detect_address_group_memory -= sizeof(DetectAddress); detect_address_group_free_cnt++; #endif SCFree(ag); return; } /** * \brief Copies the contents of one Address group in DetectAddress and returns * a new instance of the DetectAddress that contains the copied address. * * \param orig Pointer to the instance of DetectAddress that contains the * address data to be copied to the new instance. * * \retval ag Pointer to the new instance of DetectAddress that contains the * copied address. */ DetectAddress *DetectAddressCopy(DetectAddress *orig) { DetectAddress *ag = DetectAddressInit(); if (ag == NULL) return NULL; ag->flags = orig->flags; COPY_ADDRESS(&orig->ip, &ag->ip); COPY_ADDRESS(&orig->ip2, &ag->ip2); ag->cnt = 1; return ag; } /** * \brief Prints the memory statistics for the detection-engine-address section. */ void DetectAddressPrintMemory(void) { #ifdef DEBUG SCLogDebug(" * Address group memory stats (DetectAddress %" PRIuMAX "):", (uintmax_t)sizeof(DetectAddress)); SCLogDebug(" - detect_address_group_memory %" PRIu32, detect_address_group_memory); SCLogDebug(" - detect_address_group_init_cnt %" PRIu32, detect_address_group_init_cnt); SCLogDebug(" - detect_address_group_free_cnt %" PRIu32, detect_address_group_free_cnt); SCLogDebug(" - outstanding groups %" PRIu32, detect_address_group_init_cnt - detect_address_group_free_cnt); SCLogDebug(" * Address group memory stats done"); SCLogDebug(" * Address group head memory stats (DetectAddressHead %" PRIuMAX "):", (uintmax_t)sizeof(DetectAddressHead)); SCLogDebug(" - detect_address_group_head_memory %" PRIu32, detect_address_group_head_memory); SCLogDebug(" - detect_address_group_head_init_cnt %" PRIu32, detect_address_group_head_init_cnt); SCLogDebug(" - detect_address_group_head_free_cnt %" PRIu32, detect_address_group_head_free_cnt); SCLogDebug(" - outstanding groups %" PRIu32, (detect_address_group_head_init_cnt - detect_address_group_head_free_cnt)); SCLogDebug(" * Address group head memory stats done"); SCLogDebug(" X Total %" PRIu32 "\n", (detect_address_group_memory + detect_address_group_head_memory)); #endif return; } /** * \brief Used to check if a DetectAddress list contains an instance with * a similar DetectAddress. The comparison done is not the one that * checks the memory for the same instance, but one that checks that the * two instances hold the same content. * * \param head Pointer to the DetectAddress list. * \param ad Pointer to the DetectAddress that has to be checked for in * the DetectAddress list. * * \retval cur Returns a pointer to the DetectAddress on a match; NULL if * no match. */ DetectAddress *DetectAddressLookupInList(DetectAddress *head, DetectAddress *gr) { DetectAddress *cur; if (head != NULL) { for (cur = head; cur != NULL; cur = cur->next) { if (DetectAddressCmp(cur, gr) == ADDRESS_EQ) return cur; } } return NULL; } /** * \brief Prints the address data information for all the DetectAddress * instances in the DetectAddress list sent as the argument. * * \param head Pointer to a list of DetectAddress instances. */ void DetectAddressPrintList(DetectAddress *head) { DetectAddress *cur; SCLogInfo("list:"); if (head != NULL) { for (cur = head; cur != NULL; cur = cur->next) { SCLogInfo("SIGS %6u ", cur->sh ? cur->sh->sig_cnt : 0); DetectAddressPrint(cur); } } SCLogInfo("endlist"); return; } /** * \brief Frees a list of DetectAddress instances. * * \param head Pointer to a list of DetectAddress instances to be freed. */ void DetectAddressCleanupList(DetectAddress *head) { DetectAddress *cur, *next; if (head == NULL) return; for (cur = head; cur != NULL; ) { next = cur->next; cur->next = NULL; DetectAddressFree(cur); cur = next; } return; } /** * \brief Do a sorted insert, where the top of the list should be the biggest * network/range. * * XXX current sorting only works for overlapping nets * * \param head Pointer to the list of DetectAddress. * \param ag Pointer to the DetectAddress that has to be added to the * above list. * * \retval 0 On successfully inserting the DetectAddress. * \retval -1 On failure. */ int DetectAddressAdd(DetectAddress **head, DetectAddress *ag) { DetectAddress *cur, *prev_cur = NULL; int r = 0; if (*head != NULL) { for (cur = *head; cur != NULL; cur = cur->next) { prev_cur = cur; r = DetectAddressCmp(ag, cur); if (r == ADDRESS_EB) { /* insert here */ ag->prev = cur->prev; ag->next = cur; cur->prev = ag; if (*head == cur) *head = ag; else ag->prev->next = ag; return 0; } } ag->prev = prev_cur; if (prev_cur != NULL) prev_cur->next = ag; } else { *head = ag; } return 0; } /** * \internal * \brief Helper function for DetectAddressInsert. Sets one of the * DetectAddressHead head pointers, to the DetectAddress argument * based on its address family. * * \param gh Pointer to the DetectAddressHead. * \param newhead Pointer to the DetectAddress. * * \retval 0 On success. * \retval -1 On failure. */ static int SetHeadPtr(DetectAddressHead *gh, DetectAddress *newhead) { if (newhead->flags & ADDRESS_FLAG_ANY) { gh->any_head = newhead; } else if (newhead->ip.family == AF_INET) { gh->ipv4_head = newhead; } else if (newhead->ip.family == AF_INET6) { gh->ipv6_head = newhead; } else { SCLogDebug("newhead->family %u not supported", newhead->ip.family); return -1; } return 0; } /** * \internal * \brief Returns the DetectAddress head from the DetectAddressHeads, * based on the address family of the incoming DetectAddress arg. * * \param gh Pointer to the DetectAddressHead. * \param new Pointer to the DetectAddress. * * \retval head Pointer to the DetectAddress(the head from * DetectAddressHead). */ static DetectAddress *GetHeadPtr(DetectAddressHead *gh, DetectAddress *new) { DetectAddress *head = NULL; if (new->flags & ADDRESS_FLAG_ANY) head = gh->any_head; else if (new->ip.family == AF_INET) head = gh->ipv4_head; else if (new->ip.family == AF_INET6) head = gh->ipv6_head; return head; } /** * \brief Same as DetectAddressInsert, but then for inserting a address group * object. This also makes sure SigGroupContainer lists are handled * correctly. * * \param de_ctx Pointer to the detection engine context. * \param gh Pointer to the DetectAddressHead list to which it has to * be inserted. * \param new Pointer to the DetectAddress, that has to be inserted. * * \retval 1 On successfully inserting it. * \retval -1 On error. * \retval 0 Not inserted, memory of new is freed. */ int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, DetectAddress *new) { DetectAddress *head = NULL; DetectAddress *cur = NULL; DetectAddress *c = NULL; int r = 0; if (new == NULL) return 0; BUG_ON(new->ip.family == 0 && !(new->flags & ADDRESS_FLAG_ANY)); /* get our head ptr based on the address we want to insert */ head = GetHeadPtr(gh, new); /* see if it already exists or overlaps with existing ag's */ if (head != NULL) { cur = NULL; for (cur = head; cur != NULL; cur = cur->next) { r = DetectAddressCmp(new, cur); BUG_ON(r == ADDRESS_ER); /* if so, handle that */ if (r == ADDRESS_EQ) { /* exact overlap/match */ if (cur != new) { DetectPort *port = new->port; for ( ; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &cur->port, port); SigGroupHeadCopySigs(de_ctx, new->sh, &cur->sh); cur->cnt += new->cnt; DetectAddressFree(new); return 0; } return 1; } else if (r == ADDRESS_GT) { /* only add it now if we are bigger than the last group. * Otherwise we'll handle it later. */ if (cur->next == NULL) { /* put in the list */ new->prev = cur; cur->next = new; return 1; } } else if (r == ADDRESS_LT) { /* see if we need to insert the ag anywhere put in the list */ if (cur->prev != NULL) cur->prev->next = new; new->prev = cur->prev; new->next = cur; cur->prev = new; /* update head if required */ if (head == cur) { head = new; if (SetHeadPtr(gh, head) < 0) goto error; } return 1; /* alright, those were the simple cases, lets handle the more * complex ones now */ } else if (r == ADDRESS_ES) { c = NULL; r = DetectAddressCut(de_ctx, cur, new, &c); if (r == -1) goto error; DetectAddressInsert(de_ctx, gh, new); if (c != NULL) DetectAddressInsert(de_ctx, gh, c); return 1; } else if (r == ADDRESS_EB) { c = NULL; r = DetectAddressCut(de_ctx, cur, new, &c); if (r == -1) goto error; DetectAddressInsert(de_ctx, gh, new); if (c != NULL) DetectAddressInsert(de_ctx, gh, c); return 1; } else if (r == ADDRESS_LE) { c = NULL; r = DetectAddressCut(de_ctx, cur, new, &c); if (r == -1) goto error; DetectAddressInsert(de_ctx, gh, new); if (c != NULL) DetectAddressInsert(de_ctx, gh, c); return 1; } else if (r == ADDRESS_GE) { c = NULL; r = DetectAddressCut(de_ctx, cur,new,&c); if (r == -1) goto error; DetectAddressInsert(de_ctx, gh, new); if (c != NULL) DetectAddressInsert(de_ctx, gh, c); return 1; } } /* head is NULL, so get a group and set head to it */ } else { head = new; if (SetHeadPtr(gh, head) < 0) { SCLogDebug("SetHeadPtr failed"); goto error; } } return 1; error: /* XXX */ return -1; } /** * \brief Join two addresses groups together. * * \param de_ctx Pointer to the detection engine context. * \param target Pointer to the target address group. * \param source Pointer to the source address group. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressJoin(DetectEngineCtx *de_ctx, DetectAddress *target, DetectAddress *source) { DetectPort *port = NULL; if (target == NULL || source == NULL) return -1; if (target->ip.family != source->ip.family) return -1; target->cnt += source->cnt; SigGroupHeadCopySigs(de_ctx, source->sh, &target->sh); port = source->port; for ( ; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &target->port, port); if (target->ip.family == AF_INET) return DetectAddressJoinIPv4(de_ctx, target, source); else if (target->ip.family == AF_INET6) return DetectAddressJoinIPv6(de_ctx, target, source); return -1; } /** * \internal * \brief Creates a cidr ipv6 netblock, based on the cidr netblock value. * * For example if we send a cidr of 7 as argument, an ipv6 address * mask of the value FE:00:00:00:00:00:00:00 is created and updated * in the argument struct in6_addr *in6. * * \todo I think for the final section: while (cidr > 0), we can simply * replace it with a * if (cidr > 0) { * in6->s6_addr[i] = -1 << (8 - cidr); * * \param cidr The value of the cidr. * \param in6 Pointer to an ipv6 address structure(struct in6_addr) which will * hold the cidr netblock result. */ static void DetectAddressParseIPv6CIDR(int cidr, struct in6_addr *in6) { int i = 0; memset(in6, 0, sizeof(struct in6_addr)); while (cidr > 8) { in6->s6_addr[i] = 0xff; cidr -= 8; i++; } while (cidr > 0) { in6->s6_addr[i] |= 0x80; if (--cidr > 0) in6->s6_addr[i] = in6->s6_addr[i] >> 1; } return; } /** * \internal * \brief Parses an ipv4/ipv6 address string and updates the result into the * DetectAddress instance sent as the argument. * * \param dd Pointer to the DetectAddress instance which should be updated with * the address range details from the parsed ip string. * \param str Pointer to address string that has to be parsed. * * \retval 0 On successfully parsing the address string. * \retval -1 On failure. */ int DetectAddressParseString(DetectAddress *dd, char *str) { char *ip = NULL; char *ip2 = NULL; char *mask = NULL; int r = 0; while (*str != '\0' && *str == ' ') str++; char *ipdup = SCStrdup(str); if (unlikely(ipdup == NULL)) return -1; SCLogDebug("str %s", str); /* first handle 'any' */ if (strcasecmp(str, "any") == 0) { dd->flags |= ADDRESS_FLAG_ANY; SCFree(ipdup); SCLogDebug("address is \'any\'"); return 0; } /* we dup so we can put a nul-termination in it later */ ip = ipdup; /* handle the negation case */ if (ip[0] == '!') { dd->flags |= ADDRESS_FLAG_NOT; ip++; } /* see if the address is an ipv4 or ipv6 address */ if ((strchr(str, ':')) == NULL) { /* IPv4 Address */ struct in_addr in; dd->ip.family = AF_INET; if ((mask = strchr(ip, '/')) != NULL) { /* 1.2.3.4/xxx format (either dotted or cidr notation */ ip[mask - ip] = '\0'; mask++; uint32_t ip4addr = 0; uint32_t netmask = 0; size_t u = 0; if ((strchr (mask, '.')) == NULL) { /* 1.2.3.4/24 format */ for (u = 0; u < strlen(mask); u++) { if(!isdigit((unsigned char)mask[u])) goto error; } int cidr = atoi(mask); if (cidr < 0 || cidr > 32) goto error; netmask = CIDRGet(cidr); } else { /* 1.2.3.4/255.255.255.0 format */ r = inet_pton(AF_INET, mask, &in); if (r <= 0) goto error; netmask = in.s_addr; } r = inet_pton(AF_INET, ip, &in); if (r <= 0) goto error; ip4addr = in.s_addr; dd->ip.addr_data32[0] = dd->ip2.addr_data32[0] = ip4addr & netmask; dd->ip2.addr_data32[0] |=~ netmask; } else if ((ip2 = strchr(ip, '-')) != NULL) { /* 1.2.3.4-1.2.3.6 range format */ ip[ip2 - ip] = '\0'; ip2++; r = inet_pton(AF_INET, ip, &in); if (r <= 0) goto error; dd->ip.addr_data32[0] = in.s_addr; r = inet_pton(AF_INET, ip2, &in); if (r <= 0) goto error; dd->ip2.addr_data32[0] = in.s_addr; /* a > b is illegal, a = b is ok */ if (ntohl(dd->ip.addr_data32[0]) > ntohl(dd->ip2.addr_data32[0])) goto error; } else { /* 1.2.3.4 format */ r = inet_pton(AF_INET, ip, &in); if (r <= 0) goto error; /* single host */ dd->ip.addr_data32[0] = in.s_addr; dd->ip2.addr_data32[0] = in.s_addr; } } else { /* IPv6 Address */ struct in6_addr in6, mask6; uint32_t ip6addr[4], netmask[4]; dd->ip.family = AF_INET6; if ((mask = strchr(ip, '/')) != NULL) { ip[mask - ip] = '\0'; mask++; r = inet_pton(AF_INET6, ip, &in6); if (r <= 0) goto error; memcpy(&ip6addr, &in6.s6_addr, sizeof(ip6addr)); DetectAddressParseIPv6CIDR(atoi(mask), &mask6); memcpy(&netmask, &mask6.s6_addr, sizeof(netmask)); dd->ip2.addr_data32[0] = dd->ip.addr_data32[0] = ip6addr[0] & netmask[0]; dd->ip2.addr_data32[1] = dd->ip.addr_data32[1] = ip6addr[1] & netmask[1]; dd->ip2.addr_data32[2] = dd->ip.addr_data32[2] = ip6addr[2] & netmask[2]; dd->ip2.addr_data32[3] = dd->ip.addr_data32[3] = ip6addr[3] & netmask[3]; dd->ip2.addr_data32[0] |=~ netmask[0]; dd->ip2.addr_data32[1] |=~ netmask[1]; dd->ip2.addr_data32[2] |=~ netmask[2]; dd->ip2.addr_data32[3] |=~ netmask[3]; } else if ((ip2 = strchr(ip, '-')) != NULL) { /* 2001::1-2001::4 range format */ ip[ip2 - ip] = '\0'; ip2++; r = inet_pton(AF_INET6, ip, &in6); if (r <= 0) goto error; memcpy(&dd->ip.address, &in6.s6_addr, sizeof(ip6addr)); r = inet_pton(AF_INET6, ip2, &in6); if (r <= 0) goto error; memcpy(&dd->ip2.address, &in6.s6_addr, sizeof(ip6addr)); /* a > b is illegal, a=b is ok */ if (AddressIPv6Gt(&dd->ip, &dd->ip2)) goto error; } else { r = inet_pton(AF_INET6, ip, &in6); if (r <= 0) goto error; memcpy(&dd->ip.address, &in6.s6_addr, sizeof(dd->ip.address)); memcpy(&dd->ip2.address, &in6.s6_addr, sizeof(dd->ip2.address)); } } SCFree(ipdup); BUG_ON(dd->ip.family == 0); return 0; error: SCFree(ipdup); return -1; } /** * \internal * \brief Simply parse an address and return a DetectAddress instance containing * the address ranges of the parsed ip addressstring * * \param str Pointer to a character string containing the ip address * * \retval dd Pointer to the DetectAddress instance containing the address * range details from the parsed ip string */ static DetectAddress *DetectAddressParseSingle(char *str) { DetectAddress *dd; SCLogDebug("str %s", str); dd = DetectAddressInit(); if (dd == NULL) goto error; if (DetectAddressParseString(dd, str) < 0) { SCLogDebug("AddressParse failed"); goto error; } return dd; error: if (dd != NULL) DetectAddressFree(dd); return NULL; } /** * \brief Setup a single address string, parse it and add the resulting * Address-Range(s) to the AddessHead(DetectAddressHead instance). * * \param gh Pointer to the Address-Head(DetectAddressHead) to which the * resulting Address-Range(s) from the parsed ip string has to * be added. * \param s Pointer to the ip address string to be parsed. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressSetup(DetectAddressHead *gh, char *s) { DetectAddress *ad = NULL; DetectAddress *ad2 = NULL; int r = 0; char any = FALSE; SCLogDebug("gh %p, s %s", gh, s); /* parse the address */ ad = DetectAddressParseSingle(s); if (ad == NULL) { SCLogError(SC_ERR_ADDRESS_ENGINE_GENERIC, "failed to parse address \"%s\"", s); return -1; } if (ad->flags & ADDRESS_FLAG_ANY) any = TRUE; /* handle the not case, we apply the negation then insert the part(s) */ if (ad->flags & ADDRESS_FLAG_NOT) { ad2 = NULL; if (DetectAddressCutNot(ad, &ad2) < 0) { SCLogDebug("DetectAddressCutNot failed"); goto error; } /* normally a 'not' will result in two ad's unless the 'not' is on the start or end * of the address space (e.g. 0.0.0.0 or 255.255.255.255). */ if (ad2 != NULL) { if (DetectAddressInsert(NULL, gh, ad2) < 0) { SCLogDebug("DetectAddressInsert failed"); goto error; } } } r = DetectAddressInsert(NULL, gh, ad); if (r < 0) { SCLogDebug("DetectAddressInsert failed"); goto error; } SCLogDebug("r %d",r); /* if any, insert 0.0.0.0/0 and ::/0 as well */ if (r == 1 && any == TRUE) { SCLogDebug("adding 0.0.0.0/0 and ::/0 as we\'re handling \'any\'"); ad = DetectAddressParseSingle("0.0.0.0/0"); if (ad == NULL) goto error; BUG_ON(ad->ip.family == 0); if (DetectAddressInsert(NULL, gh, ad) < 0) { SCLogDebug("DetectAddressInsert failed"); goto error; } ad = DetectAddressParseSingle("::/0"); if (ad == NULL) goto error; BUG_ON(ad->ip.family == 0); if (DetectAddressInsert(NULL, gh, ad) < 0) { SCLogDebug("DetectAddressInsert failed"); goto error; } } return 0; error: SCLogError(SC_ERR_ADDRESS_ENGINE_GENERIC, "DetectAddressSetup error"); /* XXX cleanup */ return -1; } /** * \brief Parses an address string and updates the 2 address heads with the * address data. * * \todo We don't seem to be handling negated cases, like [addr,![!addr,addr]], * since we pass around negate without keeping a count of ! with depth. * Can solve this by keeping a count of the negations with depth, so that * an even no of negations would count as no negation and an odd no of * negations would count as a negation. * * \param gh Pointer to the address head that should hold address ranges * that are not negated. * \param ghn Pointer to the address head that should hold address ranges * that are negated. * \param s Pointer to the character string holding the address to be * parsed. * \param negate Flag that indicates if the receieved address string is negated * or not. 0 if it is not, 1 it it is. * * \retval 0 On successfully parsing. * \retval -1 On failure. */ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, int negate) { size_t x = 0; size_t u = 0; int o_set = 0, n_set = 0, d_set = 0; int depth = 0; size_t size = strlen(s); char address[8196] = ""; char *rule_var_address = NULL; char *temp_rule_var_address = NULL; SCLogDebug("s %s negate %s", s, negate ? "true" : "false"); for (u = 0, x = 0; u < size && x < sizeof(address); u++) { if (x == (sizeof(address) - 1)) { SCLogError(SC_ERR_ADDRESS_ENGINE_GENERIC, "Hit the address buffer" " limit for the supplied address. Invalidating sig. " "Please file a bug report on this."); goto error; } address[x] = s[u]; x++; if (!o_set && s[u] == '!') { n_set = 1; x--; } else if (s[u] == '[') { if (!o_set) { o_set = 1; x = 0; } depth++; } else if (s[u] == ']') { if (depth == 1) { address[x - 1] = '\0'; x = 0; if (DetectAddressParse2(gh, ghn, address, (negate + n_set) % 2) < 0) goto error; n_set = 0; } depth--; } else if (depth == 0 && s[u] == ',') { if (o_set == 1) { o_set = 0; } else if (d_set == 1) { address[x - 1] = '\0'; rule_var_address = SCRuleVarsGetConfVar(address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; if (strlen(rule_var_address) == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "variable %s resolved " "to nothing. This is likely a misconfiguration. " "Note that a negated address needs to be quoted, " "\"!$HOME_NET\" instead of !$HOME_NET. See issue #295.", s); goto error; } temp_rule_var_address = rule_var_address; if ((negate + n_set) % 2) { temp_rule_var_address = SCMalloc(strlen(rule_var_address) + 3); if (unlikely(temp_rule_var_address == NULL)) goto error; snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } DetectAddressParse2(gh, ghn, temp_rule_var_address, (negate + n_set) % 2); d_set = 0; n_set = 0; if (temp_rule_var_address != rule_var_address) SCFree(temp_rule_var_address); } else { address[x - 1] = '\0'; if (!((negate + n_set) % 2)) { if (DetectAddressSetup(gh, address) < 0) goto error; } else { if (DetectAddressSetup(ghn, address) < 0) goto error; } n_set = 0; } x = 0; } else if (depth == 0 && s[u] == '$') { d_set = 1; } else if (depth == 0 && u == size - 1) { if (x == sizeof(address)) { address[x - 1] = '\0'; } else { address[x] = '\0'; } x = 0; if (d_set == 1) { rule_var_address = SCRuleVarsGetConfVar(address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; if (strlen(rule_var_address) == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "variable %s resolved " "to nothing. This is likely a misconfiguration. " "Note that a negated address needs to be quoted, " "\"!$HOME_NET\" instead of !$HOME_NET. See issue #295.", s); goto error; } temp_rule_var_address = rule_var_address; if ((negate + n_set) % 2) { temp_rule_var_address = SCMalloc(strlen(rule_var_address) + 3); if (unlikely(temp_rule_var_address == NULL)) goto error; snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } DetectAddressParse2(gh, ghn, temp_rule_var_address, (negate + n_set) % 2); d_set = 0; if (temp_rule_var_address != rule_var_address) SCFree(temp_rule_var_address); } else { if (!((negate + n_set) % 2)) { if (DetectAddressSetup(gh, address) < 0) goto error; } else { if (DetectAddressSetup(ghn, address) < 0) goto error; } } n_set = 0; } } if (depth > 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "not every address block was " "properly closed in \"%s\", %d missing closing brackets (]). " "Note: problem might be in a variable.", s, depth); goto error; } else if (depth < 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "not every address block was " "properly opened in \"%s\", %d missing opening brackets ([). " "Note: problem might be in a variable.", s, depth*-1); goto error; } return 0; error: return -1; } /** * \internal * \brief See if the addresses and ranges in an address head cover the * entire ip space. * * \param gh Pointer to the DetectAddressHead to check. * * \retval 0 No. * \retval 1 Yes. * * \todo do the same for IPv6 */ static int DetectAddressIsCompleteIPSpace(DetectAddressHead *gh) { int r = DetectAddressIsCompleteIPSpaceIPv4(gh->ipv4_head); if (r == 1) return 1; return 0; } /** * \brief Merge the + and the - list (+ positive match, - 'not' match) * * \param gh Pointer to the address head containing the non-NOT groups. * \param ghn Pointer to the address head containing the NOT groups. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressMergeNot(DetectAddressHead *gh, DetectAddressHead *ghn) { DetectAddress *ad; DetectAddress *ag, *ag2; int r = 0; SCLogDebug("gh->ipv4_head %p, ghn->ipv4_head %p", gh->ipv4_head, ghn->ipv4_head); /* check if the negated list covers the entire ip space. If so * the user screwed up the rules/vars. */ if (DetectAddressIsCompleteIPSpace(ghn) == 1) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Complete IP space negated. " "Rule address range is NIL. Probably have a !any or " "an address range that supplies a NULL address range"); goto error; } /* step 0: if the gh list is empty, but the ghn list isn't we have a pure * not thingy. In that case we add a 0.0.0.0/0 first. */ if (gh->ipv4_head == NULL && ghn->ipv4_head != NULL) { r = DetectAddressSetup(gh, "0.0.0.0/0"); if (r < 0) { SCLogDebug("DetectAddressSetup for 0.0.0.0/0 failed"); goto error; } } /* ... or ::/0 for ipv6 */ if (gh->ipv6_head == NULL && ghn->ipv6_head != NULL) { r = DetectAddressSetup(gh, "::/0"); if (r < 0) { SCLogDebug("DetectAddressSetup for ::/0 failed"); goto error; } } /* step 1: insert our ghn members into the gh list */ for (ag = ghn->ipv4_head; ag != NULL; ag = ag->next) { /* work with a copy of the ad so we can easily clean up the ghn group * later. */ ad = DetectAddressCopy(ag); if (ad == NULL) { SCLogDebug("DetectAddressCopy failed"); goto error; } r = DetectAddressInsert(NULL, gh, ad); if (r < 0) { SCLogDebug("DetectAddressInsert failed"); goto error; } } /* ... and the same for ipv6 */ for (ag = ghn->ipv6_head; ag != NULL; ag = ag->next) { /* work with a copy of the ad so we can easily clean up the ghn group * later. */ ad = DetectAddressCopy(ag); if (ad == NULL) { SCLogDebug("DetectAddressCopy failed"); goto error; } r = DetectAddressInsert(NULL, gh, ad); if (r < 0) { SCLogDebug("DetectAddressInsert failed"); goto error; } } /* step 2: pull the address blocks that match our 'not' blocks */ for (ag = ghn->ipv4_head; ag != NULL; ag = ag->next) { SCLogDebug("ag %p", ag); DetectAddressPrint(ag); for (ag2 = gh->ipv4_head; ag2 != NULL; ) { SCLogDebug("ag2 %p", ag2); DetectAddressPrint(ag2); r = DetectAddressCmp(ag, ag2); /* XXX more ??? */ if (r == ADDRESS_EQ || r == ADDRESS_EB) { if (ag2->prev == NULL) gh->ipv4_head = ag2->next; else ag2->prev->next = ag2->next; if (ag2->next != NULL) ag2->next->prev = ag2->prev; /* store the next ptr and remove the group */ DetectAddress *next_ag2 = ag2->next; DetectAddressFree(ag2); ag2 = next_ag2; } else { ag2 = ag2->next; } } } /* ... and the same for ipv6 */ for (ag = ghn->ipv6_head; ag != NULL; ag = ag->next) { for (ag2 = gh->ipv6_head; ag2 != NULL; ) { r = DetectAddressCmp(ag, ag2); if (r == ADDRESS_EQ || r == ADDRESS_EB) { /* XXX more ??? */ if (ag2->prev == NULL) gh->ipv6_head = ag2->next; else ag2->prev->next = ag2->next; if (ag2->next != NULL) ag2->next->prev = ag2->prev; /* store the next ptr and remove the group */ DetectAddress *next_ag2 = ag2->next; DetectAddressFree(ag2); ag2 = next_ag2; } else { ag2 = ag2->next; } } } /* if the result is that we have no addresses we return error */ if (gh->ipv4_head == NULL && gh->ipv6_head == NULL) { SCLogDebug("no addresses left after merging addresses and not-addresses"); goto error; } return 0; error: return -1; } int DetectAddressTestConfVars(void) { SCLogDebug("Testing address conf vars for any misconfigured values"); ConfNode *address_vars_node = ConfGetNode("vars.address-groups"); if (address_vars_node == NULL) { return 0; } ConfNode *seq_node; TAILQ_FOREACH(seq_node, &address_vars_node->head, next) { SCLogDebug("Testing %s - %s", seq_node->name, seq_node->val); DetectAddressHead *gh = DetectAddressHeadInit(); if (gh == NULL) { goto error; } DetectAddressHead *ghn = DetectAddressHeadInit(); if (ghn == NULL) { goto error; } if (seq_node->val == NULL) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Address var \"%s\" probably has a sequence(something " "in brackets) value set without any quotes. Please " "quote it using \"..\".", seq_node->name); goto error; } int r = DetectAddressParse2(gh, ghn, seq_node->val, /* start with negate no */0); if (r < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "failed to parse address var \"%s\" with value \"%s\". " "Please check it's syntax", seq_node->name, seq_node->val); goto error; } if (DetectAddressIsCompleteIPSpace(ghn)) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "address var - \"%s\" has the complete IP space negated " "with it's value \"%s\". Rule address range is NIL. " "Probably have a !any or an address range that supplies " "a NULL address range", seq_node->name, seq_node->val); goto error; } if (gh != NULL) DetectAddressHeadFree(gh); if (ghn != NULL) DetectAddressHeadFree(ghn); } return 0; error: return -1; } /** * \brief Parses an address group sent as a character string and updates the * DetectAddressHead sent as the argument with the relevant address * ranges from the parsed string. * * \param gh Pointer to the DetectAddressHead. * \param str Pointer to the character string containing the address group * that has to be parsed. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressParse(DetectAddressHead *gh, char *str) { int r; DetectAddressHead *ghn = NULL; SCLogDebug("gh %p, str %s", gh, str); if (str == NULL) { SCLogDebug("DetectAddressParse can not be run with NULL address"); goto error; } ghn = DetectAddressHeadInit(); if (ghn == NULL) { SCLogDebug("DetectAddressHeadInit for ghn failed"); goto error; } r = DetectAddressParse2(gh, ghn, str, /* start with negate no */0); if (r < 0) { SCLogDebug("DetectAddressParse2 returned %d", r); goto error; } SCLogDebug("gh->ipv4_head %p, ghn->ipv4_head %p", gh->ipv4_head, ghn->ipv4_head); /* merge the 'not' address groups */ if (DetectAddressMergeNot(gh, ghn) < 0) { SCLogDebug("DetectAddressMergeNot failed"); goto error; } /* free the temp negate head */ DetectAddressHeadFree(ghn); return 0; error: if (ghn != NULL) DetectAddressHeadFree(ghn); return -1; } /** * \brief Returns a new instance of DetectAddressHead. * * \retval gh Pointer to the new instance of DetectAddressHead. */ DetectAddressHead *DetectAddressHeadInit(void) { DetectAddressHead *gh = SCMalloc(sizeof(DetectAddressHead)); if (unlikely(gh == NULL)) return NULL; memset(gh, 0, sizeof(DetectAddressHead)); #ifdef DEBUG detect_address_group_head_init_cnt++; detect_address_group_head_memory += sizeof(DetectAddressHead); #endif return gh; } /** * \brief Cleans a DetectAddressHead. The functions frees the 3 address * group heads(any, ipv4 and ipv6) inside the DetectAddressHead * instance. * * \param gh Pointer to the DetectAddressHead instance that has to be * cleaned. */ void DetectAddressHeadCleanup(DetectAddressHead *gh) { if (gh != NULL) { if (gh->any_head != NULL) { DetectAddressCleanupList(gh->any_head); gh->any_head = NULL; } if (gh->ipv4_head != NULL) { DetectAddressCleanupList(gh->ipv4_head); gh->ipv4_head = NULL; } if (gh->ipv6_head != NULL) { DetectAddressCleanupList(gh->ipv6_head); gh->ipv6_head = NULL; } } return; } /** * \brief Frees a DetectAddressHead instance. * * \param gh Pointer to the DetectAddressHead instance to be freed. */ void DetectAddressHeadFree(DetectAddressHead *gh) { if (gh != NULL) { DetectAddressHeadCleanup(gh); SCFree(gh); #ifdef DEBUG detect_address_group_head_free_cnt++; detect_address_group_head_memory -= sizeof(DetectAddressHead); #endif } return; } /** * \brief Dispatcher function that calls the ipv4 and ipv6 address cut functions. * Have a look at DetectAddressCutIPv4() and DetectAddressCutIPv6() for * explanations on what these functions do. * * \param de_ctx Pointer to the DetectEngineCtx. * \param a Pointer the the first address to be cut. * \param b Pointer to the second address to be cut. * \param c Pointer to a pointer to a third DetectAddressData, in case the * ranges from a and b, demand a third address range. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressCut(DetectEngineCtx *de_ctx, DetectAddress *a, DetectAddress *b, DetectAddress **c) { if (a->ip.family == AF_INET) return DetectAddressCutIPv4(de_ctx, a, b, c); else if (a->ip.family == AF_INET6) return DetectAddressCutIPv6(de_ctx, a, b, c); return -1; } /** * \brief Cuts a negated address range with respect to the entire ip range, and * supplies with the address range that doesn't belong to the negated * address range. * * There are 2 cases here - * * The first case includes the address being located at the extreme ends * of the ip space, in which we get a single range. * For example: !0.0.0.0, in which case we get 0.0.0.1 to 255.255.255.255. * * The second case includes the address not present at either of the * ip space extremes, in which case we get 2 ranges. The second range * would be supplied back with the argument "b" supplied to this function. * For example: !10.20.30.40, in which case we the 2 ranges, 0.0.0.0 - * 10.20.30.39 and 10.20.30.41 - 255.255.255.255. * * The above negation cases can similarly be extended to ranges, i.e. * ![0.0.0.0 - 10.20.30.40], ![255.255.240.240 - 255.255.255.255] and * ![10.20.30.40 - 10.20.30.50]. * * * \param a Pointer to the DetectAddressData instance, that contains the negated * address range that has to be cut. * \param b Pointer to a pointer to a DetectAddressData instance, that should be * filled with the address range, if the argument "a", doesn't fall at * the extreme ends of the ip address space. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressCutNot(DetectAddress *a, DetectAddress **b) { if (a->ip.family == AF_INET) return DetectAddressCutNotIPv4(a, b); else if (a->ip.family == AF_INET6) return DetectAddressCutNotIPv6(a, b); return -1; } /** * \brief Used to compare 2 address ranges. * * \param a Pointer to the first DetectAddressData to be compared. * \param b Pointer to the second DetectAddressData to be compared. */ int DetectAddressCmp(DetectAddress *a, DetectAddress *b) { if (a->ip.family != b->ip.family) return ADDRESS_ER; /* check any */ if ((a->flags & ADDRESS_FLAG_ANY) && (b->flags & ADDRESS_FLAG_ANY)) return ADDRESS_EQ; else if (a->ip.family == AF_INET) return DetectAddressCmpIPv4(a, b); else if (a->ip.family == AF_INET6) return DetectAddressCmpIPv6(a, b); return ADDRESS_ER; } /** * \brief Match a packets address against a signatures addrs array * * \param addrs array of DetectMatchAddressIPv4's * \param addrs_cnt array size in members * \param a packets address * * \retval 0 no match * \retval 1 match * * \note addresses in addrs are in host order * * \todo array should be ordered, so we can break out of the loop */ int DetectAddressMatchIPv4(DetectMatchAddressIPv4 *addrs, uint16_t addrs_cnt, Address *a) { SCEnter(); if (addrs == NULL || addrs_cnt == 0) { SCReturnInt(0); } uint16_t idx; for (idx = 0; idx < addrs_cnt; idx++) { if (ntohl(a->addr_data32[0]) >= addrs[idx].ip && ntohl(a->addr_data32[0]) <= addrs[idx].ip2) { SCReturnInt(1); } } SCReturnInt(0); } /** * \brief Match a packets address against a signatures addrs array * * \param addrs array of DetectMatchAddressIPv6's * \param addrs_cnt array size in members * \param a packets address * * \retval 0 no match * \retval 1 match * * \note addresses in addrs are in host order * * \todo array should be ordered, so we can break out of the loop */ int DetectAddressMatchIPv6(DetectMatchAddressIPv6 *addrs, uint16_t addrs_cnt, Address *a) { SCEnter(); if (addrs == NULL || addrs_cnt == 0) { SCReturnInt(0); } uint16_t idx; for (idx = 0; idx < addrs_cnt; idx++) { if ((ntohl(a->addr_data32[0]) >= addrs[idx].ip[0] && ntohl(a->addr_data32[0]) <= addrs[idx].ip2[0]) && (ntohl(a->addr_data32[1]) >= addrs[idx].ip[1] && ntohl(a->addr_data32[1]) <= addrs[idx].ip2[1]) && (ntohl(a->addr_data32[2]) >= addrs[idx].ip[2] && ntohl(a->addr_data32[2]) <= addrs[idx].ip2[2]) && (ntohl(a->addr_data32[3]) >= addrs[idx].ip[3] && ntohl(a->addr_data32[3]) <= addrs[idx].ip2[3])) { SCReturnInt(1); } } SCReturnInt(0); } /** * \brief Check if a particular address(ipv4 or ipv6) matches the address * range in the DetectAddress instance. * * We basically check that the address falls inbetween the address * range in DetectAddress. * * \param dd Pointer to the DetectAddress instance. * \param a Pointer to an Address instance. * * \param 1 On a match. * \param 0 On no match. */ int DetectAddressMatch(DetectAddress *dd, Address *a) { SCEnter(); if (dd->ip.family != a->family) { SCReturnInt(0); } //DetectAddressPrint(dd); //AddressDebugPrint(a); switch (a->family) { case AF_INET: /* XXX figure out a way to not need to do this ntohl if we switch to * Address inside DetectAddressData we can do uint8_t checks */ if (ntohl(a->addr_data32[0]) >= ntohl(dd->ip.addr_data32[0]) && ntohl(a->addr_data32[0]) <= ntohl(dd->ip2.addr_data32[0])) { SCReturnInt(1); } else { SCReturnInt(0); } break; case AF_INET6: if (AddressIPv6Ge(a, &dd->ip) == 1 && AddressIPv6Le(a, &dd->ip2) == 1) { SCReturnInt(1); } else { SCReturnInt(0); } break; default: SCLogDebug("What other address type can we have :-/"); break; } SCReturnInt(0); } /** * \brief Prints the address data held by the DetectAddress. If the * address data family is any, we print "ANY". If the address data * family is IPv4, we print the the ipv4 address and mask, and if the * address data family is IPv6, we print the ipv6 address and mask. * * \param ad Pointer to the DetectAddress instance to be printed. */ void DetectAddressPrint(DetectAddress *gr) { if (gr == NULL) return; if (gr->flags & ADDRESS_FLAG_ANY) { SCLogDebug("ANY"); } else if (gr->ip.family == AF_INET) { struct in_addr in; char ip[16], mask[16]; memcpy(&in, &gr->ip.addr_data32[0], sizeof(in)); PrintInet(AF_INET, &in, ip, sizeof(ip)); memcpy(&in, &gr->ip2.addr_data32[0], sizeof(in)); PrintInet(AF_INET, &in, mask, sizeof(mask)); SCLogDebug("%s/%s", ip, mask); // printf("%s/%s", ip, mask); } else if (gr->ip.family == AF_INET6) { struct in6_addr in6; char ip[66], mask[66]; memcpy(&in6, &gr->ip.addr_data32, sizeof(in6)); PrintInet(AF_INET6, &in6, ip, sizeof(ip)); memcpy(&in6, &gr->ip2.addr_data32, sizeof(in6)); PrintInet(AF_INET6, &in6, mask, sizeof(mask)); SCLogDebug("%s/%s", ip, mask); // printf("%s/%s", ip, mask); } return; } /** * \brief Find the group matching address in a group head. * * \param gh Pointer to the address group head(DetectAddressHead instance). * \param a Pointer to an Address instance. * * \retval g On success pointer to an DetectAddress if we find a match * for the Address "a", in the DetectAddressHead "gh". */ DetectAddress *DetectAddressLookupInHead(DetectAddressHead *gh, Address *a) { SCEnter(); DetectAddress *g; if (gh == NULL) { SCReturnPtr(NULL, "DetectAddress"); } /* XXX should we really do this check every time we run this function? */ if (a->family == AF_INET) { SCLogDebug("IPv4"); g = gh->ipv4_head; } else if (a->family == AF_INET6) { SCLogDebug("IPv6"); g = gh->ipv6_head; } else { SCLogDebug("ANY"); g = gh->any_head; } for ( ; g != NULL; g = g->next) { if (DetectAddressMatch(g,a) == 1) { SCReturnPtr(g, "DetectAddress"); } } SCReturnPtr(NULL, "DetectAddress"); } /********************************Unittests*************************************/ #ifdef UNITTESTS int AddressTestParse01(void) { DetectAddress *dd = DetectAddressParseSingle("1.2.3.4"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse02(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("1.2.3.4"); if (dd) { if (dd->ip2.addr_data32[0] != ntohl(16909060) || dd->ip.addr_data32[0] != ntohl(16909060)) { result = 0; } printf("ip %"PRIu32", ip2 %"PRIu32"\n", dd->ip.addr_data32[0], dd->ip2.addr_data32[0]); DetectAddressFree(dd); return result; } return 0; } int AddressTestParse03(void) { DetectAddress *dd = DetectAddressParseSingle("1.2.3.4/255.255.255.0"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse04(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("1.2.3.4/255.255.255.0"); if (dd) { if (dd->ip.addr_data32[0] != ntohl(16909056)|| dd->ip2.addr_data32[0] != ntohl(16909311)) { result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse05(void) { DetectAddress *dd = DetectAddressParseSingle("1.2.3.4/24"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse06(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("1.2.3.4/24"); if (dd) { if (dd->ip2.addr_data32[0] != ntohl(16909311) || dd->ip.addr_data32[0] != ntohl(16909056)) { result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse07(void) { DetectAddress *dd = DetectAddressParseSingle("2001::/3"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse08(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("2001::/3"); if (dd) { if (dd->ip.addr_data32[0] != ntohl(536870912) || dd->ip.addr_data32[1] != 0x00000000 || dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || dd->ip2.addr_data32[0] != ntohl(1073741823) || dd->ip2.addr_data32[1] != 0xFFFFFFFF || dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { DetectAddressPrint(dd); result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse09(void) { DetectAddress *dd = DetectAddressParseSingle("2001::1/128"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse10(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("2001::/128"); if (dd) { if (dd->ip.addr_data32[0] != ntohl(536936448) || dd->ip.addr_data32[1] != 0x00000000 || dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || dd->ip2.addr_data32[0] != ntohl(536936448) || dd->ip2.addr_data32[1] != 0x00000000 || dd->ip2.addr_data32[2] != 0x00000000 || dd->ip2.addr_data32[3] != 0x00000000) { DetectAddressPrint(dd); result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse11(void) { DetectAddress *dd = DetectAddressParseSingle("2001::/48"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse12(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("2001::/48"); if (dd) { if (dd->ip.addr_data32[0] != ntohl(536936448) || dd->ip.addr_data32[1] != 0x00000000 || dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || dd->ip2.addr_data32[0] != ntohl(536936448) || dd->ip2.addr_data32[1] != ntohl(65535) || dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { DetectAddressPrint(dd); result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse13(void) { DetectAddress *dd = DetectAddressParseSingle("2001::/16"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse14(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("2001::/16"); if (dd) { if (dd->ip.addr_data32[0] != ntohl(536936448) || dd->ip.addr_data32[1] != 0x00000000 || dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || dd->ip2.addr_data32[0] != ntohl(537001983) || dd->ip2.addr_data32[1] != 0xFFFFFFFF || dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse15(void) { DetectAddress *dd = DetectAddressParseSingle("2001::/0"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse16(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("2001::/0"); if (dd) { if (dd->ip.addr_data32[0] != 0x00000000 || dd->ip.addr_data32[1] != 0x00000000 || dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse17(void) { DetectAddress *dd = DetectAddressParseSingle("1.2.3.4-1.2.3.6"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse18(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("1.2.3.4-1.2.3.6"); if (dd) { if (dd->ip2.addr_data32[0] != ntohl(16909062) || dd->ip.addr_data32[0] != ntohl(16909060)) { result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse19(void) { DetectAddress *dd = DetectAddressParseSingle("1.2.3.6-1.2.3.4"); if (dd) { DetectAddressFree(dd); return 0; } return 1; } int AddressTestParse20(void) { DetectAddress *dd = DetectAddressParseSingle("2001::1-2001::4"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse21(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("2001::1-2001::4"); if (dd) { if (dd->ip.addr_data32[0] != ntohl(536936448) || dd->ip.addr_data32[1] != 0x00000000 || dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != ntohl(1) || dd->ip2.addr_data32[0] != ntohl(536936448) || dd->ip2.addr_data32[1] != 0x00000000 || dd->ip2.addr_data32[2] != 0x00000000 || dd->ip2.addr_data32[3] != ntohl(4)) { result = 0; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse22(void) { DetectAddress *dd = DetectAddressParseSingle("2001::4-2001::1"); if (dd) { DetectAddressFree(dd); return 0; } return 1; } int AddressTestParse23(void) { DetectAddress *dd = DetectAddressParseSingle("any"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse24(void) { DetectAddress *dd = DetectAddressParseSingle("Any"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse25(void) { DetectAddress *dd = DetectAddressParseSingle("ANY"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse26(void) { int result = 0; DetectAddress *dd = DetectAddressParseSingle("any"); if (dd) { if (dd->flags & ADDRESS_FLAG_ANY) result = 1; DetectAddressFree(dd); return result; } return 0; } int AddressTestParse27(void) { DetectAddress *dd = DetectAddressParseSingle("!192.168.0.1"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse28(void) { int result = 0; DetectAddress *dd = DetectAddressParseSingle("!1.2.3.4"); if (dd) { if (dd->flags & ADDRESS_FLAG_NOT && dd->ip.addr_data32[0] == ntohl(16909060)) { result = 1; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse29(void) { DetectAddress *dd = DetectAddressParseSingle("!1.2.3.0/24"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse30(void) { int result = 0; DetectAddress *dd = DetectAddressParseSingle("!1.2.3.4/24"); if (dd) { if (dd->flags & ADDRESS_FLAG_NOT && dd->ip.addr_data32[0] == ntohl(16909056) && dd->ip2.addr_data32[0] == ntohl(16909311)) { result = 1; } DetectAddressFree(dd); return result; } return 0; } /** * \test make sure !any is rejected */ int AddressTestParse31(void) { DetectAddress *dd = DetectAddressParseSingle("!any"); if (dd) { DetectAddressFree(dd); return 0; } return 1; } int AddressTestParse32(void) { DetectAddress *dd = DetectAddressParseSingle("!2001::1"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse33(void) { int result = 0; DetectAddress *dd = DetectAddressParseSingle("!2001::1"); if (dd) { if (dd->flags & ADDRESS_FLAG_NOT && dd->ip.addr_data32[0] == ntohl(536936448) && dd->ip.addr_data32[1] == 0x00000000 && dd->ip.addr_data32[2] == 0x00000000 && dd->ip.addr_data32[3] == ntohl(1)) { result = 1; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse34(void) { DetectAddress *dd = DetectAddressParseSingle("!2001::/16"); if (dd) { DetectAddressFree(dd); return 1; } return 0; } int AddressTestParse35(void) { int result = 0; DetectAddress *dd = DetectAddressParseSingle("!2001::/16"); if (dd) { if (dd->flags & ADDRESS_FLAG_NOT && dd->ip.addr_data32[0] == ntohl(536936448) && dd->ip.addr_data32[1] == 0x00000000 && dd->ip.addr_data32[2] == 0x00000000 && dd->ip.addr_data32[3] == 0x00000000 && dd->ip2.addr_data32[0] == ntohl(537001983) && dd->ip2.addr_data32[1] == 0xFFFFFFFF && dd->ip2.addr_data32[2] == 0xFFFFFFFF && dd->ip2.addr_data32[3] == 0xFFFFFFFF) { result = 1; } DetectAddressFree(dd); return result; } return 0; } int AddressTestParse36(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("ffff::/16"); if (dd) { if (dd->ip.addr_data32[0] != ntohl(0xFFFF0000) || dd->ip.addr_data32[1] != 0x00000000 || dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { DetectAddressPrint(dd); result = 0; } DetectAddressPrint(dd); DetectAddressFree(dd); return result; } return 0; } int AddressTestParse37(void) { int result = 1; DetectAddress *dd = DetectAddressParseSingle("::/0"); if (dd) { if (dd->ip.addr_data32[0] != 0x00000000 || dd->ip.addr_data32[1] != 0x00000000 || dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { DetectAddressPrint(dd); result = 0; } DetectAddressPrint(dd); DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch01(void) { DetectAddress *dd = NULL; int result = 1; struct in_addr in; Address a; if (inet_pton(AF_INET, "1.2.3.4", &in) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET; a.addr_data32[0] = in.s_addr; dd = DetectAddressParseSingle("1.2.3.4/24"); if (dd) { if (DetectAddressMatch(dd, &a) == 0) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch02(void) { DetectAddress *dd = NULL; int result = 1; struct in_addr in; Address a; if (inet_pton(AF_INET, "1.2.3.127", &in) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET; a.addr_data32[0] = in.s_addr; dd = DetectAddressParseSingle("1.2.3.4/25"); if (dd) { if (DetectAddressMatch(dd, &a) == 0) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch03(void) { DetectAddress *dd = NULL; int result = 1; struct in_addr in; Address a; if (inet_pton(AF_INET, "1.2.3.128", &in) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET; a.addr_data32[0] = in.s_addr; dd = DetectAddressParseSingle("1.2.3.4/25"); if (dd) { if (DetectAddressMatch(dd, &a) == 1) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch04(void) { DetectAddress *dd = NULL; int result = 1; struct in_addr in; Address a; if (inet_pton(AF_INET, "1.2.2.255", &in) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET; a.addr_data32[0] = in.s_addr; dd = DetectAddressParseSingle("1.2.3.4/25"); if (dd) { if (DetectAddressMatch(dd, &a) == 1) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch05(void) { DetectAddress *dd = NULL; int result = 1; struct in_addr in; Address a; if (inet_pton(AF_INET, "1.2.3.4", &in) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET; a.addr_data32[0] = in.s_addr; dd = DetectAddressParseSingle("1.2.3.4/32"); if (dd) { if (DetectAddressMatch(dd, &a) == 0) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch06(void) { DetectAddress *dd = NULL; int result = 1; struct in_addr in; Address a; if (inet_pton(AF_INET, "1.2.3.4", &in) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET; a.addr_data32[0] = in.s_addr; dd = DetectAddressParseSingle("0.0.0.0/0.0.0.0"); if (dd) { if (DetectAddressMatch(dd, &a) == 0) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch07(void) { DetectAddress *dd = NULL; int result = 1; struct in6_addr in6; Address a; if (inet_pton(AF_INET6, "2001::1", &in6) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET6; memcpy(&a.addr_data32, &in6.s6_addr, sizeof(in6.s6_addr)); dd = DetectAddressParseSingle("2001::/3"); if (dd) { if (DetectAddressMatch(dd, &a) == 0) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch08(void) { DetectAddress *dd = NULL; int result = 1; struct in6_addr in6; Address a; if (inet_pton(AF_INET6, "1999:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &in6) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET6; memcpy(&a.addr_data32, &in6.s6_addr, sizeof(in6.s6_addr)); dd = DetectAddressParseSingle("2001::/3"); if (dd) { if (DetectAddressMatch(dd, &a) == 1) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch09(void) { DetectAddress *dd = NULL; int result = 1; struct in6_addr in6; Address a; if (inet_pton(AF_INET6, "2001::2", &in6) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET6; memcpy(&a.addr_data32, &in6.s6_addr, sizeof(in6.s6_addr)); dd = DetectAddressParseSingle("2001::1/128"); if (dd) { if (DetectAddressMatch(dd, &a) == 1) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch10(void) { DetectAddress *dd = NULL; int result = 1; struct in6_addr in6; Address a; if (inet_pton(AF_INET6, "2001::2", &in6) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET6; memcpy(&a.addr_data32, &in6.s6_addr, sizeof(in6.s6_addr)); dd = DetectAddressParseSingle("2001::1/126"); if (dd) { if (DetectAddressMatch(dd, &a) == 0) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestMatch11(void) { DetectAddress *dd = NULL; int result = 1; struct in6_addr in6; Address a; if (inet_pton(AF_INET6, "2001::3", &in6) != 1) return 0; memset(&a, 0, sizeof(Address)); a.family = AF_INET6; memcpy(&a.addr_data32, &in6.s6_addr, sizeof(in6.s6_addr)); dd = DetectAddressParseSingle("2001::1/127"); if (dd) { if (DetectAddressMatch(dd, &a) == 1) result = 0; DetectAddressFree(dd); return result; } return 0; } int AddressTestCmp01(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); if (da == NULL) goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_EQ) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp02(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("192.168.0.0/255.255.0.0"); if (da == NULL) goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_EB) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp03(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); if (da == NULL) goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.0.0"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_ES) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp04(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); if (da == NULL) goto error; db = DetectAddressParseSingle("192.168.1.0/255.255.255.0"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_LT) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp05(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("192.168.1.0/255.255.255.0"); if (da == NULL) goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_GT) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp06(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("192.168.1.0/255.255.0.0"); if (da == NULL) goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.0.0"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_EQ) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmpIPv407(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("192.168.1.0/255.255.255.0"); if (da == NULL) goto error; db = DetectAddressParseSingle("192.168.1.128-192.168.2.128"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_LE) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmpIPv408(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("192.168.1.128-192.168.2.128"); if (da == NULL) goto error; db = DetectAddressParseSingle("192.168.1.0/255.255.255.0"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_GE) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp07(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("2001::/3"); if (da == NULL) goto error; db = DetectAddressParseSingle("2001::1/3"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_EQ) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp08(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("2001::/3"); if (da == NULL) goto error; db = DetectAddressParseSingle("2001::/8"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_EB) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp09(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("2001::/8"); if (da == NULL) goto error; db = DetectAddressParseSingle("2001::/3"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_ES) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp10(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("2001:1:2:3:0:0:0:0/64"); if (da == NULL) goto error; db = DetectAddressParseSingle("2001:1:2:4:0:0:0:0/64"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_LT) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp11(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("2001:1:2:4:0:0:0:0/64"); if (da == NULL) goto error; db = DetectAddressParseSingle("2001:1:2:3:0:0:0:0/64"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_GT) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestCmp12(void) { DetectAddress *da = NULL, *db = NULL; int result = 1; da = DetectAddressParseSingle("2001:1:2:3:1:0:0:0/64"); if (da == NULL) goto error; db = DetectAddressParseSingle("2001:1:2:3:2:0:0:0/64"); if (db == NULL) goto error; if (DetectAddressCmp(da, db) != ADDRESS_EQ) result = 0; DetectAddressFree(da); DetectAddressFree(db); return result; error: if (da) DetectAddressFree(da); if (db) DetectAddressFree(db); return 0; } int AddressTestAddressGroupSetup01(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "1.2.3.4"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup02(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup03(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup04(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { result = 1; } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup05(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { result = 1; } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup06(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup07(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "10.0.0.0/8"); if (r == 0 && gh->ipv4_head != NULL) { r = DetectAddressParse(gh, "10.10.10.10"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup08(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "10.10.10.10"); if (r == 0 && gh->ipv4_head != NULL) { r = DetectAddressParse(gh, "10.0.0.0/8"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup09(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "10.10.10.0/24"); if (r == 0 && gh->ipv4_head != NULL) { r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup10(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); if (r == 0 && gh->ipv4_head != NULL) { r = DetectAddressParse(gh, "10.10.10.0/24"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup11(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); if (r == 0) { r = DetectAddressParse(gh, "10.10.10.0/24"); if (r == 0) { r = DetectAddressParse(gh, "0.0.0.0/0"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, *five = four->next; /* result should be: * 0.0.0.0/10.10.9.255 * 10.10.10.0/10.10.10.9 * 10.10.10.10/10.10.10.255 * 10.10.11.0/10.10.11.1 * 10.10.11.2/255.255.255.255 */ if (one->ip.addr_data32[0] == 0x00000000 && one->ip2.addr_data32[0] == ntohl(168430079) && two->ip.addr_data32[0] == ntohl(168430080) && two->ip2.addr_data32[0] == ntohl(168430089) && three->ip.addr_data32[0] == ntohl(168430090) && three->ip2.addr_data32[0] == ntohl(168430335) && four->ip.addr_data32[0] == ntohl(168430336) && four->ip2.addr_data32[0] == ntohl(168430337) && five->ip.addr_data32[0] == ntohl(168430338) && five->ip2.addr_data32[0] == 0xFFFFFFFF) { result = 1; } } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup12 (void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); if (r == 0) { r = DetectAddressParse(gh, "0.0.0.0/0"); if (r == 0) { r = DetectAddressParse(gh, "10.10.10.0/24"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, *five = four->next; /* result should be: * 0.0.0.0/10.10.9.255 * 10.10.10.0/10.10.10.9 * 10.10.10.10/10.10.10.255 * 10.10.11.0/10.10.11.1 * 10.10.11.2/255.255.255.255 */ if (one->ip.addr_data32[0] == 0x00000000 && one->ip2.addr_data32[0] == ntohl(168430079) && two->ip.addr_data32[0] == ntohl(168430080) && two->ip2.addr_data32[0] == ntohl(168430089) && three->ip.addr_data32[0] == ntohl(168430090) && three->ip2.addr_data32[0] == ntohl(168430335) && four->ip.addr_data32[0] == ntohl(168430336) && four->ip2.addr_data32[0] == ntohl(168430337) && five->ip.addr_data32[0] == ntohl(168430338) && five->ip2.addr_data32[0] == 0xFFFFFFFF) { result = 1; } } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup13(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "0.0.0.0/0"); if (r == 0) { r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); if (r == 0) { r = DetectAddressParse(gh, "10.10.10.0/24"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, *five = four->next; /* result should be: * 0.0.0.0/10.10.9.255 * 10.10.10.0/10.10.10.9 * 10.10.10.10/10.10.10.255 * 10.10.11.0/10.10.11.1 * 10.10.11.2/255.255.255.255 */ if (one->ip.addr_data32[0] == 0x00000000 && one->ip2.addr_data32[0] == ntohl(168430079) && two->ip.addr_data32[0] == ntohl(168430080) && two->ip2.addr_data32[0] == ntohl(168430089) && three->ip.addr_data32[0] == ntohl(168430090) && three->ip2.addr_data32[0] == ntohl(168430335) && four->ip.addr_data32[0] == ntohl(168430336) && four->ip2.addr_data32[0] == ntohl(168430337) && five->ip.addr_data32[0] == ntohl(168430338) && five->ip2.addr_data32[0] == 0xFFFFFFFF) { result = 1; } } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetupIPv414(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "!1.2.3.4"); if (r == 0) { DetectAddress *one = gh->ipv4_head; DetectAddress *two = one ? one->next : NULL; if (one && two) { /* result should be: * 0.0.0.0/1.2.3.3 * 1.2.3.5/255.255.255.255 */ if (one->ip.addr_data32[0] == 0x00000000 && one->ip2.addr_data32[0] == ntohl(16909059) && two->ip.addr_data32[0] == ntohl(16909061) && two->ip2.addr_data32[0] == 0xFFFFFFFF) { result = 1; } else { printf("unexpected addresses: "); } } else { printf("one %p two %p: ", one, two); } } else { printf("DetectAddressParse returned %d, expected 0: ", r); } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetupIPv415(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "!0.0.0.0"); if (r == 0) { DetectAddress *one = gh->ipv4_head; if (one && one->next == NULL) { /* result should be: * 0.0.0.1/255.255.255.255 */ if (one->ip.addr_data32[0] == ntohl(1) && one->ip2.addr_data32[0] == 0xFFFFFFFF) result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetupIPv416(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "!255.255.255.255"); if (r == 0) { DetectAddress *one = gh->ipv4_head; if (one && one->next == NULL) { /* result should be: * 0.0.0.0/255.255.255.254 */ if (one->ip.addr_data32[0] == 0x00000000 && one->ip2.addr_data32[0] == ntohl(4294967294)) result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup14(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::1"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup15(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::1"); if (r == 0 && gh->ipv6_head != NULL) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup16(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(gh, "2001::3"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup17(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(gh, "2001::3"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(gh, "2001::2"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { result = 1; } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup18(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::2"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(gh, "2001::3"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(gh, "2001::4"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { result = 1; } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup19(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::2"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(gh, "2001::2"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup20(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL) { r = DetectAddressParse(gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup21(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { r = DetectAddressParse(gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup22(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL) { r = DetectAddressParse(gh, "2001::4-2001::6"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup23(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::4-2001::6"); if (r == 0 && gh->ipv6_head != NULL) { r = DetectAddressParse(gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { result = 1; } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup24(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::4-2001::6"); if (r == 0) { r = DetectAddressParse(gh, "2001::/3"); if (r == 0) { r = DetectAddressParse(gh, "::/0"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, *five = four->next; if (one->ip.addr_data32[0] == 0x00000000 && one->ip.addr_data32[1] == 0x00000000 && one->ip.addr_data32[2] == 0x00000000 && one->ip.addr_data32[3] == 0x00000000 && one->ip2.addr_data32[0] == ntohl(536870911) && one->ip2.addr_data32[1] == 0xFFFFFFFF && one->ip2.addr_data32[2] == 0xFFFFFFFF && one->ip2.addr_data32[3] == 0xFFFFFFFF && two->ip.addr_data32[0] == ntohl(536870912) && two->ip.addr_data32[1] == 0x00000000 && two->ip.addr_data32[2] == 0x00000000 && two->ip.addr_data32[3] == 0x00000000 && two->ip2.addr_data32[0] == ntohl(536936448) && two->ip2.addr_data32[1] == 0x00000000 && two->ip2.addr_data32[2] == 0x00000000 && two->ip2.addr_data32[3] == ntohl(3) && three->ip.addr_data32[0] == ntohl(536936448) && three->ip.addr_data32[1] == 0x00000000 && three->ip.addr_data32[2] == 0x00000000 && three->ip.addr_data32[3] == ntohl(4) && three->ip2.addr_data32[0] == ntohl(536936448) && three->ip2.addr_data32[1] == 0x00000000 && three->ip2.addr_data32[2] == 0x00000000 && three->ip2.addr_data32[3] == ntohl(6) && four->ip.addr_data32[0] == ntohl(536936448) && four->ip.addr_data32[1] == 0x00000000 && four->ip.addr_data32[2] == 0x00000000 && four->ip.addr_data32[3] == ntohl(7) && four->ip2.addr_data32[0] == ntohl(1073741823) && four->ip2.addr_data32[1] == 0xFFFFFFFF && four->ip2.addr_data32[2] == 0xFFFFFFFF && four->ip2.addr_data32[3] == 0xFFFFFFFF && five->ip.addr_data32[0] == ntohl(1073741824) && five->ip.addr_data32[1] == 0x00000000 && five->ip.addr_data32[2] == 0x00000000 && five->ip.addr_data32[3] == 0x00000000 && five->ip2.addr_data32[0] == 0xFFFFFFFF && five->ip2.addr_data32[1] == 0xFFFFFFFF && five->ip2.addr_data32[2] == 0xFFFFFFFF && five->ip2.addr_data32[3] == 0xFFFFFFFF) { result = 1; } } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup25(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "2001::4-2001::6"); if (r == 0) { r = DetectAddressParse(gh, "::/0"); if (r == 0) { r = DetectAddressParse(gh, "2001::/3"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, *five = four->next; if (one->ip.addr_data32[0] == 0x00000000 && one->ip.addr_data32[1] == 0x00000000 && one->ip.addr_data32[2] == 0x00000000 && one->ip.addr_data32[3] == 0x00000000 && one->ip2.addr_data32[0] == ntohl(536870911) && one->ip2.addr_data32[1] == 0xFFFFFFFF && one->ip2.addr_data32[2] == 0xFFFFFFFF && one->ip2.addr_data32[3] == 0xFFFFFFFF && two->ip.addr_data32[0] == ntohl(536870912) && two->ip.addr_data32[1] == 0x00000000 && two->ip.addr_data32[2] == 0x00000000 && two->ip.addr_data32[3] == 0x00000000 && two->ip2.addr_data32[0] == ntohl(536936448) && two->ip2.addr_data32[1] == 0x00000000 && two->ip2.addr_data32[2] == 0x00000000 && two->ip2.addr_data32[3] == ntohl(3) && three->ip.addr_data32[0] == ntohl(536936448) && three->ip.addr_data32[1] == 0x00000000 && three->ip.addr_data32[2] == 0x00000000 && three->ip.addr_data32[3] == ntohl(4) && three->ip2.addr_data32[0] == ntohl(536936448) && three->ip2.addr_data32[1] == 0x00000000 && three->ip2.addr_data32[2] == 0x00000000 && three->ip2.addr_data32[3] == ntohl(6) && four->ip.addr_data32[0] == ntohl(536936448) && four->ip.addr_data32[1] == 0x00000000 && four->ip.addr_data32[2] == 0x00000000 && four->ip.addr_data32[3] == ntohl(7) && four->ip2.addr_data32[0] == ntohl(1073741823) && four->ip2.addr_data32[1] == 0xFFFFFFFF && four->ip2.addr_data32[2] == 0xFFFFFFFF && four->ip2.addr_data32[3] == 0xFFFFFFFF && five->ip.addr_data32[0] == ntohl(1073741824) && five->ip.addr_data32[1] == 0x00000000 && five->ip.addr_data32[2] == 0x00000000 && five->ip.addr_data32[3] == 0x00000000 && five->ip2.addr_data32[0] == 0xFFFFFFFF && five->ip2.addr_data32[1] == 0xFFFFFFFF && five->ip2.addr_data32[2] == 0xFFFFFFFF && five->ip2.addr_data32[3] == 0xFFFFFFFF) { result = 1; } } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup26(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "::/0"); if (r == 0) { r = DetectAddressParse(gh, "2001::4-2001::6"); if (r == 0) { r = DetectAddressParse(gh, "2001::/3"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, *five = four->next; if (one->ip.addr_data32[0] == 0x00000000 && one->ip.addr_data32[1] == 0x00000000 && one->ip.addr_data32[2] == 0x00000000 && one->ip.addr_data32[3] == 0x00000000 && one->ip2.addr_data32[0] == ntohl(536870911) && one->ip2.addr_data32[1] == 0xFFFFFFFF && one->ip2.addr_data32[2] == 0xFFFFFFFF && one->ip2.addr_data32[3] == 0xFFFFFFFF && two->ip.addr_data32[0] == ntohl(536870912) && two->ip.addr_data32[1] == 0x00000000 && two->ip.addr_data32[2] == 0x00000000 && two->ip.addr_data32[3] == 0x00000000 && two->ip2.addr_data32[0] == ntohl(536936448) && two->ip2.addr_data32[1] == 0x00000000 && two->ip2.addr_data32[2] == 0x00000000 && two->ip2.addr_data32[3] == ntohl(3) && three->ip.addr_data32[0] == ntohl(536936448) && three->ip.addr_data32[1] == 0x00000000 && three->ip.addr_data32[2] == 0x00000000 && three->ip.addr_data32[3] == ntohl(4) && three->ip2.addr_data32[0] == ntohl(536936448) && three->ip2.addr_data32[1] == 0x00000000 && three->ip2.addr_data32[2] == 0x00000000 && three->ip2.addr_data32[3] == ntohl(6) && four->ip.addr_data32[0] == ntohl(536936448) && four->ip.addr_data32[1] == 0x00000000 && four->ip.addr_data32[2] == 0x00000000 && four->ip.addr_data32[3] == ntohl(7) && four->ip2.addr_data32[0] == ntohl(1073741823) && four->ip2.addr_data32[1] == 0xFFFFFFFF && four->ip2.addr_data32[2] == 0xFFFFFFFF && four->ip2.addr_data32[3] == 0xFFFFFFFF && five->ip.addr_data32[0] == ntohl(1073741824) && five->ip.addr_data32[1] == 0x00000000 && five->ip.addr_data32[2] == 0x00000000 && five->ip.addr_data32[3] == 0x00000000 && five->ip2.addr_data32[0] == 0xFFFFFFFF && five->ip2.addr_data32[1] == 0xFFFFFFFF && five->ip2.addr_data32[2] == 0xFFFFFFFF && five->ip2.addr_data32[3] == 0xFFFFFFFF) { result = 1; } } } } DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup27(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[1.2.3.4]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup28(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[1.2.3.4,4.3.2.1]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup29(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[1.2.3.4,4.3.2.1,10.10.10.10]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup30(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[[1.2.3.4,2.3.4.5],4.3.2.1,[10.10.10.10,11.11.11.11]]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup31(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[[1.2.3.4,[2.3.4.5,3.4.5.6]],4.3.2.1,[10.10.10.10,[11.11.11.11,12.12.12.12]]]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup32(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[[1.2.3.4,[2.3.4.5,[3.4.5.6,4.5.6.7]]],4.3.2.1,[10.10.10.10,[11.11.11.11,[12.12.12.12,13.13.13.13]]]]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup33(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "![1.1.1.1,[2.2.2.2,[3.3.3.3,4.4.4.4]]]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup34(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[1.0.0.0/8,![1.1.1.1,[1.2.1.1,1.3.1.1]]]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup35(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[1.0.0.0/8,[2.0.0.0/8,![1.1.1.1,2.2.2.2]]]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup36 (void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[1.0.0.0/8,[2.0.0.0/8,[3.0.0.0/8,!1.1.1.1]]]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestAddressGroupSetup37(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { int r = DetectAddressParse(gh, "[0.0.0.0/0,::/0]"); if (r == 0) result = 1; DetectAddressHeadFree(gh); } return result; } int AddressTestCutIPv401(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.0/255.255.255.0"); b = DetectAddressParseSingle("1.2.2.0-1.2.3.4"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv402(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.0/255.255.255.0"); b = DetectAddressParseSingle("1.2.2.0-1.2.3.4"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c == NULL) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv403(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.0/255.255.255.0"); b = DetectAddressParseSingle("1.2.2.0-1.2.3.4"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c == NULL) goto error; if (a->ip.addr_data32[0] != ntohl(16908800) || a->ip2.addr_data32[0] != ntohl(16909055)) goto error; if (b->ip.addr_data32[0] != ntohl(16909056) || b->ip2.addr_data32[0] != ntohl(16909060)) goto error; if (c->ip.addr_data32[0] != ntohl(16909061) || c->ip2.addr_data32[0] != ntohl(16909311)) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv404(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.3-1.2.3.6"); b = DetectAddressParseSingle("1.2.3.0-1.2.3.5"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c == NULL) goto error; if (a->ip.addr_data32[0] != ntohl(16909056) || a->ip2.addr_data32[0] != ntohl(16909058)) goto error; if (b->ip.addr_data32[0] != ntohl(16909059) || b->ip2.addr_data32[0] != ntohl(16909061)) goto error; if (c->ip.addr_data32[0] != ntohl(16909062) || c->ip2.addr_data32[0] != ntohl(16909062)) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv405(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.3-1.2.3.6"); b = DetectAddressParseSingle("1.2.3.0-1.2.3.9"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c == NULL) goto error; if (a->ip.addr_data32[0] != ntohl(16909056) || a->ip2.addr_data32[0] != ntohl(16909058)) goto error; if (b->ip.addr_data32[0] != ntohl(16909059) || b->ip2.addr_data32[0] != ntohl(16909062)) goto error; if (c->ip.addr_data32[0] != ntohl(16909063) || c->ip2.addr_data32[0] != ntohl(16909065)) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv406(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.0-1.2.3.9"); b = DetectAddressParseSingle("1.2.3.3-1.2.3.6"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c == NULL) goto error; if (a->ip.addr_data32[0] != ntohl(16909056) || a->ip2.addr_data32[0] != ntohl(16909058)) goto error; if (b->ip.addr_data32[0] != ntohl(16909059) || b->ip2.addr_data32[0] != ntohl(16909062)) goto error; if (c->ip.addr_data32[0] != ntohl(16909063) || c->ip2.addr_data32[0] != ntohl(16909065)) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv407(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.0-1.2.3.6"); b = DetectAddressParseSingle("1.2.3.0-1.2.3.9"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c != NULL) goto error; if (a->ip.addr_data32[0] != ntohl(16909056) || a->ip2.addr_data32[0] != ntohl(16909062)) goto error; if (b->ip.addr_data32[0] != ntohl(16909063) || b->ip2.addr_data32[0] != ntohl(16909065)) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv408(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.3-1.2.3.9"); b = DetectAddressParseSingle("1.2.3.0-1.2.3.9"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c != NULL) goto error; if (a->ip.addr_data32[0] != ntohl(16909056) || a->ip2.addr_data32[0] != ntohl(16909058)) goto error; if (b->ip.addr_data32[0] != ntohl(16909059) || b->ip2.addr_data32[0] != ntohl(16909065)) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv409(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.0-1.2.3.9"); b = DetectAddressParseSingle("1.2.3.0-1.2.3.6"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c != NULL) goto error; if (a->ip.addr_data32[0] != ntohl(16909056) || a->ip2.addr_data32[0] != ntohl(16909062)) goto error; if (b->ip.addr_data32[0] != ntohl(16909063) || b->ip2.addr_data32[0] != ntohl(16909065)) goto error; DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestCutIPv410(void) { DetectAddress *a, *b, *c; a = DetectAddressParseSingle("1.2.3.0-1.2.3.9"); b = DetectAddressParseSingle("1.2.3.3-1.2.3.9"); if (DetectAddressCut(NULL, a, b, &c) == -1) goto error; if (c != NULL) goto error; if (a->ip.addr_data32[0] != ntohl(16909056) || a->ip2.addr_data32[0] != ntohl(16909058)) goto error; if (b->ip.addr_data32[0] != ntohl(16909059) || b->ip2.addr_data32[0] != ntohl(16909065)) goto error; printf("ip %u ip2 %u ", htonl(a->ip.addr_data32[0]), htonl(a->ip2.addr_data32[0])); DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 1; error: DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); return 0; } int AddressTestParseInvalidMask01(void) { int result = 1; DetectAddress *dd = NULL; dd = DetectAddressParseSingle("192.168.2.0/33"); if (dd != NULL) { DetectAddressFree(dd); result = 0; } return result; } int AddressTestParseInvalidMask02(void) { int result = 1; DetectAddress *dd = NULL; dd = DetectAddressParseSingle("192.168.2.0/255.255.257.0"); if (dd != NULL) { DetectAddressFree(dd); result = 0; } return result; } int AddressTestParseInvalidMask03(void) { int result = 1; DetectAddress *dd = NULL; dd = DetectAddressParseSingle("192.168.2.0/blue"); if (dd != NULL) { DetectAddressFree(dd); result = 0; } return result; } int AddressConfVarsTest01(void) { static const char *dummy_conf_string = "%YAML 1.1\n" "---\n" "\n" "vars:\n" "\n" " address-groups:\n" "\n" " HOME_NET: \"any\"\n" "\n" " EXTERNAL_NET: \"!any\"\n" "\n" " port-groups:\n" "\n" " HTTP_PORTS: \"any\"\n" "\n" " SHELLCODE_PORTS: \"!any\"\n" "\n"; int result = 0; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); if (DetectAddressTestConfVars() < 0 && DetectPortTestConfVars() < 0) result = 1; ConfDeInit(); ConfRestoreContextBackup(); return result; } int AddressConfVarsTest02(void) { static const char *dummy_conf_string = "%YAML 1.1\n" "---\n" "\n" "vars:\n" "\n" " address-groups:\n" "\n" " HOME_NET: \"any\"\n" "\n" " EXTERNAL_NET: \"any\"\n" "\n" " port-groups:\n" "\n" " HTTP_PORTS: \"any\"\n" "\n" " SHELLCODE_PORTS: \"!any\"\n" "\n"; int result = 0; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); if (DetectAddressTestConfVars() == 0 && DetectPortTestConfVars() < 0) result = 1; ConfDeInit(); ConfRestoreContextBackup(); return result; } int AddressConfVarsTest03(void) { static const char *dummy_conf_string = "%YAML 1.1\n" "---\n" "\n" "vars:\n" "\n" " address-groups:\n" "\n" " HOME_NET: \"any\"\n" "\n" " EXTERNAL_NET: \"!$HOME_NET\"\n" "\n" " port-groups:\n" "\n" " HTTP_PORTS: \"any\"\n" "\n" " SHELLCODE_PORTS: \"!$HTTP_PORTS\"\n" "\n"; int result = 0; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); if (DetectAddressTestConfVars() < 0 && DetectPortTestConfVars() < 0) result = 1; ConfDeInit(); ConfRestoreContextBackup(); return result; } int AddressConfVarsTest04(void) { static const char *dummy_conf_string = "%YAML 1.1\n" "---\n" "\n" "vars:\n" "\n" " address-groups:\n" "\n" " HOME_NET: \"any\"\n" "\n" " EXTERNAL_NET: \"$HOME_NET\"\n" "\n" " port-groups:\n" "\n" " HTTP_PORTS: \"any\"\n" "\n" " SHELLCODE_PORTS: \"$HTTP_PORTS\"\n" "\n"; int result = 0; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); if (DetectAddressTestConfVars() == 0 && DetectPortTestConfVars() == 0) result = 1; ConfDeInit(); ConfRestoreContextBackup(); return result; } int AddressConfVarsTest05(void) { static const char *dummy_conf_string = "%YAML 1.1\n" "---\n" "\n" "vars:\n" "\n" " address-groups:\n" "\n" " HOME_NET: \"any\"\n" "\n" " EXTERNAL_NET: [192.168.0.1]\n" "\n" " port-groups:\n" "\n" " HTTP_PORTS: \"any\"\n" "\n" " SHELLCODE_PORTS: [80]\n" "\n"; int result = 0; ConfCreateContextBackup(); ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); if (DetectAddressTestConfVars() != -1 && DetectPortTestConfVars() != -1) goto end; result = 1; end: ConfDeInit(); ConfRestoreContextBackup(); return result; } #include "detect-engine.h" /** * \test Test sig distribution over address groups */ static int AddressTestFunctions01(void) { DetectAddress *a1 = NULL; DetectAddress *a2 = NULL; DetectAddressHead *h = NULL; int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature s[2]; memset(s,0x00,sizeof(s)); s[0].num = 0; s[1].num = 1; a1 = DetectAddressParseSingle("255.0.0.0/8"); if (a1 == NULL) { printf("a1 == NULL: "); goto end; } SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); a2 = DetectAddressParseSingle("0.0.0.0/0"); if (a2 == NULL) { printf("a2 == NULL: "); goto end; } SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); SCLogDebug("a1"); DetectAddressPrint(a1); SCLogDebug("a2"); DetectAddressPrint(a2); h = DetectAddressHeadInit(); if (h == NULL) goto end; DetectAddressInsert(de_ctx, h, a1); DetectAddressInsert(de_ctx, h, a2); if (h == NULL) goto end; DetectAddress *x = h->ipv4_head; for ( ; x != NULL; x = x->next) { SCLogDebug("x %p next %p", x, x->next); DetectAddressPrint(x); //SigGroupHeadPrintSigs(de_ctx, x->sh); } DetectAddress *one = h->ipv4_head; DetectAddress *two = one->next; int sig = 0; if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'two', but it shouldn't: ", sig); goto end; } result = 1; end: if (h != NULL) DetectAddressHeadFree(h); return result; } /** * \test Test sig distribution over address groups */ static int AddressTestFunctions02(void) { DetectAddress *a1 = NULL; DetectAddress *a2 = NULL; DetectAddressHead *h = NULL; int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature s[2]; memset(s,0x00,sizeof(s)); s[0].num = 0; s[1].num = 1; a1 = DetectAddressParseSingle("255.0.0.0/8"); if (a1 == NULL) { printf("a1 == NULL: "); goto end; } SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); a2 = DetectAddressParseSingle("0.0.0.0/0"); if (a2 == NULL) { printf("a2 == NULL: "); goto end; } SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); SCLogDebug("a1"); DetectAddressPrint(a1); SCLogDebug("a2"); DetectAddressPrint(a2); h = DetectAddressHeadInit(); if (h == NULL) goto end; DetectAddressInsert(de_ctx, h, a2); DetectAddressInsert(de_ctx, h, a1); BUG_ON(h == NULL); SCLogDebug("dp3"); DetectAddress *x = h->ipv4_head; for ( ; x != NULL; x = x->next) { DetectAddressPrint(x); //SigGroupHeadPrintSigs(de_ctx, x->sh); } DetectAddress *one = h->ipv4_head; DetectAddress *two = one->next; int sig = 0; if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'two', but it shouldn't: ", sig); goto end; } result = 1; end: if (h != NULL) DetectAddressHeadFree(h); return result; } /** * \test Test sig distribution over address groups */ static int AddressTestFunctions03(void) { DetectAddress *a1 = NULL; DetectAddress *a2 = NULL; DetectAddressHead *h = NULL; int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature s[2]; memset(s,0x00,sizeof(s)); s[0].num = 0; s[1].num = 1; a1 = DetectAddressParseSingle("ffff::/16"); if (a1 == NULL) { printf("a1 == NULL: "); goto end; } SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); a2 = DetectAddressParseSingle("::/0"); if (a2 == NULL) { printf("a2 == NULL: "); goto end; } SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); SCLogDebug("a1"); DetectAddressPrint(a1); SCLogDebug("a2"); DetectAddressPrint(a2); h = DetectAddressHeadInit(); if (h == NULL) goto end; DetectAddressInsert(de_ctx, h, a1); DetectAddressInsert(de_ctx, h, a2); if (h == NULL) goto end; DetectAddress *x = h->ipv6_head; for ( ; x != NULL; x = x->next) { SCLogDebug("x %p next %p", x, x->next); DetectAddressPrint(x); //SigGroupHeadPrintSigs(de_ctx, x->sh); } DetectAddress *one = h->ipv6_head; DetectAddress *two = one->next; int sig = 0; if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'two', but it shouldn't: ", sig); goto end; } result = 1; end: if (h != NULL) DetectAddressHeadFree(h); return result; } /** * \test Test sig distribution over address groups */ static int AddressTestFunctions04(void) { DetectAddress *a1 = NULL; DetectAddress *a2 = NULL; DetectAddressHead *h = NULL; int result = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature s[2]; memset(s,0x00,sizeof(s)); s[0].num = 0; s[1].num = 1; a1 = DetectAddressParseSingle("ffff::/16"); if (a1 == NULL) { printf("a1 == NULL: "); goto end; } SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); a2 = DetectAddressParseSingle("::/0"); if (a2 == NULL) { printf("a2 == NULL: "); goto end; } SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); SCLogDebug("a1"); DetectAddressPrint(a1); SCLogDebug("a2"); DetectAddressPrint(a2); h = DetectAddressHeadInit(); if (h == NULL) goto end; DetectAddressInsert(de_ctx, h, a2); DetectAddressInsert(de_ctx, h, a1); BUG_ON(h == NULL); SCLogDebug("dp3"); DetectAddress *x = h->ipv6_head; for ( ; x != NULL; x = x->next) { DetectAddressPrint(x); //SigGroupHeadPrintSigs(de_ctx, x->sh); } DetectAddress *one = h->ipv6_head; DetectAddress *two = one->next; int sig = 0; if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'two', but it shouldn't: ", sig); goto end; } result = 1; end: if (h != NULL) DetectAddressHeadFree(h); return result; } #endif /* UNITTESTS */ void DetectAddressTests(void) { #ifdef UNITTESTS DetectAddressIPv4Tests(); DetectAddressIPv6Tests(); UtRegisterTest("AddressTestParse01", AddressTestParse01, 1); UtRegisterTest("AddressTestParse02", AddressTestParse02, 1); UtRegisterTest("AddressTestParse03", AddressTestParse03, 1); UtRegisterTest("AddressTestParse04", AddressTestParse04, 1); UtRegisterTest("AddressTestParse05", AddressTestParse05, 1); UtRegisterTest("AddressTestParse06", AddressTestParse06, 1); UtRegisterTest("AddressTestParse07", AddressTestParse07, 1); UtRegisterTest("AddressTestParse08", AddressTestParse08, 1); UtRegisterTest("AddressTestParse09", AddressTestParse09, 1); UtRegisterTest("AddressTestParse10", AddressTestParse10, 1); UtRegisterTest("AddressTestParse11", AddressTestParse11, 1); UtRegisterTest("AddressTestParse12", AddressTestParse12, 1); UtRegisterTest("AddressTestParse13", AddressTestParse13, 1); UtRegisterTest("AddressTestParse14", AddressTestParse14, 1); UtRegisterTest("AddressTestParse15", AddressTestParse15, 1); UtRegisterTest("AddressTestParse16", AddressTestParse16, 1); UtRegisterTest("AddressTestParse17", AddressTestParse17, 1); UtRegisterTest("AddressTestParse18", AddressTestParse18, 1); UtRegisterTest("AddressTestParse19", AddressTestParse19, 1); UtRegisterTest("AddressTestParse20", AddressTestParse20, 1); UtRegisterTest("AddressTestParse21", AddressTestParse21, 1); UtRegisterTest("AddressTestParse22", AddressTestParse22, 1); UtRegisterTest("AddressTestParse23", AddressTestParse23, 1); UtRegisterTest("AddressTestParse24", AddressTestParse24, 1); UtRegisterTest("AddressTestParse25", AddressTestParse25, 1); UtRegisterTest("AddressTestParse26", AddressTestParse26, 1); UtRegisterTest("AddressTestParse27", AddressTestParse27, 1); UtRegisterTest("AddressTestParse28", AddressTestParse28, 1); UtRegisterTest("AddressTestParse29", AddressTestParse29, 1); UtRegisterTest("AddressTestParse30", AddressTestParse30, 1); UtRegisterTest("AddressTestParse31", AddressTestParse31, 1); UtRegisterTest("AddressTestParse32", AddressTestParse32, 1); UtRegisterTest("AddressTestParse33", AddressTestParse33, 1); UtRegisterTest("AddressTestParse34", AddressTestParse34, 1); UtRegisterTest("AddressTestParse35", AddressTestParse35, 1); UtRegisterTest("AddressTestParse36", AddressTestParse36, 1); UtRegisterTest("AddressTestParse37", AddressTestParse37, 1); UtRegisterTest("AddressTestMatch01", AddressTestMatch01, 1); UtRegisterTest("AddressTestMatch02", AddressTestMatch02, 1); UtRegisterTest("AddressTestMatch03", AddressTestMatch03, 1); UtRegisterTest("AddressTestMatch04", AddressTestMatch04, 1); UtRegisterTest("AddressTestMatch05", AddressTestMatch05, 1); UtRegisterTest("AddressTestMatch06", AddressTestMatch06, 1); UtRegisterTest("AddressTestMatch07", AddressTestMatch07, 1); UtRegisterTest("AddressTestMatch08", AddressTestMatch08, 1); UtRegisterTest("AddressTestMatch09", AddressTestMatch09, 1); UtRegisterTest("AddressTestMatch10", AddressTestMatch10, 1); UtRegisterTest("AddressTestMatch11", AddressTestMatch11, 1); UtRegisterTest("AddressTestCmp01", AddressTestCmp01, 1); UtRegisterTest("AddressTestCmp02", AddressTestCmp02, 1); UtRegisterTest("AddressTestCmp03", AddressTestCmp03, 1); UtRegisterTest("AddressTestCmp04", AddressTestCmp04, 1); UtRegisterTest("AddressTestCmp05", AddressTestCmp05, 1); UtRegisterTest("AddressTestCmp06", AddressTestCmp06, 1); UtRegisterTest("AddressTestCmpIPv407", AddressTestCmpIPv407, 1); UtRegisterTest("AddressTestCmpIPv408", AddressTestCmpIPv408, 1); UtRegisterTest("AddressTestCmp07", AddressTestCmp07, 1); UtRegisterTest("AddressTestCmp08", AddressTestCmp08, 1); UtRegisterTest("AddressTestCmp09", AddressTestCmp09, 1); UtRegisterTest("AddressTestCmp10", AddressTestCmp10, 1); UtRegisterTest("AddressTestCmp11", AddressTestCmp11, 1); UtRegisterTest("AddressTestCmp12", AddressTestCmp12, 1); UtRegisterTest("AddressTestAddressGroupSetup01", AddressTestAddressGroupSetup01, 1); UtRegisterTest("AddressTestAddressGroupSetup02", AddressTestAddressGroupSetup02, 1); UtRegisterTest("AddressTestAddressGroupSetup03", AddressTestAddressGroupSetup03, 1); UtRegisterTest("AddressTestAddressGroupSetup04", AddressTestAddressGroupSetup04, 1); UtRegisterTest("AddressTestAddressGroupSetup05", AddressTestAddressGroupSetup05, 1); UtRegisterTest("AddressTestAddressGroupSetup06", AddressTestAddressGroupSetup06, 1); UtRegisterTest("AddressTestAddressGroupSetup07", AddressTestAddressGroupSetup07, 1); UtRegisterTest("AddressTestAddressGroupSetup08", AddressTestAddressGroupSetup08, 1); UtRegisterTest("AddressTestAddressGroupSetup09", AddressTestAddressGroupSetup09, 1); UtRegisterTest("AddressTestAddressGroupSetup10", AddressTestAddressGroupSetup10, 1); UtRegisterTest("AddressTestAddressGroupSetup11", AddressTestAddressGroupSetup11, 1); UtRegisterTest("AddressTestAddressGroupSetup12", AddressTestAddressGroupSetup12, 1); UtRegisterTest("AddressTestAddressGroupSetup13", AddressTestAddressGroupSetup13, 1); UtRegisterTest("AddressTestAddressGroupSetupIPv414", AddressTestAddressGroupSetupIPv414, 1); UtRegisterTest("AddressTestAddressGroupSetupIPv415", AddressTestAddressGroupSetupIPv415, 1); UtRegisterTest("AddressTestAddressGroupSetupIPv416", AddressTestAddressGroupSetupIPv416, 1); UtRegisterTest("AddressTestAddressGroupSetup14", AddressTestAddressGroupSetup14, 1); UtRegisterTest("AddressTestAddressGroupSetup15", AddressTestAddressGroupSetup15, 1); UtRegisterTest("AddressTestAddressGroupSetup16", AddressTestAddressGroupSetup16, 1); UtRegisterTest("AddressTestAddressGroupSetup17", AddressTestAddressGroupSetup17, 1); UtRegisterTest("AddressTestAddressGroupSetup18", AddressTestAddressGroupSetup18, 1); UtRegisterTest("AddressTestAddressGroupSetup19", AddressTestAddressGroupSetup19, 1); UtRegisterTest("AddressTestAddressGroupSetup20", AddressTestAddressGroupSetup20, 1); UtRegisterTest("AddressTestAddressGroupSetup21", AddressTestAddressGroupSetup21, 1); UtRegisterTest("AddressTestAddressGroupSetup22", AddressTestAddressGroupSetup22, 1); UtRegisterTest("AddressTestAddressGroupSetup23", AddressTestAddressGroupSetup23, 1); UtRegisterTest("AddressTestAddressGroupSetup24", AddressTestAddressGroupSetup24, 1); UtRegisterTest("AddressTestAddressGroupSetup25", AddressTestAddressGroupSetup25, 1); UtRegisterTest("AddressTestAddressGroupSetup26", AddressTestAddressGroupSetup26, 1); UtRegisterTest("AddressTestAddressGroupSetup27", AddressTestAddressGroupSetup27, 1); UtRegisterTest("AddressTestAddressGroupSetup28", AddressTestAddressGroupSetup28, 1); UtRegisterTest("AddressTestAddressGroupSetup29", AddressTestAddressGroupSetup29, 1); UtRegisterTest("AddressTestAddressGroupSetup30", AddressTestAddressGroupSetup30, 1); UtRegisterTest("AddressTestAddressGroupSetup31", AddressTestAddressGroupSetup31, 1); UtRegisterTest("AddressTestAddressGroupSetup32", AddressTestAddressGroupSetup32, 1); UtRegisterTest("AddressTestAddressGroupSetup33", AddressTestAddressGroupSetup33, 1); UtRegisterTest("AddressTestAddressGroupSetup34", AddressTestAddressGroupSetup34, 1); UtRegisterTest("AddressTestAddressGroupSetup35", AddressTestAddressGroupSetup35, 1); UtRegisterTest("AddressTestAddressGroupSetup36", AddressTestAddressGroupSetup36, 1); UtRegisterTest("AddressTestAddressGroupSetup37", AddressTestAddressGroupSetup37, 1); UtRegisterTest("AddressTestCutIPv401", AddressTestCutIPv401, 1); UtRegisterTest("AddressTestCutIPv402", AddressTestCutIPv402, 1); UtRegisterTest("AddressTestCutIPv403", AddressTestCutIPv403, 1); UtRegisterTest("AddressTestCutIPv404", AddressTestCutIPv404, 1); UtRegisterTest("AddressTestCutIPv405", AddressTestCutIPv405, 1); UtRegisterTest("AddressTestCutIPv406", AddressTestCutIPv406, 1); UtRegisterTest("AddressTestCutIPv407", AddressTestCutIPv407, 1); UtRegisterTest("AddressTestCutIPv408", AddressTestCutIPv408, 1); UtRegisterTest("AddressTestCutIPv409", AddressTestCutIPv409, 1); UtRegisterTest("AddressTestCutIPv410", AddressTestCutIPv410, 1); UtRegisterTest("AddressTestParseInvalidMask01", AddressTestParseInvalidMask01, 1); UtRegisterTest("AddressTestParseInvalidMask02", AddressTestParseInvalidMask02, 1); UtRegisterTest("AddressTestParseInvalidMask03", AddressTestParseInvalidMask03, 1); UtRegisterTest("AddressConfVarsTest01 ", AddressConfVarsTest01, 1); UtRegisterTest("AddressConfVarsTest02 ", AddressConfVarsTest02, 1); UtRegisterTest("AddressConfVarsTest03 ", AddressConfVarsTest03, 1); UtRegisterTest("AddressConfVarsTest04 ", AddressConfVarsTest04, 1); UtRegisterTest("AddressConfVarsTest05 ", AddressConfVarsTest05, 1); UtRegisterTest("AddressTestFunctions01", AddressTestFunctions01, 1); UtRegisterTest("AddressTestFunctions02", AddressTestFunctions02, 1); UtRegisterTest("AddressTestFunctions03", AddressTestFunctions03, 1); UtRegisterTest("AddressTestFunctions04", AddressTestFunctions04, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-profiling-locks.c0000644000000000000000000001377612253546156015264 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * An API for profiling locks. * */ #ifdef PROFILING #ifdef PROFILE_LOCKING #include "suricata-common.h" #include "util-profiling-locks.h" #include "util-hashlist.h" __thread ProfilingLock locks[PROFILING_MAX_LOCKS]; __thread int locks_idx = 0; __thread int record_locks = 0; int profiling_locks_enabled = 0; int profiling_locks_output_to_file = 0; char *profiling_locks_file_name = NULL; char *profiling_locks_file_mode = "a"; typedef struct LockRecord_ { char *file; // hash char *func; // info int type; // info int line; // hash uint32_t cont; uint32_t ticks_cnt; uint64_t ticks_total; uint64_t ticks_max; } LockRecord; HashListTable *lock_records; pthread_mutex_t lock_records_mutex; static uint32_t LockRecordHash(HashListTable *ht, void *buf, uint16_t buflen) { LockRecord *fn = (LockRecord *)buf; uint32_t hash = strlen(fn->file) + fn->line; uint16_t u; for (u = 0; u < strlen(fn->file); u++) { hash += fn->file[u]; } return hash % ht->array_size; } static char LockRecordCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2) { LockRecord *fn1 = (LockRecord *)buf1; LockRecord *fn2 = (LockRecord *)buf2; if (fn1->line != fn2->line) return 0; if (fn1->file == fn2->file) return 1; return 0; } static void LockRecordFree(void *data) { LockRecord *fn = (LockRecord *)data; if (fn == NULL) return; SCFree(fn); } int LockRecordInitHash() { pthread_mutex_init(&lock_records_mutex, NULL); pthread_mutex_lock(&lock_records_mutex); lock_records = HashListTableInit(512, LockRecordHash, LockRecordCompare, LockRecordFree); BUG_ON(lock_records == NULL); pthread_mutex_unlock(&lock_records_mutex); return 0; } void LockRecordAdd(ProfilingLock *l) { LockRecord fn = { NULL, NULL, 0,0,0,0,0,0}, *ptr = &fn; fn.file = l->file; fn.line = l->line; LockRecord *lookup_fn = (LockRecord *)HashListTableLookup(lock_records, (void *)ptr, 0); if (lookup_fn == NULL) { LockRecord *new = SCMalloc(sizeof(LockRecord)); BUG_ON(new == NULL); new->file = l->file; new->line = l->line; new->type = l->type; new->cont = l->cont; new->func = l->func; new->ticks_max = l->ticks; new->ticks_total = l->ticks; new->ticks_cnt = 1; HashListTableAdd(lock_records, (void *)new, 0); } else { lookup_fn->ticks_total += l->ticks; if (l->ticks > lookup_fn->ticks_max) lookup_fn->ticks_max = l->ticks; lookup_fn->ticks_cnt++; lookup_fn->cont += l->cont; } return; } /** \param p void ptr to Packet struct */ void SCProfilingAddPacketLocks(void *p) { int i; for (i = 0; i < locks_idx; i++) { pthread_mutex_lock(&lock_records_mutex); LockRecordAdd(&locks[i]); pthread_mutex_unlock(&lock_records_mutex); } } void SCProfilingListLocks(void) { FILE *fp = NULL; if (profiling_locks_output_to_file == 1) { fp = fopen(profiling_locks_file_name, profiling_locks_file_mode); if (fp == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", profiling_locks_file_name, strerror(errno)); return; } } else { fp = stdout; } fprintf(fp, "\n\nLock Cnt Avg ticks Max ticks Total ticks Cont Func\n"); fprintf(fp, "------------------ ---------- --------- ------------ ------------ ------- ---------\n"); uint64_t total = 0; uint32_t cont = 0; uint64_t cnt = 0; HashListTableBucket *b = HashListTableGetListHead(lock_records); while (b) { LockRecord *r = HashListTableGetListData(b); char *lock; switch (r->type) { case LOCK_MUTEX: lock = "mtx"; break; case LOCK_SPIN: lock = "spn"; break; case LOCK_RWW: lock = "rww"; break; case LOCK_RWR: lock = "rwr"; break; default: lock = "bug"; break; } char str[128] = ""; snprintf(str, sizeof(str), "(%s) %s:%d", lock,r->file, r->line); fprintf(fp, "%-50s %-10u %-9"PRIu64" %-12"PRIu64" %-12"PRIu64" %-7u %-s\n", str, r->ticks_cnt, (uint64_t)((uint64_t)r->ticks_total/(uint64_t)r->ticks_cnt), r->ticks_max, r->ticks_total, r->cont, r->func); total += r->ticks_total; cnt += r->ticks_cnt; cont += r->cont; b = HashListTableGetListNext(b); } fprintf(fp, "\nOverall: locks %"PRIu64", average cost %"PRIu64", contentions %"PRIu32", total ticks %"PRIu64"\n", cnt, (uint64_t)((uint64_t)total/(uint64_t)cnt), cont, total); fclose(fp); } void LockRecordFreeHash() { if (profiling_locks_enabled == 0) return; pthread_mutex_lock(&lock_records_mutex); SCProfilingListLocks(); if (lock_records != NULL) { HashListTableFree(lock_records); lock_records = NULL; } pthread_mutex_unlock(&lock_records_mutex); pthread_mutex_destroy(&lock_records_mutex); } #endif #endif suricata-1.4.7/src/log-tlslog.c0000644000000000000000000004527412253546156013270 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Roliers Jean-Paul * \author Eric Leblond * * Implements tls logging portion of the engine. */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "pkt-var.h" #include "conf.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "util-print.h" #include "util-unittest.h" #include "util-debug.h" #include "output.h" #include "log-tlslog.h" #include "app-layer-ssl.h" #include "app-layer.h" #include "util-privs.h" #include "util-buffer.h" #include "util-logopenfile.h" #include "util-crypt.h" #define DEFAULT_LOG_FILENAME "tls.log" static char tls_logfile_base_dir[PATH_MAX] = "/tmp"; SC_ATOMIC_DECLARE(unsigned int, cert_id); #define MODULE_NAME "LogTlsLog" #define OUTPUT_BUFFER_SIZE 65535 #define CERT_ENC_BUFFER_SIZE 2048 #define LOG_TLS_DEFAULT 0 #define LOG_TLS_EXTENDED 1 TmEcode LogTlsLog(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogTlsLogIPv4(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogTlsLogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode LogTlsLogThreadInit(ThreadVars *, void *, void **); TmEcode LogTlsLogThreadDeinit(ThreadVars *, void *); void LogTlsLogExitPrintStats(ThreadVars *, void *); static void LogTlsLogDeInitCtx(OutputCtx *); void TmModuleLogTlsLogRegister(void) { tmm_modules[TMM_LOGTLSLOG].name = MODULE_NAME; tmm_modules[TMM_LOGTLSLOG].ThreadInit = LogTlsLogThreadInit; tmm_modules[TMM_LOGTLSLOG].Func = LogTlsLog; tmm_modules[TMM_LOGTLSLOG].ThreadExitPrintStats = LogTlsLogExitPrintStats; tmm_modules[TMM_LOGTLSLOG].ThreadDeinit = LogTlsLogThreadDeinit; tmm_modules[TMM_LOGTLSLOG].RegisterTests = NULL; tmm_modules[TMM_LOGTLSLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "tls-log", LogTlsLogInitCtx); /* enable the logger for the app layer */ AppLayerRegisterLogger(ALPROTO_TLS); SC_ATOMIC_INIT(cert_id); } void TmModuleLogTlsLogIPv4Register(void) { tmm_modules[TMM_LOGTLSLOG4].name = "LogTlsLogIPv4"; tmm_modules[TMM_LOGTLSLOG4].ThreadInit = LogTlsLogThreadInit; tmm_modules[TMM_LOGTLSLOG4].Func = LogTlsLogIPv4; tmm_modules[TMM_LOGTLSLOG4].ThreadExitPrintStats = LogTlsLogExitPrintStats; tmm_modules[TMM_LOGTLSLOG4].ThreadDeinit = LogTlsLogThreadDeinit; tmm_modules[TMM_LOGTLSLOG4].RegisterTests = NULL; } void TmModuleLogTlsLogIPv6Register(void) { tmm_modules[TMM_LOGTLSLOG6].name = "LogTlsLogIPv6"; tmm_modules[TMM_LOGTLSLOG6].ThreadInit = LogTlsLogThreadInit; tmm_modules[TMM_LOGTLSLOG6].Func = LogTlsLogIPv6; tmm_modules[TMM_LOGTLSLOG6].ThreadExitPrintStats = LogTlsLogExitPrintStats; tmm_modules[TMM_LOGTLSLOG6].ThreadDeinit = LogTlsLogThreadDeinit; tmm_modules[TMM_LOGTLSLOG6].RegisterTests = NULL; } typedef struct LogTlsFileCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ } LogTlsFileCtx; typedef struct LogTlsLogThread_ { LogTlsFileCtx *tlslog_ctx; /** LogTlsFileCtx has the pointer to the file and a mutex to allow multithreading */ uint32_t tls_cnt; MemBuffer *buffer; uint8_t* enc_buf; size_t enc_buf_len; } LogTlsLogThread; static void CreateTimeString(const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; struct tm *t = (struct tm *) localtime_r(&time, &local_tm); snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); } static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) { if (state->server_connp.cert0_fingerprint != NULL) { MemBufferWriteString(aft->buffer, " SHA1='%s'", state->server_connp.cert0_fingerprint); } switch (state->server_connp.version) { case TLS_VERSION_UNKNOWN: MemBufferWriteString(aft->buffer, " VERSION='UNDETERMINED'"); break; case SSL_VERSION_2: MemBufferWriteString(aft->buffer, " VERSION='SSLv2'"); break; case SSL_VERSION_3: MemBufferWriteString(aft->buffer, " VERSION='SSLv3'"); break; case TLS_VERSION_10: MemBufferWriteString(aft->buffer, " VERSION='TLSv1'"); break; case TLS_VERSION_11: MemBufferWriteString(aft->buffer, " VERSION='TLS 1.1'"); break; case TLS_VERSION_12: MemBufferWriteString(aft->buffer, " VERSION='TLS 1.2'"); break; default: MemBufferWriteString(aft->buffer, " VERSION='0x%04x'", state->server_connp.version); break; } MemBufferWriteString(aft->buffer, "\n"); } static int GetIPInformations(Packet *p, char* srcip, size_t srcip_len, Port* sp, char* dstip, size_t dstip_len, Port* dp, int ipproto) { if ((PKT_IS_TOSERVER(p))) { switch (ipproto) { case AF_INET: PrintInet(AF_INET, (const void *) GET_IPV4_SRC_ADDR_PTR(p), srcip, srcip_len); PrintInet(AF_INET, (const void *) GET_IPV4_DST_ADDR_PTR(p), dstip, dstip_len); break; case AF_INET6: PrintInet(AF_INET6, (const void *) GET_IPV6_SRC_ADDR(p), srcip, srcip_len); PrintInet(AF_INET6, (const void *) GET_IPV6_DST_ADDR(p), dstip, dstip_len); break; default: return 0; } *sp = p->sp; *dp = p->dp; } else { switch (ipproto) { case AF_INET: PrintInet(AF_INET, (const void *) GET_IPV4_DST_ADDR_PTR(p), srcip, srcip_len); PrintInet(AF_INET, (const void *) GET_IPV4_SRC_ADDR_PTR(p), dstip, dstip_len); break; case AF_INET6: PrintInet(AF_INET6, (const void *) GET_IPV6_DST_ADDR(p), srcip, srcip_len); PrintInet(AF_INET6, (const void *) GET_IPV6_SRC_ADDR(p), dstip, dstip_len); break; default: return 0; } *sp = p->dp; *dp = p->sp; } return 1; } static int CreateFileName(LogTlsFileCtx *log, Packet *p, SSLState *state, char *filename) { #define FILELEN 64 //filename len + extention + ending path / + some space int filenamelen = FILELEN + strlen(tls_logfile_base_dir); int file_id = SC_ATOMIC_ADD(cert_id, 1); if (filenamelen + 1 > PATH_MAX) { return 0; } /* Use format : packet time + incremental ID * When running on same pcap it will overwrite * On a live device, we will not be able to overwrite */ snprintf(filename, filenamelen, "%s/%ld.%ld-%d.pem", tls_logfile_base_dir, p->ts.tv_sec, (long int)p->ts.tv_usec, file_id); return 1; } static void LogTlsLogPem(LogTlsLogThread *aft, Packet *p, SSLState *state, LogTlsFileCtx *log, int ipproto) { #define PEMHEADER "-----BEGIN CERTIFICATE-----\n" #define PEMFOOTER "-----END CERTIFICATE-----\n" //Logging pem certificate char filename[PATH_MAX] = ""; FILE* fp = NULL; FILE* fpmeta = NULL; unsigned long pemlen; unsigned char* pembase64ptr = NULL; int ret; SSLCertsChain *cert; if ((state->server_connp.cert_input == NULL) || (state->server_connp.cert_input_len == 0)) SCReturn; CreateFileName(log, p, state, filename); if (strlen(filename) == 0) { SCLogWarning(SC_ERR_FOPEN, "Can't create PEM filename"); SCReturn; } fp = fopen(filename, "w"); if (fp == NULL) { SCLogWarning(SC_ERR_FOPEN, "Can't create PEM file: %s", filename); SCReturn; } TAILQ_FOREACH(cert, &state->server_connp.certs, next) { pemlen = (4 * (cert->cert_len + 2) / 3) +1; if (pemlen > aft->enc_buf_len) { aft->enc_buf = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen); if (aft->enc_buf == NULL) { SCLogWarning(SC_ERR_MEM_ALLOC, "Can't allocate data for base64 encoding"); goto end_fp; } aft->enc_buf_len = pemlen; } memset(aft->enc_buf, 0, aft->enc_buf_len); ret = Base64Encode((unsigned char*) cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen); if (ret != SC_BASE64_OK) { SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "Invalid return of Base64Encode function"); goto end_fwrite_fp; } if (fprintf(fp, PEMHEADER) < 0) goto end_fwrite_fp; pembase64ptr = aft->enc_buf; while (pemlen > 0) { size_t loffset = pemlen >= 64 ? 64 : pemlen; if (fwrite(pembase64ptr, 1, loffset, fp) != loffset) goto end_fwrite_fp; if (fwrite("\n", 1, 1, fp) != 1) goto end_fwrite_fp; pembase64ptr += 64; if (pemlen < 64) break; pemlen -= 64; } if (fprintf(fp, PEMFOOTER) < 0) goto end_fwrite_fp; } fclose(fp); //Logging certificate informations memcpy(filename + (strlen(filename) - 3), "meta", 4); fpmeta = fopen(filename, "w"); if (fpmeta != NULL) { #define PRINT_BUF_LEN 46 char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; char timebuf[64]; Port sp, dp; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); if (!GetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) goto end_fwrite_fpmeta; if (fprintf(fpmeta, "TIME: %s\n", timebuf) < 0) goto end_fwrite_fpmeta; if (p->pcap_cnt > 0) { if (fprintf(fpmeta, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt) < 0) goto end_fwrite_fpmeta; } if (fprintf(fpmeta, "SRC IP: %s\n", srcip) < 0) goto end_fwrite_fpmeta; if (fprintf(fpmeta, "DST IP: %s\n", dstip) < 0) goto end_fwrite_fpmeta; if (fprintf(fpmeta, "PROTO: %" PRIu32 "\n", p->proto) < 0) goto end_fwrite_fpmeta; if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { if (fprintf(fpmeta, "SRC PORT: %" PRIu16 "\n", sp) < 0) goto end_fwrite_fpmeta; if (fprintf(fpmeta, "DST PORT: %" PRIu16 "\n", dp) < 0) goto end_fwrite_fpmeta; } if (fprintf(fpmeta, "TLS SUBJECT: %s\n" "TLS ISSUERDN: %s\n" "TLS FINGERPRINT: %s\n", state->server_connp.cert0_subject, state->server_connp.cert0_issuerdn, state->server_connp.cert0_fingerprint) < 0) goto end_fwrite_fpmeta; fclose(fpmeta); } else { SCLogWarning(SC_ERR_FOPEN, "Can't open meta file: %s", filename); SCReturn; } /* Reset the store flag */ state->server_connp.cert_log_flag &= ~SSL_TLS_LOG_PEM; SCReturn; end_fwrite_fp: fclose(fp); SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); end_fwrite_fpmeta: if (fpmeta) { fclose(fpmeta); SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile"); } SCReturn; end_fp: fclose(fp); } static TmEcode LogTlsLogIPWrapper(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq, int ipproto) { SCEnter(); LogTlsLogThread *aft = (LogTlsLogThread *) data; LogTlsFileCtx *hlog = aft->tlslog_ctx; char timebuf[64]; /* no flow, no tls state */ if (p->flow == NULL) { SCReturnInt(TM_ECODE_OK); } /* check if we have TLS state or not */ FLOWLOCK_WRLOCK(p->flow); uint16_t proto = AppLayerGetProtoFromPacket(p); if (proto != ALPROTO_TLS) goto end; SSLState *ssl_state = (SSLState *) AppLayerGetProtoStateFromPacket(p); if (ssl_state == NULL) { SCLogDebug("no tls state, so no request logging"); goto end; } if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL) goto end; if (ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) { LogTlsLogPem(aft, p, ssl_state, hlog, ipproto); } int r = AppLayerTransactionGetLoggedId(p->flow); if (r != 0) { goto end; } CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); #define PRINT_BUF_LEN 46 char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; Port sp, dp; if (!GetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) { goto end; } /* reset */ MemBufferReset(aft->buffer); MemBufferWriteString(aft->buffer, "%s %s:%d -> %s:%d TLS: Subject='%s' Issuerdn='%s'", timebuf, srcip, sp, dstip, dp, ssl_state->server_connp.cert0_subject, ssl_state->server_connp.cert0_issuerdn); AppLayerTransactionUpdateLoggedId(p->flow); if (hlog->flags & LOG_TLS_EXTENDED) { LogTlsLogExtended(aft, ssl_state); } else { MemBufferWriteString(aft->buffer, "\n"); } aft->tls_cnt ++; SCMutexLock(&hlog->file_ctx->fp_mutex); MemBufferPrintToFPAsString(aft->buffer, hlog->file_ctx->fp); fflush(hlog->file_ctx->fp); SCMutexUnlock(&hlog->file_ctx->fp_mutex); end: FLOWLOCK_UNLOCK(p->flow); SCReturnInt(TM_ECODE_OK); } TmEcode LogTlsLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return LogTlsLogIPWrapper(tv, p, data, pq, postpq, AF_INET); } TmEcode LogTlsLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return LogTlsLogIPWrapper(tv, p, data, pq, postpq, AF_INET6); } TmEcode LogTlsLog(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); /* no flow, no htp state */ if (p->flow == NULL) { SCReturnInt(TM_ECODE_OK); } if (!(PKT_IS_TCP(p))) { SCReturnInt(TM_ECODE_OK); } if (PKT_IS_IPV4(p)) { SCReturnInt(LogTlsLogIPv4(tv, p, data, pq, postpq)); } else if (PKT_IS_IPV6(p)) { SCReturnInt(LogTlsLogIPv6(tv, p, data, pq, postpq)); } SCReturnInt(TM_ECODE_OK); } TmEcode LogTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) { LogTlsLogThread *aft = SCMalloc(sizeof(LogTlsLogThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(LogTlsLogThread)); if (initdata == NULL) { SCLogDebug( "Error getting context for TLSLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); if (aft->buffer == NULL) { SCFree(aft); return TM_ECODE_FAILED; } aft->enc_buf = SCMalloc(CERT_ENC_BUFFER_SIZE); if (aft->enc_buf == NULL) { SCFree(aft); return TM_ECODE_FAILED; } aft->enc_buf_len = CERT_ENC_BUFFER_SIZE; memset(aft->enc_buf, 0, aft->enc_buf_len); /* Use the Ouptut Context (file pointer and mutex) */ aft->tlslog_ctx = ((OutputCtx *) initdata)->data; *data = (void *) aft; return TM_ECODE_OK; } TmEcode LogTlsLogThreadDeinit(ThreadVars *t, void *data) { LogTlsLogThread *aft = (LogTlsLogThread *) data; if (aft == NULL) { return TM_ECODE_OK; } MemBufferFree(aft->buffer); /* clear memory */ memset(aft, 0, sizeof(LogTlsLogThread)); SCFree(aft); return TM_ECODE_OK; } void LogTlsLogExitPrintStats(ThreadVars *tv, void *data) { LogTlsLogThread *aft = (LogTlsLogThread *) data; if (aft == NULL) { return; } SCLogInfo("TLS logger logged %" PRIu32 " requests", aft->tls_cnt); } /** \brief Create a new tls log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful * */ OutputCtx *LogTlsLogInitCtx(ConfNode *conf) { LogFileCtx* file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { SCLogError(SC_ERR_TLS_LOG_GENERIC, "LogTlsLogInitCtx: Couldn't " "create new file_ctx"); return NULL; } char *s_default_log_dir = NULL; if (ConfGet("default-log-dir", &s_default_log_dir) != 1) s_default_log_dir = DEFAULT_LOG_DIR; const char *s_base_dir = NULL; s_base_dir = ConfNodeLookupChildValue(conf, "certs-log-dir"); if (s_base_dir == NULL || strlen(s_base_dir) == 0) { strlcpy(tls_logfile_base_dir, s_default_log_dir, sizeof(tls_logfile_base_dir)); } else { if (PathIsAbsolute(s_base_dir)) { strlcpy(tls_logfile_base_dir, s_base_dir, sizeof(tls_logfile_base_dir)); } else { snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir), "%s/%s", s_default_log_dir, s_base_dir); } } if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { goto filectx_error; } LogTlsFileCtx *tlslog_ctx = SCCalloc(1, sizeof(LogTlsFileCtx)); if (unlikely(tlslog_ctx == NULL)) goto filectx_error; tlslog_ctx->file_ctx = file_ctx; const char *extended = ConfNodeLookupChildValue(conf, "extended"); if (extended == NULL) { tlslog_ctx->flags |= LOG_TLS_DEFAULT; } else { if (ConfValIsTrue(extended)) { tlslog_ctx->flags |= LOG_TLS_EXTENDED; } } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) goto tlslog_error; output_ctx->data = tlslog_ctx; output_ctx->DeInit = LogTlsLogDeInitCtx; SCLogDebug("TLS log output initialized"); return output_ctx; tlslog_error: if (tlslog_ctx != NULL) SCFree(tlslog_ctx); filectx_error: LogFileFreeCtx(file_ctx); return NULL; } static void LogTlsLogDeInitCtx(OutputCtx *output_ctx) { LogTlsFileCtx *tlslog_ctx = (LogTlsFileCtx *) output_ctx->data; LogFileFreeCtx(tlslog_ctx->file_ctx); SCFree(tlslog_ctx); SCFree(output_ctx); } suricata-1.4.7/src/stream-tcp-util.h0000644000000000000000000000271312253546156014233 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __STREAM_TCP_UTIL_H__ #define __STREAM_TCP_UTIL_H__ #include "stream-tcp-private.h" void StreamTcpUTInit(TcpReassemblyThreadCtx **); void StreamTcpUTDeinit(TcpReassemblyThreadCtx *); void StreamTcpUTSetupSession(TcpSession *); void StreamTcpUTClearSession(TcpSession *); void StreamTcpUTSetupStream(TcpStream *, uint32_t isn); void StreamTcpUTClearStream(TcpStream *); int StreamTcpUTAddSegmentWithByte(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, uint32_t, uint8_t, uint16_t); int StreamTcpUTAddSegmentWithPayload(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, uint32_t, uint8_t *, uint16_t); void StreamTcpUtilRegisterTests(void); #endif /* __STREAM_TCP_UTIL_H__ */ suricata-1.4.7/src/util-syslog.h0000644000000000000000000000170312253546156013472 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * */ #ifndef UTIL_SYSLOG_H #define UTIL_SYSLOG_H SCEnumCharMap *SCSyslogGetFacilityMap(void); SCEnumCharMap *SCSyslogGetLogLevelMap(void); #endif /* UTIL_SYSLOG_H */ suricata-1.4.7/src/decode-teredo.c0000644000000000000000000000734412253546156013704 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author Eric Leblond * * Decode Teredo Tunneling protocol. * * This implementation is based upon RFC 4380: http://www.ietf.org/rfc/rfc4380.txt */ #include "suricata-common.h" #include "decode.h" #include "decode-ipv6.h" #include "util-debug.h" #define TEREDO_ORIG_INDICATION_LENGTH 8 /** * \brief Function to decode Teredo packets * * \retval 0 if packet is not a Teredo packet, 1 if it is */ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint8_t *start = pkt; /* Is this packet to short to contain an IPv6 packet ? */ if (len < IPV6_HEADER_LEN) return 0; /* Teredo encapsulate IPv6 in UDP and can add some custom message * part before the IPv6 packet. In our case, we just want to get * over an ORIGIN indication. So we just make one offset if needed. */ if (start[0] == 0x0) { switch (start[1]) { /* origin indication: compatible with tunnel */ case 0x0: /* offset is coherent with len and presence of an IPv6 header */ if (len >= TEREDO_ORIG_INDICATION_LENGTH + IPV6_HEADER_LEN) start += TEREDO_ORIG_INDICATION_LENGTH; else return 0; break; /* authentication: negotiation not real tunnel */ case 0x1: return 0; /* this case is not possible in Teredo: not that protocol */ default: return 0; } } /* There is no specific field that we can check to prove that the packet * is a Teredo packet. We've zapped here all the possible Teredo header * and we should have an IPv6 packet at the start pointer. * We then can only do two checks before sending the encapsulated packets * to decoding: * - The packet has a protocol version which is IPv6. * - The IPv6 length of the packet matches what remains in buffer. */ if (IP_GET_RAW_VER(start) == 6) { IPV6Hdr *thdr = (IPV6Hdr *)start; if (len == IPV6_HEADER_LEN + IPV6_GET_RAW_PLEN(thdr) + (start - pkt)) { if (pq != NULL) { int blen = len - (start - pkt); /* spawn off tunnel packet */ Packet *tp = PacketPseudoPktSetup(p, start, blen, IPPROTO_IPV6); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* send that to the Tunnel decoder */ DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IPV6); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); SCPerfCounterIncr(dtv->counter_teredo, tv->sc_perf_pca); return 1; } } } return 0; } return 0; } /** * @} */ suricata-1.4.7/src/app-layer-ssh.c0000644000000000000000000015523012253546156013664 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon * * App-layer parser for SSH protocol * */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-ssh.h" #include "conf.h" #include "util-spm.h" #include "util-unittest.h" #include "util-debug.h" #include "flow-private.h" #include "util-byte.h" #include "util-memcmp.h" /** * \brief Function to parse the SSH version string of the server * * \param ssh_state Pointer the state in which the value to be stored * \param pstate Application layer tarser state for this session * \param input Pointer the received input data * \param input_len Length in bytes of the received data * \param output Pointer to the list of parsed output elements */ static int SSHParseServerVersion(Flow *f, void *ssh_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { uint8_t *line_ptr = input; uint32_t line_len = input_len; uint32_t offset = 0; SshState *state = (SshState *)ssh_state; while (input_len > 0) { offset = 0; if (pstate->store_len > 0){ const uint8_t delim[] = { 0x0a, }; int r = AlpParseFieldByDelimiter(output, pstate, SSH_FIELD_SERVER_VER_STATE_LINE, delim, sizeof(delim), input, input_len, &offset); if (r == 0) SCReturnInt(0); /* process the result elements */ AppLayerParserResultElmt *e = output->head; line_ptr = NULL; line_len = 0; for (; e != NULL; e = e->next) { SCLogDebug("e %p e->name_idx %" PRIu32 ", e->data_ptr %p, e->data_len " "%" PRIu32, e, e->name_idx, e->data_ptr, e->data_len); /* no parser defined for this field. */ if (e->name_idx != SSH_FIELD_SERVER_VER_STATE_LINE) { continue; } line_ptr = e->data_ptr; line_len = e->data_len; } /* Update for the next round */ input_len -= offset; input += offset; if (line_ptr == NULL) continue; } else { const uint8_t delim[] = { 0x0a, }; int r = AlpParseFieldByDelimiter(output, pstate, SSH_FIELD_SERVER_VER_STATE_LINE, delim, sizeof(delim), input, input_len, &offset); if (r == 0) SCReturnInt(0); /* Temporal pointer / len for the current line */ line_ptr = input; line_len = offset; /* Update for the next round */ input_len -= offset; input += offset; } //printf("INPUT: \n"); //PrintRawDataFp(stdout, line_ptr, line_len); if (line_len < 5) { SCLogDebug("This is not the version line we are searching for (probably a banner or informational messages)"); continue; } /* is it the version line? */ if (SCMemcmp("SSH-", line_ptr, 4) == 0) { if (line_len > 255) { SCLogDebug("Invalid version string, it should be less than 255 characters including "); SCReturnInt(-1); } /* ok, we have found the version line/string, skip it and parse proto version */ line_ptr += 4; line_len -= 4; } else { SCLogDebug("This is not the version line we are searching for (probably a banner or informational messages)"); continue; } uint8_t *proto_end = BasicSearch(line_ptr, line_len, (uint8_t*)"-", 1); if (proto_end == NULL) { /* Strings starting with SSH- are not allowed * if they are not the real version string */ SCLogDebug("Invalid Version String for SSH (invalid usage of SSH- prefix)"); SCReturnInt(-1); } uint64_t proto_ver_len = (uint64_t)(proto_end - line_ptr); state->server_proto_version = SCMalloc(proto_ver_len + 1); if (state->server_proto_version == NULL) { SCReturnInt(-1); } memcpy(state->server_proto_version, line_ptr, proto_ver_len); state->server_proto_version[proto_ver_len] = '\0'; /* Now lets parse the software & version */ line_ptr += proto_ver_len + 1; line_len -= proto_ver_len + 1; if (line_len < 1) { SCLogDebug("No software version specified (weird)"); state->flags |= SSH_FLAG_CLIENT_VERSION_PARSED; /* Return the remaining length */ SCReturnInt(input_len); } uint8_t *sw_end = BasicSearch(line_ptr, line_len, (uint8_t*)" ", 1); if (sw_end == NULL) { sw_end = BasicSearch(line_ptr, line_len, (uint8_t*)"\r", 1); if (sw_end == NULL) { sw_end = line_ptr + line_len; } } uint64_t sw_ver_len = (uint64_t)(sw_end - line_ptr); state->server_software_version = SCMalloc(sw_ver_len + 1); if (state->server_software_version == NULL) { SCReturnInt(-1); } memcpy(state->server_software_version, line_ptr, sw_ver_len); state->server_software_version[sw_ver_len] = '\0'; if (state->server_software_version[sw_ver_len - 1] == 0x0d) state->server_software_version[sw_ver_len - 1] = '\0'; state->flags |= SSH_FLAG_SERVER_VERSION_PARSED; /* Return the remaining length */ SCReturnInt(input_len); } SCReturnInt(0); } /** * \brief Function to parse the SSH field in packet received from the server * * \param ssh_state Pointer the state in which the value to be stored * \param pstate Application layer tarser state for this session * \param input Pointer the received input data * \param input_len Length in bytes of the received data * \param output Pointer to the list of parsed output elements */ static int SSHParseServerRecord(Flow *f, void *ssh_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SshState *state = (SshState *)ssh_state; if (state->flags & SSH_FLAG_PARSER_DONE) { SCReturnInt(0); } SCEnter(); int ret = 0; SCLogDebug("ssh_state %p, pstate %p, input %p,input_len %" PRIu32 "", ssh_state, pstate, input, input_len); //PrintRawDataFp(stdout, input,input_len); if (pstate == NULL) SCReturnInt(-1); if ( !(state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { ret = SSHParseServerVersion(f, ssh_state, pstate, input, input_len, output); if (ret < 0) { if (ret <= -1) { SCLogDebug("Invalid version string"); SCReturnInt(-1); } SCLogDebug("Version string not parsed yet"); pstate->parse_field = 0; SCReturnInt(ret); } else if (state->flags & SSH_FLAG_SERVER_VERSION_PARSED) { SCLogDebug("Version string parsed"); input += input_len - ret; input_len -= (input_len - ret); pstate->parse_field = 1; ret = 1; if (input_len == 0) SCReturnInt(ret); } else { SCLogDebug("Version string not parsed yet"); pstate->parse_field = 0; SCReturnInt(ret); } } else { SCLogDebug("Version string already parsed"); } uint16_t max_fields = 4; int16_t u = 0; uint32_t offset = 0; //PrintRawDataFp(stdout, input,input_len); if (pstate == NULL) SCReturnInt(-1); for (u = pstate->parse_field; u < max_fields; u++) { SCLogDebug("u %" PRIu32 "", u); switch(u % 4) { case 0: { continue; } case 1: /* TLS CONTENT TYPE */ { uint8_t *data = input + offset; uint32_t data_len = input_len - offset; int r = AlpParseFieldBySize(output, pstate, SSH_FIELD_SERVER_PKT_LENGTH, /* single byte field */4, data, data_len, &offset); SCLogDebug("r = %" PRId32 "", r); if (r == 0) { pstate->parse_field = 1; SCReturnInt(0); } else if (r == -1) { SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, " "r %d", r); SCReturnInt(-1); } uint32_t pkt_len = 0; int ret = ByteExtractUint32(&pkt_len, BYTE_BIG_ENDIAN, output->tail->data_len, output->tail->data_ptr); if (ret != 4) { SCReturnInt(-1); } state->srv_hdr.pkt_len = pkt_len; SCLogDebug("pkt len: %"PRIu32, pkt_len); break; } case 2: /* TLS VERSION */ { uint8_t *data = input + offset; uint32_t data_len = input_len - offset; int r = AlpParseFieldBySize(output, pstate, SSH_FIELD_SERVER_PADDING_LENGTH, /* 2 byte field */1, data, data_len, &offset); if (r == 0) { pstate->parse_field = 2; SCReturnInt(0); } else if (r == -1) { SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, " "r %d", r); SCReturnInt(-1); } uint8_t padding_len = 0; if (output->tail->data_len == 1) { padding_len = (uint8_t) *output->tail->data_ptr; SCLogDebug("padding len: %"PRIu8, padding_len); } state->srv_hdr.padding_len = padding_len; break; } case 3: /* SSH_PAYLOAD */ { uint8_t *data = input + offset; uint32_t data_len = input_len - offset; /* we add a -1 to the pkt len since the padding length is already parsed */ int r = AlpParseFieldBySize(output, pstate, SSH_FIELD_SERVER_PAYLOAD, state->srv_hdr.pkt_len - 1, data, data_len, &offset); SCLogDebug("AlpParseFieldBySize returned r %d, offset %"PRIu32, r, offset); if (r == 0) { pstate->parse_field = 3; SCReturnInt(0); } else if (r == -1) { SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, " "r %d", r); SCReturnInt(-1); } uint8_t msg_code = 0; if (output->tail->data_len >= 1) { msg_code = (uint8_t) *output->tail->data_ptr; SCLogDebug("msg code: %"PRIu8, msg_code); } state->srv_hdr.msg_code = msg_code; if (state->srv_hdr.msg_code == SSH_MSG_NEWKEYS) { /* We are not going to inspect any packet more * as the data is now encrypted */ SCLogDebug("SSH parser done (the rest of the communication is encrypted)"); state->flags |= SSH_FLAG_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION; pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY; pstate->parse_field = 1; SCReturnInt(1); } pstate->parse_field = 1; ret = 1; /* If we have remaining data, continue processing */ if ((int)input_len - (int)offset > 0) { u = 0; } break; } } } SCReturnInt(ret); } /** * \brief Function to parse the SSH version string of the client * * \param ssh_state Pointer the state in which the value to be stored * \param pstate Application layer tarser state for this session * \param input Pointer the received input data * \param input_len Length in bytes of the received data * \param output Pointer to the list of parsed output elements */ static int SSHParseClientVersion(Flow *f, void *ssh_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, AppLayerParserResult *output) { uint8_t *line_ptr = input; uint32_t line_len = input_len; uint32_t offset = 0; SshState *state = (SshState *)ssh_state; while (input_len > 0) { offset = 0; if (pstate->store_len > 0){ const uint8_t delim[] = { 0x0a, }; int r = AlpParseFieldByDelimiter(output, pstate, SSH_FIELD_CLIENT_VER_STATE_LINE, delim, sizeof(delim), input, input_len, &offset); if (r == 0) SCReturnInt(0); /* process the result elements */ AppLayerParserResultElmt *e = output->head; line_ptr = NULL; line_len = 0; for (; e != NULL; e = e->next) { SCLogDebug("e %p e->name_idx %" PRIu32 ", e->data_ptr %p, e->data_len " "%" PRIu32, e, e->name_idx, e->data_ptr, e->data_len); /* no parser defined for this field. */ if (e->name_idx != SSH_FIELD_CLIENT_VER_STATE_LINE) { continue; } line_ptr = e->data_ptr; line_len = e->data_len; } /* Update for the next round */ input_len -= offset; input += offset; if (line_ptr == NULL) continue; } else { const uint8_t delim[] = { 0x0a, }; int r = AlpParseFieldByDelimiter(output, pstate, SSH_FIELD_CLIENT_VER_STATE_LINE, delim, sizeof(delim), input, input_len, &offset); if (r == 0) SCReturnInt(0); /* Temporal pointer / len for the current line */ line_ptr = input; line_len = offset; /* Update for the next round */ input_len -= offset; input += offset; } //PrintRawDataFp(stdout, line_ptr, line_len); if (line_len < 5) { SCLogDebug("This is not the version line we are searching for (probably a banner or informational messages)"); continue; } /* is it the version line? */ if (SCMemcmp("SSH-", line_ptr, 4) == 0) { if (line_len > 255) { SCLogDebug("Invalid version string, it should be less than 255 characters including "); SCReturnInt(-1); } /* ok, we have found the version line/string, skip it and parse proto version */ line_ptr += 4; line_len -= 4; } else { SCLogDebug("This is not the version line we are searching for (probably a banner or informational messages)"); continue; } uint8_t *proto_end = BasicSearch(line_ptr, line_len, (uint8_t*)"-", 1); if (proto_end == NULL) { /* Strings starting with SSH- are not allowed * if they are not the real version string */ SCLogDebug("Invalid Version String for SSH (invalid usage of SSH- prefix)"); SCReturnInt(-1); } uint64_t proto_ver_len = (uint64_t)(proto_end - line_ptr); state->client_proto_version = SCMalloc(proto_ver_len + 1); if (state->client_proto_version == NULL) { SCReturnInt(-1); } memcpy(state->client_proto_version, line_ptr, proto_ver_len); state->client_proto_version[proto_ver_len] = '\0'; /* Now lets parse the software & version */ line_ptr += proto_ver_len + 1; line_len -= proto_ver_len + 1; if (line_len < 1) { SCLogDebug("No software version specified (weird)"); state->flags |= SSH_FLAG_CLIENT_VERSION_PARSED; /* Return the remaining length */ SCReturnInt(input_len); } uint8_t *sw_end = BasicSearch(line_ptr, line_len, (uint8_t*)" ", 1); if (sw_end == NULL) { sw_end = BasicSearch(line_ptr, line_len, (uint8_t*)"\r", 1); if (sw_end == NULL) { sw_end = line_ptr + line_len; } } uint64_t sw_ver_len = (uint64_t)(sw_end - line_ptr); state->client_software_version = SCMalloc(sw_ver_len + 1); if (state->client_software_version == NULL) { SCReturnInt(-1); } memcpy(state->client_software_version, line_ptr, sw_ver_len); state->client_software_version[sw_ver_len] = '\0'; if (state->client_software_version[sw_ver_len - 1] == 0x0d) state->client_software_version[sw_ver_len - 1] = '\0'; state->flags |= SSH_FLAG_CLIENT_VERSION_PARSED; /* Return the remaining length */ SCReturnInt(input_len); } SCReturnInt(0); } /** * \brief Function to parse the SSH field in packet received from the client * * \param ssh_state Pointer the state in which the value to be stored * \param pstate Application layer tarser state for this session * \param input Pointer the received input data * \param input_len Length in bytes of the received data * \param output Pointer to the list of parsed output elements */ static int SSHParseClientRecord(Flow *f, void *ssh_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SshState *state = (SshState *)ssh_state; if (state->flags & SSH_FLAG_PARSER_DONE) { SCReturnInt(0); } SCEnter(); int ret = 0; SCLogDebug("ssh_state %p, pstate %p, input %p,input_len %" PRIu32 "", ssh_state, pstate, input, input_len); //PrintRawDataFp(stdout, input,input_len); if (pstate == NULL) SCReturnInt(-1); if ( !(state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { ret = SSHParseClientVersion(f, ssh_state, pstate, input, input_len, output); if (ret < 0) { if (ret <= -1) { SCLogDebug("Invalid version string"); SCReturnInt(-1); } SCLogDebug("Version string not parsed yet"); pstate->parse_field = 0; SCReturnInt(0); } else if (state->flags & SSH_FLAG_CLIENT_VERSION_PARSED) { SCLogDebug("Version string parsed"); input += input_len - ret; input_len -= (input_len - ret); pstate->parse_field = 1; ret = 1; } else { SCLogDebug("Version string not parsed yet"); pstate->parse_field = 0; SCReturnInt(0); } } else { SCLogDebug("Version string already parsed"); } uint16_t max_fields = 4; int16_t u = 0; uint32_t offset = 0; //printf("INPUT: \n"); //PrintRawDataFp(stdout, input,input_len); if (pstate == NULL) SCReturnInt(-1); for (u = pstate->parse_field; u < max_fields; u++) { SCLogDebug("u %" PRIu32 "", u); switch(u % 4) { case 0: { continue; } case 1: /* TLS CONTENT TYPE */ { uint8_t *data = input + offset; uint32_t data_len = input_len - offset; int r = AlpParseFieldBySize(output, pstate, SSH_FIELD_CLIENT_PKT_LENGTH, /* single byte field */4, data, data_len, &offset); SCLogDebug("r = %" PRId32 "", r); if (r == 0) { pstate->parse_field = 1; SCReturnInt(0); } else if (r == -1) { SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, " "r %d", r); SCReturnInt(-1); } uint32_t pkt_len = 0; int ret = ByteExtractUint32(&pkt_len, BYTE_BIG_ENDIAN, output->tail->data_len, output->tail->data_ptr); if (ret != 4) { SCReturnInt(-1); } state->cli_hdr.pkt_len = pkt_len; SCLogDebug("pkt len: %"PRIu32"\n", pkt_len); break; } case 2: /* TLS VERSION */ { uint8_t *data = input + offset; uint32_t data_len = input_len - offset; int r = AlpParseFieldBySize(output, pstate, SSH_FIELD_CLIENT_PADDING_LENGTH, /* 2 byte field */1, data, data_len, &offset); if (r == 0) { pstate->parse_field = 2; SCReturnInt(0); } else if (r == -1) { SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, " "r %d", r); SCReturnInt(-1); } uint8_t padding_len = 0; if (output->tail->data_len == 1) { padding_len = (uint8_t) *output->tail->data_ptr; SCLogDebug("padding len: %"PRIu8, padding_len); } state->cli_hdr.padding_len = padding_len; break; } case 3: /* SSH_PAYLOAD */ { uint8_t *data = input + offset; uint32_t data_len = input_len - offset; /* we add a -1 to the pkt len since the padding length is already parsed */ int r = AlpParseFieldBySize(output, pstate, SSH_FIELD_CLIENT_PAYLOAD, /* 1 byte field */ state->cli_hdr.pkt_len - 1, data, data_len, &offset); SCLogDebug("AlpParseFieldBySize returned r %d, offset %"PRIu32, r, offset); if (r == 0) { pstate->parse_field = 3; SCReturnInt(0); } else if (r == -1) { SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, " "r %d", r); SCReturnInt(-1); } uint8_t msg_code = 0; if (output->tail->data_len >= 1) { msg_code = (uint8_t) *output->tail->data_ptr; SCLogDebug("msg code: %"PRIu8, msg_code); } state->cli_hdr.msg_code = msg_code; if (state->cli_hdr.msg_code == SSH_MSG_NEWKEYS) { /* We are not going to inspect any packet more * as the data is now encrypted */ SCLogDebug("SSH parser done (the rest of the communication is encrypted)"); state->flags |= SSH_FLAG_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION; pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY; pstate->parse_field = 1; SCReturnInt(1); } pstate->parse_field = 1; ret = 1; /* If we have remaining data, continue processing */ if (input_len - offset > 0) { u = 0; } break; } } } SCReturnInt(ret); } /** \brief Function to allocates the SSH state memory */ static void *SSHStateAlloc(void) { void *s = SCMalloc(sizeof(SshState)); if (unlikely(s == NULL)) return NULL; memset(s, 0, sizeof(SshState)); return s; } /** \brief Function to free the SSH state memory */ static void SSHStateFree(void *state) { SshState *s = (SshState *)state; if (s->client_proto_version != NULL) SCFree(s->client_proto_version); if (s->client_software_version != NULL) SCFree(s->client_software_version); if (s->server_proto_version != NULL) SCFree(s->server_proto_version); if (s->server_software_version != NULL) SCFree(s->server_software_version); SCFree(s); } /** \brief Function to register the SSH protocol parsers and other functions */ void RegisterSSHParsers(void) { char *proto_name = "ssh"; /** SSH */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_SSH, "SSH-", 4, 0, STREAM_TOSERVER); AppLayerRegisterProto(proto_name, ALPROTO_SSH, STREAM_TOCLIENT, SSHParseServerRecord); AppLayerRegisterProto(proto_name, ALPROTO_SSH, STREAM_TOSERVER, SSHParseClientRecord); AppLayerRegisterStateFuncs(ALPROTO_SSH, SSHStateAlloc, SSHStateFree); } /* UNITTESTS */ #ifdef UNITTESTS /** \test Send a version string in one chunk (client version str). */ static int SSHParserTest01(void) { int result = 0; Flow f; uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n"; uint32_t sshlen = sizeof(sshbuf) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); result = 0; goto end; } if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { printf("Client version string not parsed: "); result = 0; goto end; } if (ssh_state->client_software_version == NULL) { printf("Client version string not parsed: "); result = 0; goto end; } if (ssh_state->client_proto_version == NULL) { printf("Client version string not parsed: "); result = 0; goto end; } if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); result = 0; goto end; } if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); result = 0; goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a version string in one chunk but multiple lines and comments. * (client version str) */ static int SSHParserTest02(void) { int result = 0; Flow f; uint8_t sshbuf[] = "lalala\n lal al al\nSSH-2.0-MySSHClient-0.5.1 some comments...\n"; uint32_t sshlen = sizeof(sshbuf) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); result = 0; goto end; } if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { printf("Client version string not parsed: "); result = 0; goto end; } if (ssh_state->client_software_version == NULL) { printf("Client version string not parsed: "); result = 0; goto end; } if (ssh_state->client_proto_version == NULL) { printf("Client version string not parsed: "); result = 0; goto end; } if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); result = 0; goto end; } if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); result = 0; goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a invalid version string in one chunk but multiple lines and comments. * (client version str) */ static int SSHParserTest03(void) { int result = 0; Flow f; uint8_t sshbuf[] = "lalala\n lal al al\nSSH-2.0 some comments...\n"; uint32_t sshlen = sizeof(sshbuf) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r); result = 0; goto end; } /* Ok, it returned an error. Let's make sure we didn't parse the string at all */ SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); result = 0; goto end; } if (ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED) { printf("Client version string parsed? It's not a valid string: "); result = 0; goto end; } if (ssh_state->client_proto_version != NULL) { result = 0; goto end; } if (ssh_state->client_software_version != NULL) { result = 0; goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a version string in one chunk (server version str). */ static int SSHParserTest04(void) { int result = 0; Flow f; uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n"; uint32_t sshlen = sizeof(sshbuf) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); result = 0; goto end; } if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { printf("Client version string not parsed: "); result = 0; goto end; } if (ssh_state->server_software_version == NULL) { printf("Client version string not parsed: "); result = 0; goto end; } if (ssh_state->server_proto_version == NULL) { printf("Client version string not parsed: "); result = 0; goto end; } if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); result = 0; goto end; } if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); result = 0; goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a version string in one chunk but multiple lines and comments. * (server version str) */ static int SSHParserTest05(void) { int result = 0; Flow f; uint8_t sshbuf[] = "lalala\n lal al al\nSSH-2.0-MySSHClient-0.5.1 some comments...\n"; uint32_t sshlen = sizeof(sshbuf) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); result = 0; goto end; } if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { printf("Client version string not parsed: "); result = 0; goto end; } if (ssh_state->server_software_version == NULL) { printf("Client version string not parsed: "); result = 0; goto end; } if (ssh_state->server_proto_version == NULL) { printf("Client version string not parsed: "); result = 0; goto end; } if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); result = 0; goto end; } if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); result = 0; goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a invalid version string in one chunk but multiple lines and comments. * (server version str) */ static int SSHParserTest06(void) { int result = 0; Flow f; uint8_t sshbuf[] = "lalala\n lal al al\nSSH-2.0 some comments...\n"; uint32_t sshlen = sizeof(sshbuf) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r); result = 0; goto end; } /* Ok, it returned an error. Let's make sure we didn't parse the string at all */ SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); result = 0; goto end; } if (ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED) { printf("Client version string parsed? It's not a valid string: "); result = 0; goto end; } if (ssh_state->server_proto_version != NULL) { result = 0; goto end; } if (ssh_state->server_software_version != NULL) { result = 0; goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } static int SSHParserTest07(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "SSH-2."; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = { "0-MySSHClient-0.5.1\r\n"}; uint32_t sshlen2 = sizeof(sshbuf2) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { printf("Client version string not parsed: "); goto end; } if (ssh_state->client_software_version == NULL) { printf("Client version string not parsed: "); goto end; } if (ssh_state->client_proto_version == NULL) { printf("Client version string not parsed: "); goto end; } if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a version banner in three chunks. */ static int SSHParserTest08(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-"; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "2."; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = { "0-MySSHClient-0.5.1\r\n"}; uint32_t sshlen3 = sizeof(sshbuf3) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { printf("Client version string not parsed: "); goto end; } if (ssh_state->client_software_version == NULL) { printf("Client version string not parsed: "); goto end; } if (ssh_state->client_proto_version == NULL) { printf("Client version string not parsed: "); goto end; } if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } static int SSHParserTest09(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "SSH-2."; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = { "0-MySSHClient-0.5.1\r\n"}; uint32_t sshlen2 = sizeof(sshbuf2) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { printf("Client version string not parsed: "); goto end; } if (ssh_state->server_software_version == NULL) { printf("Client version string not parsed: "); goto end; } if (ssh_state->server_proto_version == NULL) { printf("Client version string not parsed: "); goto end; } if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a version banner in three chunks. */ static int SSHParserTest10(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-"; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "2."; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = { "0-MySSHClient-0.5.1\r\n"}; uint32_t sshlen3 = sizeof(sshbuf3) - 1; TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { printf("Client version string not parsed: "); goto end; } if (ssh_state->server_software_version == NULL) { printf("Client version string not parsed: "); goto end; } if (ssh_state->server_proto_version == NULL) { printf("Client version string not parsed: "); goto end; } if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a banner and record in three chunks. */ static int SSHParserTest11(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-"; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00}; uint32_t sshlen3 = sizeof(sshbuf3); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { printf("Client version string not parsed: "); goto end; } if (ssh_state->client_software_version == NULL) { printf("Client version string not parsed: "); goto end; } if (ssh_state->client_proto_version == NULL) { printf("Client version string not parsed: "); goto end; } if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_PARSER_DONE)) { printf("Didn't detect the msg code of new keys (ciphered data starts): "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send a banner and 2 records record in four chunks. */ static int SSHParserTest12(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-"; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00}; uint32_t sshlen3 = sizeof(sshbuf3); uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00}; uint32_t sshlen4 = sizeof(sshbuf4); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) { printf("Client version string not parsed: "); goto end; } if (ssh_state->client_software_version == NULL) { printf("Client version string not parsed: "); goto end; } if (ssh_state->client_proto_version == NULL) { printf("Client version string not parsed: "); goto end; } if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_PARSER_DONE)) { printf("Didn't detect the msg code of new keys (ciphered data starts): "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send toserver a banner and record in three chunks. */ static int SSHParserTest13(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-"; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00}; uint32_t sshlen3 = sizeof(sshbuf3); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { printf("Client version string not parsed: "); goto end; } if (ssh_state->server_software_version == NULL) { printf("Client version string not parsed: "); goto end; } if (ssh_state->server_proto_version == NULL) { printf("Client version string not parsed: "); goto end; } if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_PARSER_DONE)) { printf("Didn't detect the msg code of new keys (ciphered data starts): "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } /** \test Send toserver a banner and 2 records record in four chunks. */ static int SSHParserTest14(void) { int result = 0; Flow f; uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-"; uint32_t sshlen1 = sizeof(sshbuf1) - 1; uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; uint32_t sshlen2 = sizeof(sshbuf2) - 1; uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00}; uint32_t sshlen3 = sizeof(sshbuf3); uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00}; uint32_t sshlen4 = sizeof(sshbuf4); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); goto end; } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { printf("no ssh state: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) { printf("Client version string not parsed: "); goto end; } if (ssh_state->server_software_version == NULL) { printf("Client version string not parsed: "); goto end; } if (ssh_state->server_proto_version == NULL) { printf("Client version string not parsed: "); goto end; } if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) { printf("Client version string not parsed correctly: "); goto end; } if ( !(ssh_state->flags & SSH_FLAG_PARSER_DONE)) { printf("Didn't detect the msg code of new keys (ciphered data starts): "); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); return result; } #endif /* UNITTESTS */ void SSHParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01, 1); UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02, 1); UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03, 1); UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04, 1); UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05, 1); UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06, 1); UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07, 1); UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08, 1); UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09, 1); UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10, 1); UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11, 1); UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12, 1); UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13, 1); UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/win32-service.c0000644000000000000000000002455412253546156013603 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Ondrej Slanina * * Windows service functions */ #ifdef OS_WIN32 #include "suricata-common.h" #include "suricata.h" #include "win32-service.h" static SERVICE_STATUS_HANDLE service_status_handle = 0; static int service_argc = 0; static char **service_argv = NULL; static int service_initialized = 0; int main(int argc, char **argv); /** * \brief Detect if running as service or console app */ int SCRunningAsService(void) { HANDLE h = INVALID_HANDLE_VALUE; if ((h = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { SCLogInfo("Running as service: yes"); return 1; } CloseHandle(h); SCLogInfo("Running as service: no"); return 0; } /** * \brief Detect if running as service or console app */ void SCAtExitHandler(void) { SERVICE_STATUS status = { SERVICE_WIN32, SERVICE_STOPPED, SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, NO_ERROR, NO_ERROR, 0, 0 }; SCLogInfo("Exit handler called."); /* mark service as stopped */ if (!SetServiceStatus(service_status_handle, &status)) { SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError()); } else { SCLogInfo("Service status set to: SERVICE_STOPPED"); } } /** * \brief Service handler */ static DWORD WINAPI SCServiceCtrlHandlerEx(DWORD code, DWORD etype, LPVOID edata, LPVOID context) { if (code == SERVICE_CONTROL_SHUTDOWN || code == SERVICE_CONTROL_STOP) { SERVICE_STATUS status = { SERVICE_WIN32, SERVICE_STOP_PENDING, SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, NO_ERROR, NO_ERROR, 0, 0 }; SCLogInfo("Service control handler called with %s control code.", ((code == SERVICE_CONTROL_SHUTDOWN) ? ("SERVICE_CONTROL_SHUTDOWN") : ("SERVICE_CONTROL_STOP"))); /* mark service as stop pending */ if (!SetServiceStatus(service_status_handle, &status)) { SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError()); } else { SCLogInfo("Service status set to: SERVICE_STOP_PENDING"); } /* mark engine as stopping */ EngineStop(); return NO_ERROR; } return ERROR_CALL_NOT_IMPLEMENTED; } /** * \brief Service main function */ static void WINAPI SCServiceMain(uint32_t argc, char** argv) { SERVICE_STATUS status = { SERVICE_WIN32, SERVICE_RUNNING, SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, NO_ERROR, NO_ERROR, 0, 0 }; if ((service_status_handle = RegisterServiceCtrlHandlerEx(PROG_NAME, SCServiceCtrlHandlerEx, NULL)) == (SERVICE_STATUS_HANDLE)0) { SCLogError(SC_ERR_SVC, "Can't register service control handler: %d", (int)GetLastError()); return; } /* register exit handler */ if (atexit(SCAtExitHandler)) { SCLogWarning(SC_ERR_SVC, "Can't register exit handler: %d", (int)GetLastError()); } /* mark service as running immediately */ if (!SetServiceStatus(service_status_handle, &status)) { SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError()); } else { SCLogInfo("Service status set to: SERVICE_RUNNING"); } SCLogInfo("Entering main function..."); /* suricata initialization -> main loop -> uninitialization */ main(service_argc, service_argv); SCLogInfo("Leaving main function."); /* mark service as stopped */ status.dwCurrentState = SERVICE_STOPPED; if (!SetServiceStatus(service_status_handle, &status)) { SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError()); } else { SCLogInfo("Service status set to: SERVICE_STOPPED"); } } /** * \brief Init suricata service * * \param argc num of arguments * \param argv passed arguments */ int SCServiceInit(int argc, char **argv) { SERVICE_TABLE_ENTRY DispatchTable[] = { {PROG_NAME, (LPSERVICE_MAIN_FUNCTION) SCServiceMain}, {NULL, NULL} }; /* continue with suricata initialization */ if (service_initialized) { SCLogWarning(SC_ERR_SVC, "Service is already initialized."); return 0; } /* save args */ service_argc = argc; service_argv = argv; service_initialized = 1; SCLogInfo("Entering service control dispatcher..."); if (!StartServiceCtrlDispatcher(DispatchTable)) { /* exit with failure */ exit(EXIT_FAILURE); } SCLogInfo("Leaving service control dispatcher."); /* exit with success */ exit(EXIT_SUCCESS); } /** * \brief Install suricata as service * * \param argc num of arguments * \param argv passed arguments */ int SCServiceInstall(int argc, char **argv) { char path[2048]; SC_HANDLE service = NULL; SC_HANDLE scm = NULL; int ret = -1; int i = 0; do { memset(path, 0, sizeof(path)); if (GetModuleFileName(NULL, path, MAX_PATH) == 0 ){ SCLogError(SC_ERR_SVC, "Can't get path to service binary: %d", (int)GetLastError()); break; } /* skip name of binary itself */ for (i = 1; i < argc; i++) { if ((strlen(argv[i]) <= strlen("--service-install")) && (strncmp("--service-install", argv[i], strlen(argv[i])) == 0)) { continue; } strlcat(path, " ", sizeof(path) - strlen(path) - 1); strlcat(path, argv[i], sizeof(path) - strlen(path) - 1); } if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) { SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError()); break; } service = CreateService( scm, PROG_NAME, PROG_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL); if (service == NULL) { SCLogError(SC_ERR_SVC, "Can't create service: %d", (int)GetLastError()); break; } ret = 0; } while(0); if (service) { CloseServiceHandle(service); } if (scm) { CloseServiceHandle(scm); } return ret; } /** * \brief Remove suricata service * * \param argc num of arguments * \param argv passed arguments */ int SCServiceRemove(int argc, char **argv) { SERVICE_STATUS status; SC_HANDLE service = NULL; SC_HANDLE scm = NULL; int ret = -1; do { if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) { SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError()); break; } if ((service = OpenService(scm, PROG_NAME, SERVICE_ALL_ACCESS)) == NULL) { SCLogError(SC_ERR_SVC, "Can't open service: %d", (int)GetLastError()); break; } if (!QueryServiceStatus(service, &status)) { SCLogError(SC_ERR_SVC, "Can't query service status: %d", (int)GetLastError()); break; } if (status.dwCurrentState != SERVICE_STOPPED) { SCLogError(SC_ERR_SVC, "Service isn't in stopped state: %d", (int)GetLastError()); break; } if (!DeleteService(service)) { SCLogError(SC_ERR_SVC, "Can't delete service: %d", (int)GetLastError()); break; } ret = 0; } while(0); if (service) { CloseServiceHandle(service); } if (scm) { CloseServiceHandle(scm); } return ret; } /** * \brief Change suricata service startup parameters * * \param argc num of arguments * \param argv passed arguments */ int SCServiceChangeParams(int argc, char **argv) { char path[2048]; SC_HANDLE service = NULL; SC_HANDLE scm = NULL; int ret = -1; int i = 0; do { memset(path, 0, sizeof(path)); if (GetModuleFileName(NULL, path, MAX_PATH) == 0 ){ SCLogError(SC_ERR_SVC, "Can't get path to service binary: %d", (int)GetLastError()); break; } /* skip name of binary itself */ for (i = 1; i < argc; i++) { if ((strlen(argv[i]) <= strlen("--service-change-params")) && (strncmp("--service-change-params", argv[i], strlen(argv[i])) == 0)) { continue; } strlcat(path, " ", sizeof(path) - strlen(path) - 1); strlcat(path, argv[i], sizeof(path) - strlen(path) - 1); } if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) { SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError()); break; } if ((service = OpenService(scm, PROG_NAME, SERVICE_ALL_ACCESS)) == NULL) { SCLogError(SC_ERR_SVC, "Can't open service: %d", (int)GetLastError()); break; } if (!ChangeServiceConfig( service, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL, PROG_NAME)) { SCLogError(SC_ERR_SVC, "Can't change service configuration: %d", (int)GetLastError()); break; } ret = 0; } while(0); return ret; } #endif /* OS_WIN32 */ suricata-1.4.7/src/stream.c0000644000000000000000000001472312253546156012473 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Stream Chunk Handling API */ #include "suricata-common.h" #include "decode.h" #include "threads.h" #include "stream.h" #include "util-pool.h" #include "util-debug.h" #include "stream-tcp.h" #include "flow-util.h" #ifdef DEBUG static SCMutex stream_pool_memuse_mutex; static uint64_t stream_pool_memuse = 0; static uint64_t stream_pool_memcnt = 0; #endif /* per queue setting */ static uint16_t toserver_min_chunk_len = 2560; static uint16_t toclient_min_chunk_len = 2560; static Pool *stream_msg_pool = NULL; static SCMutex stream_msg_pool_mutex = PTHREAD_MUTEX_INITIALIZER; int StreamMsgInit(void *data, void *initdata) { memset(data, 0, sizeof(StreamMsg)); #ifdef DEBUG SCMutexLock(&stream_pool_memuse_mutex); stream_pool_memuse += sizeof(StreamMsg); stream_pool_memcnt ++; SCMutexUnlock(&stream_pool_memuse_mutex); #endif return 1; } static void StreamMsgEnqueue (StreamMsgQueue *q, StreamMsg *s) { SCEnter(); SCLogDebug("s %p", s); /* more packets in queue */ if (q->top != NULL) { s->next = q->top; q->top->prev = s; q->top = s; /* only packet */ } else { q->top = s; q->bot = s; } q->len++; #ifdef DBG_PERF if (q->len > q->dbg_maxlen) q->dbg_maxlen = q->len; #endif /* DBG_PERF */ SCReturn; } static StreamMsg *StreamMsgDequeue (StreamMsgQueue *q) { SCEnter(); /* if the queue is empty there are no packets left. * In that case we sleep and try again. */ if (q->len == 0) { SCReturnPtr(NULL, "StreamMsg"); } /* pull the bottom packet from the queue */ StreamMsg *s = q->bot; /* more packets in queue */ if (q->bot->prev != NULL) { q->bot = q->bot->prev; q->bot->next = NULL; /* just the one we remove, so now empty */ } else { q->top = NULL; q->bot = NULL; } q->len--; s->next = NULL; s->prev = NULL; SCReturnPtr(s, "StreamMsg"); } /* Used by stream reassembler to get msgs */ StreamMsg *StreamMsgGetFromPool(void) { SCMutexLock(&stream_msg_pool_mutex); StreamMsg *s = (StreamMsg *)PoolGet(stream_msg_pool); SCMutexUnlock(&stream_msg_pool_mutex); return s; } /* Used by l7inspection to return msgs to pool */ void StreamMsgReturnToPool(StreamMsg *s) { SCLogDebug("s %p", s); SCMutexLock(&stream_msg_pool_mutex); PoolReturn(stream_msg_pool, (void *)s); SCMutexUnlock(&stream_msg_pool_mutex); } /* Used by l7inspection to get msgs with data */ StreamMsg *StreamMsgGetFromQueue(StreamMsgQueue *q) { if (q->len > 0) { StreamMsg *s = StreamMsgDequeue(q); return s; } else { /* return NULL if we have no stream msg. Should only happen on signals. */ return NULL; } } /* Used by stream reassembler to fill the queue for l7inspect reading */ void StreamMsgPutInQueue(StreamMsgQueue *q, StreamMsg *s) { StreamMsgEnqueue(q, s); SCLogDebug("q->len %" PRIu32 "", q->len); } void StreamMsgQueuesInit(void) { #ifdef DEBUG SCMutexInit(&stream_pool_memuse_mutex, NULL); #endif SCMutexLock(&stream_msg_pool_mutex); stream_msg_pool = PoolInit(0,250,sizeof(StreamMsg),NULL,StreamMsgInit,NULL,NULL,NULL); if (stream_msg_pool == NULL) exit(EXIT_FAILURE); /* XXX */ SCMutexUnlock(&stream_msg_pool_mutex); } void StreamMsgQueuesDeinit(char quiet) { SCMutexLock(&stream_msg_pool_mutex); PoolFree(stream_msg_pool); SCMutexUnlock(&stream_msg_pool_mutex); #ifdef DEBUG SCMutexDestroy(&stream_pool_memuse_mutex); if (quiet == FALSE) SCLogDebug("stream_pool_memuse %"PRIu64", stream_pool_memcnt %"PRIu64"", stream_pool_memuse, stream_pool_memcnt); #endif } /** \brief alloc a stream msg queue * \retval smq ptr to the queue or NULL */ StreamMsgQueue *StreamMsgQueueGetNew(void) { StreamMsgQueue *smq = SCMalloc(sizeof(StreamMsgQueue)); if (unlikely(smq == NULL)) return NULL; memset(smq, 0x00, sizeof(StreamMsgQueue)); return smq; } /** \brief Free a StreamMsgQueue * \param q the queue to free * \todo we may want to consider non empty queue's */ void StreamMsgQueueFree(StreamMsgQueue *q) { SCFree(q); } StreamMsgQueue *StreamMsgQueueGetByPort(uint16_t port) { /* XXX implement this */ return NULL;//&stream_q; } void StreamMsgQueueSetMinChunkLen(uint8_t dir, uint16_t len) { if (dir == FLOW_PKT_TOSERVER) { toserver_min_chunk_len = len; } else { toclient_min_chunk_len = len; } } uint16_t StreamMsgQueueGetMinChunkLen(uint8_t dir) { if (dir == FLOW_PKT_TOSERVER) { return toserver_min_chunk_len; } else { return toclient_min_chunk_len; } } /** \brief Return a list of smsgs to the pool */ void StreamMsgReturnListToPool(void *list) { /* if we have (a) smsg(s), return to the pool */ StreamMsg *smsg = (StreamMsg *)list; while (smsg != NULL) { StreamMsg *smsg_next = smsg->next; SCLogDebug("returning smsg %p to pool", smsg); smsg->next = NULL; smsg->prev = NULL; FlowDeReference(&smsg->flow); StreamMsgReturnToPool(smsg); smsg = smsg_next; } } /** \brief Run callback for all segments * * \return -1 in case of error, the number of segment in case of success */ int StreamSegmentForEach(Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data) { switch(p->proto) { case IPPROTO_TCP: return StreamTcpSegmentForEach(p, flag, CallbackFunc, data); break; case IPPROTO_UDP: SCLogWarning(SC_ERR_UNKNOWN_PROTOCOL, "UDP is currently unsupported"); break; default: SCLogWarning(SC_ERR_UNKNOWN_PROTOCOL, "This protocol is currently unsupported"); break; } return 0; } suricata-1.4.7/src/host-timeout.c0000644000000000000000000001000112253546156013622 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #include "suricata-common.h" #include "host.h" #include "detect-engine-tag.h" #include "detect-engine-threshold.h" #include "reputation.h" uint32_t HostGetSpareCount(void) { return HostSpareQueueGetSize(); } uint32_t HostGetActiveCount(void) { return SC_ATOMIC_GET(host_counter); } /** \internal * \brief See if we can really discard this host. Check use_cnt reference. * * \param h host * \param ts timestamp * * \retval 0 not timed out just yet * \retval 1 fully timed out, lets kill it */ static int HostHostTimedOut(Host *h, struct timeval *ts) { int tags = 0; int thresholds = 0; /** never prune a host that is used by a packet * we are currently processing in one of the threads */ if (SC_ATOMIC_GET(h->use_cnt) > 0) { return 0; } if (h->iprep) { if (SRepHostTimedOut(h) == 0) return 0; SCLogDebug("host %p reputation timed out", h); } if (h->tag && TagTimeoutCheck(h, ts) == 0) { tags = 1; } if (h->threshold && ThresholdTimeoutCheck(h, ts) == 0) { thresholds = 1; } if (tags || thresholds) return 0; SCLogDebug("host %p timed out", h); return 1; } /** * \internal * * \brief check all hosts in a hash row for timing out * * \param hb host hash row *LOCKED* * \param h last host in the hash row * \param ts timestamp * * \retval cnt timed out hosts */ static uint32_t HostHashRowTimeout(HostHashRow *hb, Host *h, struct timeval *ts) { uint32_t cnt = 0; do { if (SCMutexTrylock(&h->m) != 0) { h = h->hprev; continue; } Host *next_host = h->hprev; /* check if the host is fully timed out and * ready to be discarded. */ if (HostHostTimedOut(h, ts) == 1) { /* remove from the hash */ if (h->hprev != NULL) h->hprev->hnext = h->hnext; if (h->hnext != NULL) h->hnext->hprev = h->hprev; if (hb->head == h) hb->head = h->hnext; if (hb->tail == h) hb->tail = h->hprev; h->hnext = NULL; h->hprev = NULL; HostClearMemory (h); /* no one is referring to this host, use_cnt 0, removed from hash * so we can unlock it and move it back to the spare queue. */ SCMutexUnlock(&h->m); /* move to spare list */ HostMoveToSpare(h); cnt++; } else { SCMutexUnlock(&h->m); } h = next_host; } while (h != NULL); return cnt; } /** * \brief time out hosts from the hash * * \param ts timestamp * * \retval cnt number of timed out host */ uint32_t HostTimeoutHash(struct timeval *ts) { uint32_t idx = 0; uint32_t cnt = 0; for (idx = 0; idx < host_config.hash_size; idx++) { HostHashRow *hb = &host_hash[idx]; if (HRLOCK_TRYLOCK(hb) != 0) continue; /* host hash bucket is now locked */ if (hb->tail == NULL) { HRLOCK_UNLOCK(hb); continue; } /* we have a host, or more than one */ cnt += HostHashRowTimeout(hb, hb->tail, ts); HRLOCK_UNLOCK(hb); } return cnt; } suricata-1.4.7/src/Makefile.am0000644000000000000000000003172412253546156013070 00000000000000noinst_HEADERS = action-globals.h \ app-layer-nbss.h app-layer-dcerpc-common.h \ debug.h \ flow-private.h queue.h source-nfq-prototypes.h \ suricata-common.h threadvars.h util-binsearch.h \ util-validate.h bin_PROGRAMS = suricata suricata_SOURCES = \ alert-debuglog.c alert-debuglog.h \ alert-fastlog.c alert-fastlog.h \ alert-pcapinfo.c alert-pcapinfo.h \ alert-prelude.c alert-prelude.h \ alert-syslog.c alert-syslog.h \ alert-unified2-alert.c alert-unified2-alert.h \ app-layer.c app-layer.h \ app-layer-dcerpc.c app-layer-dcerpc.h \ app-layer-dcerpc-udp.c app-layer-dcerpc-udp.h \ app-layer-detect-proto.c app-layer-detect-proto.h \ app-layer-ftp.c app-layer-ftp.h \ app-layer-htp-body.c app-layer-htp-body.h \ app-layer-htp.c app-layer-htp.h \ app-layer-htp-file.c app-layer-htp-file.h \ app-layer-parser.c app-layer-parser.h \ app-layer-protos.c app-layer-protos.h \ app-layer-smb2.c app-layer-smb2.h \ app-layer-smb.c app-layer-smb.h \ app-layer-smtp.c app-layer-smtp.h \ app-layer-ssh.c app-layer-ssh.h \ app-layer-ssl.c app-layer-ssl.h \ app-layer-tls-handshake.c app-layer-tls-handshake.h \ conf.c conf.h \ conf-yaml-loader.c conf-yaml-loader.h \ counters.c counters.h \ cuda-packet-batcher.c cuda-packet-batcher.h \ data-queue.c data-queue.h \ decode.c decode.h \ decode-ethernet.c decode-ethernet.h \ decode-events.c decode-events.h \ decode-gre.c decode-gre.h \ decode-icmpv4.c decode-icmpv4.h \ decode-icmpv6.c decode-icmpv6.h \ decode-ipv4.c decode-ipv4.h \ decode-ipv6.c decode-ipv6.h \ decode-ppp.c decode-ppp.h \ decode-pppoe.c decode-pppoe.h \ decode-raw.c decode-raw.h \ decode-sctp.c decode-sctp.h \ decode-sll.c decode-sll.h \ decode-tcp.c decode-tcp.h \ decode-teredo.c decode-teredo.h \ decode-udp.c decode-udp.h \ decode-vlan.c decode-vlan.h \ defrag.c defrag.h \ defrag-hash.c defrag-hash.h \ defrag-queue.c defrag-queue.h \ defrag-timeout.c defrag-timeout.h \ detect-ack.c detect-ack.h \ detect-app-layer-event.c detect-app-layer-event.h \ detect-asn1.c detect-asn1.h \ detect-byte-extract.c detect-byte-extract.h \ detect-bytejump.c detect-bytejump.h \ detect-bytetest.c detect-bytetest.h \ detect.c detect.h \ detect-classtype.c detect-classtype.h \ detect-content.c detect-content.h \ detect-csum.c detect-csum.h \ detect-dce-iface.c detect-dce-iface.h \ detect-dce-opnum.c detect-dce-opnum.h \ detect-dce-stub-data.c detect-dce-stub-data.h \ detect-depth.c detect-depth.h \ detect-detection-filter.c detect-detection-filter.h \ detect-distance.c detect-distance.h \ detect-dsize.c detect-dsize.h \ detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ detect-engine-address-ipv6.c detect-engine-address-ipv6.h \ detect-engine-alert.c detect-engine-alert.h \ detect-engine-analyzer.c detect-engine-analyzer.h \ detect-engine.c detect-engine.h \ detect-engine-content-inspection.c detect-engine-content-inspection.h \ detect-engine-dcepayload.c detect-engine-dcepayload.h \ detect-engine-event.c detect-engine-event.h \ detect-engine-file.c detect-engine-file.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h \ detect-engine-hhd.c detect-engine-hhd.h \ detect-engine-hhhd.c detect-engine-hhhd.h \ detect-engine-hmd.c detect-engine-hmd.h \ detect-engine-hrhd.c detect-engine-hrhd.h \ detect-engine-hrhhd.c detect-engine-hrhhd.h \ detect-engine-hrud.c detect-engine-hrud.h \ detect-engine-hsbd.c detect-engine-hsbd.h \ detect-engine-hscd.c detect-engine-hscd.h \ detect-engine-hsmd.c detect-engine-hsmd.h \ detect-engine-hua.c detect-engine-hua.h \ detect-engine-iponly.c detect-engine-iponly.h \ detect-engine-mpm.c detect-engine-mpm.h \ detect-engine-payload.c detect-engine-payload.h \ detect-engine-port.c detect-engine-port.h \ detect-engine-proto.c detect-engine-proto.h \ detect-engine-siggroup.c detect-engine-siggroup.h \ detect-engine-sigorder.c detect-engine-sigorder.h \ detect-engine-state.c detect-engine-state.h \ detect-engine-tag.c detect-engine-tag.h \ detect-engine-threshold.c detect-engine-threshold.h \ detect-engine-uri.c detect-engine-uri.h \ detect-fast-pattern.c detect-fast-pattern.h \ detect-file-data.c detect-file-data.h \ detect-fileext.c detect-fileext.h \ detect-filemagic.c detect-filemagic.h \ detect-filemd5.c detect-filemd5.h \ detect-filename.c detect-filename.h \ detect-filesize.c detect-filesize.h \ detect-filestore.c detect-filestore.h \ detect-flags.c detect-flags.h \ detect-flowbits.c detect-flowbits.h \ detect-flow.c detect-flow.h \ detect-flowint.c detect-flowint.h \ detect-flowvar.c detect-flowvar.h \ detect-fragbits.c detect-fragbits.h \ detect-fragoffset.c detect-fragoffset.h \ detect-ftpbounce.c detect-ftpbounce.h \ detect-geoip.c detect-geoip.h \ detect-gid.c detect-gid.h \ detect-http-client-body.c detect-http-client-body.h \ detect-http-cookie.c detect-http-cookie.h \ detect-http-header.c detect-http-header.h \ detect-http-hh.c detect-http-hh.h \ detect-http-hrh.c detect-http-hrh.h \ detect-http-method.c detect-http-method.h \ detect-http-raw-header.c detect-http-raw-header.h \ detect-http-raw-uri.c detect-http-raw-uri.h \ detect-http-server-body.c detect-http-server-body.h \ detect-http-stat-code.c detect-http-stat-code.h \ detect-http-stat-msg.c detect-http-stat-msg.h \ detect-http-ua.c detect-http-ua.h \ detect-http-uri.c detect-http-uri.h \ detect-icmp-id.c detect-icmp-id.h \ detect-icmp-seq.c detect-icmp-seq.h \ detect-icode.c detect-icode.h \ detect-id.c detect-id.h \ detect-ipopts.c detect-ipopts.h \ detect-ipproto.c detect-ipproto.h \ detect-iprep.c detect-iprep.h \ detect-isdataat.c detect-isdataat.h \ detect-itype.c detect-itype.h \ detect-l3proto.c detect-l3proto.h \ detect-luajit.c detect-luajit.h \ detect-mark.c detect-mark.h \ detect-metadata.c detect-metadata.h \ detect-msg.c detect-msg.h \ detect-noalert.c detect-noalert.h \ detect-nocase.c detect-nocase.h \ detect-offset.c detect-offset.h \ detect-parse.c detect-parse.h \ detect-pcre.c detect-pcre.h \ detect-pkt-data.c detect-pkt-data.h \ detect-pktvar.c detect-pktvar.h \ detect-priority.c detect-priority.h \ detect-rawbytes.c detect-rawbytes.h \ detect-reference.c detect-reference.h \ detect-replace.c detect-replace.h \ detect-rev.c detect-rev.h \ detect-rpc.c detect-rpc.h \ detect-sameip.c detect-sameip.h \ detect-seq.c detect-seq.h \ detect-sid.c detect-sid.h \ detect-ssh-proto-version.c detect-ssh-proto-version.h \ detect-ssh-software-version.c detect-ssh-software-version.h \ detect-ssl-state.c detect-ssl-state.h \ detect-ssl-version.c detect-ssl-version.h \ detect-stream_size.c detect-stream_size.h \ detect-tag.c detect-tag.h \ detect-threshold.c detect-threshold.h \ detect-tls.c detect-tls.h \ detect-tls-version.c detect-tls-version.h \ detect-tos.c detect-tos.h \ detect-ttl.c detect-ttl.h \ detect-uricontent.c detect-uricontent.h \ detect-urilen.c detect-urilen.h \ detect-window.c detect-window.h \ detect-within.c detect-within.h \ flow-alert-sid.c flow-alert-sid.h \ flow-bit.c flow-bit.h \ flow.c flow.h \ flow-hash.c flow-hash.h \ flow-manager.c flow-manager.h \ flow-queue.c flow-queue.h \ flow-timeout.c flow-timeout.h \ flow-util.c flow-util.h \ flow-var.c flow-var.h \ host.c host.h \ host-queue.c host-queue.h \ host-timeout.c host-timeout.h \ log-droplog.c log-droplog.h \ log-file.c log-file.h \ log-filestore.c log-filestore.h \ log-httplog.c log-httplog.h \ log-pcap.c log-pcap.h \ log-tlslog.c log-tlslog.h \ output.c output.h \ packet-queue.c packet-queue.h \ pkt-var.c pkt-var.h \ reputation.c reputation.h \ respond-reject.c respond-reject.h \ respond-reject-libnet11.h respond-reject-libnet11.c \ runmode-af-packet.c runmode-af-packet.h \ runmode-erf-dag.c runmode-erf-dag.h \ runmode-erf-file.c runmode-erf-file.h \ runmode-ipfw.c runmode-ipfw.h \ runmode-napatech.c runmode-napatech.h \ runmode-nfq.c runmode-nfq.h \ runmode-pcap.c runmode-pcap.h \ runmode-pcap-file.c runmode-pcap-file.h \ runmode-pfring.c runmode-pfring.h \ runmode-unix-socket.c runmode-unix-socket.h \ runmodes.c runmodes.h \ source-af-packet.c source-af-packet.h \ source-erf-dag.c source-erf-dag.h \ source-erf-file.c source-erf-file.h \ source-ipfw.c source-ipfw.h \ source-napatech.c source-napatech.h \ source-nfq.c source-nfq.h \ source-pcap.c source-pcap.h \ source-pcap-file.c source-pcap-file.h \ source-pfring.c source-pfring.h \ stream.c stream.h \ stream-tcp.c stream-tcp.h stream-tcp-private.h \ stream-tcp-inline.c stream-tcp-inline.h \ stream-tcp-reassemble.c stream-tcp-reassemble.h \ stream-tcp-sack.c stream-tcp-sack.h \ stream-tcp-util.c stream-tcp-util.h \ suricata.c suricata.h \ threads.c threads.h \ tm-modules.c tm-modules.h \ tmqh-flow.c tmqh-flow.h \ tmqh-nfq.c tmqh-nfq.h \ tmqh-packetpool.c tmqh-packetpool.h \ tmqh-ringbuffer.c tmqh-ringbuffer.h \ tmqh-simple.c tmqh-simple.h \ tm-queuehandlers.c tm-queuehandlers.h \ tm-queues.c tm-queues.h \ tm-threads.c tm-threads.h tm-threads-common.h \ unix-manager.c unix-manager.h \ util-action.c util-action.h \ util-atomic.c util-atomic.h \ util-bloomfilter-counting.c util-bloomfilter-counting.h \ util-bloomfilter.c util-bloomfilter.h \ util-buffer.c util-buffer.h \ util-byte.c util-byte.h \ util-checksum.c util-checksum.h \ util-cidr.c util-cidr.h \ util-classification-config.c util-classification-config.h \ util-coredump-config.c util-coredump-config.h \ util-cpu.c util-cpu.h \ util-crypt.c util-crypt.h \ util-cuda.c util-cuda.h \ util-cuda-handlers.c util-cuda-handlers.h \ util-daemon.c util-daemon.h \ util-debug.c util-debug.h \ util-debug-filters.c util-debug-filters.h \ util-decode-asn1.c util-decode-asn1.h \ util-decode-der.c util-decode-der.h \ util-decode-der-get.c util-decode-der-get.h \ util-device.c util-device.h \ util-enum.c util-enum.h \ util-error.c util-error.h \ util-file.c util-file.h \ util-fix_checksum.c util-fix_checksum.h \ util-fmemopen.c util-fmemopen.h \ util-hash.c util-hash.h \ util-hashlist.c util-hashlist.h \ util-hash-lookup3.c util-hash-lookup3.h \ util-host-os-info.c util-host-os-info.h \ util-ioctl.h util-ioctl.c \ util-logopenfile.h util-logopenfile.c \ util-magic.c util-magic.h \ util-memcmp.c util-memcmp.h \ util-mem.h \ util-misc.c util-misc.h \ util-mpm-ac-bs.c util-mpm-ac-bs.h \ util-mpm-ac.c util-mpm-ac.h \ util-mpm-ac-gfbs.c util-mpm-ac-gfbs.h \ util-mpm-b2gc.c util-mpm-b2gc.h \ util-mpm-b2g-cuda.c util-mpm-b2g-cuda.h \ util-mpm-b2g.c util-mpm-b2g.h \ util-mpm-b2gm.c util-mpm-b2gm.h \ util-mpm-b3g.c util-mpm-b3g.h \ util-mpm.c util-mpm.h \ util-mpm-wumanber.c util-mpm-wumanber.h \ util-optimize.h \ util-path.c util-path.h \ util-pidfile.c util-pidfile.h \ util-pool.c util-pool.h \ util-print.c util-print.h \ util-privs.c util-privs.h \ util-profiling.c util-profiling.h \ util-profiling-locks.c util-profiling-locks.h \ util-profiling-rules.c \ util-proto-name.c util-proto-name.h \ util-radix-tree.c util-radix-tree.h \ util-random.c util-random.h \ util-reference-config.c util-reference-config.h \ util-ringbuffer.c util-ringbuffer.h \ util-rohash.c util-rohash.h \ util-rule-vars.c util-rule-vars.h \ util-runmodes.c util-runmodes.h \ util-signal.c util-signal.h \ util-spm-bm.c util-spm-bm.h \ util-spm-bs2bm.c util-spm-bs2bm.h \ util-spm-bs.c util-spm-bs.h \ util-spm.c util-spm.h util-clock.h \ util-strlcatu.c \ util-strlcpyu.c \ util-syslog.c util-syslog.h \ util-threshold-config.c util-threshold-config.h \ util-time.c util-time.h \ util-unittest.c util-unittest.h \ util-unittest-helper.c util-unittest-helper.h \ util-validate.h util-affinity.h util-affinity.c \ util-var.c util-var.h \ util-var-name.c util-var-name.h \ util-vector.h \ win32-misc.c win32-misc.h \ win32-service.c win32-service.h \ win32-syslog.h EXTRA_DIST = util-mpm-b2g-cuda-kernel.cu ptxdump.py # set the include path found by configure INCLUDES= $(all_includes) # the library search path. suricata_LDFLAGS = $(all_libraries) if BUILD_LIBHTP suricata_LDADD = $(top_builddir)/libhtp/htp/libhtp.la INCLUDES += -I$(top_srcdir)/libhtp endif # Rules to build CUDA ptx modules if BUILD_CUDA BUILT_SOURCES = cuda-ptxdump.h suricata_SOURCES += cuda-ptxdump.h suricata_CUDA_KERNELS = \ util-mpm-b2g-cuda-kernel.cu NVCCFLAGS=-O2 SUFFIXES = \ .ptx_sm_10 \ .ptx_sm_11 \ .ptx_sm_12 \ .ptx_sm_13 \ .ptx_sm_20 \ .ptx_sm_21 PTXS = $(suricata_CUDA_KERNELS:.cu=.ptx_sm_10) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_11) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_12) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_13) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_20) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_21) .cu.ptx_sm_10: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_10 -ptx $< .cu.ptx_sm_11: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_11 -ptx $< .cu.ptx_sm_12: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_12 -ptx $< .cu.ptx_sm_13: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_13 -ptx $< .cu.ptx_sm_20: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_20 -ptx $< .cu.ptx_sm_21: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_21 -ptx $< cuda-ptxdump.h: $(PTXS) $(PYTHON) ptxdump.py cuda-ptxdump $(PTXS) CLEANFILES = $(PTXS) cuda-ptxdump.h endif #suricata_CFLAGS = -Wall -fno-strict-aliasing AM_CFLAGS = -DLOCAL_STATE_DIR=\"$(localstatedir)\" if BUILD_UNITTESTS check-am: $(top_builddir)/src/suricata -u endif distclean-local: -rm -rf $(top_builddir)/src/build-info.h suricata-1.4.7/src/app-layer-nbss.h0000644000000000000000000000423012253546156014032 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Kirby Kuehl */ #ifndef __APP_LAYER_NBSS_H__ #define __APP_LAYER_NBSS_H__ #include "suricata-common.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "flow.h" #include "stream.h" /* http://ubiqx.org/cifs/rfc-draft/rfc1002.html#s4.3 All session packets are of the following general structure: 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TYPE | FLAGS | LENGTH | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / TRAILER (Packet Type Dependent) / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The TYPE, FLAGS, and LENGTH fields are present in every session packet. */ #define NBSS_SESSION_MESSAGE 0x00 #define NBSS_SESSION_REQUEST 0x81 #define NBSS_POSITIVE_SESSION_RESPONSE 0x82 #define NBSS_NEGATIVE_SESSION_RESPONSE 0x83 #define NBSS_RETARGET_SESSION_RESPONSE 0x84 #define NBSS_SESSION_KEEP_ALIVE 0x85 typedef struct NBSSHdr_ { uint8_t type; uint8_t flags; uint32_t length; } NBSSHdr; #define NBSS_HDR_LEN 4 #endif /* __APP_LAYER_NBSS_H__ */ suricata-1.4.7/src/util-pidfile.h0000644000000000000000000000202712253546156013566 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon Crespo * \author Victor Julien */ #ifndef __UTIL_PID_H__ #define __UTIL_PID_H__ int SCPidfileCreate(const char *); void SCPidfileRemove(const char *); int SCPidfileTestRunning(const char *pid_filename); #endif /* __UTIL_PID_H__ */ suricata-1.4.7/src/detect-itype.c0000644000000000000000000003516212253546156013600 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias * * Implements itype keyword support */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-itype.h" #include "util-byte.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-debug.h" /** *\brief Regex for parsing our itype options */ #define PARSE_REGEX "^\\s*(<|>)?\\s*([0-9]+)\\s*(?:<>\\s*([0-9]+))?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectITypeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectITypeSetup(DetectEngineCtx *, Signature *, char *); void DetectITypeRegisterTests(void); void DetectITypeFree(void *); /** * \brief Registration function for itype: keyword */ void DetectITypeRegister (void) { sigmatch_table[DETECT_ITYPE].name = "itype"; sigmatch_table[DETECT_ITYPE].desc = "matching on a specific ICMP type"; sigmatch_table[DETECT_ITYPE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#itype"; sigmatch_table[DETECT_ITYPE].Match = DetectITypeMatch; sigmatch_table[DETECT_ITYPE].Setup = DetectITypeSetup; sigmatch_table[DETECT_ITYPE].Free = DetectITypeFree; sigmatch_table[DETECT_ITYPE].RegisterTests = DetectITypeRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief This function is used to match itype rule option set on a packet with those passed via itype: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectITypeData * * \retval 0 no match * \retval 1 match */ int DetectITypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { int ret = 0; uint8_t pitype; DetectITypeData *itd = (DetectITypeData *)m->ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; if (PKT_IS_ICMPV4(p)) { pitype = ICMPV4_GET_TYPE(p); } else if (PKT_IS_ICMPV6(p)) { pitype = ICMPV6_GET_TYPE(p); } else { /* Packet not ICMPv4 nor ICMPv6 */ return ret; } switch(itd->mode) { case DETECT_ITYPE_EQ: ret = (pitype == itd->type1) ? 1 : 0; break; case DETECT_ITYPE_LT: ret = (pitype < itd->type1) ? 1 : 0; break; case DETECT_ITYPE_GT: ret = (pitype > itd->type1) ? 1 : 0; break; case DETECT_ITYPE_RN: ret = (pitype > itd->type1 && pitype < itd->type2) ? 1 : 0; break; } return ret; } /** * \brief This function is used to parse itype options passed via itype: keyword * * \param itypestr Pointer to the user provided itype options * * \retval itd pointer to DetectITypeData on success * \retval NULL on failure */ DetectITypeData *DetectITypeParse(char *itypestr) { DetectITypeData *itd = NULL; char *args[3] = {NULL, NULL, NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, itypestr, strlen(itypestr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, itypestr); goto error; } int i; const char *str_ptr; for (i = 1; i < ret; i++) { res = pcre_get_substring((char *)itypestr, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[i-1] = (char *)str_ptr; } itd = SCMalloc(sizeof(DetectITypeData)); if (unlikely(itd == NULL)) goto error; itd->type1 = 0; itd->type2 = 0; itd->mode = 0; /* we have either "<" or ">" */ if (args[0] != NULL && strlen(args[0]) != 0) { /* we have a third part ("<> y"), therefore it's invalid */ if (args[2] != NULL) { SCLogError(SC_ERR_INVALID_VALUE, "itype: invalid value"); goto error; } /* we have only a comparison ("<", ">") */ if (ByteExtractStringUint8(&itd->type1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp type %s is not " "valid", args[1]); goto error; } if ((strcmp(args[0], ">")) == 0) itd->mode = DETECT_ITYPE_GT; else itd->mode = DETECT_ITYPE_LT; } else { /* no "<", ">" */ /* we have a range ("<>") */ if (args[2] != NULL) { itd->mode = (uint8_t) DETECT_ITYPE_RN; if (ByteExtractStringUint8(&itd->type1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp type %s is not " "valid", args[1]); goto error; } if (ByteExtractStringUint8(&itd->type2, 10, 0, args[2]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp type %s is not " "valid", args[2]); goto error; } /* we check that the first given value in the range is less than the second, otherwise we swap them */ if (itd->type1 > itd->type2) { uint8_t temp = itd->type1; itd->type1 = itd->type2; itd->type2 = temp; } } else { /* we have an equality */ itd->mode = DETECT_ITYPE_EQ; if (ByteExtractStringUint8(&itd->type1, 10, 0, args[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp type %s is not " "valid", args[1]); goto error; } } } for (i = 0; i < (ret-1); i++) { if (args[i] != NULL) SCFree(args[i]); } return itd; error: for (i = 0; i < (ret-1) && i < 3; i++) { if (args[i] != NULL) SCFree(args[i]); } if (itd != NULL) DetectITypeFree(itd); return NULL; } /** * \brief this function is used to add the parsed itype data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param itypestr pointer to the user provided itype options * * \retval 0 on Success * \retval -1 on Failure */ static int DetectITypeSetup(DetectEngineCtx *de_ctx, Signature *s, char *itypestr) { DetectITypeData *itd = NULL; SigMatch *sm = NULL; itd = DetectITypeParse(itypestr); if (itd == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_ITYPE; sm->ctx = (void *)itd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: if (itd != NULL) DetectITypeFree(itd); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectITypeData * * \param ptr pointer to DetectITypeData */ void DetectITypeFree(void *ptr) { DetectITypeData *itd = (DetectITypeData *)ptr; SCFree(itd); } #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" /** * \test DetectITypeParseTest01 is a test for setting a valid itype value */ int DetectITypeParseTest01(void) { DetectITypeData *itd = NULL; int result = 0; itd = DetectITypeParse("8"); if (itd != NULL) { if (itd->type1 == 8 && itd->mode == DETECT_ITYPE_EQ) result = 1; DetectITypeFree(itd); } return result; } /** * \test DetectITypeParseTest02 is a test for setting a valid itype value * with ">" operator */ int DetectITypeParseTest02(void) { DetectITypeData *itd = NULL; int result = 0; itd = DetectITypeParse(">8"); if (itd != NULL) { if (itd->type1 == 8 && itd->mode == DETECT_ITYPE_GT) result = 1; DetectITypeFree(itd); } return result; } /** * \test DetectITypeParseTest03 is a test for setting a valid itype value * with "<" operator */ int DetectITypeParseTest03(void) { DetectITypeData *itd = NULL; int result = 0; itd = DetectITypeParse("<8"); if (itd != NULL) { if (itd->type1 == 8 && itd->mode == DETECT_ITYPE_LT) result = 1; DetectITypeFree(itd); } return result; } /** * \test DetectITypeParseTest04 is a test for setting a valid itype value * with "<>" operator */ int DetectITypeParseTest04(void) { DetectITypeData *itd = NULL; int result = 0; itd = DetectITypeParse("8<>20"); if (itd != NULL) { if (itd->type1 == 8 && itd->type2 == 20 && itd->mode == DETECT_ITYPE_RN) result = 1; DetectITypeFree(itd); } return result; } /** * \test DetectITypeParseTest05 is a test for setting a valid itype value * with spaces all around */ int DetectITypeParseTest05(void) { DetectITypeData *itd = NULL; int result = 0; itd = DetectITypeParse(" 8 "); if (itd != NULL) { if (itd->type1 == 8 && itd->mode == DETECT_ITYPE_EQ) result = 1; DetectITypeFree(itd); } return result; } /** * \test DetectITypeParseTest06 is a test for setting a valid itype value * with ">" operator and spaces all around */ int DetectITypeParseTest06(void) { DetectITypeData *itd = NULL; int result = 0; itd = DetectITypeParse(" > 8 "); if (itd != NULL) { if (itd->type1 == 8 && itd->mode == DETECT_ITYPE_GT) result = 1; DetectITypeFree(itd); } return result; } /** * \test DetectITypeParseTest07 is a test for setting a valid itype value * with "<>" operator and spaces all around */ int DetectITypeParseTest07(void) { DetectITypeData *itd = NULL; int result = 0; itd = DetectITypeParse(" 8 <> 20 "); if (itd != NULL) { if (itd->type1 == 8 && itd->type2 == 20 && itd->mode == DETECT_ITYPE_RN) result = 1; DetectITypeFree(itd); } return result; } /** * \test DetectITypeParseTest08 is a test for setting an invalid itype value */ int DetectITypeParseTest08(void) { DetectITypeData *itd = NULL; itd = DetectITypeParse("> 8 <> 20"); if (itd == NULL) return 1; DetectITypeFree(itd); return 0; } /** * \test DetectITypeMatchTest01 is a test for checking the working of itype * keyword by creating 5 rules and matching a crafted packet against * them. 4 out of 5 rules shall trigger. */ int DetectITypeMatchTest01(void) { Packet *p = NULL; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(NULL, 0, IPPROTO_ICMP); p->icmpv4h->type = 10; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert icmp any any -> any any (itype:10; sid:1;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert icmp any any -> any any (itype:<15; sid:2;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert icmp any any -> any any (itype:>20; sid:3;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert icmp any any -> any any (itype:8<>20; sid:4;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert icmp any any -> any any (itype:20<>8; sid:5;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) == 0) { SCLogDebug("sid 1 did not alert, but should have"); goto cleanup; } else if (PacketAlertCheck(p, 2) == 0) { SCLogDebug("sid 2 did not alert, but should have"); goto cleanup; } else if (PacketAlertCheck(p, 3)) { SCLogDebug("sid 3 alerted, but should not have"); goto cleanup; } else if (PacketAlertCheck(p, 4) == 0) { SCLogDebug("sid 4 did not alert, but should have"); goto cleanup; } else if (PacketAlertCheck(p, 5) == 0) { SCLogDebug("sid 5 did not alert, but should have"); goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); end: return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectIType */ void DetectITypeRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectITypeParseTest01", DetectITypeParseTest01, 1); UtRegisterTest("DetectITypeParseTest02", DetectITypeParseTest02, 1); UtRegisterTest("DetectITypeParseTest03", DetectITypeParseTest03, 1); UtRegisterTest("DetectITypeParseTest04", DetectITypeParseTest04, 1); UtRegisterTest("DetectITypeParseTest05", DetectITypeParseTest05, 1); UtRegisterTest("DetectITypeParseTest06", DetectITypeParseTest06, 1); UtRegisterTest("DetectITypeParseTest07", DetectITypeParseTest07, 1); UtRegisterTest("DetectITypeParseTest08", DetectITypeParseTest08, 1); UtRegisterTest("DetectITypeMatchTest01", DetectITypeMatchTest01, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-flowbits.c0000644000000000000000000006456212253546156014305 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Breno Silva * * Implements the flowbits keyword */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "threads.h" #include "flow.h" #include "flow-bit.h" #include "flow-util.h" #include "detect-flowbits.h" #include "util-spm.h" #include "app-layer-parser.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow-bit.h" #include "util-var-name.h" #include "util-unittest.h" #include "util-debug.h" #define PARSE_REGEX "([a-z]+)(?:,(.*))?" static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectFlowbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowbitFree (void *); void FlowBitsRegisterTests(void); void DetectFlowbitsRegister (void) { sigmatch_table[DETECT_FLOWBITS].name = "flowbits"; sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag"; sigmatch_table[DETECT_FLOWBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch; sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup; sigmatch_table[DETECT_FLOWBITS].Free = DetectFlowbitFree; sigmatch_table[DETECT_FLOWBITS].RegisterTests = FlowBitsRegisterTests; /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_FLOWBITS].flags |= SIGMATCH_IPONLY_COMPAT; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if(parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } static int DetectFlowbitMatchToggle (Packet *p, DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; FlowBitToggle(p->flow,fd->idx); return 1; } static int DetectFlowbitMatchUnset (Packet *p, DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; FlowBitUnset(p->flow,fd->idx); return 1; } static int DetectFlowbitMatchSet (Packet *p, DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; FlowBitSet(p->flow,fd->idx); return 1; } static int DetectFlowbitMatchIsset (Packet *p, DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; return FlowBitIsset(p->flow,fd->idx); } static int DetectFlowbitMatchIsnotset (Packet *p, DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; return FlowBitIsnotset(p->flow,fd->idx); } /* * returns 0: no match * 1: match * -1: error */ int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectFlowbitsData *fd = (DetectFlowbitsData *)m->ctx; if (fd == NULL) return 0; switch (fd->cmd) { case DETECT_FLOWBITS_CMD_ISSET: return DetectFlowbitMatchIsset(p,fd); case DETECT_FLOWBITS_CMD_ISNOTSET: return DetectFlowbitMatchIsnotset(p,fd); case DETECT_FLOWBITS_CMD_SET: return DetectFlowbitMatchSet(p,fd); case DETECT_FLOWBITS_CMD_UNSET: return DetectFlowbitMatchUnset(p,fd); case DETECT_FLOWBITS_CMD_TOGGLE: return DetectFlowbitMatchToggle(p,fd); default: SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd); return 0; } return 0; } int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { DetectFlowbitsData *cd = NULL; SigMatch *sm = NULL; char *fb_cmd_str = NULL, *fb_name = NULL; uint8_t fb_cmd = 0; #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 != 2 && ret != 3) { SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowbits.", rawstr); return -1; } const char *str_ptr; res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); return -1; } fb_cmd_str = (char *)str_ptr; if (ret == 3) { res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } fb_name = (char *)str_ptr; } if (strcmp(fb_cmd_str,"noalert") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_NOALERT; } else if (strcmp(fb_cmd_str,"isset") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_ISSET; } else if (strcmp(fb_cmd_str,"isnotset") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_ISNOTSET; } else if (strcmp(fb_cmd_str,"set") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_SET; } else if (strcmp(fb_cmd_str,"unset") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_UNSET; } else if (strcmp(fb_cmd_str,"toggle") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_TOGGLE; } else { SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); goto error; } switch (fb_cmd) { case DETECT_FLOWBITS_CMD_NOALERT: if(fb_name != NULL) goto error; s->flags |= SIG_FLAG_NOALERT; return 0; case DETECT_FLOWBITS_CMD_ISNOTSET: case DETECT_FLOWBITS_CMD_ISSET: case DETECT_FLOWBITS_CMD_SET: case DETECT_FLOWBITS_CMD_UNSET: case DETECT_FLOWBITS_CMD_TOGGLE: default: if(fb_name == NULL) goto error; break; } cd = SCMalloc(sizeof(DetectFlowbitsData)); if (unlikely(cd == NULL)) goto error; cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_FLOWBITS); cd->cmd = fb_cmd; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, fb_name ? fb_name : "(null)"); pcre_free_substring(fb_name); fb_name = NULL; pcre_free_substring(fb_cmd_str); fb_cmd_str = NULL; /* 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_FLOWBITS; sm->ctx = (void *)cd; switch (fb_cmd) { case DETECT_FLOWBITS_CMD_NOALERT: /* nothing to do */ break; case DETECT_FLOWBITS_CMD_ISNOTSET: case DETECT_FLOWBITS_CMD_ISSET: /* checks, so packet list */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); break; case DETECT_FLOWBITS_CMD_SET: case DETECT_FLOWBITS_CMD_UNSET: case DETECT_FLOWBITS_CMD_TOGGLE: /* modifiers, only run when entire sig has matched */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); break; } return 0; error: if (fb_name != NULL) pcre_free_substring(fb_name); if (fb_cmd_str != NULL) pcre_free_substring(fb_cmd_str); if (cd != NULL) SCFree(cd); if (sm != NULL) SCFree(sm); return -1; } void DetectFlowbitFree (void *ptr) { DetectFlowbitsData *fd = (DetectFlowbitsData *)ptr; if (fd == NULL) return; SCFree(fd); } #ifdef UNITTESTS /** * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option * * \retval 1 on succces * \retval 0 on failure */ static int FlowBitsTestSig01(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } SCFree(p); return result; } /** * \test FlowBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options * * \retval 1 on succces * \retval 0 on failure */ static int FlowBitsTestSig02(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; int error_count = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)"); if (s == NULL) { error_count++; } s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)"); if (s == NULL) { error_count++; } s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)"); if (s == NULL) { error_count++; } s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)"); if (s == NULL) { error_count++; } s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); if (s == NULL) { error_count++; } if(error_count == 5) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { goto cleanup; } if (PacketAlertCheck(p, 2)) { goto cleanup; } if (PacketAlertCheck(p, 3)) { goto cleanup; } if (PacketAlertCheck(p, 4)) { goto cleanup; } if (PacketAlertCheck(p, 5)) { goto cleanup; } result = 1; cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } SCFree(p); return result; } /** * \test FlowBitsTestSig03 is a test for a invalid flowbits option * * \retval 1 on succces * \retval 0 on failure */ static int FlowBitsTestSig03(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } SCFree(p); return result; } /** * \test FlowBitsTestSig04 is a test check idx value * * \retval 1 on succces * \retval 0 on failure */ static int FlowBitsTestSig04(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; int idx = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)"); idx = VariableNameGetIdx(de_ctx, "fbt", DETECT_FLOWBITS); if (s == NULL || idx != 1) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); SCFree(p); return result; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } SCFree(p); return result; } /** * \test FlowBitsTestSig05 is a test check noalert flag * * \retval 1 on succces * \retval 0 on failure */ static int FlowBitsTestSig05(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)"); if (s == NULL || ((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT)) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); SCFree(p); return result; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } SCFree(p); return result; } /** * \test FlowBitsTestSig06 is a test set flowbits option * * \retval 1 on succces * \retval 0 on failure */ static int FlowBitsTestSig06(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; Flow f; GenericVar flowvar, *gv = NULL; int result = 0; int idx = 0; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(Flow)); memset(&flowvar, 0, sizeof(GenericVar)); FLOW_INITIALIZE(&f); p->flow = &f; p->flow->flowvar = &flowvar; p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; p->flags |= PKT_HAS_FLOW; p->flowflags |= FLOW_PKT_TOSERVER; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); gv = p->flow->flowvar; for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { result = 1; } } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); return result; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); return result; } /** * \test FlowBitsTestSig07 is a test unset flowbits option * * \retval 1 on succces * \retval 0 on failure */ static int FlowBitsTestSig07(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; Flow f; GenericVar flowvar, *gv = NULL; int result = 0; int idx = 0; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(Flow)); memset(&flowvar, 0, sizeof(GenericVar)); FLOW_INITIALIZE(&f); p->flow = &f; p->flow->flowvar = &flowvar; p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); gv = p->flow->flowvar; for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { result = 1; } } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); return result; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); return result; } /** * \test FlowBitsTestSig08 is a test toogle flowbits option * * \retval 1 on succces * \retval 0 on failure */ static int FlowBitsTestSig08(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; Flow f; GenericVar flowvar, *gv = NULL; int result = 0; int idx = 0; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(Flow)); memset(&flowvar, 0, sizeof(GenericVar)); FLOW_INITIALIZE(&f); p->flow = &f; p->flow->flowvar = &flowvar; p->src.family = AF_INET; p->dst.family = AF_INET; p->payload = buf; p->payload_len = buflen; p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); if (s == NULL) { goto end; } s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)"); if (s == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); gv = p->flow->flowvar; for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { result = 1; } } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); return result; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); } if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for FlowBits */ void FlowBitsRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01, 0); UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02, 0); UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03, 0); UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04, 1); UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05, 1); UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06, 1); UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07, 0); UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08, 0); #endif /* UNITTESTS */ } suricata-1.4.7/src/tmqh-ringbuffer.c0000644000000000000000000001013712253546156014273 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * RingBuffer queue handler */ #include "suricata.h" #include "packet-queue.h" #include "decode.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "util-ringbuffer.h" static RingBuffer8 *ringbuffers[256]; Packet *TmqhInputRingBufferMrSw(ThreadVars *t); void TmqhOutputRingBufferMrSw(ThreadVars *t, Packet *p); Packet *TmqhInputRingBufferSrSw(ThreadVars *t); void TmqhOutputRingBufferSrSw(ThreadVars *t, Packet *p); Packet *TmqhInputRingBufferSrMw(ThreadVars *t); void TmqhOutputRingBufferSrMw(ThreadVars *t, Packet *p); void TmqhInputRingBufferShutdownHandler(ThreadVars *); /** * \brief TmqhRingBufferRegister * \initonly */ void TmqhRingBufferRegister (void) { tmqh_table[TMQH_RINGBUFFER_MRSW].name = "ringbuffer_mrsw"; tmqh_table[TMQH_RINGBUFFER_MRSW].InHandler = TmqhInputRingBufferMrSw; tmqh_table[TMQH_RINGBUFFER_MRSW].InShutdownHandler = TmqhInputRingBufferShutdownHandler; tmqh_table[TMQH_RINGBUFFER_MRSW].OutHandler = TmqhOutputRingBufferMrSw; tmqh_table[TMQH_RINGBUFFER_SRSW].name = "ringbuffer_srsw"; tmqh_table[TMQH_RINGBUFFER_SRSW].InHandler = TmqhInputRingBufferSrSw; tmqh_table[TMQH_RINGBUFFER_SRSW].InShutdownHandler = TmqhInputRingBufferShutdownHandler; tmqh_table[TMQH_RINGBUFFER_SRSW].OutHandler = TmqhOutputRingBufferSrSw; tmqh_table[TMQH_RINGBUFFER_SRMW].name = "ringbuffer_srmw"; tmqh_table[TMQH_RINGBUFFER_SRMW].InHandler = TmqhInputRingBufferSrMw; tmqh_table[TMQH_RINGBUFFER_SRMW].InShutdownHandler = TmqhInputRingBufferShutdownHandler; tmqh_table[TMQH_RINGBUFFER_SRMW].OutHandler = TmqhOutputRingBufferSrMw; memset(ringbuffers, 0, sizeof(ringbuffers)); int i = 0; for (i = 0; i < 256; i++) { ringbuffers[i] = RingBuffer8Init(); if (ringbuffers[i] == NULL) { SCLogError(SC_ERR_FATAL, "Error allocating memory to register Ringbuffers. Exiting..."); exit(EXIT_FAILURE); } } } void TmqhRingBufferDestroy (void) { int i = 0; for (i = 0; i < 256; i++) { RingBuffer8Destroy(ringbuffers[i]); } } void TmqhInputRingBufferShutdownHandler(ThreadVars *tv) { if (tv == NULL || tv->inq == NULL) { return; } RingBuffer8 *rb = ringbuffers[tv->inq->id]; if (rb == NULL) { return; } RingBuffer8Shutdown(rb); } Packet *TmqhInputRingBufferMrSw(ThreadVars *t) { RingBuffer8 *rb = ringbuffers[t->inq->id]; Packet *p = (Packet *)RingBufferMrSw8Get(rb); SCPerfSyncCountersIfSignalled(t, 0); return p; } void TmqhOutputRingBufferMrSw(ThreadVars *t, Packet *p) { RingBuffer8 *rb = ringbuffers[t->outq->id]; RingBufferMrSw8Put(rb, (void *)p); } Packet *TmqhInputRingBufferSrSw(ThreadVars *t) { RingBuffer8 *rb = ringbuffers[t->inq->id]; Packet *p = (Packet *)RingBufferSrSw8Get(rb); SCPerfSyncCountersIfSignalled(t, 0); return p; } void TmqhOutputRingBufferSrSw(ThreadVars *t, Packet *p) { RingBuffer8 *rb = ringbuffers[t->outq->id]; RingBufferSrSw8Put(rb, (void *)p); } Packet *TmqhInputRingBufferSrMw(ThreadVars *t) { RingBuffer8 *rb = ringbuffers[t->inq->id]; Packet *p = (Packet *)RingBufferSrMw8Get(rb); SCPerfSyncCountersIfSignalled(t, 0); return p; } void TmqhOutputRingBufferSrMw(ThreadVars *t, Packet *p) { RingBuffer8 *rb = ringbuffers[t->outq->id]; RingBufferSrMw8Put(rb, (void *)p); } suricata-1.4.7/src/detect-ttl.h0000644000000000000000000000261012253546156013246 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh */ #ifndef _DETECT_TTL_H #define _DETECT_TTL_H #define DETECT_TTL_LT 0 /**< "less than" operator */ #define DETECT_TTL_EQ 1 /**< "equals" operator (default) */ #define DETECT_TTL_GT 2 /**< "greater than" operator */ #define DETECT_TTL_RA 3 /**< "range" operator */ typedef struct DetectTtlData_ { uint8_t ttl1; /**< first ttl value in the signature*/ uint8_t ttl2; /**< second ttl value in the signature, in case of range operator*/ uint8_t mode; /**< operator used in the signature */ }DetectTtlData; void DetectTtlRegister(void); #endif /* _DETECT_TTL_H */ suricata-1.4.7/src/alert-debuglog.h0000644000000000000000000000204512253546156014074 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __ALERT_DEBUGLOG_H__ #define __ALERT_DEBUGLOG_H__ void TmModuleAlertDebugLogRegister (void); void TmModuleAlertDebugLogIPv4Register (void); void TmModuleAlertDebugLogIPv6Register (void); OutputCtx *AlertDebugLogInitCtx(ConfNode *); #endif /* __ALERT_DEBUGLOG_H__ */ suricata-1.4.7/src/host-timeout.h0000644000000000000000000000170412253546156013641 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __HOST_TIMEOUT_H__ #define __HOST_TIMEOUT_H__ uint32_t HostTimeoutHash(struct timeval *ts); uint32_t HostGetSpareCount(void); uint32_t HostGetActiveCount(void); #endif suricata-1.4.7/src/pkt-var.h0000644000000000000000000000175512253546156012572 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __PKT_VAR_H__ #define __PKT_VAR_H__ void PktVarAdd(Packet *, char *, uint8_t *, uint16_t); PktVar *PktVarGet(Packet *, char *); void PktVarFree(PktVar *); void PktVarPrint(PktVar *); #endif /* __PKT_VAR_H__ */ suricata-1.4.7/src/detect-engine-hcbd.c0000644000000000000000000031570612253546156014616 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP request body match corresponding to http_client_body * keyword. * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" #include "conf.h" #include "conf-yaml-loader.h" #define BUFFER_STEP 50 static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) { if (size > det_ctx->hcbd_buffers_size) { det_ctx->hcbd = SCRealloc(det_ctx->hcbd, (det_ctx->hcbd_buffers_size + BUFFER_STEP) * sizeof(HttpReassembledBody)); if (det_ctx->hcbd == NULL) { det_ctx->hcbd_buffers_size = 0; det_ctx->hcbd_buffers_list_len = 0; return -1; } memset(det_ctx->hcbd + det_ctx->hcbd_buffers_size, 0, BUFFER_STEP * sizeof(HttpReassembledBody)); det_ctx->hcbd_buffers_size += BUFFER_STEP; for (int i = det_ctx->hcbd_buffers_list_len; i < (size); i++) { det_ctx->hcbd[i].buffer_len = 0; det_ctx->hcbd[i].offset = 0; } } return 0; } static uint8_t *DetectEngineHCBDGetBufferForTX(int tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags, uint32_t *buffer_len, uint32_t *stream_start_offset) { int index = 0; uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; if (det_ctx->hcbd_buffers_list_len == 0) { if (HCBDCreateSpace(det_ctx, 1) < 0) goto end; index = 0; if (det_ctx->hcbd_buffers_list_len == 0) { det_ctx->hcbd_start_tx_id = tx_id; } det_ctx->hcbd_buffers_list_len++; } else { if ((tx_id - det_ctx->hcbd_start_tx_id) < det_ctx->hcbd_buffers_list_len) { if (det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer_len != 0) { *buffer_len = det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer_len; *stream_start_offset = det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].offset; return det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer; } } else { if (HCBDCreateSpace(det_ctx, (tx_id - det_ctx->hcbd_start_tx_id) + 1) < 0) goto end; if (det_ctx->hcbd_buffers_list_len == 0) { det_ctx->hcbd_start_tx_id = tx_id; } det_ctx->hcbd_buffers_list_len++; } index = (tx_id - det_ctx->hcbd_start_tx_id); } htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); if (tx == NULL) { SCLogDebug("no tx"); goto end; } HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); if (htud == NULL) { SCLogDebug("no htud"); goto end; } /* no new data */ if (htud->request_body.body_inspected == htud->request_body.content_len_so_far) { SCLogDebug("no new data"); goto end; } HtpBodyChunk *cur = htud->request_body.first; if (cur == NULL) { SCLogDebug("No http chunks to inspect for this transacation"); goto end; } /* in case of chunked transfer encoding, we don't have the length * of the request body until we see a chunk with length 0. This * doesn't let us use the request body callback function to * figure out the end of request body. Instead we do it here. If * the length is 0, and we have already seen content, it indicates * chunked transfer. We also check if the parser has truly seen * the last chunk by checking the progress state for the * transaction. If we are done parsing all the chunks, we would * have it set to something other than TX_PROGRESS_REQ_BODY. * Either ways we should be moving away from buffering in the end * and running content validation on this buffer type of architecture * to a stateful inspection, where we can inspect body chunks as and * when they come */ if (htud->request_body.content_len == 0) { if ((htud->request_body.content_len_so_far > 0) && tx->progress != TX_PROGRESS_REQ_BODY) { /* final length of the body */ htud->tsflags |= HTP_REQ_BODY_COMPLETE; } } else { if (htud->request_body.content_len == tx->request_entity_len) { SCLogDebug("content_len reached"); htud->tsflags |= HTP_RES_BODY_COMPLETE; } } if (flags & STREAM_EOF) { htud->tsflags |= HTP_REQ_BODY_COMPLETE; } /* inspect the body if the transfer is complete or we have hit * our body size limit */ if (htud->request_body.content_len_so_far < htp_state->cfg->request_inspect_min_size && !(htud->tsflags & HTP_REQ_BODY_COMPLETE)) { SCLogDebug("we still haven't seen the entire request body. " "Let's defer body inspection till we see the " "entire body."); goto end; } int first = 1; while (cur != NULL) { /* see if we can filter out chunks */ if (htud->request_body.body_inspected > 0) { if (cur->stream_offset < htud->request_body.body_inspected) { if ((htud->request_body.body_inspected - cur->stream_offset) > htp_state->cfg->request_inspect_min_size) { cur = cur->next; continue; } else { /* include this one */ } } else { /* include this one */ } } if (first) { det_ctx->hcbd[index].offset = cur->stream_offset; first = 0; } /* see if we need to grow the buffer */ if (det_ctx->hcbd[index].buffer == NULL || (det_ctx->hcbd[index].buffer_len + cur->len) > det_ctx->hcbd[index].buffer_size) { det_ctx->hcbd[index].buffer_size += cur->len * 2; if ((det_ctx->hcbd[index].buffer = SCRealloc(det_ctx->hcbd[index].buffer, det_ctx->hcbd[index].buffer_size)) == NULL) { det_ctx->hcbd[index].buffer_size = 0; det_ctx->hcbd[index].buffer_len = 0; goto end; } } memcpy(det_ctx->hcbd[index].buffer + det_ctx->hcbd[index].buffer_len, cur->data, cur->len); det_ctx->hcbd[index].buffer_len += cur->len; cur = cur->next; } /* update inspected tracker */ htud->request_body.body_inspected = htud->request_body.last->stream_offset + htud->request_body.last->len; buffer = det_ctx->hcbd[index].buffer; *buffer_len = det_ctx->hcbd[index].buffer_len; *stream_start_offset = det_ctx->hcbd[index].offset; end: return buffer; } int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { uint32_t stream_start_offset = 0; uint32_t cnt = 0; if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } FLOWLOCK_WRLOCK(f); if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } /* get the transaction id */ int idx = AppLayerTransactionGetInspectId(f); /* error! get out of here */ if (idx == -1) goto end; int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { uint32_t buffer_len = 0; uint8_t *buffer = DetectEngineHCBDGetBufferForTX(idx, de_ctx, det_ctx, f, htp_state, flags, &buffer_len, &stream_start_offset); if (buffer_len == 0) continue; cnt += HttpClientBodyPatternSearch(det_ctx, buffer, buffer_len, flags); } end: FLOWLOCK_UNLOCK(f); return cnt; } int DetectEngineInspectHttpClientBody(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; uint32_t stream_start_offset = 0; uint32_t buffer_len = 0; uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx_id, de_ctx, det_ctx, f, htp_state, flags, &buffer_len, &stream_start_offset); if (buffer_len == 0) return 0; det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCBDMATCH], f, buffer, buffer_len, stream_start_offset, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, NULL); if (r == 1) return 1; return 0; } void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *det_ctx) { if (det_ctx->hcbd_buffers_list_len > 0) { for (int i = 0; i < det_ctx->hcbd_buffers_list_len; i++) { det_ctx->hcbd[i].buffer_len = 0; det_ctx->hcbd[i].offset = 0; } } det_ctx->hcbd_buffers_list_len = 0; det_ctx->hcbd_start_tx_id = 0; return; } /***********************************Unittests**********************************/ #ifdef UNITTESTS static int DetectEngineHttpClientBodyTest01(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.1\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1This\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!(PacketAlertCheck(p2, 1))) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest02(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 19\r\n" "\r\n" "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; offset:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { printf("sid 1 didn't match but should have\n"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest03(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; offset:16; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest04(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:!\"body1\"; http_client_body; offset:16; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest05(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; depth:25; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest06(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:!\"body1\"; http_client_body; depth:25; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest07(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:!\"body1\"; http_client_body; depth:15; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest08(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:!\"body1\"; http_client_body; depth:25; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest09(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:\"This\"; http_client_body; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest10(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:!\"boom\"; http_client_body; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest11(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:\"boom\"; http_client_body; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest12(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:!\"This\"; http_client_body; within:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest13(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:\"dummy\"; http_client_body; distance:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest14(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:!\"dummy\"; http_client_body; distance:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest15(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:\"dummy\"; http_client_body; distance:10; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest16(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:!\"dummy\"; http_client_body; distance:5; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest17(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http1_buf[] = "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:\"bambu\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); if (r != 1) { printf("expected 1 result, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpClientBodyTest18(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http1_buf[] = "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"body1\"; http_client_body; " "content:\"bambu\"; http_client_body; fast_pattern; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); if (r != 0) { printf("expected 1 result, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpClientBodyTest19(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http1_buf[] = "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"bambu\"; http_client_body; " "content:\"is\"; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); if (r != 0) { printf("expected 1 result, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpClientBodyTest20(void) { TcpSession ssn; Packet *p1 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; uint8_t http1_buf[] = "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"bambu\"; http_client_body; " "content:\"is\"; http_client_body; fast_pattern; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* start the search phase */ det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); if (r != 2) { printf("expected 1 result, got %"PRIu32": ", r); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); return result; } static int DetectEngineHttpClientBodyTest21(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/P; " "content:!\"dummy\"; http_client_body; within:7; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest22(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/P; " "content:!\"dummy\"; within:7; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest23(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/P; " "content:!\"dummy\"; distance:3; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest24(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/P; " "content:!\"dummy\"; distance:13; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest25(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/P; " "content:\"dummy\"; within:15; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest26(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/P; " "content:\"dummy\"; within:10; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest27(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/P; " "content:\"dummy\"; distance:8; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (!PacketAlertCheck(p2, 1)) { printf("sid 1 didn't match but should have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest28(void) { TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "pcre:/body1/P; " "content:\"dummy\"; distance:14; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have"); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } static int DetectEngineHttpClientBodyTest29(void) { int result = 0; Packet *p = NULL; TcpSession ssn; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; const char *request_buffer = "GET /one HTTP/1.0\r\n" "Host: localhost\r\n" "\r\n"; #define TOTAL_REQUESTS 45 uint8_t *http_buf = SCMalloc(TOTAL_REQUESTS * strlen(request_buffer)); if (http_buf == NULL) goto end; for (int i = 0; i < TOTAL_REQUESTS; i++) { memcpy(http_buf + i * strlen(request_buffer), request_buffer, strlen(request_buffer)); } uint32_t http_buf_len = TOTAL_REQUESTS * strlen(request_buffer); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(content:\"dummyone\"; fast_pattern:0,3; http_server_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } uint8_t response_buf[] = "HTTP/1.0 200 ok\r\n" "Content-Type: text/html\r\n" "Content-Length: 5\r\n" "\r\n" "dummy"; uint32_t response_buf_len = strlen((char *)response_buf); r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT, response_buf, response_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpClientBodyTest30(void) { char input[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ \n\ default-config:\n\ personality: IDS\n\ request-body-limit: 0\n\ response-body-limit: 0\n\ \n\ request-body-inspect-window: 0\n\ response-body-inspect-window: 0\n\ request-body-minimal-inspect-size: 0\n\ response-body-minimal-inspect-size: 0\n\ "; ConfCreateContextBackup(); ConfInit(); HtpConfigCreateBackup(); ConfYamlLoadString(input, strlen(input)); HTPConfigure(); TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.openinfosecfoundation.org\r\n" "Content-Type: text/html\r\n" "Content-Length: 46\r\n" "\r\n" "This is dummy body1"; uint8_t http2_buf[] = "bags is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http client body test\"; " "content:\"bags\"; depth:4; http_client_body; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: \n"); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 1)) { printf("sid 1 matched but shouldn't have\n"); goto end; } result = 1; end: HtpConfigRestoreBackup(); ConfRestoreContextBackup(); if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpClientBodyRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpClientBodyTest01", DetectEngineHttpClientBodyTest01, 1); UtRegisterTest("DetectEngineHttpClientBodyTest02", DetectEngineHttpClientBodyTest02, 1); UtRegisterTest("DetectEngineHttpClientBodyTest03", DetectEngineHttpClientBodyTest03, 1); UtRegisterTest("DetectEngineHttpClientBodyTest04", DetectEngineHttpClientBodyTest04, 1); UtRegisterTest("DetectEngineHttpClientBodyTest05", DetectEngineHttpClientBodyTest05, 1); UtRegisterTest("DetectEngineHttpClientBodyTest06", DetectEngineHttpClientBodyTest06, 1); UtRegisterTest("DetectEngineHttpClientBodyTest07", DetectEngineHttpClientBodyTest07, 1); UtRegisterTest("DetectEngineHttpClientBodyTest08", DetectEngineHttpClientBodyTest08, 1); UtRegisterTest("DetectEngineHttpClientBodyTest09", DetectEngineHttpClientBodyTest09, 1); UtRegisterTest("DetectEngineHttpClientBodyTest10", DetectEngineHttpClientBodyTest10, 1); UtRegisterTest("DetectEngineHttpClientBodyTest11", DetectEngineHttpClientBodyTest11, 1); UtRegisterTest("DetectEngineHttpClientBodyTest12", DetectEngineHttpClientBodyTest12, 1); UtRegisterTest("DetectEngineHttpClientBodyTest13", DetectEngineHttpClientBodyTest13, 1); UtRegisterTest("DetectEngineHttpClientBodyTest14", DetectEngineHttpClientBodyTest14, 1); UtRegisterTest("DetectEngineHttpClientBodyTest15", DetectEngineHttpClientBodyTest15, 1); UtRegisterTest("DetectEngineHttpClientBodyTest16", DetectEngineHttpClientBodyTest16, 1); UtRegisterTest("DetectEngineHttpClientBodyTest17", DetectEngineHttpClientBodyTest17, 1); UtRegisterTest("DetectEngineHttpClientBodyTest18", DetectEngineHttpClientBodyTest18, 1); UtRegisterTest("DetectEngineHttpClientBodyTest19", DetectEngineHttpClientBodyTest19, 1); UtRegisterTest("DetectEngineHttpClientBodyTest20", DetectEngineHttpClientBodyTest20, 1); UtRegisterTest("DetectEngineHttpClientBodyTest21", DetectEngineHttpClientBodyTest21, 1); UtRegisterTest("DetectEngineHttpClientBodyTest22", DetectEngineHttpClientBodyTest22, 1); UtRegisterTest("DetectEngineHttpClientBodyTest23", DetectEngineHttpClientBodyTest23, 1); UtRegisterTest("DetectEngineHttpClientBodyTest24", DetectEngineHttpClientBodyTest24, 1); UtRegisterTest("DetectEngineHttpClientBodyTest25", DetectEngineHttpClientBodyTest25, 1); UtRegisterTest("DetectEngineHttpClientBodyTest26", DetectEngineHttpClientBodyTest26, 1); UtRegisterTest("DetectEngineHttpClientBodyTest27", DetectEngineHttpClientBodyTest27, 1); UtRegisterTest("DetectEngineHttpClientBodyTest28", DetectEngineHttpClientBodyTest28, 1); UtRegisterTest("DetectEngineHttpClientBodyTest29", DetectEngineHttpClientBodyTest29, 1); UtRegisterTest("DetectEngineHttpClientBodyTest30", DetectEngineHttpClientBodyTest30, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/detect-depth.c0000644000000000000000000001764312253546156013556 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * * Implements the depth keyword. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-byte-extract.h" #include "detect-parse.h" #include "flow-var.h" #include "app-layer.h" #include "util-debug.h" static int DetectDepthSetup (DetectEngineCtx *, Signature *, char *); void DetectDepthRegister (void) { sigmatch_table[DETECT_DEPTH].name = "depth"; sigmatch_table[DETECT_DEPTH].desc = "designate how many bytes from the beginning of the payload will be checked"; sigmatch_table[DETECT_DEPTH].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#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; sigmatch_table[DETECT_DEPTH].flags |= SIGMATCH_PAYLOAD; } static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depthstr) { char *str = depthstr; char dubbed = 0; SigMatch *pm = NULL; DetectContentData *cd = NULL; /* strip "'s */ if (depthstr[0] == '\"' && depthstr[strlen(depthstr) - 1] == '\"') { str = SCStrdup(depthstr + 1); if (unlikely(str == NULL)) goto error; str[strlen(depthstr) - 2] = '\0'; dubbed = 1; } switch (s->alproto) { case ALPROTO_DCERPC: /* add to the latest content keyword from either dmatch or pmatch */ pm = SigMatchGetLastSMFromLists(s, 4, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " "preceding content option for dcerpc sig"); if (dubbed) SCFree(str); return -1; } break; default: pm = SigMatchGetLastSMFromLists(s, 28, DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " "preceding content, uricontent option, http_client_body, " "http_server_body, http_header option, http_raw_header option, " "http_method option, http_cookie, http_raw_uri, " "http_stat_msg, http_stat_code, http_user_agent, " "http_host or http_raw_host option"); if (dubbed) SCFree(str); return -1; } break; } /* i swear we will clean this up :). Use a single version for all. Using * separate versions for all now, to avoiding breaking any code */ switch (pm->type) { case DETECT_CONTENT: cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); if (dubbed) SCFree(str); return -1; } if (cd->flags & DETECT_CONTENT_NEGATED) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "negated keyword set along with a fast_pattern"); goto error; } } else { if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative " "keyword set along with a fast_pattern:only;"); goto error; } } if ((cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_DISTANCE)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative keyword " "with a non-relative keyword for the same content." ); goto error; } if (cd->flags & DETECT_CONTENT_DEPTH) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple depths for the same content."); goto error; } if (str[0] != '-' && isalpha((unsigned char)str[0])) { SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s, SigMatchListSMBelongsTo(s, pm)); if (bed_sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var " "seen in depth - %s\n", str); goto error; } cd->depth = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_DEPTH_BE; } else { int depth = atoi(str); if (depth < 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Negative depth " "not allowed - %d.", depth); goto error; } if (depth < cd->content_len) { uint32_t content_len = cd->content_len; SCLogError(SC_ERR_INVALID_SIGNATURE, "depth - %"PRIu16 " smaller than content length - %"PRIu32, cd->depth, content_len); goto error; } cd->depth = depth; /* Now update the real limit, as depth is relative to the offset */ cd->depth += cd->offset; } cd->flags |= DETECT_CONTENT_DEPTH; break; default: SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceding " "content (or uricontent) option"); goto error; } if (dubbed) SCFree(str); return 0; error: if (dubbed) SCFree(str); return -1; } suricata-1.4.7/src/defrag-queue.h0000644000000000000000000000472012253546156013553 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DEFRAG_QUEUE_H__ #define __DEFRAG_QUEUE_H__ #include "suricata-common.h" #include "defrag.h" /** Spinlocks or Mutex for the defrag tracker queues. */ //#define DQLOCK_SPIN #define DQLOCK_MUTEX #ifdef DQLOCK_SPIN #ifdef DQLOCK_MUTEX #error Cannot enable both DQLOCK_SPIN and DQLOCK_MUTEX #endif #endif /* Define a queue for storing defrag trackers */ typedef struct DefragTrackerQueue_ { DefragTracker *top; DefragTracker *bot; uint32_t len; #ifdef DBG_PERF uint32_t dbg_maxlen; #endif /* DBG_PERF */ #ifdef DQLOCK_MUTEX SCMutex m; #elif defined DQLOCK_SPIN SCSpinlock s; #else #error Enable DQLOCK_SPIN or DQLOCK_MUTEX #endif } DefragTrackerQueue; #ifdef DQLOCK_SPIN #define DQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) #define DQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) #define DQLOCK_LOCK(q) SCSpinLock(&(q)->s) #define DQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) #define DQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) #elif defined DQLOCK_MUTEX #define DQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) #define DQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) #define DQLOCK_LOCK(q) SCMutexLock(&(q)->m) #define DQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) #define DQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) #else #error Enable DQLOCK_SPIN or DQLOCK_MUTEX #endif /* prototypes */ DefragTrackerQueue *DefragTrackerQueueNew(); DefragTrackerQueue *DefragTrackerQueueInit(DefragTrackerQueue *); void DefragTrackerQueueDestroy (DefragTrackerQueue *); void DefragTrackerEnqueue (DefragTrackerQueue *, DefragTracker *); DefragTracker *DefragTrackerDequeue (DefragTrackerQueue *); uint32_t DefragTrackerQueueLen(DefragTrackerQueue *); #endif /* __DEFRAG_QUEUE_H__ */ suricata-1.4.7/src/decode-pppoe.c0000644000000000000000000003200512253546156013535 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup decode * * @{ */ /** * \file * * \author James Riden * * PPPOE Decoder */ #include "suricata-common.h" #include "packet-queue.h" #include "decode.h" #include "decode-ppp.h" #include "decode-pppoe.h" #include "decode-events.h" #include "flow.h" #include "util-unittest.h" #include "util-debug.h" /** * \brief Main decoding function for PPPOE Discovery packets */ void DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_pppoe, tv->sc_perf_pca); if (len < PPPOE_DISCOVERY_HEADER_MIN_LEN) { ENGINE_SET_EVENT(p, PPPOE_PKT_TOO_SMALL); return; } p->pppoedh = NULL; p->pppoedh = (PPPOEDiscoveryHdr *)pkt; if (p->pppoedh == NULL) return; /* parse the PPPOE code */ switch (p->pppoedh->pppoe_code) { case PPPOE_CODE_PADI: break; case PPPOE_CODE_PADO: break; case PPPOE_CODE_PADR: break; case PPPOE_CODE_PADS: break; case PPPOE_CODE_PADT: break; default: SCLogDebug("unknown PPPOE code: 0x%0"PRIX8"", p->pppoedh->pppoe_code); ENGINE_SET_EVENT(p,PPPOE_WRONG_CODE); return; } /* parse any tags we have in the packet */ uint16_t tag_length = 0; PPPOEDiscoveryTag* pppoedt = (PPPOEDiscoveryTag*) (p->pppoedh + PPPOE_DISCOVERY_HEADER_MIN_LEN); uint16_t pppoe_length = ntohs(p->pppoedh->pppoe_length); uint16_t packet_length = len - PPPOE_DISCOVERY_HEADER_MIN_LEN ; SCLogDebug("pppoe_length %"PRIu16", packet_length %"PRIu16"", pppoe_length, packet_length); if (pppoe_length > packet_length) { SCLogDebug("malformed PPPOE tags"); ENGINE_SET_EVENT(p,PPPOE_MALFORMED_TAGS); return; } while (pppoedt < (PPPOEDiscoveryTag*) (pkt + (len - sizeof(PPPOEDiscoveryTag))) && pppoe_length >=4 && packet_length >=4) { #ifdef DEBUG uint16_t tag_type = ntohs(pppoedt->pppoe_tag_type); #endif tag_length = ntohs(pppoedt->pppoe_tag_length); SCLogDebug ("PPPoE Tag type %x, length %u", tag_type, tag_length); if (pppoe_length >= (4 + tag_length)) { pppoe_length -= (4 + tag_length); } else { pppoe_length = 0; // don't want an underflow } if (packet_length >= 4 + tag_length) { packet_length -= (4 + tag_length); } else { packet_length = 0; // don't want an underflow } pppoedt = pppoedt + (4 + tag_length); } return; } /** * \brief Main decoding function for PPPOE Session packets */ void DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_pppoe, tv->sc_perf_pca); if (len < PPPOE_SESSION_HEADER_LEN) { ENGINE_SET_EVENT(p, PPPOE_PKT_TOO_SMALL); return; } p->pppoesh = (PPPOESessionHdr *)pkt; if (p->pppoesh == NULL) return; SCLogDebug("PPPOE VERSION %" PRIu32 " TYPE %" PRIu32 " CODE %" PRIu32 " SESSIONID %" PRIu32 " LENGTH %" PRIu32 "", PPPOE_SESSION_GET_VERSION(p->pppoesh), PPPOE_SESSION_GET_TYPE(p->pppoesh), p->pppoesh->pppoe_code, ntohs(p->pppoesh->session_id), ntohs(p->pppoesh->pppoe_length)); /* can't use DecodePPP() here because we only get a single 2-byte word to indicate protocol instead of the full PPP header */ if (ntohs(p->pppoesh->pppoe_length) > 0) { /* decode contained PPP packet */ switch (ntohs(p->pppoesh->protocol)) { case PPP_VJ_COMP: case PPP_IPX: case PPP_OSI: case PPP_NS: case PPP_DECNET: case PPP_APPLE: case PPP_BRPDU: case PPP_STII: case PPP_VINES: case PPP_HELLO: case PPP_LUXCOM: case PPP_SNS: case PPP_MPLS_UCAST: case PPP_MPLS_MCAST: case PPP_IPCP: case PPP_OSICP: case PPP_NSCP: case PPP_DECNETCP: case PPP_APPLECP: case PPP_IPXCP: case PPP_STIICP: case PPP_VINESCP: case PPP_IPV6CP: case PPP_MPLSCP: case PPP_LCP: case PPP_PAP: case PPP_LQM: case PPP_CHAP: ENGINE_SET_EVENT(p,PPP_UNSUP_PROTO); break; case PPP_VJ_UCOMP: if(len < (PPPOE_SESSION_HEADER_LEN + IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p,PPPVJU_PKT_TOO_SMALL); return; } if(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + PPPOE_SESSION_HEADER_LEN)) == 4) { DecodeIPV4(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq ); } break; case PPP_IP: if(len < (PPPOE_SESSION_HEADER_LEN + IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p,PPPIPV4_PKT_TOO_SMALL); return; } DecodeIPV4(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq ); break; /* PPP IPv6 was not tested */ case PPP_IPV6: if(len < (PPPOE_SESSION_HEADER_LEN + IPV6_HEADER_LEN)) { ENGINE_SET_EVENT(p,PPPIPV6_PKT_TOO_SMALL); return; } DecodeIPV6(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq ); break; default: SCLogDebug("unknown PPP protocol: %" PRIx32 "",ntohs(p->ppph->protocol)); ENGINE_SET_EVENT(p,PPP_WRONG_TYPE); return; } } } #ifdef UNITTESTS /** DecodePPPOEtest01 * \brief Decode malformed PPPOE packet (too short) * \retval 1 Expected test value */ static int DecodePPPOEtest01 (void) { uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL); if (ENGINE_ISSET_EVENT(p,PPPOE_PKT_TOO_SMALL)) { SCFree(p); return 1; } SCFree(p); return 0; } /** DecodePPPOEtest02 * \brief Valid PPPOE packet - check the invalid ICMP type encapsulated is flagged * \retval 0 Expected test value */ static int DecodePPPOEtest02 (void) { uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, 0x21, 0x45, 0x00, 0x00, 0x3c, 0x05, 0x5c, 0x00, 0x00, 0x20, 0x01, 0xff, 0x30, 0xc0, 0xa8, 0x0a, 0x7f, 0xc0, 0xa8, 0x0a, 0x65, 0xab, 0xcd, 0x16, 0x5e, 0x02, 0x00, 0x37, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL); if(ENGINE_ISSET_EVENT(p,PPPOE_PKT_TOO_SMALL)) { goto end; } // and we insist that the invalid ICMP encapsulated (type 0xab, code 0xcd) is flagged if(! ENGINE_ISSET_EVENT(p,ICMPV4_UNKNOWN_TYPE)) { goto end; } ret = 1; end: FlowShutdown(); SCFree(p); return ret; } /** DecodePPPOEtest03 * \brief Valid example PADO packet PPPOE packet taken from RFC2516 * \retval 0 Expected test value */ static int DecodePPPOEtest03 (void) { /* example PADO packet taken from RFC2516 */ uint8_t raw_pppoe[] = { 0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f, 0x20, 0x52, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68, 0x65, 0x73, 0x68, 0x6f, 0x6f, 0x74 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL); if (p->pppoedh == NULL) { SCFree(p); return 0; } SCFree(p); return 1; } /** DecodePPPOEtest04 * \brief Valid example PPPOE packet taken from RFC2516 - but with wrong PPPOE code * \retval 1 Expected test value */ static int DecodePPPOEtest04 (void) { /* example PADI packet taken from RFC2516, but with wrong code */ uint8_t raw_pppoe[] = { 0x11, 0xbb, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL); if(ENGINE_ISSET_EVENT(p,PPPOE_WRONG_CODE)) { SCFree(p); return 1; } SCFree(p); return 0; } /** DecodePPPOEtest05 * \brief Valid exaple PADO PPPOE packet taken from RFC2516, but too short for given length * \retval 0 Expected test value */ static int DecodePPPOEtest05 (void) { /* example PADI packet taken from RFC2516 */ uint8_t raw_pppoe[] = { 0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f, 0x20, 0x52, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodePPPOEDiscovery(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL); if(ENGINE_ISSET_EVENT(p,PPPOE_MALFORMED_TAGS)) { SCFree(p); return 1; } SCFree(p); return 0; } /** DecodePPPOEtest06 * \brief Check that the macros work as expected. Type and version are * fields of 4 bits length. So they are sharing the same var and the macros * should extract the first 4 bits for version and the second 4 bits for type * \retval 1 Expected test value */ static int DecodePPPOEtest06 (void) { PPPOESessionHdr pppoesh; PPPOEDiscoveryHdr pppoedh; pppoesh.pppoe_version_type = 0xAB; pppoedh.pppoe_version_type = 0xCD; if (PPPOE_SESSION_GET_VERSION(&pppoesh) != 0x0A) { printf("Error, PPPOE macro pppoe_session_get_version failed: "); return 0; } if (PPPOE_SESSION_GET_TYPE(&pppoesh) != 0x0B) { printf("Error, PPPOE macro pppoe_session_get_type failed: "); return 0; } if (PPPOE_DISCOVERY_GET_VERSION(&pppoedh) != 0x0C) { printf("Error, PPPOE macro pppoe_discovery_get_version failed: "); return 0; } if (PPPOE_DISCOVERY_GET_TYPE(&pppoedh) != 0x0D) { printf("Error, PPPOE macro pppoe_discovery_get_type failed: "); return 0; } return 1; } #endif /* UNITTESTS */ /** * \brief Registers PPPOE unit tests * \todo More PPPOE tests */ void DecodePPPOERegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodePPPOEtest01", DecodePPPOEtest01, 1); UtRegisterTest("DecodePPPOEtest02", DecodePPPOEtest02, 1); UtRegisterTest("DecodePPPOEtest03", DecodePPPOEtest03, 1); UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04, 1); UtRegisterTest("DecodePPPOEtest05", DecodePPPOEtest05, 1); UtRegisterTest("DecodePPPOEtest06", DecodePPPOEtest06, 1); #endif /* UNITTESTS */ } /** * @} */ suricata-1.4.7/src/decode-teredo.h0000644000000000000000000000151112253546156013677 00000000000000/* Copyright (C) 2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq); suricata-1.4.7/src/detect-engine-address-ipv4.c0000644000000000000000000014654212253546156016223 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * IPV4 Address part of the detection engine. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "flow-var.h" #include "util-cidr.h" #include "util-unittest.h" #include "detect-engine-address.h" #include "detect-engine-siggroup.h" #include "detect-engine-port.h" #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" /** * \brief Compares 2 addresses(address ranges) and returns the relationship * between the 2 addresses. * * \param a Pointer to the first address instance to be compared. * \param b Pointer to the second address instance to be compared. * * \retval ADDRESS_EQ If the 2 address ranges a and b, are equal. * \retval ADDRESS_ES b encapsulates a. b_ip1[...a_ip1...a_ip2...]b_ip2. * \retval ADDRESS_EB a encapsulates b. a_ip1[...b_ip1....b_ip2...]a_ip2. * \retval ADDRESS_LE a_ip1(...b_ip1==a_ip2...)b_ip2 * \retval ADDRESS_LT a_ip1(...b_ip1...a_ip2...)b_ip2 * \retval ADDRESS_GE b_ip1(...a_ip1==b_ip2...)a_ip2 * \retval ADDRESS_GT a_ip1 > b_ip2, i.e. the address range for 'a' starts only * after the end of the address range for 'b' */ int DetectAddressCmpIPv4(DetectAddress *a, DetectAddress *b) { uint32_t a_ip1 = ntohl(a->ip.addr_data32[0]); uint32_t a_ip2 = ntohl(a->ip2.addr_data32[0]); uint32_t b_ip1 = ntohl(b->ip.addr_data32[0]); uint32_t b_ip2 = ntohl(b->ip2.addr_data32[0]); if (a_ip1 == b_ip1 && a_ip2 == b_ip2) { SCLogDebug("ADDRESS_EQ"); return ADDRESS_EQ; } else if (a_ip1 >= b_ip1 && a_ip1 <= b_ip2 && a_ip2 <= b_ip2) { SCLogDebug("ADDRESS_ES"); return ADDRESS_ES; } else if (a_ip1 <= b_ip1 && a_ip2 >= b_ip2) { SCLogDebug("ADDRESS_EB"); return ADDRESS_EB; } else if (a_ip1 < b_ip1 && a_ip2 < b_ip2 && a_ip2 >= b_ip1) { SCLogDebug("ADDRESS_LE"); return ADDRESS_LE; } else if (a_ip1 < b_ip1 && a_ip2 < b_ip2) { SCLogDebug("ADDRESS_LT"); return ADDRESS_LT; } else if (a_ip1 > b_ip1 && a_ip1 <= b_ip2 && a_ip2 > b_ip2) { SCLogDebug("ADDRESS_GE"); return ADDRESS_GE; } else if (a_ip1 > b_ip2) { SCLogDebug("ADDRESS_GT"); return ADDRESS_GT; } else { /* should be unreachable */ SCLogDebug("Internal Error: should be unreachable"); } return ADDRESS_ER; } /** * \brief Cut groups and merge sigs * * a = 1.2.3.4, b = 1.2.3.4-1.2.3.5 * must result in: a == 1.2.3.4, b == 1.2.3.5, c == NULL * * a = 1.2.3.4, b = 1.2.3.3-1.2.3.5 * must result in: a == 1.2.3.3, b == 1.2.3.4, c == 1.2.3.5 * * a = 1.2.3.0/24 b = 1.2.3.128-1.2.4.10 * must result in: a == 1.2.3.0/24, b == 1.2.4.0-1.2.4.10, c == NULL * * a = 1.2.3.4, b = 1.2.3.0/24 * must result in: a == 1.2.3.0-1.2.3.3, b == 1.2.3.4, c == 1.2.3.5-1.2.3.255 * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, DetectAddress *b, DetectAddress **c) { uint32_t a_ip1 = ntohl(a->ip.addr_data32[0]); uint32_t a_ip2 = ntohl(a->ip2.addr_data32[0]); uint32_t b_ip1 = ntohl(b->ip.addr_data32[0]); uint32_t b_ip2 = ntohl(b->ip2.addr_data32[0]); DetectPort *port = NULL; DetectAddress *tmp = NULL; DetectAddress *tmp_c = NULL; int r = 0; /* default to NULL */ *c = NULL; r = DetectAddressCmpIPv4(a, b); if (r != ADDRESS_ES && r != ADDRESS_EB && r != ADDRESS_LE && r != ADDRESS_GE) { SCLogDebug("we shouldn't be here"); goto error; } /* get a place to temporary put sigs lists */ tmp = DetectAddressInit(); if (tmp == NULL) goto error; /* we have 3 parts: [aaa[abab)bbb] * part a: a_ip1 <-> b_ip1 - 1 * part b: b_ip1 <-> a_ip2 * part c: a_ip2 + 1 <-> b_ip2 */ if (r == ADDRESS_LE) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_LE"); a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(b_ip1 - 1); b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET; tmp_c->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; if (de_ctx != NULL) { SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp_c->port, port); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &b->port, port); tmp_c->cnt += b->cnt; b->cnt += a->cnt; } /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 * part c: b_ip2 + 1 <-> a_ip2 */ } else if (r == ADDRESS_GE) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_GE"); a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET; tmp_c->ip.addr_data32[0] = htonl(b_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; if (de_ctx != NULL) { /* 'a' gets clean and then 'b' sigs * 'b' gets clean, then 'a' then 'b' sigs * 'c' gets 'a' sigs */ /* store old a list */ SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); /* clean a list */ SigGroupHeadClearSigs(a->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx, tmp->sh, &tmp_c->sh); /* copy old b to a */ SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); /* prepend old a before b */ SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); /* clean tmp list */ SigGroupHeadClearSigs(tmp->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp->port, port); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &a->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &b->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp_c->port, port); tmp->cnt += a->cnt; a->cnt = 0; tmp_c->cnt += tmp->cnt; a->cnt += b->cnt; b->cnt += tmp->cnt; tmp->cnt = 0; } /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] * part a: a_ip1 <-> a_ip2 * part b: a_ip2 + 1 <-> b_ip2 * * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> a_ip2 * * 3 part [bbb[aaa]bbb] * becomes[aaa[bbb]ccc] * * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> a_ip2 * part c: a_ip2 + 1 <-> b_ip2 */ } else if (r == ADDRESS_ES) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_ES"); if (a_ip1 == b_ip1) { SCLogDebug("DetectAddressCutIPv4: 1"); a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(a_ip2); b->ip.addr_data32[0] = htonl(a_ip2 + 1); b->ip2.addr_data32[0] = htonl(b_ip2); if (de_ctx != NULL) { /* 'b' overlaps 'a' so 'a' needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &a->port, port); a->cnt += b->cnt; } } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); if (de_ctx != NULL) { SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadClearSigs(a->sh); SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp->port, a->port); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &a->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &b->port, port); tmp->cnt += a->cnt; a->cnt = 0; a->cnt += b->cnt; b->cnt += tmp->cnt; tmp->cnt = 0; } } else { SCLogDebug("3"); a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET; tmp_c->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; if (de_ctx != NULL) { /* 'a' gets clean and then 'b' sigs * 'b' gets clean, then 'a' then 'b' sigs * 'c' gets 'b' sigs */ /* store old a list */ SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); /* clean a list */ SigGroupHeadClearSigs(a->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); /* copy old b to a */ SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); /* prepend old a before b */ SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); /* clean tmp list */ SigGroupHeadClearSigs(tmp->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp->port, port); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp_c->port, port); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &a->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &b->port, port); tmp->cnt += a->cnt; a->cnt = 0; tmp_c->cnt += b->cnt; a->cnt += b->cnt; b->cnt += tmp->cnt; tmp->cnt = 0; } } /* we have 2 or three parts: * * 2 part: [[baba]aaa] or [aaa[abab]] * part a: b_ip1 <-> b_ip2 * part b: b_ip2 + 1 <-> a_ip2 * * part a: a_ip1 <-> b_ip1 - 1 * part b: b_ip1 <-> b_ip2 * * 3 part [aaa[bbb]aaa] * becomes[aaa[bbb]ccc] * * part a: a_ip1 <-> b_ip2 - 1 * part b: b_ip1 <-> b_ip2 * part c: b_ip2 + 1 <-> a_ip2 */ } else if (r == ADDRESS_EB) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_EB"); if (a_ip1 == b_ip1) { SCLogDebug("DetectAddressCutIPv4: 1"); a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(b_ip2); b->ip.addr_data32[0] = htonl(b_ip2 + 1); b->ip2.addr_data32[0] = htonl(a_ip2); if (de_ctx != NULL) { /* 'b' overlaps 'a' so a needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); SigGroupHeadClearSigs(b->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); for (port = b->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp->port, b->port); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &b->port, port); for (port = tmp->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &a->port, port); tmp->cnt += b->cnt; b->cnt = 0; b->cnt += a->cnt; a->cnt += tmp->cnt; tmp->cnt = 0; } } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(b_ip1 - 1); b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); if (de_ctx != NULL) { /* 'a' overlaps 'b' so a needs the 'a' sigs */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &b->port, port); b->cnt += a->cnt; } } else { SCLogDebug("DetectAddressCutIPv4: 3"); a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(b_ip1 - 1); b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET; tmp_c->ip.addr_data32[0] = htonl(b_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; if (de_ctx != NULL) { /* 'a' stays the same wrt sigs * 'b' keeps it's own sigs and gets a's sigs prepended * 'c' gets 'a' sigs */ SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &b->port, port); for (port = a->port; port != NULL; port = port->next) DetectPortInsertCopy(de_ctx, &tmp_c->port, port); b->cnt += a->cnt; tmp_c->cnt += a->cnt; } } } if (tmp != NULL) DetectAddressFree(tmp); return 0; error: if (tmp != NULL) DetectAddressFree(tmp); return -1; } /** * \brief Check if the address group list covers the complete IPv4 IP space. * * \param ag Pointer to a DetectAddress list head, which has to be checked to * see if the address ranges in it, cover the entire IPv4 IP space. * * \retval 1 Yes, it covers the entire IPv4 address range. * \retval 0 No, it doesn't cover the entire IPv4 address range. */ int DetectAddressIsCompleteIPSpaceIPv4(DetectAddress *ag) { uint32_t next_ip = 0; if (ag == NULL) return 0; /* if we don't start with 0.0.0.0 we know we're good */ if (ntohl(ag->ip.addr_data32[0]) != 0x00000000) return 0; /* if we're ending with 255.255.255.255 while we know we started with * 0.0.0.0 it's the complete space */ if (ntohl(ag->ip2.addr_data32[0]) == 0xFFFFFFFF) return 1; next_ip = htonl(ntohl(ag->ip2.addr_data32[0]) + 1); ag = ag->next; for ( ; ag != NULL; ag = ag->next) { if (ag->ip.addr_data32[0] != next_ip) return 0; if (ntohl(ag->ip2.addr_data32[0]) == 0xFFFFFFFF) return 1; next_ip = htonl(ntohl(ag->ip2.addr_data32[0]) + 1); } return 0; } /** * \brief Cuts and returns an address range, which is the complement of the * address range that is supplied as the argument. * * For example: * * If a = 0.0.0.0-1.2.3.4, * then a = 1.2.3.4-255.255.255.255 and b = NULL * If a = 1.2.3.4-255.255.255.255, * then a = 0.0.0.0-1.2.3.4 and b = NULL * If a = 1.2.3.4-192.168.1.1, * then a = 0.0.0.0-1.2.3.3 and b = 192.168.1.2-255.255.255.255 * * \param a Pointer to an address range (DetectAddress) instance whose complement * has to be returned in a and b. * \param b Pointer to DetectAddress pointer, that will be supplied back with a * new DetectAddress instance, if the complement demands so. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressCutNotIPv4(DetectAddress *a, DetectAddress **b) { uint32_t a_ip1 = ntohl(a->ip.addr_data32[0]); uint32_t a_ip2 = ntohl(a->ip2.addr_data32[0]); DetectAddress *tmp_b = NULL; /* default to NULL */ *b = NULL; if (a_ip1 != 0x00000000 && a_ip2 != 0xFFFFFFFF) { a->ip.addr_data32[0] = htonl(0x00000000); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); tmp_b = DetectAddressInit(); if (tmp_b == NULL) goto error; tmp_b->ip.family = AF_INET; tmp_b->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_b->ip2.addr_data32[0] = htonl(0xFFFFFFFF); *b = tmp_b; } else if (a_ip1 == 0x00000000 && a_ip2 != 0xFFFFFFFF) { a->ip.addr_data32[0] = htonl(a_ip2 + 1); a->ip2.addr_data32[0] = htonl(0xFFFFFFFF); } else if (a_ip1 != 0x00000000 && a_ip2 == 0xFFFFFFFF) { a->ip.addr_data32[0] = htonl(0x00000000); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); } else { goto error; } return 0; error: return -1; } /** * \brief Extends a target address range if the the source address range is * wider than the target address range on either sides. * * Every address is a range, i.e. address->ip1....address->ip2. For * example 1.2.3.4 to 192.168.1.1. * if source->ip1 is smaller than target->ip1, it indicates that the * source's left address limit is greater(range wise) than the target's * left address limit, and hence we reassign the target's left address * limit to source's left address limit. * Similary if source->ip2 is greater than target->ip2, it indicates that * the source's right address limit is greater(range wise) than the * target's right address limit, and hence we reassign the target's right * address limit to source's right address limit. * * \param de_ctx Pointer to the detection engine context. * \param target Pointer to the target DetectAddress instance that has to be * updated. * \param source Pointer to the source DetectAddress instance that is used * to decided whether we extend the target's address range. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressJoinIPv4(DetectEngineCtx *de_ctx, DetectAddress *target, DetectAddress *source) { if (source == NULL || target == NULL) return -1; if (ntohl(source->ip.addr_data32[0]) < ntohl(target->ip.addr_data32[0])) target->ip.addr_data32[0] = source->ip.addr_data32[0]; if (ntohl(source->ip2.addr_data32[0]) > ntohl(target->ip2.addr_data32[0])) target->ip2.addr_data32[0] = source->ip2.addr_data32[0]; return 0; } /********************************Unittests*************************************/ #ifdef UNITTESTS static int DetectAddressIPv4TestAddressCmp01(void) { struct in_addr in; int result = 1; DetectAddress *a = DetectAddressInit(); if (a == NULL) return 0; DetectAddress *b = DetectAddressInit(); if (b == NULL) { DetectAddressFree(a); return 0; } if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_EQ); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_ES); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_ES); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_ES); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_ES); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_ES); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_EB); if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_EB); if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_EB); if (inet_pton(AF_INET, "1.2.3.5", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_EB); if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "128.128.128.128", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "128.128.128.128", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_LE); if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "128.128.128.128", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_LE); if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_LE); if (inet_pton(AF_INET, "170.170.170.169", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_LE); if (inet_pton(AF_INET, "170.170.170.169", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_LE); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_LT); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "185.185.185.185", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; /* we could get a LE */ result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_LT); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; /* we could get a LE */ result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_LT); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_LT); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_LT); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_LT); if (inet_pton(AF_INET, "128.128.128.128", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "128.128.128.128", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_GE); if (inet_pton(AF_INET, "128.128.128.128", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_GE); if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_GE); if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.169", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "180.180.180.180", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_GE); if (inet_pton(AF_INET, "170.170.170.169", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_GE); if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.169.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_GE); if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "200.200.200.200", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "185.185.185.185", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) == ADDRESS_GT); if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "200.200.200.200", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_GT); if (inet_pton(AF_INET, "182.168.1.2", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "200.200.200.200", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "170.170.170.170", &in) < 0) goto error; b->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; b->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCmpIPv4(a, b) != ADDRESS_GT); DetectAddressFree(a); DetectAddressFree(b); return result; error: DetectAddressFree(a); DetectAddressFree(b); return 0; } static int DetectAddressIPv4IsCompleteIPSpace02(void) { DetectAddress *a = NULL; struct in_addr in; int result = 1; if ( (a = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 1); if (inet_pton(AF_INET, "0.0.0.1", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); DetectAddressFree(a); if ( (a = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.254", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); DetectAddressFree(a); return result; error: if (a != NULL) DetectAddressFree(a); return 0; } static int DetectAddressIPv4IsCompleteIPSpace03(void) { DetectAddress *a = NULL; DetectAddress *temp = NULL; struct in_addr in; int result = 1; if ( (a = DetectAddressInit()) == NULL) goto error; temp = a; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); if ( (temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; if (inet_pton(AF_INET, "1.2.3.5", &in) < 0) goto error; temp->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "126.36.62.61", &in) < 0) goto error; temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); if ( (temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; if (inet_pton(AF_INET, "126.36.62.62", &in) < 0) goto error; temp->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "222.52.21.62", &in) < 0) goto error; temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); if ( (temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; if (inet_pton(AF_INET, "222.52.21.63", &in) < 0) goto error; temp->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.254", &in) < 0) goto error; temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); if ( (temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; temp->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 1); DetectAddressFree(a); return result; error: if (a != NULL) DetectAddressFree(a); return 0; } static int DetectAddressIPv4IsCompleteIPSpace04(void) { DetectAddress *a = NULL; DetectAddress *temp = NULL; struct in_addr in; int result = 1; if ( (a = DetectAddressInit()) == NULL) goto error; temp = a; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); if ( (temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; if (inet_pton(AF_INET, "1.2.3.5", &in) < 0) goto error; temp->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "126.36.62.61", &in) < 0) goto error; temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); if ( (temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; if (inet_pton(AF_INET, "126.36.62.62", &in) < 0) goto error; temp->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "222.52.21.62", &in) < 0) goto error; temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); if ( (temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; if (inet_pton(AF_INET, "222.52.21.64", &in) < 0) goto error; temp->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.254", &in) < 0) goto error; temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); if ( (temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; temp->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); DetectAddressFree(a); return result; error: if (a != NULL) DetectAddressFree(a); return 0; } static int DetectAddressIPv4CutNot05(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; struct in_addr in; int result = 1; if ( (a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCutNotIPv4(a, &b) == -1); DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return result; error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return 0; } static int DetectAddressIPv4CutNot06(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; struct in_addr in; int result = 1; if ( (a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCutNotIPv4(a, &b) == 0); if (inet_pton(AF_INET, "1.2.3.5", &in) < 0) goto error; result = (a->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; result &= (a->ip2.addr_data32[0] = in.s_addr); DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return result; error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return 0; } static int DetectAddressIPv4CutNot07(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; struct in_addr in; int result = 1; if ( (a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCutNotIPv4(a, &b) == 0); if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; result = (a->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; result &= (a->ip2.addr_data32[0] = in.s_addr); DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return result; error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return 0; } static int DetectAddressIPv4CutNot08(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; struct in_addr in; int result = 1; if ( (a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCutNotIPv4(a, &b) == 0); if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; result &= (a->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; result &= (a->ip2.addr_data32[0] = in.s_addr); if (b == NULL) { result = 0; goto error; } else { result &= 1; } if (inet_pton(AF_INET, "1.2.3.5", &in) < 0) goto error; result &= (b->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; result &= (b->ip2.addr_data32[0] = in.s_addr); DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return result; error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return 0; } static int DetectAddressIPv4CutNot09(void) { DetectAddress *a = NULL; DetectAddress *b = NULL; struct in_addr in; int result = 1; if ( (a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; a->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressCutNotIPv4(a, &b) == 0); if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) goto error; result &= (a->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "1.2.3.3", &in) < 0) goto error; result &= (a->ip2.addr_data32[0] = in.s_addr); if (b == NULL) { result = 0; goto error; } else { result &= 1; } if (inet_pton(AF_INET, "192.168.1.3", &in) < 0) goto error; result &= (b->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "255.255.255.255", &in) < 0) goto error; result &= (b->ip2.addr_data32[0] = in.s_addr); DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return result; error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); return 0; } static int DetectAddressIPv4Join10(void) { struct in_addr in; int result = 1; DetectAddress *source = DetectAddressInit(); if (source == NULL) return 0; DetectAddress *target = DetectAddressInit(); if (target == NULL) { DetectAddressFree(source); return 0; } if (inet_pton(AF_INET, "128.51.61.124", &in) < 0) goto error; target->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; target->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; source->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; source->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressJoinIPv4(NULL, target, source) == 0); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; result &= (target->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; result &= (target->ip2.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; target->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; target->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.5", &in) < 0) goto error; source->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.1", &in) < 0) goto error; source->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressJoinIPv4(NULL, target, source) == 0); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; result &= (target->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; result &= (target->ip2.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; target->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; target->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "128.1.5.15", &in) < 0) goto error; source->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "200.202.200.200", &in) < 0) goto error; source->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressJoinIPv4(NULL, target, source) == 0); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; result &= (target->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "200.202.200.200", &in) < 0) goto error; result &= (target->ip2.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "128.51.61.124", &in) < 0) goto error; target->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; target->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; source->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; source->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressJoinIPv4(NULL, target, source) == 0); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; result &= (target->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; result &= (target->ip2.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; target->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; target->ip2.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; source->ip.addr_data32[0] = in.s_addr; if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; source->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressJoinIPv4(NULL, target, source) == 0); if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) goto error; result &= (target->ip.addr_data32[0] == in.s_addr); if (inet_pton(AF_INET, "192.168.1.2", &in) < 0) goto error; result &= (target->ip2.addr_data32[0] == in.s_addr); DetectAddressFree(source); DetectAddressFree(target); return result; error: DetectAddressFree(source); DetectAddressFree(target); return 0; } #endif void DetectAddressIPv4Tests(void) { #ifdef UNITTESTS UtRegisterTest("DetectAddressIPv4TestAddressCmp01", DetectAddressIPv4TestAddressCmp01, 1); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace02", DetectAddressIPv4IsCompleteIPSpace02, 1); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace03", DetectAddressIPv4IsCompleteIPSpace03, 1); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace04", DetectAddressIPv4IsCompleteIPSpace04, 1); UtRegisterTest("DetectAddressIPv4CutNot05", DetectAddressIPv4CutNot05, 1); UtRegisterTest("DetectAddressIPv4CutNot06", DetectAddressIPv4CutNot06, 1); UtRegisterTest("DetectAddressIPv4CutNot07", DetectAddressIPv4CutNot07, 1); UtRegisterTest("DetectAddressIPv4CutNot08", DetectAddressIPv4CutNot08, 1); UtRegisterTest("DetectAddressIPv4CutNot09", DetectAddressIPv4CutNot09, 1); UtRegisterTest("DetectAddressIPv4Join10", DetectAddressIPv4Join10, 1); #endif } suricata-1.4.7/src/source-pcap.h0000644000000000000000000000346212253546156013424 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __SOURCE_PCAP_H__ #define __SOURCE_PCAP_H__ void TmModuleReceivePcapRegister (void); void TmModuleDecodePcapRegister (void); void PcapTranslateIPToDevice(char *pcap_dev, size_t len); int PcapLiveRegisterDevice(char *); int PcapLiveGetDeviceCount(void); char *PcapLiveGetDevice(int); #define LIBPCAP_SNAPLEN 1518 #define LIBPCAP_COPYWAIT 500 #define LIBPCAP_PROMISC 1 /* per packet Pcap vars */ typedef struct PcapPacketVars_ { } PcapPacketVars; /** needs to be able to contain Windows adapter id's, so * must be quite long. */ #define PCAP_IFACE_NAME_LENGTH 128 typedef struct PcapIfaceConfig_ { char iface[PCAP_IFACE_NAME_LENGTH]; /* number of threads */ int threads; /* socket buffer size */ int buffer_size; /* snapshot length */ int snaplen; /* promiscuous value */ int promisc; /* BPF filter */ char *bpf_filter; ChecksumValidationMode checksum_mode; SC_ATOMIC_DECLARE(unsigned int, ref); void (*DerefFunc)(void *); } PcapIfaceConfig; #endif /* __SOURCE_PCAP_H__ */ suricata-1.4.7/src/util-mpm-b2g-cuda.h0000644000000000000000000001043012253546156014322 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Anoop Saldanha * \author Martin Beyer */ #ifndef __UTIL_MPM_B2G_CUDA_H__ #define __UTIL_MPM_B2G_CUDA_H__ #ifdef __SC_CUDA_SUPPORT__ #include #include "decode.h" #include "util-mpm.h" #include "util-bloomfilter.h" #define B2G_CUDA_HASHSHIFT 4 #define B2G_CUDA_TYPE uint32_t #define B2G_CUDA_WORD_SIZE 32 #define B2G_CUDA_Q 2 #define B2G_CUDA_HASH16(a, b) (((a) << B2G_CUDA_HASHSHIFT) | (b)) #define B2G_CUDA_SEARCHFUNC B2gCudaSearchBNDMq #define B2G_CUDA_SEARCHFUNC_NAME "B2gCudaSearchBNDMq" typedef struct B2gCudaPattern_ { uint8_t flags; /** \todo we're limited to 32/64 byte lengths, uint8_t would be fine here */ uint16_t len; /* case sensitive */ uint8_t *cs; /* case INsensitive */ uint8_t *ci; struct B2gCudaPattern_ *next; uint32_t id; uint8_t *original_pat; } B2gCudaPattern; typedef struct B2gCudaHashItem_ { uint16_t idx; uint8_t flags; struct B2gCudaHashItem_ *nxt; } B2gCudaHashItem; typedef struct B2gCudaCtx_ { /* unique handle given by the cuda-handlers API, which indicates the module * in the engine that is holding this B2g_Cuda_Ctx */ int module_handle; /* cuda device pointer to B2gCudaCtx->B2G */ CUdeviceptr cuda_B2G; B2G_CUDA_TYPE *B2G; B2G_CUDA_TYPE m; BloomFilter **bloom; /* array containing the minimal length of the patters in a hash bucket. * Used for the BloomFilter. */ uint8_t *pminlen; /* pattern arrays */ B2gCudaPattern **parray; uint16_t pat_1_cnt; #ifdef B2G_CUDA_SEARCH2 uint16_t pat_2_cnt; #endif uint16_t pat_x_cnt; uint32_t hash_size; B2gCudaHashItem **hash; B2gCudaHashItem hash1[256]; #ifdef B2G_CUDA_SEARCH2 B2gCudaHashItem **hash2; #endif /* hash used during ctx initialization */ B2gCudaPattern **init_hash; uint8_t s0; /* we store our own multi byte search func ptr here for B2gCudaSearch1 */ uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* we store our own multi byte search func ptr here for B2gCudaSearch2 */ uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); } B2gCudaCtx; typedef struct B2gCudaThreadCtx_ { #ifdef B2G_CUDA_COUNTERS uint32_t stat_pminlen_calls; uint32_t stat_pminlen_total; uint32_t stat_bloom_calls; uint32_t stat_bloom_hits; uint32_t stat_calls; uint32_t stat_m_total; uint32_t stat_d0; uint32_t stat_d0_hashloop; uint32_t stat_loop_match; uint32_t stat_loop_no_match; uint32_t stat_num_shift; uint32_t stat_total_shift; #endif /* B2G_CUDA_COUNTERS */ } B2gCudaThreadCtx; void MpmB2gCudaRegister(void); void TmModuleCudaMpmB2gRegister(void); int B2gCudaStartDispatcherThreadRC(const char *); void B2gCudaKillDispatcherThreadRC(void); int B2gCudaResultsPostProcessing(Packet *, MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *); uint32_t B2gCudaSearch1(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); #ifdef B2G_CUDA_SEARCH2 uint32_t B2gCudaSearch2(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); #endif #endif /* __SC_CUDA_SUPPORT__ */ #endif /* __UTIL_MPM_B2G_CUDA_H__ */ suricata-1.4.7/src/defrag-queue.c0000644000000000000000000000614012253546156013544 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Defrag tracker queue handler functions */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "defrag-queue.h" #include "util-error.h" #include "util-debug.h" #include "util-print.h" DefragTrackerQueue *DefragTrackerQueueInit (DefragTrackerQueue *q) { if (q != NULL) { memset(q, 0, sizeof(DefragTrackerQueue)); DQLOCK_INIT(q); } return q; } DefragTrackerQueue *DefragTrackerQueueNew() { DefragTrackerQueue *q = (DefragTrackerQueue *)SCMalloc(sizeof(DefragTrackerQueue)); if (q == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in DefragTrackerQueueNew. Exiting..."); exit(EXIT_SUCCESS); } q = DefragTrackerQueueInit(q); return q; } /** * \brief Destroy a tracker queue * * \param q the tracker queue to destroy */ void DefragTrackerQueueDestroy (DefragTrackerQueue *q) { DQLOCK_DESTROY(q); } /** * \brief add a tracker to a queue * * \param q queue * \param dt tracker */ void DefragTrackerEnqueue (DefragTrackerQueue *q, DefragTracker *dt) { #ifdef DEBUG BUG_ON(q == NULL || dt == NULL); #endif DQLOCK_LOCK(q); /* more trackers in queue */ if (q->top != NULL) { dt->lnext = q->top; q->top->lprev = dt; q->top = dt; /* only tracker */ } else { q->top = dt; q->bot = dt; } q->len++; #ifdef DBG_PERF if (q->len > q->dbg_maxlen) q->dbg_maxlen = q->len; #endif /* DBG_PERF */ DQLOCK_UNLOCK(q); } /** * \brief remove a tracker from the queue * * \param q queue * * \retval dt tracker or NULL if empty list. */ DefragTracker *DefragTrackerDequeue (DefragTrackerQueue *q) { DQLOCK_LOCK(q); DefragTracker *dt = q->bot; if (dt == NULL) { DQLOCK_UNLOCK(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; } #ifdef DEBUG BUG_ON(q->len == 0); #endif if (q->len > 0) q->len--; dt->lnext = NULL; dt->lprev = NULL; DQLOCK_UNLOCK(q); return dt; } uint32_t DefragTrackerQueueLen(DefragTrackerQueue *q) { uint32_t len; DQLOCK_LOCK(q); len = q->len; DQLOCK_UNLOCK(q); return len; } suricata-1.4.7/src/stream.h0000644000000000000000000000542512253546156012477 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __STREAM_H__ #define __STREAM_H__ #include "flow.h" #define STREAM_START 0x01 #define STREAM_EOF 0x02 #define STREAM_TOSERVER 0x04 #define STREAM_TOCLIENT 0x08 #define STREAM_GAP 0x10 /* data gap encountered */ #define STREAM_DEPTH 0x20 /* depth reached */ /** size of the data chunks sent to the app layer parser. */ #define MSG_DATA_SIZE 4024 /* 4096 - 72 (size of rest of the struct) */ typedef struct StreamMsg_ { uint8_t flags; /**< msg flags */ Flow *flow; /**< parent flow */ struct StreamMsg_ *next; struct StreamMsg_ *prev; union { /* case !STREAM_EOF && !STREAM_GAP */ struct { uint32_t seq; /**< sequence number */ uint32_t data_len; /**< length of the data */ uint8_t data[MSG_DATA_SIZE];/**< reassembled data */ } data; /* case STREAM_GAP */ struct { uint32_t gap_size; } gap; }; } StreamMsg; typedef struct StreamMsgQueue_ { StreamMsg *top; StreamMsg *bot; uint16_t len; //uint8_t flags; #ifdef DBG_PERF uint16_t dbg_maxlen; #endif /* DBG_PERF */ } StreamMsgQueue; /* prototypes */ void StreamMsgQueuesInit(void); void StreamMsgQueuesDeinit(char); StreamMsg *StreamMsgGetFromPool(void); void StreamMsgReturnToPool(StreamMsg *); StreamMsg *StreamMsgGetFromQueue(StreamMsgQueue *); void StreamMsgPutInQueue(StreamMsgQueue *, StreamMsg *); StreamMsgQueue *StreamMsgQueueGetNew(void); void StreamMsgQueueFree(StreamMsgQueue *); StreamMsgQueue *StreamMsgQueueGetByPort(uint16_t); void StreamMsgQueueSetMinChunkLen(uint8_t dir, uint16_t len); uint16_t StreamMsgQueueGetMinChunkLen(uint8_t); void StreamMsgReturnListToPool(void *); typedef int (*StreamSegmentCallback)(Packet *, void *, uint8_t *, uint32_t); int StreamSegmentForEach(Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); #endif /* __STREAM_H__ */ suricata-1.4.7/src/detect-bytetest.h0000644000000000000000000001156312253546156014315 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Brian Rectanus */ #ifndef __DETECT_BYTETEST_H__ #define __DETECT_BYTETEST_H__ /** Bytetest Operators */ #define DETECT_BYTETEST_OP_LT 1 /**< "less than" operator */ #define DETECT_BYTETEST_OP_GT 2 /**< "greater than" operator */ #define DETECT_BYTETEST_OP_EQ 3 /**< "equals" operator */ #define DETECT_BYTETEST_OP_AND 4 /**< "bitwise and" operator */ #define DETECT_BYTETEST_OP_OR 5 /**< "bitwise or" operator */ #define DETECT_BYTETEST_OP_GE 6 /**< greater than equal operator */ #define DETECT_BYTETEST_OP_LE 7 /**< less than equal operator */ /** Bytetest Base */ #define DETECT_BYTETEST_BASE_UNSET 0 /**< Unset type value string (automatic)*/ #define DETECT_BYTETEST_BASE_OCT 8 /**< "oct" type value string */ #define DETECT_BYTETEST_BASE_DEC 10 /**< "dec" type value string */ #define DETECT_BYTETEST_BASE_HEX 16 /**< "hex" type value string */ /** Bytetest Flags */ #define DETECT_BYTETEST_NEGOP 0x01 /**< "!" negated operator */ #define DETECT_BYTETEST_LITTLE 0x02 /**< "little" endian value */ #define DETECT_BYTETEST_BIG 0x04 /**< "bi" endian value */ #define DETECT_BYTETEST_STRING 0x08 /**< "string" value */ #define DETECT_BYTETEST_RELATIVE 0x10 /**< "relative" offset */ #define DETECT_BYTETEST_DCE 0x20 /**< dce enabled */ #define DETECT_BYTETEST_VALUE_BE 0x40 /**< byte extract value enabled */ #define DETECT_BYTETEST_OFFSET_BE 0x80 /**< byte extract value enabled */ typedef struct DetectBytetestData_ { uint8_t nbytes; /**< Number of bytes to compare */ uint8_t op; /**< Operator used to compare */ uint8_t base; /**< String value base (oct|dec|hex) */ uint8_t flags; /**< Flags (big|little|relative|string) */ int32_t offset; /**< Offset in payload */ uint64_t value; /**< Value to compare against */ } DetectBytetestData; /* prototypes */ /** * Registration function for byte_test. * * \todo add support for no_stream and stream_only */ void DetectBytetestRegister (void); /** * This function is used to add the parsed byte_test data * into the current signature. * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param optstr pointer to the user provided options * * \retval 0 on Success * \retval -1 on Failure */ int DetectBytetestSetup(DetectEngineCtx *, Signature *, char *); /** * \brief this function will free memory associated with DetectBytetestData * * \param data pointer to DetectBytetestData */ void DetectBytetestFree(void *ptr); /** * This function is used to parse byte_test options passed via * * byte_test: bytes, [!]op, value, offset [,flags [, ...]] * * flags: "big", "little", "relative", "string", "oct", "dec", "hex" * * \param optstr Pointer to the user provided byte_test options * \param value Used to pass the value back, if byte_test uses a byte_extract * var. * \param offset Used to pass the offset back, if byte_test uses a byte_extract * var. * * \retval data pointer to DetectBytetestData on success * \retval NULL on failure */ DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offset); /** * This function is used to match byte_test * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet * \param m pointer to the sigmatch that we will cast into DetectBytetestData * * \retval -1 error * \retval 0 no match * \retval 1 match * * \todo The return seems backwards. We should return a non-zero error code. One of the error codes is "no match". As-is if someone accidentally does: if (DetectBytetestMatch(...)) { match }, then they catch an error as a match. */ int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m); int DetectBytetestDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, uint8_t *, uint32_t, uint8_t, int32_t, uint64_t); #endif /* __DETECT_BYTETEST_H__ */ suricata-1.4.7/src/util-debug.h0000644000000000000000000005553012253546156013247 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_DEBUG_H__ #define __UTIL_DEBUG_H__ #include #include #include #include "threads.h" #include "util-enum.h" #include "util-error.h" #include "util-debug-filters.h" /** * \brief ENV vars that can be used to set the properties for the logging module */ #define SC_LOG_ENV_LOG_LEVEL "SC_LOG_LEVEL" #define SC_LOG_ENV_LOG_OP_IFACE "SC_LOG_OP_IFACE" #define SC_LOG_ENV_LOG_FILE "SC_LOG_FILE" #define SC_LOG_ENV_LOG_FACILITY "SC_LOG_FACILITY" #define SC_LOG_ENV_LOG_FORMAT "SC_LOG_FORMAT" #define SC_LOG_ENV_LOG_OP_FILTER "SC_LOG_OP_FILTER" /** * \brief The various log levels */ typedef enum { SC_LOG_NOTSET = -1, SC_LOG_NONE = 0, SC_LOG_EMERGENCY, SC_LOG_ALERT, SC_LOG_CRITICAL, SC_LOG_ERROR, SC_LOG_WARNING, SC_LOG_NOTICE, SC_LOG_INFO, SC_LOG_DEBUG, SC_LOG_LEVEL_MAX, } SCLogLevel; /** * \brief The various output interfaces supported */ typedef enum { SC_LOG_OP_IFACE_CONSOLE, SC_LOG_OP_IFACE_FILE, SC_LOG_OP_IFACE_SYSLOG, SC_LOG_OP_IFACE_MAX, } SCLogOPIface; /* The default log_format, if it is not supplied by the user */ #ifdef RELEASE #define SC_LOG_DEF_LOG_FORMAT "%t - <%d> - " #else #define SC_LOG_DEF_LOG_FORMAT "[%i] %t - (%f:%l) <%d> (%n) -- " #endif /* The maximum length of the log message */ #define SC_LOG_MAX_LOG_MSG_LEN 2048 /* The maximum length of the log format */ #define SC_LOG_MAX_LOG_FORMAT_LEN 128 /* The default log level, if it is not supplied by the user */ #define SC_LOG_DEF_LOG_LEVEL SC_LOG_INFO /* The default output interface to be used */ #define SC_LOG_DEF_LOG_OP_IFACE SC_LOG_OP_IFACE_CONSOLE /* The default log file to be used */ #define SC_LOG_DEF_LOG_FILE "sc_ids_log.log" /* The default syslog facility to be used */ #define SC_LOG_DEF_SYSLOG_FACILITY_STR "local0" #define SC_LOG_DEF_SYSLOG_FACILITY LOG_LOCAL0 /** * \brief Structure to be used when log_level override support would be provided * by the logging module */ typedef struct SCLogOPBuffer_ { char msg[SC_LOG_MAX_LOG_MSG_LEN]; char *temp; const char *log_format; } SCLogOPBuffer; /** * \brief The output interface context for the logging module */ typedef struct SCLogOPIfaceCtx_ { SCLogOPIface iface; /* the output file to be used if the interface is SC_LOG_IFACE_FILE */ const char *file; /* the output file descriptor for the above file */ FILE * file_d; /* the facility code if the interface is SC_LOG_IFACE_SYSLOG */ int facility; /* override for the global_log_format(currently not used) */ const char *log_format; /* override for the global_log_level */ SCLogLevel log_level; struct SCLogOPIfaceCtx_ *next; } SCLogOPIfaceCtx; /** * \brief Structure containing init data, that would be passed to * SCInitDebugModule() */ typedef struct SCLogInitData_ { /* startup message */ char *startup_message; /* the log level */ SCLogLevel global_log_level; /* the log format */ char *global_log_format; /* output filter */ char *op_filter; /* list of output interfaces to be used */ SCLogOPIfaceCtx *op_ifaces; /* no of op ifaces */ uint8_t op_ifaces_cnt; } SCLogInitData; /** * \brief Holds the config state used by the logging api */ typedef struct SCLogConfig_ { char *startup_message; SCLogLevel log_level; char *log_format; char *op_filter; /* compiled pcre filter expression */ pcre *op_filter_regex; pcre_extra *op_filter_regex_study; /* op ifaces used */ SCLogOPIfaceCtx *op_ifaces; /* no of op ifaces */ uint8_t op_ifaces_cnt; } SCLogConfig; /* The different log format specifiers supported by the API */ #define SC_LOG_FMT_TIME 't' /* Timestamp in standard format */ #define SC_LOG_FMT_PID 'p' /* PID */ #define SC_LOG_FMT_TID 'i' /* Thread ID */ #define SC_LOG_FMT_TM 'm' /* Thread module name */ #define SC_LOG_FMT_LOG_LEVEL 'd' /* Log level */ #define SC_LOG_FMT_FILE_NAME 'f' /* File name */ #define SC_LOG_FMT_LINE 'l' /* Line number */ #define SC_LOG_FMT_FUNCTION 'n' /* Function */ /* The log format prefix for the format specifiers */ #define SC_LOG_FMT_PREFIX '%' extern SCLogLevel sc_log_global_log_level; extern int sc_log_module_initialized; extern int sc_log_module_cleaned; #define SCLog(x, ...) do { \ char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ char *_sc_log_temp = _sc_log_msg; \ if ( !( \ (sc_log_global_log_level >= x) && \ SCLogMessage(x, &_sc_log_temp, \ __FILE__, \ __LINE__, \ __FUNCTION__) \ == SC_OK) ) \ { } else { \ snprintf(_sc_log_temp, \ (SC_LOG_MAX_LOG_MSG_LEN - \ (_sc_log_temp - _sc_log_msg)), \ __VA_ARGS__); \ SCLogOutputBuffer(x, _sc_log_msg); \ } \ } while(0) #define SCLogErr(x, err, ...) do { \ char _sc_log_err_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ char *_sc_log_err_temp = _sc_log_err_msg; \ if ( !( \ (sc_log_global_log_level >= x) && \ SCLogMessage(x, &_sc_log_err_temp,\ __FILE__, \ __LINE__, \ __FUNCTION__) \ == SC_OK) ) \ { } else { \ _sc_log_err_temp = \ _sc_log_err_temp + \ snprintf(_sc_log_err_temp, \ (SC_LOG_MAX_LOG_MSG_LEN - \ (_sc_log_err_temp - _sc_log_err_msg)), \ "[ERRCODE: %s(%d)] - ", \ SCErrorToString(err), \ err); \ if ((_sc_log_err_temp - _sc_log_err_msg) > \ SC_LOG_MAX_LOG_MSG_LEN) { \ printf("Warning: Log message exceeded message length limit of %d\n",\ SC_LOG_MAX_LOG_MSG_LEN); \ _sc_log_err_temp = _sc_log_err_msg + \ SC_LOG_MAX_LOG_MSG_LEN; \ } else { \ snprintf(_sc_log_err_temp, \ (SC_LOG_MAX_LOG_MSG_LEN - \ (_sc_log_err_temp - _sc_log_err_msg)), \ __VA_ARGS__); \ } \ SCLogOutputBuffer(x, _sc_log_err_msg); \ } \ } while(0) /** * \brief Macro used to log INFORMATIONAL messages. * * \retval ... Takes as argument(s), a printf style format message */ #define SCLogInfo(...) SCLog(SC_LOG_INFO, __VA_ARGS__) /** * \brief Macro used to log NOTICE messages. * * \retval ... Takes as argument(s), a printf style format message */ #define SCLogNotice(...) SCLog(SC_LOG_NOTICE, __VA_ARGS__) /** * \brief Macro used to log WARNING messages. * * \retval err_code Error code that has to be logged along with the * warning message * \retval ... Takes as argument(s), a printf style format message */ #define SCLogWarning(err_code, ...) SCLogErr(SC_LOG_WARNING, err_code, \ __VA_ARGS__) /** * \brief Macro used to log ERROR messages. * * \retval err_code Error code that has to be logged along with the * error message * \retval ... Takes as argument(s), a printf style format message */ #define SCLogError(err_code, ...) SCLogErr(SC_LOG_ERROR, err_code, \ __VA_ARGS__) /** * \brief Macro used to log CRITICAL messages. * * \retval err_code Error code that has to be logged along with the * critical message * \retval ... Takes as argument(s), a printf style format message */ #define SCLogCritical(err_code, ...) SCLogErr(SC_LOG_CRITICAL, err_code, \ __VA_ARGS__) /** * \brief Macro used to log ALERT messages. * * \retval err_code Error code that has to be logged along with the * alert message * \retval ... Takes as argument(s), a printf style format message */ #define SCLogAlert(err_code, ...) SCLogErr(SC_LOG_ALERT, err_code, \ __VA_ARGS__) /** * \brief Macro used to log EMERGENCY messages. * * \retval err_code Error code that has to be logged along with the * emergency message * \retval ... Takes as argument(s), a printf style format message */ #define SCLogEmerg(err_code, ...) SCLogErr(SC_LOG_EMERGENCY, err_code, \ __VA_ARGS__) /* Avoid the overhead of using the debugging subsystem, in production mode */ #ifndef DEBUG #define SCLogDebug(...) do { } while (0) #define SCEnter(...) #define SCReturn return #define SCReturnInt(x) return x #define SCReturnUInt(x) return x #define SCReturnDbl(x) return x #define SCReturnChar(x) return x #define SCReturnCharPtr(x) return x #define SCReturnCT(x, type) return x #define SCReturnPtr(x, type) return x /* Please use it only for debugging purposes */ #else /** * \brief Macro used to log DEBUG messages. Comes under the debugging subsystem, * and hence will be enabled only in the presence of the DEBUG macro. * * \retval ... Takes as argument(s), a printf style format message */ #define SCLogDebug(...) SCLog(SC_LOG_DEBUG, __VA_ARGS__) /** * \brief Macro used to log debug messages on function entry. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_entry logs, it also * processes the FD filters, if any FD filters are registered. * * \retval f An argument can be supplied, although it is not used */ #define SCEnter(f) do { \ char _sc_enter_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ char *_sc_enter_temp = _sc_enter_msg; \ if (sc_log_global_log_level >= SC_LOG_DEBUG &&\ SCLogCheckFDFilterEntry(__FUNCTION__) && \ SCLogMessage(SC_LOG_DEBUG, &_sc_enter_temp, \ __FILE__, \ __LINE__, \ __FUNCTION__) == SC_OK) { \ snprintf(_sc_enter_temp, (SC_LOG_MAX_LOG_MSG_LEN - \ (_sc_enter_msg - _sc_enter_temp)), \ "Entering ... >>"); \ SCLogOutputBuffer(SC_LOG_DEBUG, \ _sc_enter_msg); \ } \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging sybsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that don't return * a value. */ #define SCReturn do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning ... <<" ); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging sybsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns an * integer value. * * \retval x Variable of type 'integer' that has to be returned */ #define SCReturnInt(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %"PRIdMAX" ... <<", (intmax_t)x); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging sybsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns an * unsigned integer value. * * \retval x Variable of type 'unsigned integer' that has to be returned */ #define SCReturnUInt(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %"PRIuMAX" ... <<", (uintmax_t)x); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging sybsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a * float/double value. * * \retval x Variable of type 'float/double' that has to be returned */ #define SCReturnDbl(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %f ... <<", x); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging sybsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a var * of character type. * * \retval x Variable of type 'char' that has to be returned */ #define SCReturnChar(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %c ... <<", x); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging sybsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a * character string. * * \retval x Pointer to the char string that has to be returned */ #define SCReturnCharPtr(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ if ((x) != NULL) { \ SCLogDebug("Returning: %s ... <<", x); \ } else { \ SCLogDebug("Returning: NULL ... <<"); \ } SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging sybsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a var * of custom type * * \retval x Variable instance of a custom type that has to be returned * \retval type Pointer to a character string holding the name of the custom * type(the argument x) that has to be returned */ #define SCReturnCT(x, type) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning var of " \ "type %s ... <<", type); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging sybsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a * pointer to a custom type * * \retval x Pointer to a variable instance of a custom type that has to be * returned * \retval type Pointer to a character string holding the name of the custom * type(the argument x) that has to be returned */ #define SCReturnPtr(x, type) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning pointer %p of " \ "type %s ... <<", x, type); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) #endif /* DEBUG */ SCLogInitData *SCLogAllocLogInitData(void); SCLogOPIfaceCtx *SCLogInitOPIfaceCtx(const char *, const char *, int, const char *); void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *, SCLogInitData *); void SCLogInitLogModule(SCLogInitData *); void SCLogInitLogModuleIfEnvSet(void); void SCLogDeInitLogModule(void); SCError SCLogMessage(SCLogLevel, char **, const char *, unsigned, const char *); void SCLogOutputBuffer(SCLogLevel, char *); SCLogOPBuffer *SCLogAllocLogOPBuffer(void); int SCLogDebugEnabled(void); void SCLogRegisterTests(void); void SCLogLoadConfig(int daemon); #endif /* __UTIL_DEBUG_H__ */ suricata-1.4.7/src/detect-content.c0000644000000000000000000024734612253546156014131 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Simple content match part of the detection engine. */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-content.h" #include "detect-uricontent.h" #include "detect-engine-mpm.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "detect-parse.h" #include "util-mpm.h" #include "flow.h" #include "flow-util.h" #include "flow-var.h" #include "detect-flow.h" #include "app-layer.h" #include "util-unittest.h" #include "util-print.h" #include "util-debug.h" #include "util-spm-bm.h" #include "threads.h" #include "util-unittest-helper.h" int DetectContentMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static int DetectContentSetup (DetectEngineCtx *, Signature *, char *); void DetectContentRegisterTests(void); void DetectContentRegister (void) { sigmatch_table[DETECT_CONTENT].name = "content"; sigmatch_table[DETECT_CONTENT].desc = "match on payload content"; sigmatch_table[DETECT_CONTENT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Content"; sigmatch_table[DETECT_CONTENT].Match = NULL; sigmatch_table[DETECT_CONTENT].Setup = DetectContentSetup; sigmatch_table[DETECT_CONTENT].Free = DetectContentFree; sigmatch_table[DETECT_CONTENT].RegisterTests = DetectContentRegisterTests; sigmatch_table[DETECT_CONTENT].flags |= SIGMATCH_PAYLOAD; } /* pass on the content_max_id */ uint32_t DetectContentMaxId(DetectEngineCtx *de_ctx) { return MpmPatternIdStoreGetMaxId(de_ctx->mpm_pattern_id_store); } int DetectContentDataParse(char *keyword, char *contentstr, char** pstr, uint16_t *plen, int *flags) { char *str = NULL; uint16_t len; uint16_t pos = 0; uint16_t slen = 0; slen = strlen(contentstr); if (slen == 0) { return -1; } /* skip the first spaces */ while (pos < slen && isspace((unsigned char)contentstr[pos])) pos++; if (contentstr[pos] == '!') { *flags = DETECT_CONTENT_NEGATED; pos++; } else *flags = 0; if (contentstr[pos] == '\"' && ((slen - pos) <= 1)) goto error; if (!(contentstr[pos] == '\"' && contentstr[slen - 1] == '\"')) { SCLogError(SC_ERR_INVALID_SIGNATURE, "%s keyword arguments " "should be always enclosed in double quotes. Invalid " "content keyword passed in this rule - \"%s\"", keyword, contentstr); goto error; } if ((str = SCStrdup(contentstr + pos + 1)) == NULL) goto error; str[strlen(str) - 1] = '\0'; len = strlen(str); if (len == 0) goto error; SCLogDebug("\"%s\", len %" PRIu32 "", str, len); len = strlen(str); if (len == 0) goto error; //SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len); char converted = 0; { uint16_t i, x; uint8_t bin = 0; uint8_t escape = 0; uint8_t binstr[3] = ""; uint8_t binpos = 0; uint16_t bin_count = 0; for (i = 0, x = 0; i < len; i++) { // SCLogDebug("str[%02u]: %c", i, str[i]); if (str[i] == '|') { bin_count++; if (bin) { bin = 0; } else { bin = 1; } } else if(!escape && str[i] == '\\') { escape = 1; } else { if (bin) { if (isdigit((unsigned char)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') { // SCLogDebug("part of binary: %c", str[i]); binstr[binpos] = (char)str[i]; binpos++; if (binpos == 2) { uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF; binpos = 0; str[x] = c; x++; converted = 1; } } else if (str[i] == ' ') { // SCLogDebug("space as part of binary string"); } else if (str[i] != ',') { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid hex code in " "content - %s, hex %c. Invalidating signature", str, str[i]); goto error; } } else if (escape) { if (str[i] == ':' || str[i] == ';' || str[i] == '\\' || str[i] == '\"') { str[x] = str[i]; x++; } else { //SCLogDebug("Can't escape %c", str[i]); goto error; } escape = 0; converted = 1; } else { str[x] = str[i]; x++; } } } if (bin_count % 2 != 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid hex code assembly in " "%s - %s. Invalidating signature", keyword, contentstr); goto error; } if (converted) { len = x; } } *plen = len; *pstr = str; return 0; error: if (str != NULL) SCFree(str); return -1; } /** * \brief DetectContentParse * \initonly */ DetectContentData *DetectContentParse (char *contentstr) { DetectContentData *cd = NULL; char *str = NULL; uint16_t len; int flags; int ret; ret = DetectContentDataParse("content", contentstr, &str, &len, &flags); if (ret == -1) { return NULL; } if (len > 255) { SCLogError(SC_ERR_NOT_SUPPORTED, "Currently we don't support content " "length greater than 255. Please split the pattern, if " "length > 255. The length of the content after " "normalization is \"%"PRIu16"\".", len); return NULL; } cd = SCMalloc(sizeof(DetectContentData) + len); if (unlikely(cd == NULL)) { SCFree(str); exit(EXIT_FAILURE); } memset(cd, 0, sizeof(DetectContentData) + len); if (flags == DETECT_CONTENT_NEGATED) cd->flags |= DETECT_CONTENT_NEGATED; cd->content = (uint8_t *)cd + sizeof(DetectContentData); memcpy(cd->content, str, len); cd->content_len = len; /* Prepare Boyer Moore context for searching faster */ cd->bm_ctx = BoyerMooreCtxInit(cd->content, cd->content_len); cd->depth = 0; cd->offset = 0; cd->within = 0; cd->distance = 0; SCFree(str); return cd; } DetectContentData *DetectContentParseEncloseQuotes(char *contentstr) { char str[strlen(contentstr) + 3]; // 2 for quotes, 1 for \0 str[0] = '\"'; memcpy(str + 1, contentstr, strlen(contentstr)); str[strlen(contentstr) + 1] = '\"'; str[strlen(contentstr) + 2] = '\0'; return DetectContentParse(str); } /** * \brief Helper function to print a DetectContentData */ void DetectContentPrint(DetectContentData *cd) { int i = 0; if (cd == NULL) { SCLogDebug("DetectContentData \"cd\" is NULL"); return; } char *tmpstr=SCMalloc(sizeof(char) * cd->content_len + 1); if (tmpstr != NULL) { for (i = 0; i < cd->content_len; i++) { if (isprint(cd->content[i])) tmpstr[i] = cd->content[i]; else tmpstr[i] = '.'; } tmpstr[i] = '\0'; SCLogDebug("Content: \"%s\"", tmpstr); SCFree(tmpstr); } else { SCLogDebug("Content: "); for (i = 0; i < cd->content_len; i++) SCLogDebug("%c", cd->content[i]); } SCLogDebug("Content_id: %"PRIu32, cd->id); SCLogDebug("Content_len: %"PRIu16, cd->content_len); SCLogDebug("Depth: %"PRIu16, cd->depth); SCLogDebug("Offset: %"PRIu16, cd->offset); SCLogDebug("Within: %"PRIi32, cd->within); SCLogDebug("Distance: %"PRIi32, cd->distance); SCLogDebug("flags: %u ", cd->flags); SCLogDebug("negated: %s ", cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); SCLogDebug("relative match next: %s ", cd->flags & DETECT_CONTENT_RELATIVE_NEXT ? "true" : "false"); if (cd->replace && cd->replace_len) { char *tmpstr=SCMalloc(sizeof(char) * cd->replace_len + 1); if (tmpstr != NULL) { for (i = 0; i < cd->replace_len; i++) { if (isprint(cd->replace[i])) tmpstr[i] = cd->replace[i]; else tmpstr[i] = '.'; } tmpstr[i] = '\0'; SCLogDebug("Replace: \"%s\"", tmpstr); SCFree(tmpstr); } else { SCLogDebug("Replace: "); for (i = 0; i < cd->replace_len; i++) SCLogDebug("%c", cd->replace[i]); } } SCLogDebug("-----------"); } /** * \brief Print list of DETECT_CONTENT SigMatch's allocated in a * SigMatch list, from the current sm to the end * \param sm pointer to the current SigMatch to start printing from */ void DetectContentPrintAll(SigMatch *sm) { #ifdef DEBUG if (SCLogDebugEnabled()) { int i = 0; if (sm == NULL) return; SigMatch *first_sm = sm; /* Print all of them */ for (; first_sm != NULL; first_sm = first_sm->next) { if (first_sm->type == DETECT_CONTENT) { SCLogDebug("Printing SigMatch DETECT_CONTENT %d", ++i); DetectContentPrint(first_sm->ctx); } } } #endif /* DEBUG */ } /** * \brief Function to setup a content pattern. * * \param de_ctx pointer to the current detection_engine * \param s pointer to the current Signature * \param m pointer to the last parsed SigMatch * \param contentstr pointer to the current keyword content string * \retval -1 if error * \retval 0 if all was ok */ static int DetectContentSetup (DetectEngineCtx *de_ctx, Signature *s, char *contentstr) { DetectContentData *cd = NULL; SigMatch *sm = NULL; cd = DetectContentParse(contentstr); if (cd == NULL) goto error; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_CONTENT; sm->ctx = (void *)cd; cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_PMATCH); DetectContentPrint(cd); SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) { cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HSBDMATCH); sm->type = DETECT_CONTENT; /* transfer the sm from the pmatch list to hsbdmatch list */ SigMatchTransferSigMatchAcrossLists(sm, &s->sm_lists[DETECT_SM_LIST_PMATCH], &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], &s->sm_lists[DETECT_SM_LIST_HSBDMATCH], &s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]); /* flag the signature to indicate that we scan the app layer data */ s->flags |= SIG_FLAG_APPLAYER; s->alproto = ALPROTO_HTTP; /* enable http request body callback in the http app layer parser */ AppLayerHtpEnableResponseBodyCallback(); } return 0; error: if (cd != NULL) DetectContentFree(cd); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will SCFree memory associated with DetectContentData * * \param cd pointer to DetectCotentData */ void DetectContentFree(void *ptr) { SCEnter(); DetectContentData *cd = (DetectContentData *)ptr; if (cd == NULL) SCReturn; BoyerMooreCtxDeInit(cd->bm_ctx); SCFree(cd); SCReturn; } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectCotentParseTest01 this is a test to make sure we can deal with escaped colons */ int DetectContentParseTest01 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\:def\""; char *teststringparsed = "abc:def"; cd = DetectContentParse(teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); PrintRawUriFp(stdout,cd->content,cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(cd); } } else { SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } return result; } /** * \test DetectCotentParseTest02 this is a test to make sure we can deal with escaped semi-colons */ int DetectContentParseTest02 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\;def\""; char *teststringparsed = "abc;def"; cd = DetectContentParse(teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); PrintRawUriFp(stdout,cd->content,cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(cd); } } else { SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } return result; } /** * \test DetectCotentParseTest03 this is a test to make sure we can deal with escaped double-quotes */ int DetectContentParseTest03 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\\"def\""; char *teststringparsed = "abc\"def"; cd = DetectContentParse(teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); PrintRawUriFp(stdout,cd->content,cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(cd); } } else { SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } return result; } /** * \test DetectCotentParseTest04 this is a test to make sure we can deal with escaped backslashes */ int DetectContentParseTest04 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\\\def\""; char *teststringparsed = "abc\\def"; cd = DetectContentParse(teststring); if (cd != NULL) { uint16_t len = (cd->content_len > strlen(teststringparsed)); if (memcmp(cd->content, teststringparsed, len) != 0) { SCLogDebug("expected %s got ", teststringparsed); PrintRawUriFp(stdout,cd->content,cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(cd); } } else { SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } return result; } /** * \test DetectCotentParseTest05 test illegal escape */ int DetectContentParseTest05 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\def\""; cd = DetectContentParse(teststring); if (cd != NULL) { SCLogDebug("expected NULL got "); PrintRawUriFp(stdout,cd->content,cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(cd); } return result; } /** * \test DetectCotentParseTest06 test a binary content */ int DetectContentParseTest06 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"a|42|c|44|e|46|\""; char *teststringparsed = "abcdef"; cd = DetectContentParse(teststring); if (cd != NULL) { uint16_t len = (cd->content_len > strlen(teststringparsed)); if (memcmp(cd->content, teststringparsed, len) != 0) { SCLogDebug("expected %s got ", teststringparsed); PrintRawUriFp(stdout,cd->content,cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(cd); } } else { SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } return result; } /** * \test DetectCotentParseTest07 test an empty content */ int DetectContentParseTest07 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"\""; cd = DetectContentParse(teststring); if (cd != NULL) { SCLogDebug("expected NULL got %p: ", cd); result = 0; DetectContentFree(cd); } return result; } /** * \test DetectCotentParseTest08 test an empty content */ int DetectContentParseTest08 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"\""; cd = DetectContentParse(teststring); if (cd != NULL) { SCLogDebug("expected NULL got %p: ", cd); result = 0; DetectContentFree(cd); } return result; } /** * \test Test packet Matches * \param raw_eth_pkt pointer to the ethernet packet * \param pktsize size of the packet * \param sig pointer to the signature to test * \param sid sid number of the signature * \retval return 1 if match * \retval return 0 if not */ int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, uint32_t sid) { int result = 0; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, raw_eth_pkt, pktsize, NULL); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig); if (de_ctx->sig_list == NULL) { goto end; } de_ctx->sig_list->next = NULL; if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->type == DETECT_CONTENT) { DetectContentData *co = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (co->flags & DETECT_CONTENT_RELATIVE_NEXT) { printf("relative next flag set on final match which is content: "); goto end; } } SCLogDebug("---DetectContentLongPatternMatchTest---"); DetectContentPrintAll(de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, sid) != 1) { goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } FlowShutdown(); SCFree(p); return result; } /** * \brief Wrapper for DetectContentLongPatternMatchTest */ int DetectContentLongPatternMatchTestWrp(char *sig, uint32_t sid) { /** Real packet with the following tcp data: * "Hi, this is a big test to check content matches of splitted" * "patterns between multiple chunks!" * (without quotes! :) ) */ uint8_t raw_eth_pkt[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00, 0x00,0x85,0x00,0x01,0x00,0x00,0x40,0x06, 0x7c,0x70,0x7f,0x00,0x00,0x01,0x7f,0x00, 0x00,0x01,0x00,0x14,0x00,0x50,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x02, 0x20,0x00,0xc9,0xad,0x00,0x00,0x48,0x69, 0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69, 0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20, 0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20, 0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f, 0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61, 0x74,0x63,0x68,0x65,0x73,0x20,0x6f,0x66, 0x20,0x73,0x70,0x6c,0x69,0x74,0x74,0x65, 0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72, 0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65, 0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69, 0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e, 0x6b,0x73,0x21 }; /* end raw_eth_pkt */ return DetectContentLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), sig, sid); } /** * \test Check if we match a normal pattern (not splitted) */ int DetectContentLongPatternMatchTest01() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"Hi, this is a big test\"; sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check if we match a splitted pattern */ int DetectContentLongPatternMatchTest02() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"Hi, this is a big test to check content matches of" " splitted patterns between multiple chunks!\"; sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check that we don't match the signature if one of the splitted * chunks doesn't match the packet */ int DetectContentLongPatternMatchTest03() { /** The last chunk of the content should not match */ char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"Hi, this is a big test to check content matches of" " splitted patterns between multiple splitted chunks!\"; sid:1;)"; return (DetectContentLongPatternMatchTestWrp(sig, 1) == 0) ? 1: 0; } /** * \test Check if we match multiple content (not splitted) */ int DetectContentLongPatternMatchTest04() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is\"; depth:15 ;content:\"a big test\"; " " within:15; content:\"to check content matches of\"; " " within:30; content:\"splitted patterns\"; distance:1; " " within:30; " " sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check that we match packets with multiple chunks and not chunks * Here we should specify only contents that fit in 32 bytes * Each of them with their modifier values */ int DetectContentLongPatternMatchTest05() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big\"; depth:17; " " isdataat:30, relative; " " content:\"test\"; within: 5; distance:1; " " isdataat:15, relative; " " content:\"of splitted\"; within:37; distance:15; " " isdataat:20,relative; " " content:\"patterns\"; within:9; distance:1; " " isdataat:10, relative; " " sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check that we match packets with multiple chunks and not chunks * Here we should specify contents that fit and contents that must be splitted * Each of them with their modifier values */ int DetectContentLongPatternMatchTest06() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big test to check cont\"; depth:36;" " content:\"ent matches\"; within:11; distance:0; " " content:\"of splitted patterns between multiple\"; " " within:38; distance:1; " " content:\"chunks!\"; within: 8; distance:1; " " sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ int DetectContentLongPatternMatchTest07() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"chunks!\"; " " content:\"content matches\"; offset:32; depth:47; " " content:\"of splitted patterns between multiple\"; " " content:\"Hi, this is a big\"; offset:0; depth:17; " " sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ int DetectContentLongPatternMatchTest08() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"ent matches\"; " " content:\"of splitted patterns between multiple\"; " " within:38; distance:1; " " content:\"chunks!\"; within: 8; distance:1; " " content:\"Hi, this is a big test to check cont\"; depth:36;" " sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ int DetectContentLongPatternMatchTest09() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"ent matches\"; " " content:\"of splitted patterns between multiple\"; " " offset:47; depth:85; " " content:\"chunks!\"; within: 8; distance:1; " " content:\"Hi, this is a big test to chec\"; depth:36;" " content:\"k cont\"; distance:0; within:6;" " sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check if we match two consecutive simple contents */ int DetectContentLongPatternMatchTest10() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big test to check \"; " " content:\"con\"; " " sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } /** * \test Check if we match two contents of length 1 */ int DetectContentLongPatternMatchTest11() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"H\"; " " content:\"i\"; " " sid:1;)"; return DetectContentLongPatternMatchTestWrp(sig, 1); } int DetectContentParseTest09(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "!\"boo\""; cd = DetectContentParse(teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } return result; } int DetectContentParseTest10(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "!\"boo\""; cd = DetectContentParse(teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } return result; } int DetectContentParseNegTest11(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "\"boo\""; cd = DetectContentParse(teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } return result; } int DetectContentParseNegTest12(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "\"boo\""; cd = DetectContentParse(teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } return result; } int DetectContentParseNegTest13(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "!\"boo\""; cd = DetectContentParse(teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } return result; } int DetectContentParseNegTest14(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = " \"!boo\""; cd = DetectContentParse(teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } return result; } int DetectContentParseNegTest15(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = " !\"boo\""; cd = DetectContentParse(teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } return result; } int DetectContentParseNegTest16(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = " \"boo\""; cd = DetectContentParse(teststring); if (cd != NULL) { result = (cd->content_len == 3 && memcmp(cd->content,"boo",3) == 0); DetectContentFree(cd); } return result; } /** * \test Test cases where if within specified is < content lenggth we invalidate * the sig. */ int DetectContentParseTest17(void) { int result = 0; char *sigstr = "alert tcp any any -> any any (msg:\"Dummy\"; " "content:\"one\"; content:\"two\"; within:2; sid:1;)"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->sig_list = SigInit(de_ctx, sigstr); if (de_ctx->sig_list != NULL) goto end; result = 1; end: SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DetectContentParseTest18(void) { Signature *s = SigAlloc(); int result = 1; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { result = 0; goto end; } s->alproto = ALPROTO_DCERPC; result &= (DetectContentSetup(de_ctx, s, "\"one\"") == 0); result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); s = SigAlloc(); if (s == NULL) return 0; result &= (DetectContentSetup(de_ctx, s, "\"one\"") == 0); result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); end: SigFree(s); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DetectContentParseTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; Signature *s = NULL; DetectContentData *data = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing dce iface, stub_data with content\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; sid:1;)"); if (de_ctx->sig_list == NULL) { printf ("failed dce iface, stub_data with content "); result = 0; goto end; } s = de_ctx->sig_list; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing dce iface, stub_data with contents & distance, within\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; content:\"two\"; within:10; sid:1;)"); if (s->next == NULL) { printf("failed dce iface, stub_data with content & distance, within"); result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } result &= (data->within == 10); /* s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing dce iface, stub_data with contents & offset, depth\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; offset:5; depth:9; " "content:\"two\"; within:10; sid:1;)"); if (s->next == NULL) { printf ("failed dce iface, stub_data with contents & offset, depth"); result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } result &= (data->offset == 5 && data->depth == 9); data = (DetectContentData *)s->sm_lists[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing dce iface, stub with contents, distance\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "content:\"two\"; distance:2; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } result &= (data->distance == 2); */ s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing dce iface, stub with contents, distance, within\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; distance:0; " "content:\"two\"; within:10; distance:2; sid:1;)"); if (s->next == NULL) { result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || !(data->flags & DETECT_CONTENT_DISTANCE) || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } result &= (data->within == 10 && data->distance == 2); /* s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing dce iface, stub_data with content, offset\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; offset:10; sid:1;)"); if (s->next == NULL) { printf ("Failed dce iface, stub_data with content, offset "); result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } result &= (data->offset == 10); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing dce iface, stub_data with content, depth\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; depth:10; sid:1;)"); if (s->next == NULL) { printf ("failed dce iface, stub_data with content, depth"); result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } result &= (data->depth == 10); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing dce iface, stub_data with content, offset, depth\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "content:\"one\"; offset:10; depth:3; sid:1;)"); if (s->next == NULL) { printf("failed dce iface, stub_data with content, offset, depth"); result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { result = 0; goto end; } result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || data->flags & DETECT_CONTENT_DISTANCE || data->flags & DETECT_CONTENT_FAST_PATTERN || data->flags & DETECT_CONTENT_NEGATED || result == 0) { result = 0; goto end; } result &= (data->offset == 10 && data->depth == 13); */ s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing content\"; " "content:\"one\"; sid:1;)"); if (s->next == NULL) { printf ("failed testing content"); result = 0; goto end; } s = s->next; if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { result = 0; goto end; } result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Test content for dce sig. */ int DetectContentParseTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"boo; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:boo\"; sid:238012;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest24(void) { DetectEngineCtx *de_ctx = NULL; DetectContentData *cd = 0; Signature *s = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content: !\"boo\"; sid:238012;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL: "); result = 0; goto end; } if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL || s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx == NULL) { printf("de_ctx->pmatch_tail == NULL || de_ctx->pmatch_tail->ctx == NULL: "); result = 0; goto end; } cd = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; result = (strncmp("boo", (char *)cd->content, cd->content_len) == 0); end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"|\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"|af\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"af|\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"|af|\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"aast|\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"aast|af\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"aast|af|\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"|af|asdf\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"|af|af|\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"|af|af|af\"; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test */ int DetectContentParseTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"test\"; content:\"|af|af|af|\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test: file_data */ static int DetectContentParseTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; file_data; content:\"abc\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("content still in PMATCH list: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("content not in HSBDMATCH list: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test: file_data */ static int DetectContentParseTest37(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; file_data; content:\"abc\"; content:\"def\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("content still in PMATCH list: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("content not in HSBDMATCH list: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test: file_data */ static int DetectContentParseTest38(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; file_data; content:\"abc\"; content:\"def\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("content still in PMATCH list: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("content not in HSBDMATCH list: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } static int SigTestPositiveTestContent(char *rule, uint8_t *buf) { uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, rule); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) != 1) { goto end; } result = 1; end: if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); } UTHFreePackets(&p, 1); return result; } /** * \test Parsing test: file_data, within relative to file_data */ static int DetectContentParseTest39(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; file_data; content:\"abc\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("content still in PMATCH list: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("content not in HSBDMATCH list: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } /** * \test Parsing test: file_data, distance relative to file_data */ static int DetectContentParseTest40(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"test\"; file_data; content:\"abc\"; distance:3; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { printf("content still in PMATCH list: "); goto end; } if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { printf("content not in HSBDMATCH list: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); return result; } int DetectContentParseTest41(void) { int result = 1; DetectContentData *cd = NULL; int patlen = 257; char *teststring = SCMalloc(sizeof(char) * (patlen + 1)); if (teststring == NULL) return 0; int idx = 0; teststring[idx++] = '\"'; for (int i = 0; i < (patlen - 2); idx++, i++) { teststring[idx] = 'a'; } teststring[idx++] = '\"'; teststring[idx++] = '\0'; cd = DetectContentParse(teststring); if (cd == NULL) { SCLogDebug("expected not NULL"); result = 0; } SCFree(teststring); DetectContentFree(cd); return result; } int DetectContentParseTest42(void) { int result = 1; DetectContentData *cd = NULL; int patlen = 258; char *teststring = SCMalloc(sizeof(char) * (patlen + 1)); if (teststring == NULL) return 0; int idx = 0; teststring[idx++] = '\"'; for (int i = 0; i < (patlen - 2); idx++, i++) { teststring[idx] = 'a'; } teststring[idx++] = '\"'; teststring[idx++] = '\0'; cd = DetectContentParse(teststring); if (cd != NULL) { SCLogDebug("expected NULL got %p: ", cd); result = 0; } SCFree(teststring); DetectContentFree(cd); return result; } int DetectContentParseTest43(void) { int result = 1; DetectContentData *cd = NULL; int patlen = 260; char *teststring = SCMalloc(sizeof(char) * (patlen + 1)); if (teststring == NULL) return 0; int idx = 0; teststring[idx++] = '\"'; teststring[idx++] = '|'; teststring[idx++] = '4'; teststring[idx++] = '6'; teststring[idx++] = '|'; for (int i = 0; i < (patlen - 6); idx++, i++) { teststring[idx] = 'a'; } teststring[idx++] = '\"'; teststring[idx++] = '\0'; cd = DetectContentParse(teststring); if (cd == NULL) { SCLogDebug("expected not NULL"); result = 0; } SCFree(teststring); DetectContentFree(cd); return result; } int DetectContentParseTest44(void) { int result = 1; DetectContentData *cd = NULL; int patlen = 261; char *teststring = SCMalloc(sizeof(char) * (patlen + 1)); if (teststring == NULL) return 0; int idx = 0; teststring[idx++] = '\"'; teststring[idx++] = '|'; teststring[idx++] = '4'; teststring[idx++] = '6'; teststring[idx++] = '|'; for (int i = 0; i < (patlen - 6); idx++, i++) { teststring[idx] = 'a'; } teststring[idx++] = '\"'; teststring[idx++] = '\0'; cd = DetectContentParse(teststring); if (cd != NULL) { SCLogDebug("expected NULL got %p: ", cd); result = 0; } SCFree(teststring); DetectContentFree(cd); return result; } static int SigTestNegativeTestContent(char *rule, uint8_t *buf) { uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, rule); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) != 0) { goto end; } result = 1; end: if (det_ctx != NULL) { DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } UTHFreePackets(&p, 1); return result; } /** * \test A positive test that checks that the content string doesn't contain * the negated content */ static int SigTest41TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!\"GES\"; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); } /** * \test A positive test that checks that the content string doesn't contain * the negated content within the specified depth */ static int SigTest42TestNegatedContent(void) { // 01 5 10 15 20 24 return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!\"twentythree\"; depth:22; offset:35; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A negative test that checks that the content string doesn't contain * the negated content within the specified depth, and also after the * specified offset. Since the content is there, the match fails. * * Match is at offset:23, depth:34 */ static int SigTest43TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:!\"twentythree\"; depth:34; offset:23; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A negative test that checks that the content string doesn't contain * the negated content after the specified offset and within the specified * depth. */ static int SigTest44TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!\"twentythree\"; offset:40; depth:35; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A positive test that uses a combination of content string with negated * content string */ static int SigTest45TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; depth:5; content:!\"twentythree\"; depth:23; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A negative test that uses a combination of content string with negated * content string, with we receiving a failure for 'onee' itself. */ static int SigTest46TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"onee\"; content:!\"twentythree\"; depth:23; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A negative test that uses a combination of content string with negated * content string, with we receiving a failure of first content's offset * condition */ static int SigTest47TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; offset:5; content:!\"twentythree\"; depth:23; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A positive test that checks that we don't have a negated content within * the specified length from the previous content match. */ static int SigTest48TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET\"; content:!\"GES\"; within:26; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); } /** * \test A negative test that checks the combined use of content and negated * content with the use of within */ static int SigTest49TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET\"; content:!\"Host\"; within:26; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); } /** * \test A positive test that checks the combined use of content and negated * content with the use of distance */ static int SigTest50TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET\"; content:!\"GES\"; distance:25; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); } /** * \test A negative test that checks the combined use of content and negated * content with the use of distance * * First GET at offset 0 * First Host at offset 21 */ static int SigTest51TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"GET\"; content:!\"Host\"; distance:17; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\nHost: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); } /** * \test A negative test that checks the combined use of content and negated * content, with the content not being present */ static int SigTest52TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GES\"; content:!\"BOO\"; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); } /** * \test A negative test that checks the combined use of content and negated * content, in the presence of within */ static int SigTest53TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; content:!\"fourty\"; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A positive test that checks the combined use of content and negated * content, in the presence of within */ static int SigTest54TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; content:!\"fourty\"; within:20; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A negative test that checks the use of negated content along with * the presence of depth */ static int SigTest55TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!\"one\"; depth:5; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A positive test that checks the combined use of 2 contents in the * presence of within */ static int SigTest56TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; content:\"fourty\"; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A negative test that checks the combined use of content and negated * content, in the presence of within */ static int SigTest57TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; content:!\"fourty\"; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A positive test that checks the combined use of content and negated * content, in the presence of distance */ static int SigTest58TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; content:!\"fourty\"; distance:57; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** * \test A negative test that checks the combined use of content and negated * content, in the presence of distance */ static int SigTest59TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; content:!\"fourty\"; distance:30; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest60TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!\"one\"; content:\"fourty\"; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest61TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"one\"; depth:10; content:!\"fourty\"; within:30; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** \test Test negation in combination with within and depth * * Match of "one" at offset:0, depth:3 * Match of "fourty" at offset:46, depth:52 * * This signature should not match for the test to pass. */ static int SigTest62TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"one\"; depth:10; content:!\"fourty\"; within:49; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest63TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; depth:10; content:!\"fourty\"; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest64TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"one\"; depth:10; content:!\"fourty\"; within:30; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** \test Test negation in combination with within and depth * * Match of "one" at offset:0, depth:3 * Match of "fourty" at offset:46, depth:52 * * This signature should not match for the test to pass. */ static int SigTest65TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"one\"; depth:10; content:!\"fourty\"; distance:0; within:49; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest66TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"one\"; depth:10; content:!\"fourty\"; within:30; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest67TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"one\"; depth:10; content:!\"four\"; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest68TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (content:\"one\"; depth:10; content:\"nine\"; offset:8; content:!\"fourty\"; within:28; content:\"fiftysix\"; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest69TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"one\"; depth:10; content:\"nine\"; offset:8; content:!\"fourty\"; within:48; content:\"fiftysix\"; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest70TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"one\"; content:!\"fourty\"; within:52; distance:45 sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } /** \test within and distance */ static int SigTest71TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"one\"; content:!\"fourty\"; within:40; distance:43; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest72TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (content:\"one\"; content:!\"fourty\"; within:49; distance:43; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest73TestNegatedContent(void) { return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"one\"; depth:5; content:!\"twentythree\"; depth:35; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix"); } static int SigTest74TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"USER\"; content:!\"PASS\"; sid:1;)", (uint8_t *)"USER apple"); } static int SigTest75TestNegatedContent(void) { return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"USER\"; content:\"!PASS\"; sid:1;)", (uint8_t *)"USER !PASS"); } static int SigTest76TestBug134(void) { uint8_t *buf = (uint8_t *)"test detect ${IFS} in traffic"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; Flow f; memset(&f, 0, sizeof(Flow)); FLOW_INITIALIZE(&f); p->dp = 515; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flowflags |= FLOW_PKT_TOSERVER; p->flow = &f; p->flags |= PKT_HAS_FLOW; char sig[] = "alert tcp any any -> any 515 " "(msg:\"detect IFS\"; flow:to_server,established; content:\"${IFS}\";" " depth:50; offset:0; sid:900091; rev:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); FLOW_DESTROY(&f); return result; } static int SigTest77TestBug139(void) { uint8_t buf[] = { 0x12, 0x23, 0x34, 0x35, 0x52, 0x52, 0x24, 0x42, 0x22, 0x24, 0x52, 0x24, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x34 }; uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_UDP); int result = 0; p->dp = 53; char sig[] = "alert udp any any -> any 53 (msg:\"dns testing\";" " content:\"|00 00|\"; depth:5; offset:13; sid:9436601;" " rev:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { result = 0; goto end; } result = 1; end: if (p != NULL) UTHFreePacket(p); return result; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectContent */ void DetectContentRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01, 1); UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02, 1); UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03, 1); UtRegisterTest("DetectContentParseTest04", DetectContentParseTest04, 1); UtRegisterTest("DetectContentParseTest05", DetectContentParseTest05, 1); UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06, 1); UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07, 1); UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08, 1); UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09, 1); UtRegisterTest("DetectContentParseTest10", DetectContentParseTest10, 1); UtRegisterTest("DetectContentParseNegTest11", DetectContentParseNegTest11, 1); UtRegisterTest("DetectContentParseNegTest12", DetectContentParseNegTest12, 1); UtRegisterTest("DetectContentParseNegTest13", DetectContentParseNegTest13, 1); UtRegisterTest("DetectContentParseNegTest14", DetectContentParseNegTest14, 1); UtRegisterTest("DetectContentParseNegTest15", DetectContentParseNegTest15, 1); UtRegisterTest("DetectContentParseNegTest16", DetectContentParseNegTest16, 1); UtRegisterTest("DetectContentParseTest17", DetectContentParseTest17, 1); UtRegisterTest("DetectContentParseTest18", DetectContentParseTest18, 1); UtRegisterTest("DetectContentParseTest19", DetectContentParseTest19, 1); UtRegisterTest("DetectContentParseTest20", DetectContentParseTest20, 1); UtRegisterTest("DetectContentParseTest21", DetectContentParseTest21, 1); UtRegisterTest("DetectContentParseTest22", DetectContentParseTest22, 1); UtRegisterTest("DetectContentParseTest23", DetectContentParseTest23, 1); UtRegisterTest("DetectContentParseTest24", DetectContentParseTest24, 1); UtRegisterTest("DetectContentParseTest25", DetectContentParseTest25, 1); UtRegisterTest("DetectContentParseTest26", DetectContentParseTest26, 1); UtRegisterTest("DetectContentParseTest27", DetectContentParseTest27, 1); UtRegisterTest("DetectContentParseTest28", DetectContentParseTest28, 1); UtRegisterTest("DetectContentParseTest29", DetectContentParseTest29, 1); UtRegisterTest("DetectContentParseTest30", DetectContentParseTest30, 1); UtRegisterTest("DetectContentParseTest31", DetectContentParseTest31, 1); UtRegisterTest("DetectContentParseTest32", DetectContentParseTest32, 1); UtRegisterTest("DetectContentParseTest33", DetectContentParseTest33, 1); UtRegisterTest("DetectContentParseTest34", DetectContentParseTest34, 1); UtRegisterTest("DetectContentParseTest35", DetectContentParseTest35, 1); UtRegisterTest("DetectContentParseTest36", DetectContentParseTest36, 1); UtRegisterTest("DetectContentParseTest37", DetectContentParseTest37, 1); UtRegisterTest("DetectContentParseTest38", DetectContentParseTest38, 1); UtRegisterTest("DetectContentParseTest39", DetectContentParseTest39, 1); UtRegisterTest("DetectContentParseTest40", DetectContentParseTest40, 1); UtRegisterTest("DetectContentParseTest41", DetectContentParseTest41, 1); UtRegisterTest("DetectContentParseTest42", DetectContentParseTest42, 1); UtRegisterTest("DetectContentParseTest43", DetectContentParseTest43, 1); UtRegisterTest("DetectContentParseTest44", DetectContentParseTest44, 1); /* The reals */ UtRegisterTest("DetectContentLongPatternMatchTest01", DetectContentLongPatternMatchTest01, 1); UtRegisterTest("DetectContentLongPatternMatchTest02", DetectContentLongPatternMatchTest02, 1); UtRegisterTest("DetectContentLongPatternMatchTest03", DetectContentLongPatternMatchTest03, 1); UtRegisterTest("DetectContentLongPatternMatchTest04", DetectContentLongPatternMatchTest04, 1); UtRegisterTest("DetectContentLongPatternMatchTest05", DetectContentLongPatternMatchTest05, 1); UtRegisterTest("DetectContentLongPatternMatchTest06", DetectContentLongPatternMatchTest06, 1); UtRegisterTest("DetectContentLongPatternMatchTest07", DetectContentLongPatternMatchTest07, 1); UtRegisterTest("DetectContentLongPatternMatchTest08", DetectContentLongPatternMatchTest08, 1); UtRegisterTest("DetectContentLongPatternMatchTest09", DetectContentLongPatternMatchTest09, 1); UtRegisterTest("DetectContentLongPatternMatchTest10", DetectContentLongPatternMatchTest10, 1); UtRegisterTest("DetectContentLongPatternMatchTest11", DetectContentLongPatternMatchTest11, 1); /* Negated content tests */ UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent, 1); UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent, 1); UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent, 1); UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent, 1); UtRegisterTest("SigTest45TestNegatedContent", SigTest45TestNegatedContent, 1); UtRegisterTest("SigTest46TestNegatedContent", SigTest46TestNegatedContent, 1); UtRegisterTest("SigTest47TestNegatedContent", SigTest47TestNegatedContent, 1); UtRegisterTest("SigTest48TestNegatedContent", SigTest48TestNegatedContent, 1); UtRegisterTest("SigTest49TestNegatedContent", SigTest49TestNegatedContent, 1); UtRegisterTest("SigTest50TestNegatedContent", SigTest50TestNegatedContent, 1); UtRegisterTest("SigTest51TestNegatedContent", SigTest51TestNegatedContent, 1); UtRegisterTest("SigTest52TestNegatedContent", SigTest52TestNegatedContent, 1); UtRegisterTest("SigTest53TestNegatedContent", SigTest53TestNegatedContent, 1); UtRegisterTest("SigTest54TestNegatedContent", SigTest54TestNegatedContent, 1); UtRegisterTest("SigTest55TestNegatedContent", SigTest55TestNegatedContent, 1); UtRegisterTest("SigTest56TestNegatedContent", SigTest56TestNegatedContent, 1); UtRegisterTest("SigTest57TestNegatedContent", SigTest57TestNegatedContent, 1); UtRegisterTest("SigTest58TestNegatedContent", SigTest58TestNegatedContent, 1); UtRegisterTest("SigTest59TestNegatedContent", SigTest59TestNegatedContent, 1); UtRegisterTest("SigTest60TestNegatedContent", SigTest60TestNegatedContent, 1); UtRegisterTest("SigTest61TestNegatedContent", SigTest61TestNegatedContent, 1); UtRegisterTest("SigTest62TestNegatedContent", SigTest62TestNegatedContent, 1); UtRegisterTest("SigTest63TestNegatedContent", SigTest63TestNegatedContent, 1); UtRegisterTest("SigTest64TestNegatedContent", SigTest64TestNegatedContent, 1); UtRegisterTest("SigTest65TestNegatedContent", SigTest65TestNegatedContent, 1); UtRegisterTest("SigTest66TestNegatedContent", SigTest66TestNegatedContent, 1); UtRegisterTest("SigTest67TestNegatedContent", SigTest67TestNegatedContent, 1); UtRegisterTest("SigTest68TestNegatedContent", SigTest68TestNegatedContent, 1); UtRegisterTest("SigTest69TestNegatedContent", SigTest69TestNegatedContent, 1); UtRegisterTest("SigTest70TestNegatedContent", SigTest70TestNegatedContent, 1); UtRegisterTest("SigTest71TestNegatedContent", SigTest71TestNegatedContent, 1); UtRegisterTest("SigTest72TestNegatedContent", SigTest72TestNegatedContent, 1); UtRegisterTest("SigTest73TestNegatedContent", SigTest73TestNegatedContent, 1); UtRegisterTest("SigTest74TestNegatedContent", SigTest74TestNegatedContent, 1); UtRegisterTest("SigTest75TestNegatedContent", SigTest75TestNegatedContent, 1); UtRegisterTest("SigTest76TestBug134", SigTest76TestBug134, 1); UtRegisterTest("SigTest77TestBug139", SigTest77TestBug139, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-ipopts.h0000644000000000000000000000357012253546156013767 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Breno Silva */ #ifndef __DETECT_IPOPTS_H__ #define __DETECT_IPOPTS_H__ #include "decode-events.h" #include "decode-ipv4.h" /** * \struct DetectIpOptsData_ * DetectIpOptsData_ is used to store ipopts: input value */ /** * \typedef DetectIpOptsData * A typedef for DetectIpOptsData_ */ typedef struct DetectIpOptsData_ { uint8_t ipopt; /**< Ip option */ } DetectIpOptsData; /** * Registration function for ipopts: keyword */ void DetectIpOptsRegister (void); #ifdef DETECT_EVENTS /** * Used to check ipopts:any */ #define IPV4_OPT_ANY 0xff /** * \struct DetectIpOptss_ * DetectIpOptss_ is used to store supported iptops values */ struct DetectIpOptss_ { char *ipopt_name; /**< Ip option name */ uint8_t code; /**< Ip option value */ } DIpOpts[] = { { "rr", IPV4_OPT_RR, }, { "lsrr", IPV4_OPT_LSRR, }, { "eol", IPV4_OPT_EOL, }, { "nop", IPV4_OPT_NOP, }, { "ts", IPV4_OPT_TS, }, { "sec", IPV4_OPT_SEC, }, { "ssrr", IPV4_OPT_SSRR, }, { "satid", IPV4_OPT_SID, }, { "any", IPV4_OPT_ANY, }, { NULL, 0 }, }; #endif /* DETECT_EVENTS */ #endif /*__DETECT_IPOPTS_H__ */ suricata-1.4.7/src/detect-engine-analyzer.c0000644000000000000000000010570512253546156015537 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eileen Donlon * * Rule analyzer for the detection engine */ #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine-analyzer.h" #include "detect-engine-mpm.h" #include "conf.h" #include "detect-content.h" #include "detect-flow.h" #include "detect-flags.h" #include "util-print.h" static int rule_warnings_only = 0; static FILE *rule_engine_analysis_FD = NULL; static FILE *fp_engine_analysis_FD = NULL; static pcre *percent_re = NULL; static pcre_extra *percent_re_study = NULL; static char log_path[PATH_MAX]; void EngineAnalysisFP(Signature *s, char *line) { int fast_pattern_set = 0; int fast_pattern_only_set = 0; int fast_pattern_chop_set = 0; DetectContentData *fp_cd = NULL; SigMatch *mpm_sm = s->mpm_sm; if (mpm_sm != NULL) { fp_cd = (DetectContentData *)mpm_sm->ctx; if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { fast_pattern_set = 1; if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { fast_pattern_only_set = 1; } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { fast_pattern_chop_set = 1; } } } fprintf(fp_engine_analysis_FD, "== Sid: %u ==\n", s->id); fprintf(fp_engine_analysis_FD, "%s\n", line); fprintf(fp_engine_analysis_FD, " Fast Pattern analysis:\n"); if (fp_cd == NULL) { fprintf(fp_engine_analysis_FD, " No content present\n"); fprintf(fp_engine_analysis_FD, "\n"); return; } fprintf(fp_engine_analysis_FD, " Fast pattern matcher: "); int list_type = SigMatchListSMBelongsTo(s, mpm_sm); if (list_type == DETECT_SM_LIST_PMATCH) fprintf(fp_engine_analysis_FD, "content\n"); else if (list_type == DETECT_SM_LIST_UMATCH) fprintf(fp_engine_analysis_FD, "http uri content\n"); else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(fp_engine_analysis_FD, "http raw uri content\n"); else if (list_type == DETECT_SM_LIST_HHDMATCH) fprintf(fp_engine_analysis_FD, "http header content\n"); else if (list_type == DETECT_SM_LIST_HRHDMATCH) fprintf(fp_engine_analysis_FD, "http raw header content\n"); else if (list_type == DETECT_SM_LIST_HMDMATCH) fprintf(fp_engine_analysis_FD, "http method content\n"); else if (list_type == DETECT_SM_LIST_HCDMATCH) fprintf(fp_engine_analysis_FD, "http cookie content\n"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(fp_engine_analysis_FD, "http client body content\n"); else if (list_type == DETECT_SM_LIST_HSBDMATCH) fprintf(fp_engine_analysis_FD, "http server body content\n"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) fprintf(fp_engine_analysis_FD, "http stat code content\n"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) fprintf(fp_engine_analysis_FD, "http stat msg content\n"); else if (list_type == DETECT_SM_LIST_HUADMATCH) fprintf(fp_engine_analysis_FD, "http user agent content\n"); fprintf(fp_engine_analysis_FD, " Fast pattern set: %s\n", fast_pattern_set ? "yes" : "no"); fprintf(fp_engine_analysis_FD, " Fast pattern only set: %s\n", fast_pattern_only_set ? "yes" : "no"); fprintf(fp_engine_analysis_FD, " Fast pattern chop set: %s\n", fast_pattern_chop_set ? "yes" : "no"); if (fast_pattern_chop_set) { fprintf(fp_engine_analysis_FD, " Fast pattern offset, length: %u, %u\n", fp_cd->fp_chop_offset, fp_cd->fp_chop_len); } fprintf(fp_engine_analysis_FD, " Content negated: %s\n", (fp_cd->flags & DETECT_CONTENT_NEGATED) ? "yes" : "no"); uint16_t patlen = fp_cd->content_len; uint8_t *pat = SCMalloc(fp_cd->content_len + 1); if (unlikely(pat == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memcpy(pat, fp_cd->content, fp_cd->content_len); pat[fp_cd->content_len] = '\0'; fprintf(fp_engine_analysis_FD, " Original content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); if (fast_pattern_chop_set) { SCFree(pat); patlen = fp_cd->fp_chop_len; pat = SCMalloc(fp_cd->fp_chop_len + 1); if (unlikely(pat == NULL)) { exit(EXIT_FAILURE); } memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len); pat[fp_cd->fp_chop_len] = '\0'; fprintf(fp_engine_analysis_FD, " Final content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); } else { fprintf(fp_engine_analysis_FD, " Final content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); } SCFree(pat); fprintf(fp_engine_analysis_FD, "\n"); return; } /** * \brief Sets up the fast pattern analyzer according to the config. * * \retval 1 If rule analyzer successfully enabled. * \retval 0 If not enabled. */ int SetupFPAnalyzer(void) { int fp_engine_analysis_set = 0; if ((ConfGetBool("engine-analysis.rules-fast-pattern", &fp_engine_analysis_set)) == 0) { return 0; } if (fp_engine_analysis_set == 0) return 0; char *log_dir; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, "rules_fast_pattern.txt"); fp_engine_analysis_FD = fopen(log_path, "w"); if (fp_engine_analysis_FD == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path, strerror(errno)); return 0; } SCLogInfo("Engine-Analysis for fast_pattern printed to file - %s", log_path); struct timeval tval; struct tm *tms; gettimeofday(&tval, NULL); struct tm local_tm; tms = (struct tm *)SCLocalTime(tval.tv_sec, &local_tm); fprintf(fp_engine_analysis_FD, "----------------------------------------------" "---------------------\n"); fprintf(fp_engine_analysis_FD, "Date: %" PRId32 "/%" PRId32 "/%04d -- " "%02d:%02d:%02d\n", tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec); fprintf(fp_engine_analysis_FD, "----------------------------------------------" "---------------------\n"); return 1; } /** * \brief Sets up the rule analyzer according to the config * \retval 1 if rule analyzer successfully enabled * \retval 0 if not enabled */ int SetupRuleAnalyzer(void) { ConfNode *conf = ConfGetNode("engine-analysis"); int enabled = 0; if (conf != NULL) { const char *value = ConfNodeLookupChildValue(conf, "rules"); if (value && ConfValIsTrue(value)) { enabled = 1; } else if (value && strcasecmp(value, "warnings-only") == 0) { enabled = 1; rule_warnings_only = 1; } if (enabled) { char *log_dir; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, "rules_analysis.txt"); rule_engine_analysis_FD = fopen(log_path, "w"); if (rule_engine_analysis_FD == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path, strerror(errno)); return 0; } SCLogInfo("Engine-Analysis for rules printed to file - %s", log_path); struct timeval tval; struct tm *tms; gettimeofday(&tval, NULL); struct tm local_tm; tms = (struct tm *)localtime_r(&tval.tv_sec, &local_tm); fprintf(rule_engine_analysis_FD, "----------------------------------------------" "---------------------\n"); fprintf(rule_engine_analysis_FD, "Date: %" PRId32 "/%" PRId32 "/%04d -- " "%02d:%02d:%02d\n", tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec); fprintf(rule_engine_analysis_FD, "----------------------------------------------" "---------------------\n"); /*compile regex's for rule analysis*/ if (PerCentEncodingSetup()== 0) { fprintf(rule_engine_analysis_FD, "Error compiling regex; can't check for percent encoding in normalized http content.\n"); } } } else { SCLogInfo("Conf parameter \"engine-analysis.rules\" not found. " "Defaulting to not printing the rules analysis report."); } if (!enabled) { SCLogInfo("Engine-Analysis for rules disabled in conf file."); return 0; } return 1; } void CleanupFPAnalyzer(void) { if (fp_engine_analysis_FD != NULL) { fclose(fp_engine_analysis_FD); fp_engine_analysis_FD = NULL; } return; } void CleanupRuleAnalyzer(void) { if (rule_engine_analysis_FD != NULL) { SCLogInfo("Engine-Analyis for rules printed to file - %s", log_path); fclose(rule_engine_analysis_FD); rule_engine_analysis_FD = NULL; } } /** * \brief Compiles regex for rule analysis * \retval 1 if successful * \retval 0 if on error */ int PerCentEncodingSetup () { #define DETECT_PERCENT_ENCODING_REGEX "%[0-9|a-f|A-F]{2}" const char *eb = NULL; int eo = 0; int opts = 0; //PCRE_NEWLINE_ANY?? percent_re = pcre_compile(DETECT_PERCENT_ENCODING_REGEX, opts, &eb, &eo, NULL); if (percent_re == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", DETECT_PERCENT_ENCODING_REGEX, eo, eb); return 0; } percent_re_study = pcre_study(percent_re, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); return 0; } return 1; } /** * \brief Checks for % encoding in content. * \param Pointer to content * \retval number of matches if content has % encoding * \retval 0 if it doesn't have % encoding * \retval -1 on error */ int PerCentEncodingMatch (uint8_t *content, uint8_t content_len) { #define MAX_ENCODED_CHARS 240 int ret = 0; int ov[MAX_ENCODED_CHARS]; ret = pcre_exec(percent_re, percent_re_study, (char *)content, content_len, 0, 0, ov, MAX_ENCODED_CHARS); if (ret == -1) { return 0; } else if (ret < -1) { SCLogError(SC_ERR_PCRE_MATCH, "Error parsing content - %s; error code is %d", content, ret); return -1; } return ret; } static void EngineAnalysisRulesPrintFP(Signature *s) { DetectContentData *fp_cd = NULL; SigMatch *mpm_sm = s->mpm_sm; if (mpm_sm != NULL) { fp_cd = (DetectContentData *)mpm_sm->ctx; } if (fp_cd == NULL) { return; } uint16_t patlen = fp_cd->content_len; uint8_t *pat = SCMalloc(fp_cd->content_len + 1); if (unlikely(pat == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memcpy(pat, fp_cd->content, fp_cd->content_len); pat[fp_cd->content_len] = '\0'; if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { SCFree(pat); patlen = fp_cd->fp_chop_len; pat = SCMalloc(fp_cd->fp_chop_len + 1); if (unlikely(pat == NULL)) { exit(EXIT_FAILURE); } memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len); pat[fp_cd->fp_chop_len] = '\0'; fprintf(rule_engine_analysis_FD, " Fast Pattern \""); PrintRawUriFp(rule_engine_analysis_FD, pat, patlen); } else { fprintf(rule_engine_analysis_FD, " Fast Pattern \""); PrintRawUriFp(rule_engine_analysis_FD, pat, patlen); } SCFree(pat); fprintf(rule_engine_analysis_FD, "\" on \""); int list_type = SigMatchListSMBelongsTo(s, mpm_sm); if (list_type == DETECT_SM_LIST_PMATCH) { int payload = 0; int stream = 0; if (SignatureHasPacketContent(s)) payload = 1; if (SignatureHasStreamContent(s)) stream = 1; fprintf(rule_engine_analysis_FD, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); } else if (list_type == DETECT_SM_LIST_UMATCH) fprintf(rule_engine_analysis_FD, "http uri content"); else if (list_type == DETECT_SM_LIST_HRUDMATCH) fprintf(rule_engine_analysis_FD, "http raw uri content"); else if (list_type == DETECT_SM_LIST_HHDMATCH) fprintf(rule_engine_analysis_FD, "http header content"); else if (list_type == DETECT_SM_LIST_HRHDMATCH) fprintf(rule_engine_analysis_FD, "http raw header content"); else if (list_type == DETECT_SM_LIST_HMDMATCH) fprintf(rule_engine_analysis_FD, "http method content"); else if (list_type == DETECT_SM_LIST_HCDMATCH) fprintf(rule_engine_analysis_FD, "http cookie content"); else if (list_type == DETECT_SM_LIST_HCBDMATCH) fprintf(rule_engine_analysis_FD, "http client body content"); else if (list_type == DETECT_SM_LIST_HSBDMATCH) fprintf(rule_engine_analysis_FD, "http server body content"); else if (list_type == DETECT_SM_LIST_HSCDMATCH) fprintf(rule_engine_analysis_FD, "http stat code content"); else if (list_type == DETECT_SM_LIST_HSMDMATCH) fprintf(rule_engine_analysis_FD, "http stat msg content"); else if (list_type == DETECT_SM_LIST_HUADMATCH) fprintf(rule_engine_analysis_FD, "http user agent content"); fprintf(rule_engine_analysis_FD, "\" buffer.\n"); return; } void EngineAnalysisRulesFailure(char *line, char *file, int lineno) { fprintf(rule_engine_analysis_FD, "== Sid: UNKNOWN ==\n"); fprintf(rule_engine_analysis_FD, "%s\n", line); fprintf(rule_engine_analysis_FD, " FAILURE: invalid rule.\n"); fprintf(rule_engine_analysis_FD, " File: %s.\n", file); fprintf(rule_engine_analysis_FD, " Line: %d.\n", lineno); fprintf(rule_engine_analysis_FD, "\n"); } /** * \brief Prints analysis of loaded rules. * * Warns if potential rule issues are detected. For example, * warns if a rule uses a construct that may perform poorly, * e.g. pcre without content or with http_method content only; * warns if a rule uses a construct that may not be consistent with intent, * e.g. client side ports only, http and content without any http_* modifiers, etc. * * \param s Pointer to the signature. */ void EngineAnalysisRules(Signature *s, char *line) { uint32_t rule_bidirectional = 0; uint32_t rule_pcre = 0; uint32_t rule_pcre_http = 0; uint32_t rule_content = 0; uint32_t rule_flow = 0; uint32_t rule_flags = 0; uint32_t rule_flow_toserver = 0; uint32_t rule_flow_toclient = 0; uint32_t rule_flow_nostream = 0; uint32_t rule_ipv4_only = 0; uint32_t rule_ipv6_only = 0; uint32_t rule_flowbits = 0; uint32_t rule_flowint = 0; //uint32_t rule_flowvar = 0; uint32_t rule_content_http = 0; uint32_t rule_content_offset_depth = 0; uint32_t list_id = 0; uint32_t rule_warning = 0; uint32_t raw_http_buf = 0; uint32_t norm_http_buf = 0; uint32_t stream_buf = 0; uint32_t packet_buf = 0; uint32_t http_header_buf = 0; uint32_t http_uri_buf = 0; uint32_t http_method_buf = 0; uint32_t http_cookie_buf = 0; uint32_t http_client_body_buf = 0; uint32_t http_server_body_buf = 0; uint32_t http_stat_code_buf = 0; uint32_t http_stat_msg_buf = 0; uint32_t http_raw_header_buf = 0; uint32_t http_raw_uri_buf = 0; uint32_t http_ua_buf = 0; uint32_t warn_pcre_no_content = 0; uint32_t warn_pcre_http_content = 0; uint32_t warn_pcre_http = 0; uint32_t warn_content_http_content = 0; uint32_t warn_content_http = 0; uint32_t warn_tcp_no_flow = 0; uint32_t warn_client_ports = 0; uint32_t warn_direction = 0; uint32_t warn_method_toclient = 0; uint32_t warn_method_serverbody = 0; uint32_t warn_pcre_method = 0; uint32_t warn_encoding_norm_http_buf = 0; uint32_t warn_offset_depth_pkt_stream = 0; uint32_t warn_offset_depth_alproto = 0; uint32_t warn_non_alproto_fp_for_alproto_sig = 0; if (s->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; } if (s->flags & SIG_FLAG_REQUIRE_PACKET) { packet_buf += 1; } if (s->flags & SIG_FLAG_REQUIRE_STREAM) { stream_buf += 1; } if (s->proto.flags & DETECT_PROTO_IPV4) { rule_ipv4_only += 1; } if (s->proto.flags & DETECT_PROTO_IPV6) { rule_ipv6_only += 1; } for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { SigMatch *sm = NULL; for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_PCRE) { if (list_id == DETECT_SM_LIST_HCBDMATCH) { rule_pcre_http += 1; http_client_body_buf += 1; raw_http_buf += 1; } else if (list_id == DETECT_SM_LIST_UMATCH) { rule_pcre_http += 1; norm_http_buf += 1; http_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HHDMATCH) { rule_pcre_http += 1; norm_http_buf += 1; http_header_buf += 1; } else if (list_id == DETECT_SM_LIST_HCDMATCH) { rule_pcre_http += 1; norm_http_buf += 1; http_cookie_buf += 1; } else if (list_id == DETECT_SM_LIST_HSBDMATCH) { rule_pcre_http += 1; http_server_body_buf += 1; raw_http_buf += 1; } else if (list_id == DETECT_SM_LIST_HRHDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_raw_header_buf += 1; } else if (list_id == DETECT_SM_LIST_HMDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_method_buf += 1; } else if (list_id == DETECT_SM_LIST_HRUDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_raw_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HSMDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_stat_msg_buf += 1; } else if (list_id == DETECT_SM_LIST_HSCDMATCH) { rule_pcre_http += 1; raw_http_buf += 1; http_stat_code_buf += 1; } else if (list_id == DETECT_SM_LIST_HUADMATCH) { rule_pcre_http += 1; norm_http_buf += 1; http_ua_buf += 1; } else { rule_pcre += 1; } } else if (sm->type == DETECT_CONTENT) { if (list_id == DETECT_SM_LIST_UMATCH || list_id == DETECT_SM_LIST_HHDMATCH || list_id == DETECT_SM_LIST_HCDMATCH) { rule_content_http += 1; norm_http_buf += 1; DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd != NULL && PerCentEncodingMatch(cd->content, cd->content_len) > 0) { warn_encoding_norm_http_buf += 1; rule_warning += 1; } if (list_id == DETECT_SM_LIST_UMATCH) { http_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HHDMATCH) { http_header_buf += 1; } else if (list_id == DETECT_SM_LIST_HCDMATCH) { http_cookie_buf += 1; } } else if (list_id == DETECT_SM_LIST_HCBDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_client_body_buf += 1; } else if (list_id == DETECT_SM_LIST_HSBDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_server_body_buf += 1; } else if (list_id == DETECT_SM_LIST_HRHDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_raw_header_buf += 1; } else if (list_id == DETECT_SM_LIST_HRUDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_raw_uri_buf += 1; } else if (list_id == DETECT_SM_LIST_HSMDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_stat_msg_buf += 1; } else if (list_id == DETECT_SM_LIST_HSCDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_stat_code_buf += 1; } else if (list_id == DETECT_SM_LIST_HMDMATCH) { rule_content_http += 1; raw_http_buf += 1; http_method_buf += 1; } else if (list_id == DETECT_SM_LIST_PMATCH) { rule_content += 1; DetectContentData *cd = (DetectContentData *)sm->ctx; if (cd->flags & (DETECT_CONTENT_OFFSET | DETECT_CONTENT_DEPTH)) { rule_content_offset_depth++; } } } else if (sm->type == DETECT_FLOW) { rule_flow += 1; if ((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { rule_flow_toserver = 1; } else if ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) { rule_flow_toclient = 1; } DetectFlowData *fd = (DetectFlowData *)sm->ctx; if (fd != NULL) { if (fd->flags & FLOW_PKT_NOSTREAM) rule_flow_nostream = 1; } } else if (sm->type == DETECT_FLOWBITS) { if (list_id == DETECT_SM_LIST_MATCH) { rule_flowbits += 1; } } else if (sm->type == DETECT_FLOWINT) { if (list_id == DETECT_SM_LIST_MATCH) { rule_flowint += 1; } } else if (sm->type == DETECT_FLAGS) { DetectFlagsData *fd = (DetectFlagsData *)sm->ctx; if (fd != NULL) { rule_flags = 1; } } } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */ } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */ if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) { rule_warning += 1; warn_pcre_no_content = 1; } if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) { rule_warning += 1; warn_pcre_http_content = 1; } else if (s->alproto == ALPROTO_HTTP && rule_pcre > 0 && rule_pcre_http == 0) { rule_warning += 1; warn_pcre_http = 1; } if (rule_content > 0 && rule_content_http > 0) { rule_warning += 1; warn_content_http_content = 1; } if (s->alproto == ALPROTO_HTTP && rule_content > 0 && rule_content_http == 0) { rule_warning += 1; warn_content_http = 1; } if (rule_content == 1) { //todo: warning if content is weak, separate warning for pcre + weak content } if (rule_flow == 0 && rule_flags == 0 && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP) && (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits)) { rule_warning += 1; warn_tcp_no_flow = 1; } if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient) && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) { if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)) || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))) { rule_warning += 1; warn_client_ports = 1; } } if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) { rule_warning += 1; warn_direction = 1; } if (http_method_buf) { if (rule_flow && rule_flow_toclient) { rule_warning += 1; warn_method_toclient = 1; } if (http_server_body_buf) { rule_warning += 1; warn_method_serverbody = 1; } if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) { rule_warning += 1; warn_pcre_method = 1; } } if (rule_content_offset_depth > 0 && stream_buf && packet_buf) { rule_warning += 1; warn_offset_depth_pkt_stream = 1; } if (rule_content_offset_depth > 0 && !stream_buf && packet_buf && s->alproto != ALPROTO_UNKNOWN) { rule_warning += 1; warn_offset_depth_alproto = 1; } if (s->mpm_sm != NULL && s->alproto == ALPROTO_HTTP && SigMatchListSMBelongsTo(s, s->mpm_sm) == DETECT_SM_LIST_PMATCH) { rule_warning += 1; warn_non_alproto_fp_for_alproto_sig = 1; } if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) { fprintf(rule_engine_analysis_FD, "== Sid: %u ==\n", s->id); fprintf(rule_engine_analysis_FD, "%s\n", line); if (s->flags & SIG_FLAG_IPONLY) fprintf(rule_engine_analysis_FD, " Rule is ip only.\n"); if (rule_ipv6_only) fprintf(rule_engine_analysis_FD, " Rule is IPv6 only.\n"); if (rule_ipv4_only) fprintf(rule_engine_analysis_FD, " Rule is IPv4 only.\n"); if (packet_buf) fprintf(rule_engine_analysis_FD, " Rule matches on packets.\n"); if (!rule_flow_nostream && stream_buf && (rule_flow || rule_flowbits || rule_content || rule_pcre)) { fprintf(rule_engine_analysis_FD, " Rule matches on reassembled stream.\n"); } if (http_uri_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http uri buffer.\n"); if (http_header_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http header buffer.\n"); if (http_cookie_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http cookie buffer.\n"); if (http_raw_uri_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http raw uri buffer.\n"); if (http_raw_header_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http raw header buffer.\n"); if (http_method_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http method buffer.\n"); if (http_server_body_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http server body buffer.\n"); if (http_client_body_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http client body buffer.\n"); if (http_stat_msg_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http stat msg buffer.\n"); if (http_stat_code_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http stat code buffer.\n"); if (http_ua_buf) fprintf(rule_engine_analysis_FD, " Rule matches on http user agent buffer.\n"); if (s->alproto != ALPROTO_UNKNOWN) { fprintf(rule_engine_analysis_FD, " App layer protocol is %s.\n", TmModuleAlprotoToString(s->alproto)); } if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) { fprintf(rule_engine_analysis_FD, " Rule contains %d content options, %d http content options, %d pcre options, and %d pcre options with http modifiers.\n", rule_content, rule_content_http, rule_pcre, rule_pcre_http); } /* print fast pattern info */ EngineAnalysisRulesPrintFP(s); /* this is where the warnings start */ if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre without a content option present.\n" " -Consider adding a content to improve performance of this rule.\n"); } if (warn_pcre_http_content /*rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses content options with http_* and pcre options without http modifiers.\n" " -Consider adding http pcre modifier.\n"); } else if (warn_pcre_http /*s->alproto == ALPROTO_HTTP && rule_pcre > 0 && rule_pcre_http == 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule app layer protocol is http, but pcre options do not have http modifiers.\n" " -Consider adding http pcre modifiers.\n"); } if (warn_content_http_content /*rule_content > 0 && rule_content_http > 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule contains content with http_* and content without http_*.\n" " -Consider adding http content modifiers.\n"); } if (warn_content_http /*s->alproto == ALPROTO_HTTP && rule_content > 0 && rule_content_http == 0*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule app layer protocol is http, but content options do not have http_* modifiers.\n" " -Consider adding http content modifiers.\n"); } if (rule_content == 1) { //todo: warning if content is weak, separate warning for pcre + weak content } if (warn_encoding_norm_http_buf) { fprintf(rule_engine_analysis_FD, " Warning: Rule may contain percent encoded content for a normalized http buffer match.\n"); } if (warn_tcp_no_flow /*rule_flow == 0 && rule_flow == 0 && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP)*/) { fprintf(rule_engine_analysis_FD, " Warning: TCP rule without a flow or flags option.\n" " -Consider adding flow or flags to improve performance of this rule.\n"); } if (warn_client_ports /*rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient) && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)) || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule contains ports or port variables only on the client side.\n" " -Flow direction possibly inconsistent with rule.\n"); } if (warn_direction /*rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule is bidirectional and has a flow option with a specific direction.\n"); } if (warn_method_toclient /*http_method_buf && rule_flow && rule_flow_toclient*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses content or pcre for http_method with flow:to_client or from_server\n"); } if (warn_method_serverbody /*http_method_buf && http_server_body_buf*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses content or pcre for http_method with content or pcre for http_server_body.\n"); } if (warn_pcre_method /*http_method_buf && rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)*/) { fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre with only a http_method content; possible performance issue.\n"); } if (warn_offset_depth_pkt_stream) { fprintf(rule_engine_analysis_FD, " Warning: Rule has depth" "/offset with raw content keywords. Please note the " "offset/depth will be checked against both packet " "payloads and stream. If you meant to have the offset/" "depth checked against just the payload, you can update " "the signature as \"alert tcp-pkt...\"\n"); } if (warn_offset_depth_alproto) { fprintf(rule_engine_analysis_FD, " Warning: Rule has " "offset/depth set along with a match on a specific " "app layer protocol - %d. This can lead to FNs if we " "have a offset/depth content match on a packet payload " "before we can detect the app layer protocol for the " "flow.\n", s->alproto); } if (warn_non_alproto_fp_for_alproto_sig) { fprintf(rule_engine_analysis_FD, " Warning: Rule app layer " "protocol is http, but the fast_pattern is set on the raw " "stream. Consider adding fast_pattern over a http " "buffer for increased performance."); } if (rule_warning == 0) { fprintf(rule_engine_analysis_FD, " No warnings for this rule.\n"); } fprintf(rule_engine_analysis_FD, "\n"); } return; } suricata-1.4.7/src/alert-prelude.h0000644000000000000000000000201112253546156013735 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * * \file * * \author Pierre Chifflier * \author Yoann Vandoorselaere */ #ifndef __ALERT_PRELUDE_H__ #define __ALERT_PRELUDE_H__ void TmModuleAlertPreludeRegister (void); LogFileCtx *AlertPreludeInitCtx(ConfNode *conf); #endif /* __ALERT_PRELUDE_H__ */ suricata-1.4.7/src/source-erf-file.h0000644000000000000000000000165012253546156014167 00000000000000/* Copyright (C) 2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Endace Technology Limited */ #ifndef __SOURCE_ERF_H__ #define __SOURCE_ERF_H__ void TmModuleReceiveErfFileRegister(void); void TmModuleDecodeErfFileRegister(void); #endif /* __SOURCE_ERF_H__ */ suricata-1.4.7/src/decode-sll.h0000644000000000000000000000230312253546156013207 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DECODE_SLL_H__ #define __DECODE_SLL_H__ #define SLL_HEADER_LEN 16 typedef struct SllHdr_ { uint16_t sll_pkttype; /* packet type */ uint16_t sll_hatype; /* link-layer address type */ uint16_t sll_halen; /* link-layer address length */ uint8_t sll_addr[8]; /* link-layer address */ uint16_t sll_protocol; /* protocol */ } SllHdr; #endif /* __DECODE_SLL_H__ */ suricata-1.4.7/src/log-tlslog.h0000644000000000000000000000206612253546156013265 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Roliers Jean-Paul * \author Eric Leblond */ #ifndef __LOG_TLSLOG_H__ #define __LOG_TLSLOG_H__ void TmModuleLogTlsLogRegister (void); void TmModuleLogTlsLogIPv4Register (void); void TmModuleLogTlsLogIPv6Register (void); OutputCtx *LogTlsLogInitCtx(ConfNode *); #endif /* __LOG_TLSLOG_H__ */ suricata-1.4.7/src/detect-dce-stub-data.c0000644000000000000000000022623412253546156015065 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implements dce_stub_data keyword */ #include "suricata-common.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "app-layer.h" #include "app-layer-dcerpc.h" #include "queue.h" #include "stream-tcp-reassemble.h" #include "detect-dce-stub-data.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "stream-tcp.h" int DetectDceStubDataMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); static int DetectDceStubDataSetup(DetectEngineCtx *, Signature *, char *); /** * \brief Registers the keyword handlers for the "dce_stub_data" keyword. */ void DetectDceStubDataRegister(void) { sigmatch_table[DETECT_DCE_STUB_DATA].name = "dce_stub_data"; sigmatch_table[DETECT_DCE_STUB_DATA].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_STUB_DATA].Match = NULL; sigmatch_table[DETECT_DCE_STUB_DATA].AppLayerMatch = DetectDceStubDataMatch; sigmatch_table[DETECT_DCE_STUB_DATA].Setup = DetectDceStubDataSetup; sigmatch_table[DETECT_DCE_STUB_DATA].Free = NULL; sigmatch_table[DETECT_DCE_STUB_DATA].RegisterTests = DetectDceStubDataRegisterTests; sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_PAYLOAD; return; } /** * \brief App layer match function for the "dce_stub_data" keyword. * * \todo Check the need for passing a pointer to hold the address of the stub_data. * * \param t Pointer to the ThreadVars instance. * \param det_ctx Pointer to the DetectEngineThreadCtx. * \param f Pointer to the flow. * \param flags Pointer to the flags indicating the flow direction. * \param state Pointer to the app layer state data. * \param s Pointer to the Signature instance. * \param m Pointer to the SigMatch. * * \retval 1 On Match. * \retval 0 On no match. */ int DetectDceStubDataMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) { SCEnter(); DCERPCState *dcerpc_state = (DCERPCState *)state; if (dcerpc_state == NULL) { SCLogDebug("No DCERPCState for the flow"); SCReturnInt(0); } if (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL || dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer != NULL) { SCReturnInt(1); } else { SCReturnInt(0); } } /** * \brief Creates a SigMatch for the \"dce_stub_data\" keyword being sent as argument, * and appends it to the Signature(s). * * \param de_ctx Pointer to the detection engine context * \param s Pointer to signature for the current Signature being parsed * from the rules * \param arg Pointer to the string holding the keyword value * * \retval 0 on success, -1 on failure */ static int DetectDceStubDataSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { SigMatch *sm = NULL; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_DCE_STUB_DATA; sm->ctx = NULL; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } s->alproto = ALPROTO_DCERPC; /* Flagged the signature as to inspect the app layer data */ s->flags |= SIG_FLAG_APPLAYER; return 0; error: if (sm != NULL) SCFree(sm); return -1; } /************************************Unittests*********************************/ #ifdef UNITTESTS static int DetectDceStubDataTestParse01(void) { Signature s; int result = 0; memset(&s, 0, sizeof(Signature)); result = (DetectDceStubDataSetup(NULL, &s, NULL) == 0); if (s.sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { result = 1; } else { result = 0; } return result; } /** * \test Test a valid dce_stub_data entry with bind, bind_ack, request frags. */ static int DetectDceStubDataTestParse02(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x26, 0x3d, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; /* todo chop the request frag length and change the * length related parameters in the frag */ uint8_t dcerpc_request[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xec, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd4, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x83, 0xc7, 0x0b, 0x47, 0x47, 0x47, 0x47, 0x81, 0x37, 0x22, 0xa5, 0x9b, 0x4a, 0x75, 0xf4, 0xa3, 0x61, 0xd3, 0xbe, 0xdd, 0x5a, 0xfb, 0x20, 0x1e, 0xfc, 0x10, 0x8e, 0x0f, 0xa5, 0x9f, 0x4a, 0x22, 0x20, 0x9b, 0xa8, 0xd5, 0xc4, 0xff, 0xc1, 0x3f, 0xbd, 0x9b, 0x4a, 0x22, 0x2e, 0xc0, 0x7a, 0xa9, 0xfe, 0x97, 0xc9, 0xe1, 0xa9, 0xf3, 0x2f, 0x22, 0xc9, 0x9b, 0x22, 0x50, 0xa5, 0xf5, 0x4a, 0x4a, 0xce, 0x9b, 0x2f, 0x22, 0x2e, 0x6f, 0xc1, 0xe1, 0xf3, 0xa8, 0x83, 0xa2, 0x64, 0x98, 0xc1, 0x62, 0xa1, 0xa0, 0x89, 0x56, 0xa8, 0x1b, 0x8b, 0x2b, 0x2e, 0xe3, 0x7a, 0xd1, 0x03, 0xef, 0x58, 0x7c, 0x4e, 0x7d, 0x14, 0x76, 0xfa, 0xc3, 0x7f, 0x02, 0xa5, 0xbb, 0x4a, 0x89, 0x47, 0x6c, 0x12, 0xc9, 0x70, 0x18, 0x8e, 0x3a, 0x2e, 0xcb, 0x52, 0xa9, 0x67, 0x98, 0x0a, 0x1e, 0x2e, 0xc3, 0x32, 0x21, 0x7f, 0x10, 0x31, 0x3e, 0xa6, 0x61, 0xc1, 0x61, 0x85, 0x98, 0x88, 0xa9, 0xee, 0x83, 0x22, 0x51, 0xd6, 0xda, 0x4a, 0x4a, 0xc1, 0xff, 0x38, 0x47, 0xcd, 0xe9, 0x25, 0x41, 0xe4, 0xf3, 0x0d, 0x47, 0xd1, 0xcb, 0xc1, 0xd6, 0x1e, 0x95, 0x4a, 0x22, 0xa5, 0x73, 0x08, 0x22, 0xa5, 0x9b, 0xc9, 0xe6, 0xb5, 0xcd, 0x22, 0x43, 0xd7, 0xe2, 0x0b, 0x4a, 0xe9, 0xf2, 0x28, 0x50, 0xcd, 0xd7, 0x25, 0x43, 0xc1, 0x10, 0xbe, 0x99, 0xa9, 0x9b, 0x4a, 0x22, 0x4d, 0xb8, 0x4a, 0x22, 0xa5, 0x18, 0x8e, 0x2e, 0xf3, 0xc9, 0x22, 0x4e, 0xc9, 0x9b, 0x4a, 0x4a, 0x96, 0xa9, 0x64, 0x46, 0xcd, 0xec, 0x39, 0x10, 0xfa, 0xcf, 0xb5, 0x76, 0x81, 0x8f, 0xc9, 0xe6, 0xa9, 0x10, 0x82, 0x7c, 0xff, 0xc4, 0xa1, 0x0a, 0xf5, 0xcc, 0x1b, 0x74, 0xf4, 0x10, 0x81, 0xa9, 0x9d, 0x98, 0xb0, 0xa1, 0x65, 0x9f, 0xb9, 0x84, 0xd1, 0x9f, 0x13, 0x7c, 0x47, 0x76, 0x12, 0x7c, 0xfc, 0x10, 0xbb, 0x09, 0x55, 0x5a, 0xac, 0x20, 0xfa, 0x10, 0x7e, 0x15, 0xa6, 0x69, 0x12, 0xe1, 0xf7, 0xca, 0x22, 0x57, 0xd5, 0x9b, 0x4a, 0x4a, 0xd1, 0xfa, 0x38, 0x56, 0xcd, 0xcc, 0x19, 0x63, 0xf6, 0xf3, 0x2f, 0x56, 0xa5, 0x9b, 0x22, 0x51, 0xca, 0xf8, 0x21, 0x48, 0xa5, 0xf3, 0x28, 0x4b, 0xcb, 0xff, 0x22, 0x47, 0xcb, 0x9b, 0x4a, 0x4a, 0xc9, 0xf2, 0x39, 0x56, 0xcd, 0xeb, 0x3e, 0x22, 0xa5, 0xf3, 0x2b, 0x41, 0xc6, 0xfe, 0xc1, 0xfe, 0xf6, 0xca, 0xc9, 0xe1, 0xad, 0xc8, 0x1b, 0xa1, 0x66, 0x93, 0x19, 0x73, 0x26, 0x58, 0x42, 0x71, 0xf4, 0x18, 0x89, 0x2a, 0xf6, 0xca, 0xb5, 0xf5, 0x2c, 0xd8, 0x42, 0xdd, 0x72, 0x12, 0x09, 0x26, 0x5a, 0x4c, 0xc3, 0x21, 0x5a, 0x4c, 0xc3, 0x61, 0x59, 0x64, 0x9d, 0xab, 0xe6, 0x63, 0xc9, 0xc9, 0xad, 0x10, 0xa9, 0xa3, 0x49, 0x0b, 0x4b, 0x22, 0xa5, 0xcf, 0x22, 0x23, 0xa4, 0x9b, 0x4a, 0xdd, 0x31, 0xbf, 0xe2, 0x23, 0xa5, 0x9b, 0xcb, 0xe6, 0x35, 0x9a, 0x4a, 0x22, 0xcf, 0x9d, 0x20, 0x23, 0xcf, 0x99, 0xb5, 0x76, 0x81, 0x83, 0x20, 0x22, 0xcf, 0x9b, 0x20, 0x22, 0xcd, 0x99, 0x4a, 0xe6, 0x96, 0x10, 0x96, 0x71, 0xf6, 0xcb, 0x20, 0x23, 0xf5, 0xf1, 0x5a, 0x71, 0xf5, 0x64, 0x1e, 0x06, 0x9d, 0x64, 0x1e, 0x06, 0x8d, 0x5c, 0x49, 0x32, 0xa5, 0x9b, 0x4a, 0xdd, 0xf1, 0xbf, 0x56, 0xa1, 0x61, 0xbf, 0x13, 0x78, 0xf4, 0xc9, 0x1a, 0x11, 0x77, 0xc9, 0x22, 0x51, 0xc0, 0xf5, 0x2e, 0xa9, 0x61, 0xc9, 0x22, 0x50, 0xc0, 0xf8, 0x3c, 0xa9, 0x71, 0xc9, 0x1b, 0x72, 0xf4, 0x64, 0x9d, 0xb1, 0x5a, 0x4c, 0xdf, 0xa1, 0x61, 0x8b, 0x12, 0x78, 0xfc, 0xc8, 0x1f, 0x72, 0x2e, 0x77, 0x1a, 0x42, 0xcf, 0x9f, 0x10, 0x72, 0x2e, 0x47, 0xa2, 0x63, 0xa5, 0x9b, 0x4a, 0x48, 0xa5, 0xf3, 0x26, 0x4e, 0xca, 0xf8, 0x22, 0x57, 0xc4, 0xf7, 0x0b, 0x4a, 0xf3, 0xf2, 0x38, 0x56, 0xf1, 0xcd, 0xb5, 0xf5, 0x26, 0x5f, 0x5a, 0x78, 0xf7, 0xf1, 0x0a, 0x4a, 0xa5, 0x8b, 0x4a, 0x22, 0xf7, 0xf1, 0x4a, 0xdd, 0x75, 0x12, 0x0e, 0x06, 0x81, 0xc1, 0xd9, 0xca, 0xb5, 0x9b, 0x4a, 0x22, 0xc4, 0xc0, 0xb5, 0xc1, 0xc5, 0xa8, 0x8a, 0x92, 0xa1, 0x73, 0x5c, 0x22, 0xa5, 0x9b, 0x2b, 0xe1, 0xc5, 0xc9, 0x19, 0x11, 0x65, 0x73, 0x40, 0x22, 0xa5, 0x9b, 0x11, 0x78, 0xa6, 0x43, 0x61, 0xf2, 0xd0, 0x74, 0x2b, 0xe1, 0x96, 0x52, 0x1b, 0x70, 0xf6, 0x64, 0x3f, 0x22, 0x5a, 0xcf, 0x4f, 0x26, 0x20, 0x5b, 0x34, 0x23, 0x66, 0x64, 0x1f, 0xd2, 0xa5, 0x9b, 0x4a, 0x22, 0xa5, 0x9b, 0x4a, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x54, 0x58, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x43, 0x42, 0x42, 0x50, 0x5f, 0x57, 0xc3, 0x33, 0x5f, 0x37, 0x74, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0xeb, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x53, 0x69, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x73, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x44, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x6e, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x65, 0x66, 0x31, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x72, 0x65, 0x66, 0x32, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x01, 0x02, 0x03, 0x04 }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint32_t dcerpc_request_len = sizeof(dcerpc_request); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_stub_data; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* we shouldn't have any stub data */ if (PacketAlertCheck(p, 1)) goto end; /* do detect */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* we shouldn't have any stub data */ if (PacketAlertCheck(p, 1)) goto end; r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* we should have the stub data since we previously parsed a request frag */ if (!PacketAlertCheck(p, 1)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test a valid dce_stub_data with just a request frag. */ static int DetectDceStubDataTestParse03(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; /* todo chop the request frag length and change the * length related parameters in the frag */ uint8_t dcerpc_request[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xec, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd4, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x83, 0xc7, 0x0b, 0x47, 0x47, 0x47, 0x47, 0x81, 0x37, 0x22, 0xa5, 0x9b, 0x4a, 0x75, 0xf4, 0xa3, 0x61, 0xd3, 0xbe, 0xdd, 0x5a, 0xfb, 0x20, 0x1e, 0xfc, 0x10, 0x8e, 0x0f, 0xa5, 0x9f, 0x4a, 0x22, 0x20, 0x9b, 0xa8, 0xd5, 0xc4, 0xff, 0xc1, 0x3f, 0xbd, 0x9b, 0x4a, 0x22, 0x2e, 0xc0, 0x7a, 0xa9, 0xfe, 0x97, 0xc9, 0xe1, 0xa9, 0xf3, 0x2f, 0x22, 0xc9, 0x9b, 0x22, 0x50, 0xa5, 0xf5, 0x4a, 0x4a, 0xce, 0x9b, 0x2f, 0x22, 0x2e, 0x6f, 0xc1, 0xe1, 0xf3, 0xa8, 0x83, 0xa2, 0x64, 0x98, 0xc1, 0x62, 0xa1, 0xa0, 0x89, 0x56, 0xa8, 0x1b, 0x8b, 0x2b, 0x2e, 0xe3, 0x7a, 0xd1, 0x03, 0xef, 0x58, 0x7c, 0x4e, 0x7d, 0x14, 0x76, 0xfa, 0xc3, 0x7f, 0x02, 0xa5, 0xbb, 0x4a, 0x89, 0x47, 0x6c, 0x12, 0xc9, 0x70, 0x18, 0x8e, 0x3a, 0x2e, 0xcb, 0x52, 0xa9, 0x67, 0x98, 0x0a, 0x1e, 0x2e, 0xc3, 0x32, 0x21, 0x7f, 0x10, 0x31, 0x3e, 0xa6, 0x61, 0xc1, 0x61, 0x85, 0x98, 0x88, 0xa9, 0xee, 0x83, 0x22, 0x51, 0xd6, 0xda, 0x4a, 0x4a, 0xc1, 0xff, 0x38, 0x47, 0xcd, 0xe9, 0x25, 0x41, 0xe4, 0xf3, 0x0d, 0x47, 0xd1, 0xcb, 0xc1, 0xd6, 0x1e, 0x95, 0x4a, 0x22, 0xa5, 0x73, 0x08, 0x22, 0xa5, 0x9b, 0xc9, 0xe6, 0xb5, 0xcd, 0x22, 0x43, 0xd7, 0xe2, 0x0b, 0x4a, 0xe9, 0xf2, 0x28, 0x50, 0xcd, 0xd7, 0x25, 0x43, 0xc1, 0x10, 0xbe, 0x99, 0xa9, 0x9b, 0x4a, 0x22, 0x4d, 0xb8, 0x4a, 0x22, 0xa5, 0x18, 0x8e, 0x2e, 0xf3, 0xc9, 0x22, 0x4e, 0xc9, 0x9b, 0x4a, 0x4a, 0x96, 0xa9, 0x64, 0x46, 0xcd, 0xec, 0x39, 0x10, 0xfa, 0xcf, 0xb5, 0x76, 0x81, 0x8f, 0xc9, 0xe6, 0xa9, 0x10, 0x82, 0x7c, 0xff, 0xc4, 0xa1, 0x0a, 0xf5, 0xcc, 0x1b, 0x74, 0xf4, 0x10, 0x81, 0xa9, 0x9d, 0x98, 0xb0, 0xa1, 0x65, 0x9f, 0xb9, 0x84, 0xd1, 0x9f, 0x13, 0x7c, 0x47, 0x76, 0x12, 0x7c, 0xfc, 0x10, 0xbb, 0x09, 0x55, 0x5a, 0xac, 0x20, 0xfa, 0x10, 0x7e, 0x15, 0xa6, 0x69, 0x12, 0xe1, 0xf7, 0xca, 0x22, 0x57, 0xd5, 0x9b, 0x4a, 0x4a, 0xd1, 0xfa, 0x38, 0x56, 0xcd, 0xcc, 0x19, 0x63, 0xf6, 0xf3, 0x2f, 0x56, 0xa5, 0x9b, 0x22, 0x51, 0xca, 0xf8, 0x21, 0x48, 0xa5, 0xf3, 0x28, 0x4b, 0xcb, 0xff, 0x22, 0x47, 0xcb, 0x9b, 0x4a, 0x4a, 0xc9, 0xf2, 0x39, 0x56, 0xcd, 0xeb, 0x3e, 0x22, 0xa5, 0xf3, 0x2b, 0x41, 0xc6, 0xfe, 0xc1, 0xfe, 0xf6, 0xca, 0xc9, 0xe1, 0xad, 0xc8, 0x1b, 0xa1, 0x66, 0x93, 0x19, 0x73, 0x26, 0x58, 0x42, 0x71, 0xf4, 0x18, 0x89, 0x2a, 0xf6, 0xca, 0xb5, 0xf5, 0x2c, 0xd8, 0x42, 0xdd, 0x72, 0x12, 0x09, 0x26, 0x5a, 0x4c, 0xc3, 0x21, 0x5a, 0x4c, 0xc3, 0x61, 0x59, 0x64, 0x9d, 0xab, 0xe6, 0x63, 0xc9, 0xc9, 0xad, 0x10, 0xa9, 0xa3, 0x49, 0x0b, 0x4b, 0x22, 0xa5, 0xcf, 0x22, 0x23, 0xa4, 0x9b, 0x4a, 0xdd, 0x31, 0xbf, 0xe2, 0x23, 0xa5, 0x9b, 0xcb, 0xe6, 0x35, 0x9a, 0x4a, 0x22, 0xcf, 0x9d, 0x20, 0x23, 0xcf, 0x99, 0xb5, 0x76, 0x81, 0x83, 0x20, 0x22, 0xcf, 0x9b, 0x20, 0x22, 0xcd, 0x99, 0x4a, 0xe6, 0x96, 0x10, 0x96, 0x71, 0xf6, 0xcb, 0x20, 0x23, 0xf5, 0xf1, 0x5a, 0x71, 0xf5, 0x64, 0x1e, 0x06, 0x9d, 0x64, 0x1e, 0x06, 0x8d, 0x5c, 0x49, 0x32, 0xa5, 0x9b, 0x4a, 0xdd, 0xf1, 0xbf, 0x56, 0xa1, 0x61, 0xbf, 0x13, 0x78, 0xf4, 0xc9, 0x1a, 0x11, 0x77, 0xc9, 0x22, 0x51, 0xc0, 0xf5, 0x2e, 0xa9, 0x61, 0xc9, 0x22, 0x50, 0xc0, 0xf8, 0x3c, 0xa9, 0x71, 0xc9, 0x1b, 0x72, 0xf4, 0x64, 0x9d, 0xb1, 0x5a, 0x4c, 0xdf, 0xa1, 0x61, 0x8b, 0x12, 0x78, 0xfc, 0xc8, 0x1f, 0x72, 0x2e, 0x77, 0x1a, 0x42, 0xcf, 0x9f, 0x10, 0x72, 0x2e, 0x47, 0xa2, 0x63, 0xa5, 0x9b, 0x4a, 0x48, 0xa5, 0xf3, 0x26, 0x4e, 0xca, 0xf8, 0x22, 0x57, 0xc4, 0xf7, 0x0b, 0x4a, 0xf3, 0xf2, 0x38, 0x56, 0xf1, 0xcd, 0xb5, 0xf5, 0x26, 0x5f, 0x5a, 0x78, 0xf7, 0xf1, 0x0a, 0x4a, 0xa5, 0x8b, 0x4a, 0x22, 0xf7, 0xf1, 0x4a, 0xdd, 0x75, 0x12, 0x0e, 0x06, 0x81, 0xc1, 0xd9, 0xca, 0xb5, 0x9b, 0x4a, 0x22, 0xc4, 0xc0, 0xb5, 0xc1, 0xc5, 0xa8, 0x8a, 0x92, 0xa1, 0x73, 0x5c, 0x22, 0xa5, 0x9b, 0x2b, 0xe1, 0xc5, 0xc9, 0x19, 0x11, 0x65, 0x73, 0x40, 0x22, 0xa5, 0x9b, 0x11, 0x78, 0xa6, 0x43, 0x61, 0xf2, 0xd0, 0x74, 0x2b, 0xe1, 0x96, 0x52, 0x1b, 0x70, 0xf6, 0x64, 0x3f, 0x22, 0x5a, 0xcf, 0x4f, 0x26, 0x20, 0x5b, 0x34, 0x23, 0x66, 0x64, 0x1f, 0xd2, 0xa5, 0x9b, 0x4a, 0x22, 0xa5, 0x9b, 0x4a, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x54, 0x58, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x41, 0x3f, 0x3f, 0x2d, 0x6f, 0x43, 0x42, 0x42, 0x50, 0x5f, 0x57, 0xc3, 0x33, 0x5f, 0x37, 0x74, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0xeb, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x53, 0x69, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x73, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x44, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x6e, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x65, 0x66, 0x31, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x72, 0x65, 0x66, 0x32, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x01, 0x02, 0x03, 0x04 }; uint32_t dcerpc_request_len = sizeof(dcerpc_request); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_stub_data; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectDceStubDataTestParse04(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xd0, 0x8c, 0x33, 0x44, 0x22, 0xf1, 0x31, 0xaa, 0xaa, 0x90, 0x00, 0x38, 0x00, 0x10, 0x03, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x65, 0x8e, 0x00, 0x00, 0x0d, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x77, 0x69, 0x6e, 0x72, 0x65, 0x67, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x5c, 0x00, 0x5c, 0x00, 0xa8, 0xb9, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x54, 0x00, 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x0c, 0x00, 0x0c, 0x00, 0x98, 0xda, 0x14, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x73, 0x00, 0x61, 0x00, 0x33, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x41, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); uint32_t dcerpc_request2_len = sizeof(dcerpc_request2); uint32_t dcerpc_response2_len = sizeof(dcerpc_response2); uint32_t dcerpc_request3_len = sizeof(dcerpc_request3); uint32_t dcerpc_response3_len = sizeof(dcerpc_response3); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; dce_stub_data; sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* request1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; /* request2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; /* request3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectDceStubDataTestParse05(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; DCERPCState *dcerpc_state = NULL; int r = 0; uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x5c, 0x00, 0x5c, 0x00, 0xa8, 0xb9, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x54, 0x00, 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x0c, 0x00, 0x0c, 0x00, 0x98, 0xda, 0x14, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x73, 0x00, 0x61, 0x00, 0x33, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x41, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); uint32_t dcerpc_request2_len = sizeof(dcerpc_request2); uint32_t dcerpc_response2_len = sizeof(dcerpc_response2); uint32_t dcerpc_request3_len = sizeof(dcerpc_request3); uint32_t dcerpc_response3_len = sizeof(dcerpc_response3); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_stub_data;" "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } dcerpc_state = f.alstate; if (dcerpc_state == NULL) { SCLogDebug("no dcerpc state: "); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; /* request2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; /* request3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) goto end; /* response3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) goto end; result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif void DetectDceStubDataRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectDceStubDataTestParse01", DetectDceStubDataTestParse01, 1); UtRegisterTest("DetectDceStubDataTestParse02", DetectDceStubDataTestParse02, 1); UtRegisterTest("DetectDceStubDataTestParse03", DetectDceStubDataTestParse03, 1); UtRegisterTest("DetectDceStubDataTestParse04", DetectDceStubDataTestParse04, 1); UtRegisterTest("DetectDceStubDataTestParse05", DetectDceStubDataTestParse05, 1); #endif return; } suricata-1.4.7/src/log-pcap.h0000644000000000000000000000043712253546156012704 00000000000000/** Copyright (c) 2009 Open Information Security Foundation * * \author Breno Silva */ #ifndef __PCAP_LOG_ALERT_H__ #define __PCAP_LOG_ALERT_H__ void TmModulePcapLogRegister (void); OutputCtx *PcapLogInitCtx(ConfNode *); #endif /* __PCAP_LOG_ALERT_H__ */ suricata-1.4.7/src/alert-prelude.c0000644000000000000000000006325112253546156013745 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pierre Chifflier * \author Yoann Vandoorselaere * * Logs alerts to the Prelude system, using IDMEF (RFC 4765) messages. * * Each message contains the alert description and reference (using * the SID/GID), and a normalized description (assessment, impact, * sources etc.) * * libprelude handles the connection with the manager (collecting component), * spooling and sending the event asynchronously. It also offers transport * security (using TLS and trusted certificates) and reliability (events * are retransmitted if not sent successfully). * * This modules requires a Prelude profile to work (see man prelude-admin * and the Prelude Handbook for help). */ #include "suricata-common.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "conf.h" #include "threads.h" #include "threadvars.h" #include "tm-threads.h" #include "util-unittest.h" #include "util-time.h" #include "util-debug.h" #include "util-error.h" #include "util-print.h" #include "output.h" #include "util-privs.h" #include "util-optimize.h" #include "stream.h" #ifndef PRELUDE /** Handle the case where no PRELUDE support is compiled in. * */ TmEcode AlertPrelude (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertPreludeThreadInit(ThreadVars *, void *, void **); TmEcode AlertPreludeThreadDeinit(ThreadVars *, void *); int AlertPreludeOpenFileCtx(LogFileCtx *, char *); void AlertPreludeRegisterTests(void); void TmModuleAlertPreludeRegister (void) { tmm_modules[TMM_ALERTPRELUDE].name = "AlertPrelude"; tmm_modules[TMM_ALERTPRELUDE].ThreadInit = AlertPreludeThreadInit; tmm_modules[TMM_ALERTPRELUDE].Func = AlertPrelude; tmm_modules[TMM_ALERTPRELUDE].ThreadDeinit = AlertPreludeThreadDeinit; tmm_modules[TMM_ALERTPRELUDE].RegisterTests = AlertPreludeRegisterTests; } LogFileCtx *AlertPreludeInitCtx(ConfNode *conf) { SCLogDebug("Can't init Prelude output - Prelude support was disabled during build."); return NULL; } TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data) { SCLogDebug("Can't init Prelude output thread - Prelude support was disabled during build."); return TM_ECODE_FAILED; } TmEcode AlertPrelude (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { return TM_ECODE_OK; } TmEcode AlertPreludeThreadDeinit(ThreadVars *t, void *data) { return TM_ECODE_FAILED; } void AlertPreludeRegisterTests (void) { } #else /* implied we do have PRELUDE support */ #include #define ANALYZER_CLASS "NIDS" #define ANALYZER_MODEL "Suricata" #define ANALYZER_MANUFACTURER "http://www.openinfosecfoundation.org/" #define ANALYZER_SID_URL "http://www.snort.org/search/sid/" #define SNORT_MAX_OWNED_SID 1000000 #define DEFAULT_ANALYZER_NAME "suricata" #define DEFAULT_PRELUDE_PROFILE "suricata" static unsigned int info_priority = 4; static unsigned int low_priority = 3; static unsigned int mid_priority = 2; OutputCtx *AlertPreludeInitCtx(ConfNode *conf); TmEcode AlertPrelude (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode AlertPreludeThreadInit(ThreadVars *, void *, void **); TmEcode AlertPreludeThreadDeinit(ThreadVars *, void *); int AlertPreludeOpenFileCtx(LogFileCtx *, char *); void AlertPreludeRegisterTests(void); static void AlertPreludeDeinitCtx(OutputCtx *output_ctx); void TmModuleAlertPreludeRegister (void) { tmm_modules[TMM_ALERTPRELUDE].name = "AlertPrelude"; tmm_modules[TMM_ALERTPRELUDE].ThreadInit = AlertPreludeThreadInit; tmm_modules[TMM_ALERTPRELUDE].Func = AlertPrelude; tmm_modules[TMM_ALERTPRELUDE].ThreadDeinit = AlertPreludeThreadDeinit; tmm_modules[TMM_ALERTPRELUDE].RegisterTests = AlertPreludeRegisterTests; tmm_modules[TMM_ALERTPRELUDE].cap_flags = 0; OutputRegisterModule("AlertPrelude", "alert-prelude", AlertPreludeInitCtx); } /** * This holds global structures and variables. Since libprelude is thread-safe, * there is no need to store a mutex. */ typedef struct AlertPreludeCtx_ { /** The client (which has the send function) */ prelude_client_t *client; int log_packet_content; int log_packet_header; } AlertPreludeCtx; /** * This holds per-thread specific structures and variables. */ typedef struct AlertPreludeThread_ { /** Pointer to the global context */ AlertPreludeCtx *ctx; } AlertPreludeThread; /** * \brief Initialize analyzer description * * \return 0 if ok */ static int SetupAnalyzer(idmef_analyzer_t *analyzer) { int ret; prelude_string_t *string; SCEnter(); ret = idmef_analyzer_new_model(analyzer, &string); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_constant(string, ANALYZER_MODEL); ret = idmef_analyzer_new_class(analyzer, &string); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_constant(string, ANALYZER_CLASS); ret = idmef_analyzer_new_manufacturer(analyzer, &string); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_constant(string, ANALYZER_MANUFACTURER); ret = idmef_analyzer_new_version(analyzer, &string); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_constant(string, VERSION); SCReturnInt(0); } /** * \brief Create event impact description (see section * 4.2.6.1 of RFC 4765). * The impact contains the severity, completion (succeeded or failed) * and basic classification of the attack type. * Here, we don't set the completion since we don't know it (default * is unknown). * * \return 0 if ok */ static int EventToImpact(PacketAlert *pa, Packet *p, idmef_alert_t *alert) { int ret; prelude_string_t *str; idmef_impact_t *impact; idmef_assessment_t *assessment; idmef_impact_severity_t severity; SCEnter(); ret = idmef_alert_new_assessment(alert, &assessment); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_assessment_new_impact(assessment, &impact); if ( ret < 0 ) SCReturnInt(ret); if ( (unsigned int)pa->s->prio < mid_priority ) severity = IDMEF_IMPACT_SEVERITY_HIGH; else if ( (unsigned int)pa->s->prio < low_priority ) severity = IDMEF_IMPACT_SEVERITY_MEDIUM; else if ( (unsigned int)pa->s->prio < info_priority ) severity = IDMEF_IMPACT_SEVERITY_LOW; else severity = IDMEF_IMPACT_SEVERITY_INFO; idmef_impact_set_severity(impact, severity); if (PACKET_TEST_ACTION(p, ACTION_DROP)) { idmef_action_t *action; ret = idmef_action_new(&action); if ( ret < 0 ) SCReturnInt(ret); idmef_action_set_category(action, IDMEF_ACTION_CATEGORY_BLOCK_INSTALLED); idmef_assessment_set_action(assessment, action, 0); } if (pa->s->class_msg) { ret = idmef_impact_new_description(impact, &str); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_ref(str, pa->s->class_msg); } SCReturnInt(0); } /** * \brief Add Source and Target fields to the IDMEF alert. * These objects contains IP addresses, source and destination * ports (see sections 4.2.4.3 and 4.2.4.4 of RFC 4765). * * \return 0 if ok */ static int EventToSourceTarget(Packet *p, idmef_alert_t *alert) { int ret; idmef_node_t *node; idmef_source_t *source; idmef_target_t *target; idmef_address_t *address; idmef_service_t *service; prelude_string_t *string; static char saddr[128], daddr[128]; uint8_t ip_vers; uint8_t ip_proto; SCEnter(); if ( !p ) SCReturnInt(0); if ( ! IPH_IS_VALID(p) ) SCReturnInt(0); if (PKT_IS_IPV4(p)) { ip_vers = 4; ip_proto = IPV4_GET_RAW_IPPROTO(p->ip4h); PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), saddr, sizeof(saddr)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), daddr, sizeof(daddr)); } else if (PKT_IS_IPV6(p)) { ip_vers = 6; ip_proto = IPV6_GET_L4PROTO(p); PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), saddr, sizeof(saddr)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), daddr, sizeof(daddr)); } else SCReturnInt(0); ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_source_new_service(source, &service); if ( ret < 0 ) SCReturnInt(ret); if ( p->tcph || p->udph ) idmef_service_set_port(service, p->sp); idmef_service_set_ip_version(service, ip_vers); idmef_service_set_iana_protocol_number(service, ip_proto); ret = idmef_source_new_node(source, &node); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_address_new_address(address, &string); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_ref(string, saddr); ret = idmef_alert_new_target(alert, &target, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_target_new_service(target, &service); if ( ret < 0 ) SCReturnInt(ret); if ( p->tcph || p->udph ) idmef_service_set_port(service, p->dp); idmef_service_set_ip_version(service, ip_vers); idmef_service_set_iana_protocol_number(service, ip_proto); ret = idmef_target_new_node(target, &node); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_address_new_address(address, &string); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_ref(string, daddr); SCReturnInt(0); } /** * \brief Add binary data, to be stored in the Additional Data * field of the IDMEF alert (see section 4.2.4.6 of RFC 4765). * * \return 0 if ok */ static int AddByteData(idmef_alert_t *alert, const char *meaning, const unsigned char *data, size_t size) { int ret; prelude_string_t *str; idmef_additional_data_t *ad; SCEnter(); if ( ! data || ! size ) SCReturnInt(0); ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(0); ret = idmef_additional_data_set_byte_string_ref(ad, data, size); if ( ret < 0 ) { SCLogDebug("%s: error setting byte string data: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = idmef_additional_data_new_meaning(ad, &str); if ( ret < 0 ) { SCLogDebug("%s: error creating additional-data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = prelude_string_set_ref(str, meaning); if ( ret < 0 ) { SCLogDebug("%s: error setting byte string data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } SCReturnInt(0); } /** * \brief Add integer data, to be stored in the Additional Data * field of the IDMEF alert (see section 4.2.4.6 of RFC 4765). * * \return 0 if ok */ static int AddIntData(idmef_alert_t *alert, const char *meaning, uint32_t data) { int ret; prelude_string_t *str; idmef_additional_data_t *ad; SCEnter(); ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); idmef_additional_data_set_integer(ad, data); ret = idmef_additional_data_new_meaning(ad, &str); if ( ret < 0 ) { SCLogDebug("%s: error creating additional-data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = prelude_string_set_ref(str, meaning); if ( ret < 0 ) { SCLogDebug("%s: error setting integer data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } SCReturnInt(0); } /** * \brief Add IPv4 header data, to be stored in the Additional Data * field of the IDMEF alert (see section 4.2.4.6 of RFC 4765). * * \return 0 if ok */ static int PacketToDataV4(Packet *p, PacketAlert *pa, idmef_alert_t *alert) { SCEnter(); AddIntData(alert, "ip_ver", IPV4_GET_RAW_VER(p->ip4h)); AddIntData(alert, "ip_hlen", IPV4_GET_RAW_HLEN(p->ip4h)); AddIntData(alert, "ip_tos", IPV4_GET_RAW_IPTOS(p->ip4h)); AddIntData(alert, "ip_len", ntohs(IPV4_GET_RAW_IPLEN(p->ip4h))); AddIntData(alert, "ip_id", ntohs(IPV4_GET_RAW_IPID(p->ip4h))); AddIntData(alert, "ip_off", ntohs(IPV4_GET_RAW_IPOFFSET(p->ip4h))); AddIntData(alert, "ip_ttl", IPV4_GET_RAW_IPTTL(p->ip4h)); AddIntData(alert, "ip_proto", IPV4_GET_RAW_IPPROTO(p->ip4h)); AddIntData(alert, "ip_sum", ntohs(p->ip4h->ip_csum)); SCReturnInt(0); } /** * \brief Add IPv6 header data, to be stored in the Additional Data * field of the IDMEF alert (see section 4.2.4.6 of RFC 4765). * * \return 0 if ok */ static int PacketToDataV6(Packet *p, PacketAlert *pa, idmef_alert_t *alert) { return 0; } /** * \brief Convert IP packet to an IDMEF alert (RFC 4765). * This function stores the alert SID (description and reference), * the payload of the packet, and pre-processed data. * * \return 0 if ok */ static int PacketToData(Packet *p, PacketAlert *pa, idmef_alert_t *alert, AlertPreludeCtx *ctx) { SCEnter(); if ( ! p ) SCReturnInt(0); AddIntData(alert, "snort_rule_sid", pa->s->id); AddIntData(alert, "snort_rule_rev", pa->s->rev); if (ctx->log_packet_header) { if ( PKT_IS_IPV4(p) ) PacketToDataV4(p, pa, alert); else if ( PKT_IS_IPV6(p) ) PacketToDataV6(p, pa, alert); if ( PKT_IS_TCP(p) ) { AddIntData(alert, "tcp_seq", ntohl(p->tcph->th_seq)); AddIntData(alert, "tcp_ack", ntohl(p->tcph->th_ack)); AddIntData(alert, "tcp_off", TCP_GET_RAW_OFFSET(p->tcph)); AddIntData(alert, "tcp_res", TCP_GET_RAW_X2(p->tcph)); AddIntData(alert, "tcp_flags", p->tcph->th_flags); AddIntData(alert, "tcp_win", ntohs(p->tcph->th_win)); AddIntData(alert, "tcp_sum", ntohs(p->tcph->th_sum)); AddIntData(alert, "tcp_urp", ntohs(p->tcph->th_urp)); } else if ( PKT_IS_UDP(p) ) { AddIntData(alert, "udp_len", ntohs(p->udph->uh_len)); AddIntData(alert, "udp_sum", ntohs(p->udph->uh_sum)); } else if ( PKT_IS_ICMPV4(p) ) { AddIntData(alert, "icmp_type", p->icmpv4h->type); AddIntData(alert, "icmp_code", p->icmpv4h->code); AddIntData(alert, "icmp_sum", ntohs(p->icmpv4h->checksum)); } } if (ctx->log_packet_content) AddByteData(alert, "payload", p->payload, p->payload_len); SCReturnInt(0); } /** * \brief Store reference on rule (SID and GID) in the IDMEF alert, * and embed an URL pointing to the rule description. * * \return 0 if ok */ static int AddSnortReference(idmef_classification_t *class, int gen_id, int sig_id) { int ret; prelude_string_t *str; idmef_reference_t *ref; SCEnter(); if ( sig_id >= SNORT_MAX_OWNED_SID ) SCReturnInt(0); ret = idmef_classification_new_reference(class, &ref, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_reference_new_name(ref, &str); if ( ret < 0 ) SCReturnInt(ret); idmef_reference_set_origin(ref, IDMEF_REFERENCE_ORIGIN_VENDOR_SPECIFIC); if ( gen_id == 0 ) ret = prelude_string_sprintf(str, "%u", sig_id); else ret = prelude_string_sprintf(str, "%u:%u", gen_id, sig_id); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_reference_new_meaning(ref, &str); if ( ret < 0 ) SCReturnInt(ret); ret = prelude_string_sprintf(str, "Snort Signature ID"); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_reference_new_url(ref, &str); if ( ret < 0 ) SCReturnInt(ret); if ( gen_id == 0 ) ret = prelude_string_sprintf(str, ANALYZER_SID_URL "%u", sig_id); else ret = prelude_string_sprintf(str, ANALYZER_SID_URL "%u-%u", gen_id, sig_id); SCReturnInt(ret); } /** * \brief Create event classification description (see section * 4.2.4.2 of RFC 4765). * The classification is the "name" of the alert, identification of the * rule signature, and additional information on the rule. * * \return 0 if ok */ static int EventToReference(PacketAlert *pa, Packet *p, idmef_classification_t *class) { int ret; prelude_string_t *str; SCEnter(); ret = idmef_classification_new_ident(class, &str); if ( ret < 0 ) SCReturnInt(ret); if ( pa->s->gid == 0 ) ret = prelude_string_sprintf(str, "%u", pa->s->id); else ret = prelude_string_sprintf(str, "%u:%u", pa->s->gid, pa->s->id); if ( ret < 0 ) SCReturnInt(ret); ret = AddSnortReference(class, pa->s->gid, pa->s->id); if ( ret < 0 ) SCReturnInt(ret); SCReturnInt(0); } static int PreludePrintStreamSegmentCallback(Packet *p, void *data, uint8_t *buf, uint32_t buflen) { int ret; ret = AddByteData((idmef_alert_t *)data, "stream-segment", buf, buflen); if (ret == 0) return 1; else return -1; } /** * \brief Handle Suricata alert: convert it to and IDMEF alert (see RFC 4765) * and send it asynchronously (so, this function does not block and returns * immediately). * If the destination Prelude Manager is not available, the alert is spooled * (and the function also returns immediately). * An IDMEF object is created, and all available information is added: IP packet * header and data, rule signature ID, additional data like URL pointing to * rule description, CVE, etc. * The IDMEF alert has a reference to all created objects, so freeing it will * automatically free all allocated memory. * * \note This function is thread safe. * * \return TM_ECODE_OK if ok, else TM_ECODE_FAILED */ TmEcode AlertPrelude (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { AlertPreludeThread *apn = (AlertPreludeThread *)data; int ret; idmef_time_t *time; idmef_alert_t *alert; prelude_string_t *str; idmef_message_t *idmef = NULL; idmef_classification_t *class; PacketAlert *pa; SCEnter(); if (apn == NULL || apn->ctx == NULL) { SCReturnInt(TM_ECODE_FAILED); } if (p->alerts.cnt == 0) SCReturnInt(TM_ECODE_OK); if ( !IPH_IS_VALID(p) ) SCReturnInt(TM_ECODE_OK); /* XXX which one to add to this alert? Lets see how Snort solves this. * For now just take last alert. */ pa = &p->alerts.alerts[p->alerts.cnt-1]; if (pa->s == NULL) goto err; ret = idmef_message_new(&idmef); if ( ret < 0 ) SCReturnInt(TM_ECODE_FAILED); ret = idmef_message_new_alert(idmef, &alert); if ( ret < 0 ) goto err; ret = idmef_alert_new_classification(alert, &class); if ( ret < 0 ) goto err; if (pa->s->msg) { ret = idmef_classification_new_text(class, &str); if ( ret < 0 ) goto err; prelude_string_set_ref(str, pa->s->msg); } ret = EventToImpact(pa, p, alert); if ( ret < 0 ) goto err; ret = EventToReference(pa, p, class); if ( ret < 0 ) goto err; ret = EventToSourceTarget(p, alert); if ( ret < 0 ) goto err; ret = PacketToData(p, pa, alert, apn->ctx); if ( ret < 0 ) goto err; if (pa->flags & PACKET_ALERT_FLAG_STATE_MATCH) { uint8_t flag; if (p->flowflags & FLOW_PKT_TOSERVER) { flag = FLOW_PKT_TOCLIENT; } else { flag = FLOW_PKT_TOSERVER; } ret = StreamSegmentForEach(p, flag, PreludePrintStreamSegmentCallback, (void *)alert); } if (ret < 0) goto err; ret = idmef_alert_new_detect_time(alert, &time); if ( ret < 0 ) goto err; idmef_time_set_from_timeval(time, &p->ts); ret = idmef_time_new_from_gettimeofday(&time); if ( ret < 0 ) goto err; idmef_alert_set_create_time(alert, time); idmef_alert_set_analyzer(alert, idmef_analyzer_ref(prelude_client_get_analyzer(apn->ctx->client)), IDMEF_LIST_PREPEND); /* finally, send event */ prelude_client_send_idmef(apn->ctx->client, idmef); idmef_message_destroy(idmef); SCReturnInt(TM_ECODE_OK); err: if (idmef != NULL) idmef_message_destroy(idmef); SCReturnInt(TM_ECODE_FAILED); } /** * \brief Initialize thread-specific data. Each thread structure contains * a pointer to the \a AlertPreludeCtx context. * * \return TM_ECODE_OK if ok, else TM_ECODE_FAILED */ TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data) { AlertPreludeThread *aun; SCEnter(); if(initdata == NULL) { SCLogDebug("Error getting context for Prelude. \"initdata\" argument NULL"); SCReturnInt(TM_ECODE_FAILED); } aun = SCMalloc(sizeof(AlertPreludeThread)); if (unlikely(aun == NULL)) SCReturnInt(TM_ECODE_FAILED); memset(aun, 0, sizeof(AlertPreludeThread)); /** Use the Ouput Context */ aun->ctx = ((OutputCtx *)initdata)->data; *data = (void *)aun; SCReturnInt(TM_ECODE_OK); } /** * \brief Free thread-specific data. * * \return TM_ECODE_OK if ok, else TM_ECODE_FAILED */ TmEcode AlertPreludeThreadDeinit(ThreadVars *t, void *data) { AlertPreludeThread *aun = (AlertPreludeThread *)data; SCEnter(); if (aun == NULL) { SCLogDebug("AlertPreludeThreadDeinit done (error)"); SCReturnInt(TM_ECODE_FAILED); } /* clear memory */ memset(aun, 0, sizeof(AlertPreludeThread)); SCFree(aun); SCReturnInt(TM_ECODE_OK); } /** \brief Initialize the Prelude logging module: initialize * library, create the client and try to establish the connection * to the Prelude Manager. * Client flags are set to force asynchronous (non-blocking) mode for * both alerts and heartbeats. * This function requires an existing Prelude profile to work. * * \return A newly allocated AlertPreludeCtx structure, or NULL */ OutputCtx *AlertPreludeInitCtx(ConfNode *conf) { int ret; prelude_client_t *client; AlertPreludeCtx *ctx; const char *prelude_profile_name; const char *log_packet_content; const char *log_packet_header; OutputCtx *output_ctx; SCEnter(); ret = prelude_init(0, NULL); if ( ret < 0 ) { prelude_perror(ret, "unable to initialize the prelude library"); SCReturnPtr(NULL, "AlertPreludeCtx"); } prelude_profile_name = ConfNodeLookupChildValue(conf, "profile"); if (prelude_profile_name == NULL) prelude_profile_name = DEFAULT_PRELUDE_PROFILE; log_packet_content = ConfNodeLookupChildValue(conf, "log-packet-content"); log_packet_header = ConfNodeLookupChildValue(conf, "log-packet-header"); ret = prelude_client_new(&client, prelude_profile_name); if ( ret < 0 || ! client ) { prelude_perror(ret, "Unable to create a prelude client object"); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } ret = prelude_client_set_flags(client, prelude_client_get_flags(client) | PRELUDE_CLIENT_FLAGS_ASYNC_TIMER|PRELUDE_CLIENT_FLAGS_ASYNC_SEND); if ( ret < 0 ) { SCLogDebug("Unable to set asynchronous send and timer."); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } SetupAnalyzer(prelude_client_get_analyzer(client)); ret = prelude_client_start(client); if ( ret < 0 ) { prelude_perror(ret, "Unable to start prelude client"); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } ctx = SCMalloc(sizeof(AlertPreludeCtx)); if (unlikely(ctx == NULL)) { prelude_perror(ret, "Unable to allocate memory"); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } ctx->client = client; ctx->log_packet_content = 0; ctx->log_packet_header = 1; if (log_packet_content && ConfValIsTrue(log_packet_content)) ctx->log_packet_content = 1; if (log_packet_header && ConfValIsFalse(log_packet_header)) ctx->log_packet_header = 0; output_ctx = SCMalloc(sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { SCFree(ctx); prelude_perror(ret, "Unable to allocate memory"); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } output_ctx->data = ctx; output_ctx->DeInit = AlertPreludeDeinitCtx; SCReturnPtr((void*)output_ctx, "OutputCtx"); } static void AlertPreludeDeinitCtx(OutputCtx *output_ctx) { AlertPreludeCtx *ctx = (AlertPreludeCtx *)output_ctx->data; prelude_client_destroy(ctx->client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCFree(output_ctx); } void AlertPreludeRegisterTests (void) { #ifdef UNITTESTS #endif /* UNITTESTS */ } #endif /* PRELUDE */ suricata-1.4.7/src/util-random.h0000644000000000000000000000162512253546156013435 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Pablo Rincon */ #ifndef __UTIL_RANDOM_H__ #define __UTIL_RANDOM_H__ unsigned int RandomTimePreseed(void); #endif /* __UTIL_RANDOM_H__ */ suricata-1.4.7/src/log-filestore.h0000644000000000000000000000162312253546156013753 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __LOG_FILESTORE_H__ #define __LOG_FILESTORE_H__ void TmModuleLogFilestoreRegister (void); #endif /* __LOG_FILELOG_H__ */ suricata-1.4.7/src/detect-filename.c0000644000000000000000000002061412253546156014222 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon * */ #include "suricata-common.h" #include "threads.h" #include "debug.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-debug.h" #include "util-spm-bm.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "stream-tcp.h" #include "detect-filename.h" static int DetectFilenameMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, Signature *, SigMatch *); static int DetectFilenameSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilenameRegisterTests(void); static void DetectFilenameFree(void *); /** * \brief Registration function for keyword: filename */ void DetectFilenameRegister(void) { sigmatch_table[DETECT_FILENAME].name = "filename"; sigmatch_table[DETECT_FILENAME].desc = "match on the file name"; sigmatch_table[DETECT_FILENAME].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filename"; sigmatch_table[DETECT_FILENAME].FileMatch = DetectFilenameMatch; sigmatch_table[DETECT_FILENAME].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILENAME].Setup = DetectFilenameSetup; sigmatch_table[DETECT_FILENAME].Free = DetectFilenameFree; sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; SCLogDebug("registering filename rule option"); return; } /** * \brief match the specified filename * * \param t thread local vars * \param det_ctx pattern matcher thread local data * \param f *LOCKED* flow * \param flags direction flags * \param file file being inspected * \param s signature being inspected * \param m sigmatch that we will cast into DetectFilenameData * * \retval 0 no match * \retval 1 match */ static int DetectFilenameMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) { SCEnter(); int ret = 0; DetectFilenameData *filename = m->ctx; if (file->name == NULL) SCReturnInt(0); if (file->txid < det_ctx->tx_id) SCReturnInt(0); if (file->txid > det_ctx->tx_id) SCReturnInt(0); if (BoyerMooreNocase(filename->name, filename->len, file->name, file->name_len, filename->bm_ctx->bmGs, filename->bm_ctx->bmBc) != NULL) { #ifdef DEBUG if (SCLogDebugEnabled()) { char *name = SCMalloc(filename->len + 1); if (name != NULL) { memcpy(name, filename->name, filename->len); name[filename->len] = '\0'; SCLogDebug("will look for filename %s", name); } } #endif if (!(filename->flags & DETECT_CONTENT_NEGATED)) { ret = 1; } } if (ret == 0 && (filename->flags & DETECT_CONTENT_NEGATED)) { SCLogDebug("negated match"); ret = 1; } SCReturnInt(ret); } /** * \brief Parse the filename keyword * * \param idstr Pointer to the user provided option * * \retval filename pointer to DetectFilenameData on success * \retval NULL on failure */ static DetectFilenameData *DetectFilenameParse (char *str) { DetectFilenameData *filename = NULL; /* We have a correct filename option */ filename = SCMalloc(sizeof(DetectFilenameData)); if (unlikely(filename == NULL)) goto error; memset(filename, 0x00, sizeof(DetectFilenameData)); if (DetectParseContentString (str, &filename->name, &filename->len, &filename->flags) == -1) { goto error; } filename->bm_ctx = BoyerMooreCtxInit(filename->name, filename->len); if (filename->bm_ctx == NULL) { goto error; } SCLogDebug("flags %02X", filename->flags); if (filename->flags & DETECT_CONTENT_NEGATED) { SCLogDebug("negated filename"); } BoyerMooreCtxToNocase(filename->bm_ctx, filename->name, filename->len); #ifdef DEBUG if (SCLogDebugEnabled()) { char *name = SCMalloc(filename->len + 1); if (name != NULL) { memcpy(name, filename->name, filename->len); name[filename->len] = '\0'; SCLogDebug("will look for filename %s", name); } } #endif return filename; error: if (filename != NULL) DetectFilenameFree(filename); return NULL; } /** * \brief this function is used to parse filename options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature * \param str pointer to the user provided "filename" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { DetectFilenameData *filename = NULL; SigMatch *sm = NULL; filename = DetectFilenameParse(str); if (filename == 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_FILENAME; sm->ctx = (void *)filename; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); goto error; } AppLayerHtpNeedFileInspection(); s->alproto = ALPROTO_HTTP; s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; error: if (filename != NULL) DetectFilenameFree(filename); if (sm != NULL) SCFree(sm); return -1; } /** * \brief this function will free memory associated with DetectFilenameData * * \param filename pointer to DetectFilenameData */ static void DetectFilenameFree(void *ptr) { if (ptr != NULL) { DetectFilenameData *filename = (DetectFilenameData *)ptr; if (filename->bm_ctx != NULL) { BoyerMooreCtxDeInit(filename->bm_ctx); } if (filename->name != NULL) SCFree(filename->name); SCFree(filename); } } #ifdef UNITTESTS /* UNITTESTS */ /** * \test DetectFilenameTestParse01 */ int DetectFilenameTestParse01 (void) { DetectFilenameData *dnd = DetectFilenameParse("secret.pdf"); if (dnd != NULL) { DetectFilenameFree(dnd); return 1; } return 0; } /** * \test DetectFilenameTestParse02 */ int DetectFilenameTestParse02 (void) { int result = 0; DetectFilenameData *dnd = DetectFilenameParse("\"backup.tar.gz\""); if (dnd != NULL) { if (dnd->len == 13 && memcmp(dnd->name, "backup.tar.gz", 13) == 0) { result = 1; } DetectFilenameFree(dnd); return result; } return 0; } /** * \test DetectFilenameTestParse03 */ int DetectFilenameTestParse03 (void) { int result = 0; DetectFilenameData *dnd = DetectFilenameParse("cmd.exe"); if (dnd != NULL) { if (dnd->len == 7 && memcmp(dnd->name, "cmd.exe", 7) == 0) { result = 1; } DetectFilenameFree(dnd); return result; } return 0; } #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectFilename */ void DetectFilenameRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ UtRegisterTest("DetectFilenameTestParse01", DetectFilenameTestParse01, 1); UtRegisterTest("DetectFilenameTestParse02", DetectFilenameTestParse02, 1); UtRegisterTest("DetectFilenameTestParse03", DetectFilenameTestParse03, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/detect-detection-filter.h0000644000000000000000000000227012253546156015706 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gerardo Iglesias */ #ifndef __DETECT_DETECTION_FILTER_H__ #define __DETECT_DETECTION_FILTER_H__ #include "decode-events.h" #include "decode-ipv4.h" #include "decode-tcp.h" /** * Registration function for detection_filter: keyword */ void DetectDetectionFilterRegister (void); /** * This function registers unit tests for detection_filter */ void DetectDetectionFilterRegisterTests(void); #endif /*__DETECT_DETECTION_FILTER_H__ */ suricata-1.4.7/src/util-spm-bs.c0000644000000000000000000001004312253546156013343 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon Crespo * * bs is a bruteforce search. It will try to search the pattern * from all characters until the available text len is less * than the length of the pattern. It needs no context but it * time cost is not good. */ #include "suricata-common.h" #include "suricata.h" #include "util-debug.h" #include "util-spm-bs.h" /** * \brief Basic search improved. Limits are better handled, so * it doesn't start searches that wont fit in the remaining buffer * * \param haystack pointer to the buffer to search in * \param haystack_len length limit of the buffer * \param neddle pointer to the pattern we ar searching for * \param needle_len length limit of the needle * * \retval ptr to start of the match; NULL if no match */ uint8_t *BasicSearch(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len) { SCEnter(); const uint8_t *h, *n; const uint8_t *hmax = haystack + haystack_len; const uint8_t *nmax = needle + needle_len; if (needle_len == 0 || needle_len > haystack_len) { SCReturnPtr(NULL, "uint8_t"); } //PrintRawDataFp(stdout,needle,needle_len); //PrintRawDataFp(stdout,haystack,haystack_len); for (n = needle; nmax - n <= hmax - haystack; haystack++) { if (*haystack != *n) { continue; } SCLogDebug("*haystack == *n, %c == %c", *haystack, *n); /* one byte needles */ if (needle_len == 1) { SCReturnPtr((uint8_t *)haystack, "uint8_t"); } for (h = haystack+1, n++; nmax - n <= hmax - haystack; h++, n++) { if (*h != *n) { break; } SCLogDebug("*haystack == *n, %c == %c", *haystack, *n); /* if we run out of needle we fully matched */ if (n == nmax - 1) { SCReturnPtr((uint8_t *)haystack, "uint8_t"); } } n = needle; } SCReturnPtr(NULL, "uint8_t"); } /** * \brief Basic search case less * * \param haystack pointer to the buffer to search in * \param haystack_len length limit of the buffer * \param neddle pointer to the pattern we ar searching for * \param needle_len length limit of the needle * * \retval ptr to start of the match; NULL if no match */ uint8_t *BasicSearchNocase(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len) { const uint8_t *h, *n; const uint8_t *hmax = haystack + haystack_len; const uint8_t *nmax = needle + needle_len; if (needle_len == 0 || needle_len > haystack_len) return NULL; for (n = needle; nmax - n <= hmax - haystack; haystack++) { if (u8_tolower(*haystack) != u8_tolower(*n)) { continue; } /* one byte needles */ if (needle_len == 1) { return (uint8_t *)haystack; } for (h = haystack+1, n++; nmax - n <= hmax - h ; h++, n++) { if (u8_tolower(*h) != u8_tolower(*n)) { break; } /* if we run out of needle we fully matched */ if (n == nmax - 1) { return (uint8_t *)haystack; } } n = needle; } return NULL; } void BasicSearchInit (void) { /* nothing no more */ } suricata-1.4.7/src/app-layer-dcerpc.c0000644000000000000000000077644012253546156014343 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Kirby Kuehl * \author Anoop Saldanha * * \file DCE/RPC parser and decoder * * \todo Remove all the unnecessary per byte incremental loops with a full one * time jump, i.e. * * input[0], input_len * for (i = 0; i < x; i++) * input++; * * with * * input += x; * * You'll be surprised at how many such cases we have here. We also need * to do the same for htp parser. Should speed up the engine drastically. */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "util-print.h" #include "util-pool.h" #include "util-debug.h" #include "flow-util.h" #include "detect-engine-state.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "util-spm.h" #include "util-unittest.h" #include "app-layer-dcerpc.h" enum { DCERPC_FIELD_NONE = 0, DCERPC_PARSE_DCERPC_HEADER, DCERPC_PARSE_DCERPC_BIND, DCERPC_PARSE_DCERPC_BIND_ACK, DCERPC_PARSE_DCERPC_REQUEST, /* must be last */ DCERPC_FIELD_MAX, }; /* \brief hexdump function from libdnet, used for debugging only */ void hexdump(/*Flow *f,*/ const void *buf, size_t len) { /* dumps len bytes of *buf to stdout. Looks like: * [0000] 75 6E 6B 6E 6F 77 6E 20 * 30 FF 00 00 00 00 39 00 unknown 0.....9. * (in a single line of course) */ const unsigned char *p = buf; unsigned char c; size_t n; char bytestr[4] = {0}; char addrstr[10] = {0}; char hexstr[ 16*3 + 5] = {0}; char charstr[16*1 + 5] = {0}; for (n=1; n<=len; n++) { if (n%16 == 1) { /* store address for this line */ #if __WORDSIZE == 64 snprintf(addrstr, sizeof(addrstr), "%.4"PRIx64, ((uint64_t)p-(uint64_t)buf) ); #else snprintf(addrstr, sizeof(addrstr), "%.4"PRIx32, ((uint32_t)p-(uint32_t)buf) ); #endif } c = *p; if (isalnum(c) == 0) { c = '.'; } /* store hex str (for left side) */ snprintf(bytestr, sizeof(bytestr), "%02X ", *p); strlcat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1); /* store char str (for right side) */ snprintf(bytestr, sizeof(bytestr), "%c", c); strlcat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1); if(n%16 == 0) { /* line completed */ printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); hexstr[0] = 0; charstr[0] = 0; } else if(n%8 == 0) { /* half line: add whitespaces */ strlcat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1); strlcat(charstr, " ", sizeof(charstr)-strlen(charstr)-1); } p++; /* next byte */ } if (strlen(hexstr) > 0) { /* print rest of buffer if not empty */ printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); } } /** * \brief printUUID function used to print UUID, Major and Minor Version Number * and if it was Accepted or Rejected in the BIND_ACK. */ void printUUID(char *type, DCERPCUuidEntry *uuid) { uint8_t i = 0; if (uuid == NULL) { return; } printf("%s UUID [%2u] %s ", type, uuid->ctxid, (uuid->result == 0) ? "Accepted" : "Rejected"); for (i = 0; i < 16; i++) { printf("%02x", uuid->uuid[i]); } printf(" Major Version 0x%04x Minor Version 0x%04x\n", uuid->version, uuid->versionminor); } /** * \brief DCERPCParseSecondaryAddr reads secondaryaddrlen bytes from the BIND_ACK * DCERPC call. */ static uint32_t DCERPCParseSecondaryAddr(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t *p = input; while (dcerpc->dcerpcbindbindack.secondaryaddrlenleft-- && input_len--) { SCLogDebug("0x%02x ", *p); p++; } dcerpc->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } static uint32_t PaddingParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t *p = input; while (dcerpc->padleft-- && input_len--) { SCLogDebug("0x%02x ", *p); p++; } dcerpc->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } static uint32_t DCERPCGetCTXItems(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t *p = input; if (input_len) { switch (dcerpc->dcerpcbindbindack.ctxbytesprocessed) { case 0: if (input_len >= 4) { dcerpc->dcerpcbindbindack.numctxitems = *p; dcerpc->dcerpcbindbindack.numctxitemsleft = dcerpc->dcerpcbindbindack.numctxitems; dcerpc->dcerpcbindbindack.ctxbytesprocessed += 4; dcerpc->bytesprocessed += 4; SCReturnUInt(4U); } else { dcerpc->dcerpcbindbindack.numctxitems = *(p++); dcerpc->dcerpcbindbindack.numctxitemsleft = dcerpc->dcerpcbindbindack.numctxitems; if (!(--input_len)) break; } case 1: p++; if (!(--input_len)) break; case 2: p++; if (!(--input_len)) break; case 3: p++; input_len--; break; } } dcerpc->dcerpcbindbindack.ctxbytesprocessed += (p - input); dcerpc->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } /** * \brief DCERPCParseBINDCTXItem is called for each CTXItem found the DCERPC BIND call. * each UUID is added to a TAILQ. */ static uint32_t DCERPCParseBINDCTXItem(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t *p = input; if (input_len) { switch (dcerpc->dcerpcbindbindack.ctxbytesprocessed) { case 0: if (input_len >= 44) { if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.ctxid = *(p); dcerpc->dcerpcbindbindack.ctxid |= *(p + 1) << 8; dcerpc->dcerpcbindbindack.uuid[3] = *(p + 4); dcerpc->dcerpcbindbindack.uuid[2] = *(p + 5); dcerpc->dcerpcbindbindack.uuid[1] = *(p + 6); dcerpc->dcerpcbindbindack.uuid[0] = *(p + 7); dcerpc->dcerpcbindbindack.uuid[5] = *(p + 8); dcerpc->dcerpcbindbindack.uuid[4] = *(p + 9); dcerpc->dcerpcbindbindack.uuid[7] = *(p + 10); dcerpc->dcerpcbindbindack.uuid[6] = *(p + 11); dcerpc->dcerpcbindbindack.uuid[8] = *(p + 12); dcerpc->dcerpcbindbindack.uuid[9] = *(p + 13); dcerpc->dcerpcbindbindack.uuid[10] = *(p + 14); dcerpc->dcerpcbindbindack.uuid[11] = *(p + 15); dcerpc->dcerpcbindbindack.uuid[12] = *(p + 16); dcerpc->dcerpcbindbindack.uuid[13] = *(p + 17); dcerpc->dcerpcbindbindack.uuid[14] = *(p + 18); dcerpc->dcerpcbindbindack.uuid[15] = *(p + 19); dcerpc->dcerpcbindbindack.version = *(p + 20); dcerpc->dcerpcbindbindack.version |= *(p + 21) << 8; dcerpc->dcerpcbindbindack.versionminor = *(p + 22); dcerpc->dcerpcbindbindack.versionminor |= *(p + 23) << 8; } else { /* Big Endian */ dcerpc->dcerpcbindbindack.ctxid = *(p) << 8; dcerpc->dcerpcbindbindack.ctxid |= *(p + 1); dcerpc->dcerpcbindbindack.uuid[0] = *(p + 4); dcerpc->dcerpcbindbindack.uuid[1] = *(p + 5); dcerpc->dcerpcbindbindack.uuid[2] = *(p + 6); dcerpc->dcerpcbindbindack.uuid[3] = *(p + 7); dcerpc->dcerpcbindbindack.uuid[4] = *(p + 8); dcerpc->dcerpcbindbindack.uuid[5] = *(p + 9); dcerpc->dcerpcbindbindack.uuid[6] = *(p + 10); dcerpc->dcerpcbindbindack.uuid[7] = *(p + 11); dcerpc->dcerpcbindbindack.uuid[8] = *(p + 12); dcerpc->dcerpcbindbindack.uuid[9] = *(p + 13); dcerpc->dcerpcbindbindack.uuid[10] = *(p + 14); dcerpc->dcerpcbindbindack.uuid[11] = *(p + 15); dcerpc->dcerpcbindbindack.uuid[12] = *(p + 16); dcerpc->dcerpcbindbindack.uuid[13] = *(p + 17); dcerpc->dcerpcbindbindack.uuid[14] = *(p + 18); dcerpc->dcerpcbindbindack.uuid[15] = *(p + 19); dcerpc->dcerpcbindbindack.version = *(p + 20) << 8; dcerpc->dcerpcbindbindack.version |= *(p + 21); dcerpc->dcerpcbindbindack.versionminor = *(p + 22) << 8; dcerpc->dcerpcbindbindack.versionminor |= *(p + 23); } //if (dcerpc->dcerpcbindbindack.ctxid == dcerpc->dcerpcbindbindack.numctxitems // - dcerpc->dcerpcbindbindack.numctxitemsleft) { dcerpc->dcerpcbindbindack.uuid_entry = (DCERPCUuidEntry *)SCCalloc(1, sizeof(DCERPCUuidEntry)); if (dcerpc->dcerpcbindbindack.uuid_entry == NULL) { SCLogDebug("UUID Entry is NULL"); SCReturnUInt(0); } dcerpc->dcerpcbindbindack.uuid_entry->internal_id = dcerpc->dcerpcbindbindack.uuid_internal_id++; memcpy(dcerpc->dcerpcbindbindack.uuid_entry->uuid, dcerpc->dcerpcbindbindack.uuid, sizeof(dcerpc->dcerpcbindbindack.uuid)); dcerpc->dcerpcbindbindack.uuid_entry->ctxid = dcerpc->dcerpcbindbindack.ctxid; dcerpc->dcerpcbindbindack.uuid_entry->version = dcerpc->dcerpcbindbindack.version; dcerpc->dcerpcbindbindack.uuid_entry->versionminor = dcerpc->dcerpcbindbindack.versionminor; /* store the first frag flag in the uuid as pfc_flags will * be overwritten by new packets. */ if (dcerpc->dcerpchdr.pfc_flags & PFC_FIRST_FRAG) { dcerpc->dcerpcbindbindack.uuid_entry->flags |= DCERPC_UUID_ENTRY_FLAG_FF; } TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.uuid_list, dcerpc->dcerpcbindbindack.uuid_entry, next); #ifdef UNITTESTS if (RunmodeIsUnittests()) { printUUID("BIND", dcerpc->dcerpcbindbindack.uuid_entry); } #endif dcerpc->dcerpcbindbindack.numctxitemsleft--; dcerpc->bytesprocessed += (44); dcerpc->dcerpcbindbindack.ctxbytesprocessed += (44); SCReturnUInt(44U); //} else { // SCLogDebug("ctxitem %u, expected %u\n", dcerpc->dcerpcbindbindack.ctxid, // dcerpc->dcerpcbindbindack.numctxitems - dcerpc->dcerpcbindbindack.numctxitemsleft); // SCReturnUInt(0); //} } else { if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.ctxid = *(p++); } else { dcerpc->dcerpcbindbindack.ctxid = *(p++) << 8; } if (!(--input_len)) break; } case 1: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.ctxid |= *(p++) << 8; } else { dcerpc->dcerpcbindbindack.ctxid |= *(p++); } if (!(--input_len)) break; case 2: /* num transact items */ p++; if (!(--input_len)) break; case 3: /* reserved */ p++; if (!(--input_len)) break; case 4: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.uuid[3] = *(p++); } else { dcerpc->dcerpcbindbindack.uuid[0] = *(p++); } if (!(--input_len)) break; case 5: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.uuid[2] = *(p++); } else { dcerpc->dcerpcbindbindack.uuid[1] = *(p++); } if (!(--input_len)) break; case 6: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.uuid[1] = *(p++); } else { dcerpc->dcerpcbindbindack.uuid[2] = *(p++); } if (!(--input_len)) break; case 7: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.uuid[0] = *(p++); } else { dcerpc->dcerpcbindbindack.uuid[3] = *(p++); } if (!(--input_len)) break; case 8: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.uuid[5] = *(p++); } else { dcerpc->dcerpcbindbindack.uuid[4] = *(p++); } if (!(--input_len)) break; case 9: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.uuid[4] = *(p++); } else { dcerpc->dcerpcbindbindack.uuid[5] = *(p++); } if (!(--input_len)) break; case 10: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.uuid[7] = *(p++); } else { dcerpc->dcerpcbindbindack.uuid[6] = *(p++); } if (!(--input_len)) break; case 11: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.uuid[6] = *(p++); } else { dcerpc->dcerpcbindbindack.uuid[7] = *(p++); } if (!(--input_len)) break; case 12: /* The following bytes are in the same order for both big and little endian */ dcerpc->dcerpcbindbindack.uuid[8] = *(p++); if (!(--input_len)) break; case 13: dcerpc->dcerpcbindbindack.uuid[9] = *(p++); if (!(--input_len)) break; case 14: dcerpc->dcerpcbindbindack.uuid[10] = *(p++); if (!(--input_len)) break; case 15: dcerpc->dcerpcbindbindack.uuid[11] = *(p++); if (!(--input_len)) break; case 16: dcerpc->dcerpcbindbindack.uuid[12] = *(p++); if (!(--input_len)) break; case 17: dcerpc->dcerpcbindbindack.uuid[13] = *(p++); if (!(--input_len)) break; case 18: dcerpc->dcerpcbindbindack.uuid[14] = *(p++); if (!(--input_len)) break; case 19: dcerpc->dcerpcbindbindack.uuid[15] = *(p++); if (!(--input_len)) break; case 20: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.version = *(p++); } else { dcerpc->dcerpcbindbindack.version = *(p++) << 8; } if (!(--input_len)) break; case 21: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.version |= *(p++) << 8; } else { dcerpc->dcerpcbindbindack.version |= *(p++); } if (!(--input_len)) break; case 22: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.versionminor = *(p++); } else { dcerpc->dcerpcbindbindack.versionminor = *(p++) << 8; } if (!(--input_len)) break; case 23: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.versionminor |= *(p++) << 8; } else { dcerpc->dcerpcbindbindack.versionminor |= *(p++); } if (!(--input_len)) break; case 24: p++; if (!(--input_len)) break; case 25: p++; if (!(--input_len)) break; case 26: p++; if (!(--input_len)) break; case 27: p++; if (!(--input_len)) break; case 28: p++; if (!(--input_len)) break; case 29: p++; if (!(--input_len)) break; case 30: p++; if (!(--input_len)) break; case 31: p++; if (!(--input_len)) break; case 32: p++; if (!(--input_len)) break; case 33: p++; if (!(--input_len)) break; case 34: p++; if (!(--input_len)) break; case 35: p++; if (!(--input_len)) break; case 36: p++; if (!(--input_len)) break; case 37: p++; if (!(--input_len)) break; case 38: p++; if (!(--input_len)) break; case 39: p++; if (!(--input_len)) break; case 40: p++; if (!(--input_len)) break; case 41: p++; if (!(--input_len)) break; case 42: p++; if (!(--input_len)) break; case 43: p++; --input_len; //if (dcerpc->dcerpcbindbindack.ctxid == dcerpc->dcerpcbindbindack.numctxitems - dcerpc->dcerpcbindbindack.numctxitemsleft) { dcerpc->dcerpcbindbindack.uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); if (dcerpc->dcerpcbindbindack.uuid_entry == NULL) { SCLogDebug("UUID Entry is NULL\n"); SCReturnUInt(0); } dcerpc->dcerpcbindbindack.uuid_entry->internal_id = dcerpc->dcerpcbindbindack.uuid_internal_id++; memcpy(dcerpc->dcerpcbindbindack.uuid_entry->uuid, dcerpc->dcerpcbindbindack.uuid, sizeof(dcerpc->dcerpcbindbindack.uuid)); dcerpc->dcerpcbindbindack.uuid_entry->ctxid = dcerpc->dcerpcbindbindack.ctxid; dcerpc->dcerpcbindbindack.uuid_entry->version = dcerpc->dcerpcbindbindack.version; dcerpc->dcerpcbindbindack.uuid_entry->versionminor = dcerpc->dcerpcbindbindack.versionminor; /* store the first frag flag in the uuid as pfc_flags will * be overwritten by new packets. */ if (dcerpc->dcerpchdr.pfc_flags & PFC_FIRST_FRAG) { dcerpc->dcerpcbindbindack.uuid_entry->flags |= DCERPC_UUID_ENTRY_FLAG_FF; } TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.uuid_list, dcerpc->dcerpcbindbindack.uuid_entry, next); #ifdef UNITTESTS if (RunmodeIsUnittests()) { printUUID("BINDACK", dcerpc->dcerpcbindbindack.uuid_entry); } #endif dcerpc->dcerpcbindbindack.numctxitemsleft--; dcerpc->bytesprocessed += (p - input); dcerpc->dcerpcbindbindack.ctxbytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); //} else { // SCLogDebug("ctxitem %u, expected %u\n", dcerpc->dcerpcbindbindack.ctxid, // dcerpc->dcerpcbindbindack.numctxitems - dcerpc->dcerpcbindbindack.numctxitemsleft); // SCReturnUInt(0); //} break; } } dcerpc->dcerpcbindbindack.ctxbytesprocessed += (p - input); dcerpc->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } /** * \brief DCERPCParseBINDACKCTXItem is called for each CTXItem found in * the BIND_ACK call. The result (Accepted or Rejected) is added to the * correct UUID from the BIND call. */ static uint32_t DCERPCParseBINDACKCTXItem(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t *p = input; DCERPCUuidEntry *uuid_entry; if (input_len) { switch (dcerpc->dcerpcbindbindack.ctxbytesprocessed) { case 0: if (input_len >= 24) { if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.result = *p; dcerpc->dcerpcbindbindack.result |= *(p + 1) << 8; } else { dcerpc->dcerpcbindbindack.result = *p << 8; dcerpc->dcerpcbindbindack.result |= *(p + 1); } TAILQ_FOREACH(uuid_entry, &dcerpc->dcerpcbindbindack.uuid_list, next) { if (uuid_entry->internal_id == dcerpc->dcerpcbindbindack.uuid_internal_id) { uuid_entry->result = dcerpc->dcerpcbindbindack.result; #ifdef UNITTESTS if (RunmodeIsUnittests()) { printUUID("BIND_ACK", uuid_entry); } #endif if (uuid_entry->result != 0) break; dcerpc->dcerpcbindbindack.uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); if (dcerpc->dcerpcbindbindack.uuid_entry == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory\n"); exit(EXIT_FAILURE); } memcpy(dcerpc->dcerpcbindbindack.uuid_entry, uuid_entry, sizeof(DCERPCUuidEntry)); TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, dcerpc->dcerpcbindbindack.uuid_entry, next); break; } } dcerpc->dcerpcbindbindack.uuid_internal_id++; dcerpc->dcerpcbindbindack.numctxitemsleft--; dcerpc->bytesprocessed += (24); dcerpc->dcerpcbindbindack.ctxbytesprocessed += (24); SCReturnUInt(24U); } else { if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.result = *(p++); } else { dcerpc->dcerpcbindbindack.result = *(p++) << 8; } if (!(--input_len)) break; } case 1: if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.result |= *(p++) << 8; } else { dcerpc->dcerpcbindbindack.result |= *(p++); } if (!(--input_len)) break; case 2: /* num transact items */ p++; if (!(--input_len)) break; case 3: /* reserved */ p++; if (!(--input_len)) break; case 4: p++; if (!(--input_len)) break; case 5: p++; if (!(--input_len)) break; case 6: p++; if (!(--input_len)) break; case 7: p++; if (!(--input_len)) break; case 8: p++; if (!(--input_len)) break; case 9: p++; if (!(--input_len)) break; case 10: p++; if (!(--input_len)) break; case 11: p++; if (!(--input_len)) break; case 12: p++; if (!(--input_len)) break; case 13: p++; if (!(--input_len)) break; case 14: p++; if (!(--input_len)) break; case 15: p++; if (!(--input_len)) break; case 16: p++; if (!(--input_len)) break; case 17: p++; if (!(--input_len)) break; case 18: p++; if (!(--input_len)) break; case 19: p++; if (!(--input_len)) break; case 20: p++; if (!(--input_len)) break; case 21: p++; if (!(--input_len)) break; case 22: p++; if (!(--input_len)) break; case 23: TAILQ_FOREACH(uuid_entry, &dcerpc->dcerpcbindbindack.uuid_list, next) { if (uuid_entry->internal_id == dcerpc->dcerpcbindbindack.uuid_internal_id) { uuid_entry->result = dcerpc->dcerpcbindbindack.result; #ifdef UNITTESTS if (RunmodeIsUnittests()) { printUUID("BIND_ACK", uuid_entry); } #endif if (uuid_entry->result != 0) break; dcerpc->dcerpcbindbindack.uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); if (dcerpc->dcerpcbindbindack.uuid_entry == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory\n"); exit(EXIT_FAILURE); } memcpy(dcerpc->dcerpcbindbindack.uuid_entry, uuid_entry, sizeof(DCERPCUuidEntry)); TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, dcerpc->dcerpcbindbindack.uuid_entry, next); break; } } dcerpc->dcerpcbindbindack.uuid_internal_id++; dcerpc->dcerpcbindbindack.numctxitemsleft--; p++; --input_len; break; } } dcerpc->dcerpcbindbindack.ctxbytesprocessed += (p - input); dcerpc->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } static uint32_t DCERPCParseBIND(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); DCERPCUuidEntry *item; uint8_t *p = input; if (input_len) { switch (dcerpc->bytesprocessed) { case 16: dcerpc->dcerpcbindbindack.numctxitems = 0; if (input_len >= 12) { while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.uuid_list))) { TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.uuid_list, item, next); SCFree(item); } if (dcerpc->dcerpchdr.type == BIND) { while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.accepted_uuid_list))) { TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, item, next); SCFree(item); } TAILQ_INIT(&dcerpc->dcerpcbindbindack.accepted_uuid_list); } dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = *(p + 8); dcerpc->dcerpcbindbindack.numctxitemsleft = dcerpc->dcerpcbindbindack.numctxitems; TAILQ_INIT(&dcerpc->dcerpcbindbindack.uuid_list); dcerpc->bytesprocessed += 12; SCReturnUInt(12U); } else { /* max_xmit_frag */ p++; if (!(--input_len)) break; } case 17: /* max_xmit_frag */ p++; if (!(--input_len)) break; case 18: /* max_recv_frag */ p++; if (!(--input_len)) break; case 19: /* max_recv_frag */ p++; if (!(--input_len)) break; case 20: /* assoc_group_id */ p++; if (!(--input_len)) break; case 21: /* assoc_group_id */ p++; if (!(--input_len)) break; case 22: /* assoc_group_id */ p++; if (!(--input_len)) break; case 23: /* assoc_group_id */ p++; if (!(--input_len)) break; case 24: while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.uuid_list))) { TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.uuid_list, item, next); SCFree(item); } if (dcerpc->dcerpchdr.type == BIND) { while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.accepted_uuid_list))) { TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, item, next); SCFree(item); } TAILQ_INIT(&dcerpc->dcerpcbindbindack.accepted_uuid_list); } dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = *(p++); dcerpc->dcerpcbindbindack.numctxitemsleft = dcerpc->dcerpcbindbindack.numctxitems; TAILQ_INIT(&dcerpc->dcerpcbindbindack.uuid_list); if (!(--input_len)) break; case 25: /* pad byte 1 */ p++; if (!(--input_len)) break; case 26: /* pad byte 2 */ p++; if (!(--input_len)) break; case 27: /* pad byte 3 */ p++; --input_len; break; default: dcerpc->bytesprocessed++; SCReturnUInt(1); break; } } dcerpc->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } static uint32_t DCERPCParseBINDACK(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t *p = input; switch (dcerpc->bytesprocessed) { case 16: dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = 0; if (input_len >= 10) { if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.secondaryaddrlen = *(p + 8); dcerpc->dcerpcbindbindack.secondaryaddrlen |= *(p + 9) << 8; } else { dcerpc->dcerpcbindbindack.secondaryaddrlen = *(p + 8) << 8; dcerpc->dcerpcbindbindack.secondaryaddrlen |= *(p + 9); } dcerpc->dcerpcbindbindack.secondaryaddrlenleft = dcerpc->dcerpcbindbindack.secondaryaddrlen; dcerpc->bytesprocessed += 10; SCReturnUInt(10U); } else { /* max_xmit_frag */ p++; if (!(--input_len)) break; } case 17: /* max_xmit_frag */ p++; if (!(--input_len)) break; case 18: /* max_recv_frag */ p++; if (!(--input_len)) break; case 19: /* max_recv_frag */ p++; if (!(--input_len)) break; case 20: /* assoc_group_id */ p++; if (!(--input_len)) break; case 21: /* assoc_group_id */ p++; if (!(--input_len)) break; case 22: /* assoc_group_id */ p++; if (!(--input_len)) break; case 23: /* assoc_group_id */ p++; if (!(--input_len)) break; case 24: dcerpc->dcerpcbindbindack.secondaryaddrlen = *(p++) << 8; if (!(--input_len)) break; case 25: dcerpc->dcerpcbindbindack.secondaryaddrlen |= *(p++); if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcbindbindack.secondaryaddrlen = SCByteSwap16(dcerpc->dcerpcbindbindack.secondaryaddrlen); } dcerpc->dcerpcbindbindack.secondaryaddrlenleft = dcerpc->dcerpcbindbindack.secondaryaddrlen; SCLogDebug("secondaryaddrlen %u 0x%04x\n", dcerpc->dcerpcbindbindack.secondaryaddrlen, dcerpc->dcerpcbindbindack.secondaryaddrlen); --input_len; break; default: dcerpc->bytesprocessed++; SCReturnUInt(1); break; } dcerpc->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } static uint32_t DCERPCParseREQUEST(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t *p = input; switch (dcerpc->bytesprocessed) { case 16: dcerpc->dcerpcbindbindack.numctxitems = 0; if (input_len >= 8) { if (dcerpc->dcerpchdr.type == REQUEST) { if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpcrequest.ctxid = *(p + 4); dcerpc->dcerpcrequest.ctxid |= *(p + 5) << 8; dcerpc->dcerpcrequest.opnum = *(p + 6); dcerpc->dcerpcrequest.opnum |= *(p + 7) << 8; } else { dcerpc->dcerpcrequest.ctxid = *(p + 4) << 8; dcerpc->dcerpcrequest.ctxid |= *(p + 5); dcerpc->dcerpcrequest.opnum = *(p + 6) << 8; dcerpc->dcerpcrequest.opnum |= *(p + 7); } dcerpc->dcerpcrequest.first_request_seen = 1; } dcerpc->bytesprocessed += 8; SCReturnUInt(8U); } else { /* alloc hint 1 */ p++; if (!(--input_len)) break; } case 17: /* alloc hint 2 */ p++; if (!(--input_len)) break; case 18: /* alloc hint 3 */ p++; if (!(--input_len)) break; case 19: /* alloc hint 4 */ p++; if (!(--input_len)) break; case 20: /* context id 1 */ dcerpc->dcerpcrequest.ctxid = *(p++); if (!(--input_len)) break; case 21: /* context id 2 */ dcerpc->dcerpcrequest.ctxid |= *(p++) << 8; if (!(dcerpc->dcerpchdr.packed_drep[0] & 0x10)) { dcerpc->dcerpcrequest.ctxid = SCByteSwap16(dcerpc->dcerpcrequest.ctxid); } dcerpc->dcerpcrequest.first_request_seen = 1; if (!(--input_len)) break; case 22: if (dcerpc->dcerpchdr.type == REQUEST) { dcerpc->dcerpcrequest.opnum = *(p++); } else { p++; } if (!(--input_len)) break; case 23: if (dcerpc->dcerpchdr.type == REQUEST) { dcerpc->dcerpcrequest.opnum |= *(p++) << 8; if (!(dcerpc->dcerpchdr.packed_drep[0] & 0x10)) { dcerpc->dcerpcrequest.opnum = SCByteSwap16(dcerpc->dcerpcrequest.opnum); } } else { p++; } --input_len; break; default: dcerpc->bytesprocessed++; SCReturnUInt(1); break; } dcerpc->bytesprocessed += (p - input); SCReturnUInt((uint32_t)(p - input)); } static uint32_t StubDataParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t **stub_data_buffer = NULL; uint32_t *stub_data_buffer_len = NULL; uint8_t *stub_data_fresh = NULL; uint16_t stub_len = 0; /* request PDU. Retrieve the request stub buffer */ if (dcerpc->dcerpchdr.type == REQUEST) { stub_data_buffer = &dcerpc->dcerpcrequest.stub_data_buffer; stub_data_buffer_len = &dcerpc->dcerpcrequest.stub_data_buffer_len; stub_data_fresh = &dcerpc->dcerpcrequest.stub_data_fresh; /* response PDU. Retrieve the response stub buffer */ } else { stub_data_buffer = &dcerpc->dcerpcresponse.stub_data_buffer; stub_data_buffer_len = &dcerpc->dcerpcresponse.stub_data_buffer_len; stub_data_fresh = &dcerpc->dcerpcresponse.stub_data_fresh; } stub_len = (dcerpc->padleft < input_len) ? dcerpc->padleft : input_len; if (stub_len == 0) { SCLogError(SC_ERR_DCERPC, "stub_len is NULL. We shouldn't be seeing " "this. In case you are, there is something gravely wrong " "with the dcerpc parser"); SCReturnInt(0); } /* To see what is in this stub fragment */ //hexdump(input, stub_len); /* if the frag is the the first frag irrespective of it being a part of * a multi frag PDU or not, it indicates the previous PDU's stub would * have been buffered and processed and we can use the buffer to hold * frags from a fresh request/response. Also if the state is in the * process of processing a fragmented pdu, we should append to the * existing stub and not reset the stub buffer */ if ((dcerpc->dcerpchdr.pfc_flags & PFC_FIRST_FRAG) && !dcerpc->pdu_fragged) { *stub_data_buffer_len = 0; /* just a hack to get thing working. We shouldn't be setting * this var here. The ideal thing would have been to use * an extra state var, to indicate that the stub parser has made a * fresh entry after reseting the buffer, but maintaing an extra var * would be a nuisance, while we can achieve the same thing with * little or no effort, with a simple set here, although semantically * it is a wrong thing to set it here, since we still can't conclude * if a pdu is fragmented or not at this point, if we are parsing a PDU * that has some stub data in the first segment, but it still doesn't * contain the entire PDU */ dcerpc->pdu_fragged = 1; } *stub_data_buffer = SCRealloc(*stub_data_buffer, *stub_data_buffer_len + stub_len); if (*stub_data_buffer == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); goto end; } memcpy(*stub_data_buffer + *stub_data_buffer_len, input, stub_len); *stub_data_fresh = 1; /* length of the buffered stub */ *stub_data_buffer_len += stub_len; /* To see the total reassembled stubdata */ //hexdump(*stub_data_buffer, *stub_data_buffer_len); dcerpc->padleft -= stub_len; dcerpc->bytesprocessed += stub_len; #ifdef DEBUG if (SCLogDebugEnabled()) { int i = 0; for (i = 0; i < stub_len; i++) { SCLogDebug("0x%02x ", input[i]); } } #endif end: SCReturnUInt((uint32_t)stub_len); } /** * \brief DCERPCParseHeader parses the 16 byte DCERPC header * A fast path for normal decoding is used when there is enough bytes * present to parse the entire header. A slow path is used to parse * fragmented packets. * \retval -1 if DCERPC Header does not validate * \retval Number of bytes processed */ static int DCERPCParseHeader(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint8_t *p = input; if (input_len) { SCLogDebug("dcerpc->bytesprocessed %u", dcerpc->bytesprocessed); switch (dcerpc->bytesprocessed) { case 0: if (input_len >= DCERPC_HDR_LEN) { dcerpc->dcerpchdr.rpc_vers = *p; dcerpc->dcerpchdr.rpc_vers_minor = *(p + 1); if ((dcerpc->dcerpchdr.rpc_vers != 5) || ((dcerpc->dcerpchdr.rpc_vers_minor != 0) && (dcerpc->dcerpchdr.rpc_vers_minor != 1))) { SCLogDebug("DCERPC Header did not validate"); SCReturnInt(-1); } dcerpc->dcerpchdr.type = *(p + 2); SCLogDebug("dcerpc->dcerpchdr.type %02x", dcerpc->dcerpchdr.type); dcerpc->dcerpchdr.pfc_flags = *(p + 3); dcerpc->dcerpchdr.packed_drep[0] = *(p + 4); dcerpc->dcerpchdr.packed_drep[1] = *(p + 5); dcerpc->dcerpchdr.packed_drep[2] = *(p + 6); dcerpc->dcerpchdr.packed_drep[3] = *(p + 7); if (dcerpc->dcerpchdr.packed_drep[0] & 0x10) { dcerpc->dcerpchdr.frag_length = *(p + 8); dcerpc->dcerpchdr.frag_length |= *(p + 9) << 8; dcerpc->dcerpchdr.auth_length = *(p + 10); dcerpc->dcerpchdr.auth_length |= *(p + 11) << 8; dcerpc->dcerpchdr.call_id = *(p + 12) << 24; dcerpc->dcerpchdr.call_id |= *(p + 13) << 16; dcerpc->dcerpchdr.call_id |= *(p + 14) << 8; dcerpc->dcerpchdr.call_id |= *(p + 15); } else { dcerpc->dcerpchdr.frag_length = *(p + 8) << 8; dcerpc->dcerpchdr.frag_length |= *(p + 9); dcerpc->dcerpchdr.auth_length = *(p + 10) << 8; dcerpc->dcerpchdr.auth_length |= *(p + 11); dcerpc->dcerpchdr.call_id = *(p + 12); dcerpc->dcerpchdr.call_id |= *(p + 13) << 8; dcerpc->dcerpchdr.call_id |= *(p + 14) << 16; dcerpc->dcerpchdr.call_id |= *(p + 15) << 24; } dcerpc->bytesprocessed = DCERPC_HDR_LEN; SCReturnInt(16); break; } else { dcerpc->dcerpchdr.rpc_vers = *(p++); if (!(--input_len)) break; } case 1: dcerpc->dcerpchdr.rpc_vers_minor = *(p++); if ((dcerpc->dcerpchdr.rpc_vers != 5) || ((dcerpc->dcerpchdr.rpc_vers_minor != 0) && (dcerpc->dcerpchdr.rpc_vers_minor != 1))) { SCLogDebug("DCERPC Header did not validate"); SCReturnInt(-1); } if (!(--input_len)) break; case 2: dcerpc->dcerpchdr.type = *(p++); SCLogDebug("dcerpc->dcerpchdr.type %02x", dcerpc->dcerpchdr.type); if (!(--input_len)) break; case 3: dcerpc->dcerpchdr.pfc_flags = *(p++); if (!(--input_len)) break; case 4: dcerpc->dcerpchdr.packed_drep[0] = *(p++); if (!(--input_len)) break; case 5: dcerpc->dcerpchdr.packed_drep[1] = *(p++); if (!(--input_len)) break; case 6: dcerpc->dcerpchdr.packed_drep[2] = *(p++); if (!(--input_len)) break; case 7: dcerpc->dcerpchdr.packed_drep[3] = *(p++); if (!(--input_len)) break; case 8: dcerpc->dcerpchdr.frag_length = *(p++); if (!(--input_len)) break; case 9: dcerpc->dcerpchdr.frag_length |= *(p++) << 8; if (!(--input_len)) break; case 10: dcerpc->dcerpchdr.auth_length = *(p++); if (!(--input_len)) break; case 11: dcerpc->dcerpchdr.auth_length |= *(p++) << 8; if (!(--input_len)) break; case 12: dcerpc->dcerpchdr.call_id = *(p++); if (!(--input_len)) break; case 13: dcerpc->dcerpchdr.call_id |= *(p++) << 8; if (!(--input_len)) break; case 14: dcerpc->dcerpchdr.call_id |= *(p++) << 16; if (!(--input_len)) break; case 15: dcerpc->dcerpchdr.call_id |= *(p++) << 24; if (!(dcerpc->dcerpchdr.packed_drep[0] & 0x10)) { dcerpc->dcerpchdr.frag_length = SCByteSwap16(dcerpc->dcerpchdr.frag_length); dcerpc->dcerpchdr.auth_length = SCByteSwap16(dcerpc->dcerpchdr.auth_length); dcerpc->dcerpchdr.call_id = SCByteSwap32(dcerpc->dcerpchdr.call_id); } --input_len; break; default: dcerpc->bytesprocessed++; SCReturnInt(1); } } dcerpc->bytesprocessed += (p - input); SCReturnInt((p - input)); } static inline void DCERPCResetParsingState(DCERPC *dcerpc) { dcerpc->bytesprocessed = 0; dcerpc->pdu_fragged = 0; dcerpc->dcerpcbindbindack.ctxbytesprocessed = 0; return; } static inline void DCERPCResetStub(DCERPC *dcerpc) { if (dcerpc->dcerpchdr.type == REQUEST) dcerpc->dcerpcrequest.stub_data_buffer_len = 0; else if (dcerpc->dcerpchdr.type == RESPONSE) dcerpc->dcerpcresponse.stub_data_buffer_len = 0; return; } static inline int DCERPCThrowOutExtraData(DCERPC *dcerpc, uint8_t *input, uint16_t input_len) { int parsed = 0; /* the function always assumes that * dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length */ if (input_len > (dcerpc->dcerpchdr.frag_length - dcerpc->bytesprocessed)) { parsed = dcerpc->dcerpchdr.frag_length - dcerpc->bytesprocessed; } else { parsed = input_len; } dcerpc->bytesprocessed += parsed; return parsed; } /** * \todo - Currently the parser is very generic. Enable target based * reassembly. * - Disable reiniting tailq for mid and last bind/alter_context pdus. * - Use a PM to search for subsequent 05 00 when we see an inconsistent * pdu. This should be done for each platform based on how it handles * a condition where it has receives a segment with 2 pdus, while the * first pdu in the segment is corrupt. */ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); uint32_t retval = 0; uint32_t parsed = 0; int hdrretval = 0; dcerpc->dcerpcrequest.stub_data_fresh = 0; dcerpc->dcerpcresponse.stub_data_fresh = 0; /* temporary use. we will get rid of this later, once we have ironed out * all the endless loops cases */ int counter = 0; while (input_len) { /* in case we have any corner cases remainging, we have this */ if (counter++ == 30) { SCLogDebug("Somehow seem to be stuck inside the dce " "parser for quite sometime. Let's get out of here."); DCERPCResetParsingState(dcerpc); SCReturnInt(0); } while (dcerpc->bytesprocessed < DCERPC_HDR_LEN && input_len) { hdrretval = DCERPCParseHeader(dcerpc, input + parsed, input_len); if (hdrretval == -1 || hdrretval > (int32_t)input_len) { SCLogDebug("Error parsing dce header. Discarding " "PDU and reseting parsing state to parse next PDU"); /* error parsing pdu header. Let's clear the dce state */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } else { parsed += hdrretval; input_len -= hdrretval; } } SCLogDebug("Done with DCERPCParseHeader bytesprocessed %u/%u left %u", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, input_len); #if 0 printf("Done with DCERPCParseHeader bytesprocessed %u/%u input_len left %u\n", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, input_len); printf("\nDCERPC Version:\t%u\n", dcerpc->dcerpchdr.rpc_vers); printf("DCERPC Version Minor:\t%u\n", dcerpc->dcerpchdr.rpc_vers_minor); printf("DCERPC Type:\t%u\n", dcerpc->dcerpchdr.type); printf("DCERPC Flags:\t0x%02x\n", dcerpc->dcerpchdr.pfc_flags); printf("DCERPC Packed Drep:\t%02x %02x %02x %02x\n", dcerpc->dcerpchdr.packed_drep[0], dcerpc->dcerpchdr.packed_drep[1], dcerpc->dcerpchdr.packed_drep[2], dcerpc->dcerpchdr.packed_drep[3]); printf("DCERPC Frag Length:\t0x%04x %u\n", dcerpc->dcerpchdr.frag_length, dcerpc->dcerpchdr.frag_length); printf("DCERPC Auth Length:\t0x%04x\n", dcerpc->dcerpchdr.auth_length); printf("DCERPC Call Id:\t0x%08x\n", dcerpc->dcerpchdr.call_id); #endif /* check if we have parsed the entire input passed in the header parser. * If we have, time to leave */ if (input_len == 0) { if (dcerpc->bytesprocessed < 10) { /* if the parser is known to be fragmented at this stage itself, * we reset the stub buffer here itself */ if (!dcerpc->pdu_fragged && (dcerpc->dcerpchdr.pfc_flags & PFC_FIRST_FRAG)) { DCERPCResetStub(dcerpc); } dcerpc->pdu_fragged = 1; } else { if (dcerpc->bytesprocessed >= dcerpc->dcerpchdr.frag_length) { SCLogDebug("Weird DCE PDU"); DCERPCResetParsingState(dcerpc); } else { /* if the parser is known to be fragmented at this stage itself, * we reset the stub buffer here itself */ if (!dcerpc->pdu_fragged && (dcerpc->dcerpchdr.pfc_flags & PFC_FIRST_FRAG)) { DCERPCResetStub(dcerpc); } dcerpc->pdu_fragged = 1; } } SCReturnInt(parsed); } switch (dcerpc->dcerpchdr.type) { case BIND: case ALTER_CONTEXT: while (dcerpc->bytesprocessed < DCERPC_HDR_LEN + 12 && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && input_len) { retval = DCERPCParseBIND(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; } else if (input_len) { SCLogDebug("Error Parsing DCERPC %s PDU", (dcerpc->dcerpchdr.type == BIND) ? "BIND" : "ALTER_CONTEXT"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } SCLogDebug("Done with DCERPCParseBIND bytesprocessed %u/%u numctxitems %u", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, dcerpc->dcerpcbindbindack.numctxitems); while (dcerpc->dcerpcbindbindack.numctxitemsleft && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && input_len) { retval = DCERPCParseBINDCTXItem(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { if (dcerpc->dcerpcbindbindack.ctxbytesprocessed == 44) { dcerpc->dcerpcbindbindack.ctxbytesprocessed = 0; } parsed += retval; input_len -= retval; SCLogDebug("BIND processed %u/%u ctxitems %u/%u input_len left %u\n", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, dcerpc->dcerpcbindbindack.numctxitemsleft, dcerpc->dcerpcbindbindack.numctxitems, input_len); } else if (input_len) { //parsed -= input_len; SCLogDebug("Error Parsing CTX Item %u\n", parsed); parsed = 0; input_len = 0; dcerpc->dcerpcbindbindack.numctxitemsleft = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } if (dcerpc->bytesprocessed == dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); } else if (dcerpc->bytesprocessed > dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); SCReturnInt(0); } else { /* temporary fix */ if (input_len) { retval = DCERPCThrowOutExtraData(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { input_len -= retval; parsed += retval; if (dcerpc->bytesprocessed == dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); } else { dcerpc->pdu_fragged = 1; } } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } else { dcerpc->pdu_fragged = 1; } } break; case BIND_ACK: case ALTER_CONTEXT_RESP: while (dcerpc->bytesprocessed < DCERPC_HDR_LEN + 9 && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && input_len) { retval = DCERPCParseBINDACK(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; SCLogDebug("DCERPCParseBINDACK processed %u/%u input_len left %u", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, input_len); } else if (input_len) { SCLogDebug("Error parsing %s\n", (dcerpc->dcerpchdr.type == BIND_ACK) ? "BIND_ACK" : "ALTER_CONTEXT_RESP"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } while (dcerpc->bytesprocessed < DCERPC_HDR_LEN + 10 + dcerpc->dcerpcbindbindack.secondaryaddrlen && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && input_len) { retval = DCERPCParseSecondaryAddr(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; SCLogDebug("DCERPCParseSecondaryAddr %u/%u left %u secondaryaddr len(%u)", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, input_len, dcerpc->dcerpcbindbindack.secondaryaddrlen); } else if (input_len) { SCLogDebug("Error parsing Secondary Address"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } if (dcerpc->bytesprocessed == DCERPC_HDR_LEN + 10 + dcerpc->dcerpcbindbindack.secondaryaddrlen) { if (dcerpc->bytesprocessed % 4) { dcerpc->pad = (4 - dcerpc->bytesprocessed % 4); dcerpc->padleft = dcerpc->pad; } } while (dcerpc->bytesprocessed < DCERPC_HDR_LEN + 10 + dcerpc->dcerpcbindbindack.secondaryaddrlen + dcerpc->pad && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && input_len) { retval = PaddingParser(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; SCLogDebug("PaddingParser %u/%u left %u pad(%u)", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, input_len, dcerpc->pad); } else if (input_len) { SCLogDebug("Error parsing DCERPC Padding"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } while (dcerpc->bytesprocessed >= DCERPC_HDR_LEN + 10 + dcerpc->pad + dcerpc->dcerpcbindbindack.secondaryaddrlen && dcerpc->bytesprocessed < DCERPC_HDR_LEN + 14 + dcerpc->pad + dcerpc->dcerpcbindbindack.secondaryaddrlen && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && input_len) { retval = DCERPCGetCTXItems(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; SCLogDebug("DCERPCGetCTXItems %u/%u (%u)", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, dcerpc->dcerpcbindbindack.numctxitems); } else if (input_len) { SCLogDebug("Error parsing CTX Items"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } if (dcerpc->bytesprocessed == DCERPC_HDR_LEN + 14 + dcerpc->pad + dcerpc->dcerpcbindbindack.secondaryaddrlen) { dcerpc->dcerpcbindbindack.ctxbytesprocessed = 0; } while (dcerpc->dcerpcbindbindack.numctxitemsleft && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && input_len) { retval = DCERPCParseBINDACKCTXItem(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { if (dcerpc->dcerpcbindbindack.ctxbytesprocessed == 24) { dcerpc->dcerpcbindbindack.ctxbytesprocessed = 0; } parsed += retval; input_len -= retval; } else if (input_len) { SCLogDebug("Error parsing CTX Items"); parsed = 0; input_len = 0; dcerpc->dcerpcbindbindack.numctxitemsleft = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } SCLogDebug("BINDACK processed %u/%u input_len left %u", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, input_len); if (dcerpc->bytesprocessed == dcerpc->dcerpchdr.frag_length) { /* response and request done */ if (dcerpc->dcerpchdr.type == BIND_ACK) { /* update transaction id */ dcerpc->transaction_id++; SCLogDebug("transaction_id updated to %"PRIu16, dcerpc->transaction_id); } DCERPCResetParsingState(dcerpc); } else if (dcerpc->bytesprocessed > dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); SCReturnInt(0); } else { /* temporary fix */ if (input_len) { retval = DCERPCThrowOutExtraData(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { input_len -= retval; parsed += retval; if (dcerpc->bytesprocessed == dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); } else { dcerpc->pdu_fragged = 1; } } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } else { dcerpc->pdu_fragged = 1; } } break; case REQUEST: case RESPONSE: while (dcerpc->bytesprocessed < DCERPC_HDR_LEN + 8 && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && input_len) { retval = DCERPCParseREQUEST(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; dcerpc->padleft = dcerpc->dcerpchdr.frag_length - dcerpc->bytesprocessed; } else if (input_len) { SCLogDebug("Error parsing DCERPC %s", (dcerpc->dcerpchdr.type == REQUEST) ? "REQUEST" : "RESPONSE"); parsed = 0; dcerpc->padleft = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } while (dcerpc->bytesprocessed >= DCERPC_HDR_LEN + 8 && dcerpc->bytesprocessed < dcerpc->dcerpchdr.frag_length && dcerpc->padleft && input_len) { retval = StubDataParser(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { parsed += retval; input_len -= retval; } else if (input_len) { SCLogDebug("Error parsing DCERPC Stub Data"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } if (dcerpc->dcerpchdr.type == REQUEST) { SCLogDebug("REQUEST processed %u frag length %u opnum %u input_len %u", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, dcerpc->dcerpcrequest.opnum, input_len); } else { SCLogDebug("RESPONSE processed %u frag length %u opnum %u input_len %u", dcerpc->bytesprocessed, dcerpc->dcerpchdr.frag_length, dcerpc->dcerpcrequest.opnum, input_len); } /* don't see how we could break the parser for request pdus, by * pusing bytesprocessed beyond frag_length. Let's have the * check anyways */ if (dcerpc->bytesprocessed == dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); } else if (dcerpc->bytesprocessed > dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); SCReturnInt(0); } else { if (!dcerpc->pdu_fragged && (dcerpc->dcerpchdr.pfc_flags & PFC_FIRST_FRAG)) { DCERPCResetStub(dcerpc); } /* temporary fix */ if (input_len) { retval = DCERPCThrowOutExtraData(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { input_len -= retval; parsed += retval; if (dcerpc->bytesprocessed == dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); } else { dcerpc->pdu_fragged = 1; } } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } } else { dcerpc->pdu_fragged = 1; } } /* response and request done */ if (dcerpc->dcerpchdr.type == RESPONSE) { /* update transaction id */ dcerpc->transaction_id++; SCLogDebug("transaction_id updated to %"PRIu16, dcerpc->transaction_id); } break; default: SCLogDebug("DCERPC Type 0x%02x not implemented yet", dcerpc->dcerpchdr.type); retval = DCERPCThrowOutExtraData(dcerpc, input + parsed, input_len); if (retval && retval <= input_len) { input_len -= retval; parsed += retval; if (dcerpc->bytesprocessed == dcerpc->dcerpchdr.frag_length) { DCERPCResetParsingState(dcerpc); } else { dcerpc->pdu_fragged = 1; } } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; input_len = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); } break; } } SCReturnInt(parsed); } static int DCERPCParse(Flow *f, void *dcerpc_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output, int dir) { SCEnter(); int32_t retval = 0; DCERPCState *sstate = (DCERPCState *) dcerpc_state; if (sstate->dcerpc.bytesprocessed != 0 && sstate->data_needed_for_dir != dir) { SCReturnInt(-1); } retval = DCERPCParser(&sstate->dcerpc, input, input_len); if (retval == -1) { SCReturnInt(0); } sstate->data_needed_for_dir = dir; if (pstate == NULL) SCReturnInt(-1); pstate->parse_field = 0; SCReturnInt(1); } static int DCERPCParseRequest(Flow *f, void *dcerpc_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { return DCERPCParse(f, dcerpc_state, pstate, input, input_len, local_data, output, 0); } static int DCERPCParseResponse(Flow *f, void *dcerpc_state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { return DCERPCParse(f, dcerpc_state, pstate, input, input_len, local_data, output, 1); } static void *DCERPCStateAlloc(void) { SCEnter(); DCERPCState *s = SCMalloc(sizeof(DCERPCState)); if (unlikely(s == NULL)) { SCReturnPtr(NULL, "void"); } memset(s, 0, sizeof(DCERPCState)); s->dcerpc.transaction_id = 1; SCReturnPtr((void *)s, "void"); } static void DCERPCStateFree(void *s) { DCERPCState *sstate = (DCERPCState *) s; DCERPCUuidEntry *item; while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.uuid_list))) { //printUUID("Free", item); TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.uuid_list, item, next); SCFree(item); } while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.accepted_uuid_list))) { //printUUID("Free", item); TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.accepted_uuid_list, item, next); SCFree(item); } if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; sstate->dcerpc.dcerpcrequest.stub_data_buffer_len = 0; } if (sstate->dcerpc.dcerpcresponse.stub_data_buffer != NULL) { SCFree(sstate->dcerpc.dcerpcresponse.stub_data_buffer); sstate->dcerpc.dcerpcresponse.stub_data_buffer = NULL; sstate->dcerpc.dcerpcresponse.stub_data_buffer_len = 0; } if (s) { SCFree(s); s = NULL; } } /** * \brief Update the transaction id based on the DCERPC state */ void DCERPCUpdateTransactionId(void *state, uint16_t *id) { SCEnter(); DCERPCState *s = (DCERPCState *)state; SCLogDebug("original id %"PRIu16, *id); (*id) = s->dcerpc.transaction_id; SCLogDebug("updated id %"PRIu16, *id); SCReturn; } void RegisterDCERPCParsers(void) { char *proto_name = "dcerpc"; /** DCERPC */ AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_DCERPC, "|05 00|", 2, 0, STREAM_TOSERVER); AppLayerRegisterProto(proto_name, ALPROTO_DCERPC, STREAM_TOSERVER, DCERPCParseRequest); AppLayerRegisterProto(proto_name, ALPROTO_DCERPC, STREAM_TOCLIENT, DCERPCParseResponse); AppLayerRegisterStateFuncs(ALPROTO_DCERPC, DCERPCStateAlloc, DCERPCStateFree); AppLayerRegisterTransactionIdFuncs(ALPROTO_DCERPC, DCERPCUpdateTransactionId, NULL); } /* UNITTESTS */ #ifdef UNITTESTS /** \test DCERPC Header Parsing and BIND / BIND_ACK multiple UUID handling */ /* set this to 1 to see problem */ int DCERPCParserTest01(void) { int result = 1; Flow f; uint8_t dcerpcbind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2c, 0xd0, 0x28, 0xda, 0x76, 0x91, 0xf6, 0x6e, 0xcb, 0x0f, 0xbf, 0x85, 0xcd, 0x9b, 0xf6, 0x39, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x2c, 0x75, 0xce, 0x7e, 0x82, 0x3b, 0x06, 0xac, 0x1b, 0xf0, 0xf5, 0xb7, 0xa7, 0xf7, 0x28, 0xaf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0xe3, 0xb2, 0x10, 0xd1, 0xd0, 0x0c, 0xcc, 0x3d, 0x2f, 0x80, 0x20, 0x7c, 0xef, 0xe7, 0x09, 0xe0, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xde, 0x85, 0x70, 0xc4, 0x02, 0x7c, 0x60, 0x23, 0x67, 0x0c, 0x22, 0xbf, 0x18, 0x36, 0x79, 0x17, 0x01, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x41, 0x65, 0x29, 0x51, 0xaa, 0xe7, 0x7b, 0xa8, 0xf2, 0x37, 0x0b, 0xd0, 0x3f, 0xb3, 0x36, 0xed, 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x14, 0x96, 0x80, 0x01, 0x2e, 0x78, 0xfb, 0x5d, 0xb4, 0x3c, 0x14, 0xb3, 0x3d, 0xaa, 0x02, 0xfb, 0x06, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x3b, 0x04, 0x68, 0x3e, 0x63, 0xfe, 0x9f, 0xd8, 0x64, 0x55, 0xcd, 0xe7, 0x39, 0xaf, 0x98, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x16, 0x7a, 0x4f, 0x1b, 0xdb, 0x25, 0x92, 0x55, 0xdd, 0xae, 0x9e, 0x5b, 0x3e, 0x93, 0x66, 0x93, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0xe8, 0xa4, 0x8a, 0xcf, 0x95, 0x6c, 0xc7, 0x8f, 0x14, 0xcc, 0x56, 0xfc, 0x7b, 0x5f, 0x4f, 0xe8, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xd8, 0xda, 0xfb, 0xbc, 0xa2, 0x55, 0x6f, 0x5d, 0xc0, 0x2d, 0x88, 0x6f, 0x00, 0x17, 0x52, 0x8d, 0x06, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x3f, 0x17, 0x55, 0x0c, 0xf4, 0x23, 0x3c, 0xca, 0xe6, 0xa0, 0xaa, 0xcc, 0xb5, 0xe3, 0xf9, 0xce, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0xc9, 0x9f, 0x3e, 0x6e, 0x82, 0x0a, 0x2b, 0x28, 0x37, 0x78, 0xe1, 0x13, 0x70, 0x05, 0x38, 0x4d, 0x01, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x11, 0xaa, 0x4b, 0x15, 0xdf, 0xa6, 0x86, 0x3f, 0xfb, 0xe0, 0x09, 0xb7, 0xf8, 0x56, 0xd2, 0x3f, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0xee, 0x99, 0xc4, 0x25, 0x11, 0xe4, 0x95, 0x62, 0x29, 0xfa, 0xfd, 0x26, 0x57, 0x02, 0xf1, 0xce, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0xba, 0x81, 0x9e, 0x1a, 0xdf, 0x2b, 0xba, 0xe4, 0xd3, 0x17, 0x41, 0x60, 0x6d, 0x2d, 0x9e, 0x28, 0x03, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0xa0, 0x24, 0x03, 0x9a, 0xa9, 0x99, 0xfb, 0xbe, 0x49, 0x11, 0xad, 0x77, 0x30, 0xaa, 0xbc, 0xb6, 0x02, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x32, 0x04, 0x7e, 0xae, 0xec, 0x28, 0xd1, 0x55, 0x83, 0x4e, 0xc3, 0x47, 0x5d, 0x1d, 0xc6, 0x65, 0x02, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, 0xc6, 0xa4, 0x81, 0x48, 0x66, 0x2a, 0x74, 0x7d, 0x56, 0x6e, 0xc5, 0x1d, 0x19, 0xf2, 0xb5, 0xb6, 0x03, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0xcb, 0xae, 0xb3, 0xc0, 0x0c, 0xf4, 0xa4, 0x5e, 0x91, 0x72, 0xdd, 0x53, 0x24, 0x70, 0x89, 0x02, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0xb8, 0xd0, 0xa0, 0x1a, 0x5e, 0x7a, 0x2d, 0xfe, 0x35, 0xc6, 0x7d, 0x08, 0x0d, 0x33, 0x73, 0x18, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x01, 0x00, 0x21, 0xd3, 0xaa, 0x09, 0x03, 0xa7, 0x0b, 0xc2, 0x06, 0x45, 0xd9, 0x6c, 0x75, 0xc2, 0x15, 0xa8, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0xe1, 0xbd, 0x59, 0xfc, 0xbc, 0xa9, 0x95, 0xc2, 0x68, 0x79, 0xf3, 0x75, 0xe0, 0xae, 0x6c, 0xe5, 0x04, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00, 0x06, 0x52, 0xb4, 0x71, 0x70, 0x15, 0x4e, 0xf5, 0x7f, 0x08, 0x86, 0x14, 0xe6, 0x17, 0xd5, 0x97, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00}; uint8_t dcerpcbindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x6c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0xce, 0x47, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0xf6, 0x6e, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t dcerpcrequest[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x4d, 0x00, 0x73, 0x00, 0x53, 0x00, 0x59, 0x00, 0x2a, 0x00, 0x4a, 0x00, 0x7a, 0x00, 0x3e, 0x00, 0x58, 0x00, 0x21, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x41, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x24, 0x00, 0x38, 0x00, 0x54, 0x00, 0x60, 0x00, 0x2d, 0x00, 0x29, 0x00, 0x64, 0x00, 0x5b, 0x00, 0x77, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x23, 0x00, 0x66, 0x00, 0x43, 0x00, 0x68, 0x00, 0x22, 0x00, 0x55, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x4f, 0x00, 0x5a, 0x00, 0x50, 0x00, 0x61, 0x00, 0x2a, 0x00, 0x6f, 0x00, 0x2f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x68, 0x00, 0x68, 0x00, 0x49, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x72, 0x00, 0x53, 0x00, 0x4c, 0x00, 0x25, 0x00, 0x4d, 0x00, 0x67, 0x00, 0x2e, 0x00, 0x4f, 0x00, 0x64, 0x00, 0x61, 0x00, 0x73, 0x00, 0x24, 0x00, 0x46, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x33, 0x00, 0x38, 0x00, 0x47, 0x00, 0x71, 0x00, 0x5a, 0x00, 0x37, 0x00, 0x7a, 0x00, 0x35, 0x00, 0x6b, 0x00, 0x3c, 0x00, 0x26, 0x00, 0x37, 0x00, 0x69, 0x00, 0x75, 0x00, 0x36, 0x00, 0x37, 0x00, 0x47, 0x00, 0x21, 0x00, 0x2d, 0x00, 0x69, 0x00, 0x37, 0x00, 0x78, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x4b, 0x00, 0x5c, 0x00, 0x74, 0x00, 0x3e, 0x00, 0x52, 0x00, 0x7a, 0x00, 0x49, 0x00, 0x31, 0x00, 0x5a, 0x00, 0x7b, 0x00, 0x29, 0x00, 0x3b, 0x00, 0x78, 0x00, 0x3b, 0x00, 0x55, 0x00, 0x3e, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x59, 0x00, 0x6b, 0x00, 0x42, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x6a, 0x00, 0x49, 0x00, 0x2c, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x35, 0x00, 0x4f, 0x00, 0x49, 0x00, 0x55, 0x00, 0x35, 0x00, 0x61, 0x00, 0x72, 0x00, 0x77, 0x00, 0x38, 0x00, 0x32, 0x00, 0x24, 0x00, 0x46, 0x00, 0x32, 0x00, 0x32, 0x00, 0x27, 0x00, 0x64, 0x00, 0x5a, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x28, 0x00, 0x63, 0x00, 0x4f, 0x00, 0x67, 0x00, 0x64, 0x00, 0x39, 0x00, 0x37, 0x00, 0x31, 0x00, 0x30, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x3e, 0x00, 0x59, 0x00, 0x28, 0x00, 0x67, 0x00, 0x52, 0x00, 0x35, 0x00, 0x5a, 0x00, 0x7c, 0x00, 0x56, 0x00, 0x6a, 0x00, 0x5c, 0x00, 0x3c, 0x00, 0x30, 0x00, 0x59, 0x00, 0x5c, 0x00, 0x5e, 0x00, 0x38, 0x00, 0x54, 0x00, 0x5c, 0x00, 0x5b, 0x00, 0x42, 0x00, 0x62, 0x00, 0x70, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x7a, 0x00, 0x4b, 0x00, 0x2f, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x41, 0x00, 0x33, 0x00, 0x52, 0x00, 0x36, 0x00, 0x27, 0x00, 0x30, 0x00, 0x6d, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x78, 0x00, 0x46, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x29, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x72, 0x00, 0x71, 0x00, 0x75, 0x00, 0x4c, 0x00, 0x2b, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x52, 0x00, 0x7b, 0x00, 0x5c, 0x00, 0x69, 0x00, 0x66, 0x00, 0x56, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x72, 0x00, 0x61, 0x00, 0x68, 0x00, 0x28, 0x00, 0x7d, 0x00, 0x58, 0x00, 0x2a, 0x00, 0x7b, 0x00, 0x28, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x3a, 0x00, 0x26, 0x00, 0x52, 0x00, 0x44, 0x00, 0x60, 0x00, 0x50, 0x00, 0x65, 0x00, 0x48, 0x00, 0x7d, 0x00, 0x2a, 0x00, 0x74, 0x00, 0x49, 0x00, 0x7b, 0x00, 0x21, 0x00, 0x61, 0x00, 0x52, 0x00, 0x43, 0x00, 0x5f, 0x00, 0x5a, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x62, 0x00, 0x68, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x2b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x42, 0x00, 0x67, 0x00, 0x32, 0x00, 0x58, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2f, 0x00, 0x2d, 0x00, 0x60, 0x00, 0x62, 0x00, 0x51, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x31, 0x00, 0x48, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x25, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x76, 0x00, 0x32, 0x00, 0x62, 0x00, 0x27, 0x00, 0x42, 0x00, 0x40, 0x00, 0x53, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x50, 0x00, 0x3d, 0x00, 0x40, 0x00, 0x76, 0x00, 0x38, 0x00, 0x58, 0x00, 0x39, 0x00, 0x63, 0x00, 0x3c, 0x00, 0x5b, 0x00, 0x23, 0x00, 0x53, 0x00, 0x7a, 0x00, 0x54, 0x00, 0x74, 0x00, 0x61, 0x00, 0x76, 0x00, 0x4a, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x75, 0x00, 0x66, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x33, 0x00, 0x71, 0x00, 0x76, 0x00, 0x48, 0x00, 0x71, 0x00, 0x41, 0x00, 0x6f, 0x00, 0x2a, 0x00, 0x67, 0x00, 0x70, 0x00, 0x21, 0x00, 0x70, 0x00, 0x4b, 0x00, 0x52, 0x00, 0x58, 0x00, 0x68, 0x00, 0x23, 0x00, 0x39, 0x00, 0x46, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x57, 0x00, 0x3a, 0x00, 0x79, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x55, 0x00, 0x33, 0x00, 0x65, 0x00, 0x49, 0x00, 0x72, 0x00, 0x30, 0x00, 0x4f, 0x00, 0x41, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x4a, 0x00, 0x60, 0x00, 0x79, 0x00, 0x70, 0x00, 0x4f, 0x00, 0x58, 0x00, 0x75, 0x00, 0x44, 0x00, 0x59, 0x00, 0x58, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x74, 0x00, 0x51, 0x00, 0x57, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x23, 0x00, 0x45, 0x00, 0x60, 0x00, 0x4c, 0x00, 0x72, 0x00, 0x4e, 0x00, 0x74, 0x00, 0x40, 0x00, 0x76, 0x00, 0x75, 0x00, 0x74, 0x00, 0x56, 0x00, 0x44, 0x00, 0x29, 0x00, 0x62, 0x00, 0x58, 0x00, 0x31, 0x00, 0x78, 0x00, 0x32, 0x00, 0x52, 0x00, 0x4a, 0x00, 0x6b, 0x00, 0x55, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x7d, 0x00, 0x68, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x21, 0x00, 0x53, 0x00, 0x48, 0x00, 0x5a, 0x00, 0x34, 0x00, 0x36, 0x00, 0x35, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x75, 0x00, 0x69, 0x00, 0x23, 0x00, 0x75, 0x00, 0x55, 0x00, 0x43, 0x00, 0x75, 0x00, 0x2f, 0x00, 0x73, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x37, 0x00, 0x4e, 0x00, 0x25, 0x00, 0x25, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x71, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x36, 0x00, 0x62, 0x00, 0x63, 0x00, 0x53, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x61, 0x00, 0x4c, 0x00, 0x28, 0x00, 0x2b, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x66, 0x00, 0x5f, 0x00, 0x4b, 0x00, 0x43, 0x00, 0x75, 0x00, 0x45, 0x00, 0x37, 0x00, 0x28, 0x00, 0x56, 0x00, 0x36, 0x00, 0x6a, 0x00, 0x3e, 0x00, 0x64, 0x00, 0x34, 0x00, 0x6a, 0x00, 0x7d, 0x00, 0x4a, 0x00, 0x66, 0x00, 0x7a, 0x00, 0x3e, 0x00, 0x75, 0x00, 0x38, 0x00, 0x7b, 0x00, 0x42, 0x00, 0x76, 0x00, 0x29, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x2b, 0x00, 0x51, 0x00, 0x47, 0x00, 0x22, 0x00, 0x48, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x44, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x63, 0x00, 0x5c, 0x00, 0x24, 0x00, 0x35, 0x00, 0x34, 0x00, 0x70, 0x00, 0x69, 0x00}; uint32_t requestlen = sizeof(dcerpcrequest); uint32_t bindlen = sizeof(dcerpcbind); uint32_t bindacklen = sizeof(dcerpcbindack); TcpSession ssn; DCERPCUuidEntry *uuid_entry; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcbind, bindlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.rpc_vers != 5) { printf("expected dcerpc version 0x05, got 0x%02x : ", dcerpc_state->dcerpc.dcerpchdr.rpc_vers); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.type != BIND) { printf("expected dcerpc type 0x%02x , got 0x%02x : ", BIND, dcerpc_state->dcerpc.dcerpchdr.type); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.frag_length != 1084) { printf("expected dcerpc frag_length 0x%02x , got 0x%02x : ", 1084, dcerpc_state->dcerpc.dcerpchdr.frag_length); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpcbindack, bindacklen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.type != BIND_ACK) { printf("expected dcerpc type 0x%02x , got 0x%02x : ", BIND_ACK, dcerpc_state->dcerpc.dcerpchdr.type); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.frag_length != 620) { printf("expected dcerpc frag_length 0x%02x , got 0x%02x : ", 620, dcerpc_state->dcerpc.dcerpchdr.frag_length); result = 0; goto end; } TAILQ_FOREACH(uuid_entry, &dcerpc_state->dcerpc.dcerpcbindbindack.uuid_list, next) { printUUID("BIND_ACK", uuid_entry); } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_EOF, dcerpcrequest, requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.type != REQUEST) { printf("expected dcerpc type 0x%02x , got 0x%02x : ", REQUEST, dcerpc_state->dcerpc.dcerpchdr.type); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** \test DCERPC Request decoding and opnum parsing. */ int DCERPCParserTest02(void) { int result = 1; Flow f; uint8_t dcerpcrequest[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x4d, 0x00, 0x73, 0x00, 0x53, 0x00, 0x59, 0x00, 0x2a, 0x00, 0x4a, 0x00, 0x7a, 0x00, 0x3e, 0x00, 0x58, 0x00, 0x21, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x41, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x24, 0x00, 0x38, 0x00, 0x54, 0x00, 0x60, 0x00, 0x2d, 0x00, 0x29, 0x00, 0x64, 0x00, 0x5b, 0x00, 0x77, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x23, 0x00, 0x66, 0x00, 0x43, 0x00, 0x68, 0x00, 0x22, 0x00, 0x55, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x4f, 0x00, 0x5a, 0x00, 0x50, 0x00, 0x61, 0x00, 0x2a, 0x00, 0x6f, 0x00, 0x2f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x68, 0x00, 0x68, 0x00, 0x49, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x72, 0x00, 0x53, 0x00, 0x4c, 0x00, 0x25, 0x00, 0x4d, 0x00, 0x67, 0x00, 0x2e, 0x00, 0x4f, 0x00, 0x64, 0x00, 0x61, 0x00, 0x73, 0x00, 0x24, 0x00, 0x46, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x33, 0x00, 0x38, 0x00, 0x47, 0x00, 0x71, 0x00, 0x5a, 0x00, 0x37, 0x00, 0x7a, 0x00, 0x35, 0x00, 0x6b, 0x00, 0x3c, 0x00, 0x26, 0x00, 0x37, 0x00, 0x69, 0x00, 0x75, 0x00, 0x36, 0x00, 0x37, 0x00, 0x47, 0x00, 0x21, 0x00, 0x2d, 0x00, 0x69, 0x00, 0x37, 0x00, 0x78, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x4b, 0x00, 0x5c, 0x00, 0x74, 0x00, 0x3e, 0x00, 0x52, 0x00, 0x7a, 0x00, 0x49, 0x00, 0x31, 0x00, 0x5a, 0x00, 0x7b, 0x00, 0x29, 0x00, 0x3b, 0x00, 0x78, 0x00, 0x3b, 0x00, 0x55, 0x00, 0x3e, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x59, 0x00, 0x6b, 0x00, 0x42, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x6a, 0x00, 0x49, 0x00, 0x2c, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x35, 0x00, 0x4f, 0x00, 0x49, 0x00, 0x55, 0x00, 0x35, 0x00, 0x61, 0x00, 0x72, 0x00, 0x77, 0x00, 0x38, 0x00, 0x32, 0x00, 0x24, 0x00, 0x46, 0x00, 0x32, 0x00, 0x32, 0x00, 0x27, 0x00, 0x64, 0x00, 0x5a, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x28, 0x00, 0x63, 0x00, 0x4f, 0x00, 0x67, 0x00, 0x64, 0x00, 0x39, 0x00, 0x37, 0x00, 0x31, 0x00, 0x30, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x3e, 0x00, 0x59, 0x00, 0x28, 0x00, 0x67, 0x00, 0x52, 0x00, 0x35, 0x00, 0x5a, 0x00, 0x7c, 0x00, 0x56, 0x00, 0x6a, 0x00, 0x5c, 0x00, 0x3c, 0x00, 0x30, 0x00, 0x59, 0x00, 0x5c, 0x00, 0x5e, 0x00, 0x38, 0x00, 0x54, 0x00, 0x5c, 0x00, 0x5b, 0x00, 0x42, 0x00, 0x62, 0x00, 0x70, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x7a, 0x00, 0x4b, 0x00, 0x2f, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x41, 0x00, 0x33, 0x00, 0x52, 0x00, 0x36, 0x00, 0x27, 0x00, 0x30, 0x00, 0x6d, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x78, 0x00, 0x46, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x29, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x72, 0x00, 0x71, 0x00, 0x75, 0x00, 0x4c, 0x00, 0x2b, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x52, 0x00, 0x7b, 0x00, 0x5c, 0x00, 0x69, 0x00, 0x66, 0x00, 0x56, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x72, 0x00, 0x61, 0x00, 0x68, 0x00, 0x28, 0x00, 0x7d, 0x00, 0x58, 0x00, 0x2a, 0x00, 0x7b, 0x00, 0x28, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x3a, 0x00, 0x26, 0x00, 0x52, 0x00, 0x44, 0x00, 0x60, 0x00, 0x50, 0x00, 0x65, 0x00, 0x48, 0x00, 0x7d, 0x00, 0x2a, 0x00, 0x74, 0x00, 0x49, 0x00, 0x7b, 0x00, 0x21, 0x00, 0x61, 0x00, 0x52, 0x00, 0x43, 0x00, 0x5f, 0x00, 0x5a, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x62, 0x00, 0x68, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x2b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x42, 0x00, 0x67, 0x00, 0x32, 0x00, 0x58, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2f, 0x00, 0x2d, 0x00, 0x60, 0x00, 0x62, 0x00, 0x51, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x31, 0x00, 0x48, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x25, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x76, 0x00, 0x32, 0x00, 0x62, 0x00, 0x27, 0x00, 0x42, 0x00, 0x40, 0x00, 0x53, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x50, 0x00, 0x3d, 0x00, 0x40, 0x00, 0x76, 0x00, 0x38, 0x00, 0x58, 0x00, 0x39, 0x00, 0x63, 0x00, 0x3c, 0x00, 0x5b, 0x00, 0x23, 0x00, 0x53, 0x00, 0x7a, 0x00, 0x54, 0x00, 0x74, 0x00, 0x61, 0x00, 0x76, 0x00, 0x4a, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x75, 0x00, 0x66, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x33, 0x00, 0x71, 0x00, 0x76, 0x00, 0x48, 0x00, 0x71, 0x00, 0x41, 0x00, 0x6f, 0x00, 0x2a, 0x00, 0x67, 0x00, 0x70, 0x00, 0x21, 0x00, 0x70, 0x00, 0x4b, 0x00, 0x52, 0x00, 0x58, 0x00, 0x68, 0x00, 0x23, 0x00, 0x39, 0x00, 0x46, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x57, 0x00, 0x3a, 0x00, 0x79, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x55, 0x00, 0x33, 0x00, 0x65, 0x00, 0x49, 0x00, 0x72, 0x00, 0x30, 0x00, 0x4f, 0x00, 0x41, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x4a, 0x00, 0x60, 0x00, 0x79, 0x00, 0x70, 0x00, 0x4f, 0x00, 0x58, 0x00, 0x75, 0x00, 0x44, 0x00, 0x59, 0x00, 0x58, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x74, 0x00, 0x51, 0x00, 0x57, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x23, 0x00, 0x45, 0x00, 0x60, 0x00, 0x4c, 0x00, 0x72, 0x00, 0x4e, 0x00, 0x74, 0x00, 0x40, 0x00, 0x76, 0x00, 0x75, 0x00, 0x74, 0x00, 0x56, 0x00, 0x44, 0x00, 0x29, 0x00, 0x62, 0x00, 0x58, 0x00, 0x31, 0x00, 0x78, 0x00, 0x32, 0x00, 0x52, 0x00, 0x4a, 0x00, 0x6b, 0x00, 0x55, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x7d, 0x00, 0x68, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x21, 0x00, 0x53, 0x00, 0x48, 0x00, 0x5a, 0x00, 0x34, 0x00, 0x36, 0x00, 0x35, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x75, 0x00, 0x69, 0x00, 0x23, 0x00, 0x75, 0x00, 0x55, 0x00, 0x43, 0x00, 0x75, 0x00, 0x2f, 0x00, 0x73, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x37, 0x00, 0x4e, 0x00, 0x25, 0x00, 0x25, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x71, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x36, 0x00, 0x62, 0x00, 0x63, 0x00, 0x53, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x61, 0x00, 0x4c, 0x00, 0x28, 0x00, 0x2b, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x66, 0x00, 0x5f, 0x00, 0x4b, 0x00, 0x43, 0x00, 0x75, 0x00, 0x45, 0x00, 0x37, 0x00, 0x28, 0x00, 0x56, 0x00, 0x36, 0x00, 0x6a, 0x00, 0x3e, 0x00, 0x64, 0x00, 0x34, 0x00, 0x6a, 0x00, 0x7d, 0x00, 0x4a, 0x00, 0x66, 0x00, 0x7a, 0x00, 0x3e, 0x00, 0x75, 0x00, 0x38, 0x00, 0x7b, 0x00, 0x42, 0x00, 0x76, 0x00, 0x29, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x2b, 0x00, 0x51, 0x00, 0x47, 0x00, 0x22, 0x00, 0x48, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x44, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x63, 0x00, 0x5c, 0x00, 0x24, 0x00, 0x35, 0x00, 0x34, 0x00, 0x70, 0x00, 0x69, 0x00}; uint32_t requestlen = sizeof(dcerpcrequest); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.rpc_vers != 5) { printf("expected dcerpc version 0x05, got 0x%02x : ", dcerpc_state->dcerpc.dcerpchdr.rpc_vers); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.type != REQUEST) { printf("expected dcerpc type 0x%02x , got 0x%02x : ", REQUEST, dcerpc_state->dcerpc.dcerpchdr.type); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.frag_length != 1024) { printf("expected dcerpc frag_length 0x%02x , got 0x%02x : ", 1024, dcerpc_state->dcerpc.dcerpchdr.frag_length); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 9) { printf("expected dcerpc opnum 0x%02x , got 0x%02x : ", 9, dcerpc_state->dcerpc.dcerpcrequest.opnum); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** \test Test endianness handling */ int DCERPCParserTest03(void) { int result = 1; Flow f; uint8_t dcerpcrequest[] = { 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x45, 0x00, 0x2c, 0x00, 0x4d, 0x00, 0x73, 0x00, 0x53, 0x00, 0x59, 0x00, 0x2a, 0x00, 0x4a, 0x00, 0x7a, 0x00, 0x3e, 0x00, 0x58, 0x00, 0x21, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x41, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x24, 0x00, 0x38, 0x00, 0x54, 0x00, 0x60, 0x00, 0x2d, 0x00, 0x29, 0x00, 0x64, 0x00, 0x5b, 0x00, 0x77, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x23, 0x00, 0x66, 0x00, 0x43, 0x00, 0x68, 0x00, 0x22, 0x00, 0x55, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x4f, 0x00, 0x5a, 0x00, 0x50, 0x00, 0x61, 0x00, 0x2a, 0x00, 0x6f, 0x00, 0x2f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x68, 0x00, 0x68, 0x00, 0x49, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x72, 0x00, 0x53, 0x00, 0x4c, 0x00, 0x25, 0x00, 0x4d, 0x00, 0x67, 0x00, 0x2e, 0x00, 0x4f, 0x00, 0x64, 0x00, 0x61, 0x00, 0x73, 0x00, 0x24, 0x00, 0x46, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x33, 0x00, 0x38, 0x00, 0x47, 0x00, 0x71, 0x00, 0x5a, 0x00, 0x37, 0x00, 0x7a, 0x00, 0x35, 0x00, 0x6b, 0x00, 0x3c, 0x00, 0x26, 0x00, 0x37, 0x00, 0x69, 0x00, 0x75, 0x00, 0x36, 0x00, 0x37, 0x00, 0x47, 0x00, 0x21, 0x00, 0x2d, 0x00, 0x69, 0x00, 0x37, 0x00, 0x78, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x4b, 0x00, 0x5c, 0x00, 0x74, 0x00, 0x3e, 0x00, 0x52, 0x00, 0x7a, 0x00, 0x49, 0x00, 0x31, 0x00, 0x5a, 0x00, 0x7b, 0x00, 0x29, 0x00, 0x3b, 0x00, 0x78, 0x00, 0x3b, 0x00, 0x55, 0x00, 0x3e, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x59, 0x00, 0x6b, 0x00, 0x42, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x6a, 0x00, 0x49, 0x00, 0x2c, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x35, 0x00, 0x4f, 0x00, 0x49, 0x00, 0x55, 0x00, 0x35, 0x00, 0x61, 0x00, 0x72, 0x00, 0x77, 0x00, 0x38, 0x00, 0x32, 0x00, 0x24, 0x00, 0x46, 0x00, 0x32, 0x00, 0x32, 0x00, 0x27, 0x00, 0x64, 0x00, 0x5a, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x28, 0x00, 0x63, 0x00, 0x4f, 0x00, 0x67, 0x00, 0x64, 0x00, 0x39, 0x00, 0x37, 0x00, 0x31, 0x00, 0x30, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x3e, 0x00, 0x59, 0x00, 0x28, 0x00, 0x67, 0x00, 0x52, 0x00, 0x35, 0x00, 0x5a, 0x00, 0x7c, 0x00, 0x56, 0x00, 0x6a, 0x00, 0x5c, 0x00, 0x3c, 0x00, 0x30, 0x00, 0x59, 0x00, 0x5c, 0x00, 0x5e, 0x00, 0x38, 0x00, 0x54, 0x00, 0x5c, 0x00, 0x5b, 0x00, 0x42, 0x00, 0x62, 0x00, 0x70, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x7a, 0x00, 0x4b, 0x00, 0x2f, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x41, 0x00, 0x33, 0x00, 0x52, 0x00, 0x36, 0x00, 0x27, 0x00, 0x30, 0x00, 0x6d, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x78, 0x00, 0x46, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x29, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x72, 0x00, 0x71, 0x00, 0x75, 0x00, 0x4c, 0x00, 0x2b, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x52, 0x00, 0x7b, 0x00, 0x5c, 0x00, 0x69, 0x00, 0x66, 0x00, 0x56, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x72, 0x00, 0x61, 0x00, 0x68, 0x00, 0x28, 0x00, 0x7d, 0x00, 0x58, 0x00, 0x2a, 0x00, 0x7b, 0x00, 0x28, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x3a, 0x00, 0x26, 0x00, 0x52, 0x00, 0x44, 0x00, 0x60, 0x00, 0x50, 0x00, 0x65, 0x00, 0x48, 0x00, 0x7d, 0x00, 0x2a, 0x00, 0x74, 0x00, 0x49, 0x00, 0x7b, 0x00, 0x21, 0x00, 0x61, 0x00, 0x52, 0x00, 0x43, 0x00, 0x5f, 0x00, 0x5a, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x62, 0x00, 0x68, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x2b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x42, 0x00, 0x67, 0x00, 0x32, 0x00, 0x58, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2f, 0x00, 0x2d, 0x00, 0x60, 0x00, 0x62, 0x00, 0x51, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x31, 0x00, 0x48, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x25, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x76, 0x00, 0x32, 0x00, 0x62, 0x00, 0x27, 0x00, 0x42, 0x00, 0x40, 0x00, 0x53, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x50, 0x00, 0x3d, 0x00, 0x40, 0x00, 0x76, 0x00, 0x38, 0x00, 0x58, 0x00, 0x39, 0x00, 0x63, 0x00, 0x3c, 0x00, 0x5b, 0x00, 0x23, 0x00, 0x53, 0x00, 0x7a, 0x00, 0x54, 0x00, 0x74, 0x00, 0x61, 0x00, 0x76, 0x00, 0x4a, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x75, 0x00, 0x66, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x33, 0x00, 0x71, 0x00, 0x76, 0x00, 0x48, 0x00, 0x71, 0x00, 0x41, 0x00, 0x6f, 0x00, 0x2a, 0x00, 0x67, 0x00, 0x70, 0x00, 0x21, 0x00, 0x70, 0x00, 0x4b, 0x00, 0x52, 0x00, 0x58, 0x00, 0x68, 0x00, 0x23, 0x00, 0x39, 0x00, 0x46, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x57, 0x00, 0x3a, 0x00, 0x79, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x55, 0x00, 0x33, 0x00, 0x65, 0x00, 0x49, 0x00, 0x72, 0x00, 0x30, 0x00, 0x4f, 0x00, 0x41, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x4a, 0x00, 0x60, 0x00, 0x79, 0x00, 0x70, 0x00, 0x4f, 0x00, 0x58, 0x00, 0x75, 0x00, 0x44, 0x00, 0x59, 0x00, 0x58, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x74, 0x00, 0x51, 0x00, 0x57, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x23, 0x00, 0x45, 0x00, 0x60, 0x00, 0x4c, 0x00, 0x72, 0x00, 0x4e, 0x00, 0x74, 0x00, 0x40, 0x00, 0x76, 0x00, 0x75, 0x00, 0x74, 0x00, 0x56, 0x00, 0x44, 0x00, 0x29, 0x00, 0x62, 0x00, 0x58, 0x00, 0x31, 0x00, 0x78, 0x00, 0x32, 0x00, 0x52, 0x00, 0x4a, 0x00, 0x6b, 0x00, 0x55, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x7d, 0x00, 0x68, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x21, 0x00, 0x53, 0x00, 0x48, 0x00, 0x5a, 0x00, 0x34, 0x00, 0x36, 0x00, 0x35, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x75, 0x00, 0x69, 0x00, 0x23, 0x00, 0x75, 0x00, 0x55, 0x00, 0x43, 0x00, 0x75, 0x00, 0x2f, 0x00, 0x73, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x37, 0x00, 0x4e, 0x00, 0x25, 0x00, 0x25, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x71, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x36, 0x00, 0x62, 0x00, 0x63, 0x00, 0x53, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x61, 0x00, 0x4c, 0x00, 0x28, 0x00, 0x2b, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x66, 0x00, 0x5f, 0x00, 0x4b, 0x00, 0x43, 0x00, 0x75, 0x00, 0x45, 0x00, 0x37, 0x00, 0x28, 0x00, 0x56, 0x00, 0x36, 0x00, 0x6a, 0x00, 0x3e, 0x00, 0x64, 0x00, 0x34, 0x00, 0x6a, 0x00, 0x7d, 0x00, 0x4a, 0x00, 0x66, 0x00, 0x7a, 0x00, 0x3e, 0x00, 0x75, 0x00, 0x38, 0x00, 0x7b, 0x00, 0x42, 0x00, 0x76, 0x00, 0x29, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x2b, 0x00, 0x51, 0x00, 0x47, 0x00, 0x22, 0x00, 0x48, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x44, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x63, 0x00, 0x5c, 0x00, 0x24, 0x00, 0x35, 0x00, 0x34, 0x00, 0x70, 0x00, 0x69, 0x00}; uint32_t requestlen = sizeof(dcerpcrequest); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.packed_drep[0] != 0x01) { printf("expected dcerpc data representation 0x01, got 0x%02x : ", dcerpc_state->dcerpc.dcerpchdr.packed_drep[0]); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpchdr.frag_length != 1024) { printf("expected dcerpc frag_length 0x%02x , got 0x%02x : ", 1024, dcerpc_state->dcerpc.dcerpchdr.frag_length); result = 0; goto end; } if (dcerpc_state->dcerpc.dcerpcrequest.opnum != 9) { printf("expected dcerpc opnum 0x%02x , got 0x%02x : ", 9, dcerpc_state->dcerpc.dcerpcrequest.opnum); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \todo Needs to be rewritten */ int DCERPCParserTest04(void) { /* AWS - Disabled this test since clamav FPs on the payloads used. * We will have to rewrite this test with new payloads. Will be done * as a part of dcerpc update/fixes */ #if 0 int result = 1; Flow f; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t request1[] = { 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 }; uint32_t request2_len = sizeof(request2); uint8_t request3[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x26, 0x65, 0x3c, 0x6e, 0x6d, 0x64, 0x24, 0x39, 0x56, 0x43, 0x3e, 0x61, 0x5c, 0x54, 0x42, 0x23, 0x75, 0x6b, 0x71, 0x27, 0x66, 0x2e, 0x6e, 0x3d, 0x58, 0x23, 0x54, 0x77, 0x3b, 0x52, 0x6b, 0x50, 0x3b, 0x74, 0x2c, 0x54, 0x25, 0x5c, 0x51, 0x7c, 0x29, 0x7c, 0x5f, 0x4a, 0x35, 0x5c, 0x3d, 0x3f, 0x33, 0x55, 0x3b, 0x5a, 0x57, 0x31, 0x59, 0x4f, 0x6d, 0x6d, 0x7b, 0x3e, 0x38, 0x4d, 0x68, 0x75, 0x64, 0x21, 0x50, 0x63, 0x47, 0x42, 0x56, 0x39, 0x6c, 0x6f, 0x61, 0x53, 0x32, 0x56, 0x43, 0x52, 0x43, 0x67, 0x26, 0x45, 0x28, 0x6b, 0x77, 0x28, 0x7c, 0x64, 0x61, 0x24, 0x38, 0x6b, 0x59, 0x2a, 0x4f, 0x6e, 0x5b, 0x57, 0x24, 0x54, 0x33, 0x37, 0x47, 0x58, 0x4b, 0x58, 0x3d, 0x21, 0x38, 0x7c, 0x2c, 0x24, 0x5f, 0x67, 0x3a, 0x41, 0x3e, 0x2a, 0x72, 0x66, 0x2d, 0x6b, 0x66, 0x7b, 0x2b, 0x75, 0x78, 0x2f, 0x4d, 0x4c, 0x51, 0x70, 0x5d, 0x55, 0x54, 0x3c, 0x63, 0x46, 0x6b, 0x64, 0x4d, 0x25, 0x45, 0x21, 0x34, 0x65, 0x48, 0x32, 0x58, 0x4c, 0x70, 0x4c, 0x4c, 0x75, 0x5c, 0x77, 0x68, 0x78, 0x34, 0x5c, 0x2d, 0x39, 0x58, 0x3b, 0x40, 0x71, 0x77, 0x47, 0x32, 0x2e, 0x3c, 0x61, 0x6f, 0x6d, 0x5f, 0x43, 0x74, 0x36, 0x4f, 0x21, 0x44, 0x66, 0x36, 0x62, 0x30, 0x29, 0x5a, 0x34, 0x66, 0x4e, 0x51, 0x23, 0x4e, 0x38, 0x51, 0x78, 0x74, 0x58, 0x2e, 0x6d, 0x51, 0x49, 0x55, 0x73, 0x2a, 0x71, 0x3c, 0x74, 0x38, 0x6f, 0x5d, 0x4b, 0x74, 0x68, 0x65, 0x4a, 0x58, 0x41, 0x55, 0x29, 0x42, 0x69, 0x55, 0x3b, 0x2b, 0x47, 0x64, 0x3b, 0x77, 0x72, 0x74, 0x38, 0x53, 0x5c, 0x69, 0x49, 0x49, 0x5b, 0x31, 0x41, 0x6a, 0x4e, 0x2c, 0x6a, 0x63, 0x3f, 0x58, 0x4e, 0x25, 0x3e, 0x57, 0x41, 0x61, 0x26, 0x5e, 0x24, 0x69, 0x7a, 0x38, 0x60, 0x73, 0x70, 0x7d, 0x63, 0x34, 0x78, 0x4d, 0x50, 0x35, 0x69, 0x49, 0x22, 0x45, 0x44, 0x3f, 0x6e, 0x75, 0x64, 0x57, 0x3a, 0x61, 0x60, 0x34, 0x21, 0x61, 0x21, 0x2a, 0x78, 0x7b, 0x52, 0x43, 0x50, 0x5b, 0x76, 0x5f, 0x4b, 0x6a, 0x5d, 0x23, 0x5b, 0x57, 0x40, 0x53, 0x51, 0x33, 0x21, 0x35, 0x7d, 0x31, 0x46, 0x65, 0x52, 0x28, 0x25, 0x30, 0x5a, 0x37, 0x7c, 0x2c, 0x3d, 0x2a, 0x48, 0x24, 0x5a, 0x2f, 0x47, 0x64, 0x73, 0x64, 0x3d, 0x7a, 0x5b, 0x34, 0x5e, 0x42, 0x22, 0x32, 0x47, 0x6e, 0x58, 0x3b, 0x3e, 0x25, 0x2f, 0x58, 0x78, 0x42, 0x66, 0x71, 0x56, 0x2a, 0x66, 0x66, 0x5b, 0x55, 0x35, 0x7a, 0x41, 0x7c, 0x7c, 0x6a, 0x2d, 0x59, 0x25, 0x22, 0x34, 0x5a, 0x61, 0x37, 0x48, 0x39, 0x31, 0x4a, 0x55, 0x6a, 0x68, 0x40, 0x2f, 0x45, 0x69, 0x46, 0x25, 0x51, 0x7d, 0x4f, 0x71, 0x21, 0x33, 0x55, 0x50, 0x56, 0x5f, 0x75, 0x27, 0x64, 0x36, 0x7a, 0x39, 0x40, 0x6a, 0x77, 0x38, 0x5d, 0x39, 0x30, 0x5e, 0x74, 0x54, 0x24, 0x3f, 0x3d, 0x79, 0x3b, 0x27, 0x7d, 0x68, 0x7d, 0x40, 0x71, 0x7a, 0x65, 0x54, 0x50, 0x66, 0x33, 0x3c, 0x42, 0x69, 0x6e, 0x3c, 0x63, 0x63, 0x69, 0x7a, 0x5e, 0x7b, 0x76, 0x26, 0x71, 0x6f, 0x4a, 0x6d, 0x70, 0x73, 0x66, 0x3b, 0x26, 0x70, 0x43, 0x5b, 0x52, 0x4c, 0x6d, 0x51, 0x2a, 0x66, 0x6c, 0x3e, 0x68, 0x6a, 0x31, 0x41, 0x79, 0x72, 0x37, 0x47, 0x7d, 0x2b, 0x3c, 0x40, 0x6b, 0x75, 0x56, 0x70, 0x7b, 0x2d, 0x5f, 0x33, 0x30, 0x30, 0x21, 0x35, 0x7a, 0x7a, 0x67, 0x48, 0x5e, 0x3b, 0x73, 0x50, 0x54, 0x47, 0x23, 0x2b, 0x4c, 0x4e, 0x2f, 0x24, 0x44, 0x34, 0x23, 0x5d, 0x76, 0x51, 0x5a, 0x73, 0x72, 0x3e, 0x47, 0x77, 0x40, 0x28, 0x65, 0x2e, 0x2a, 0x75, 0x3c, 0x2a, 0x27, 0x4a, 0x3f, 0x3c, 0x66, 0x2d, 0x21, 0x79, 0x2d, 0x2b, 0x78, 0x7c, 0x5a, 0x73, 0x46, 0x6b, 0x39, 0x65, 0x5e, 0x3d, 0x38, 0x40, 0x32, 0x3e, 0x21, 0x62, 0x34, 0x41, 0x58, 0x53, 0x67, 0x34, 0x58, 0x56, 0x61, 0x5b, 0x3e, 0x4e, 0x2c, 0x5b, 0x73, 0x35, 0x34, 0x35, 0x21, 0x3a, 0x61, 0x5f, 0x6e, 0x45, 0x78, 0x44, 0x28, 0x23, 0x48, 0x65, 0x53, 0x47, 0x6e, 0x2c, 0x38, 0x5e, 0x2c, 0x57, 0x58, 0x30, 0x7a, 0x3b, 0x4b, 0x4a, 0x74, 0x7d, 0x3e, 0x4d, 0x30, 0x24, 0x76, 0x66, 0x6d, 0x2e, 0x74, 0x75, 0x28, 0x48, 0x5c, 0x23, 0x6c, 0x46, 0x27, 0x46, 0x6e, 0x34, 0x63, 0x21, 0x58, 0x54, 0x50, 0x2f, 0x40, 0x47, 0x40, 0x32, 0x36, 0x48, 0x5f, 0x7d, 0x4a, 0x41, 0x6e, 0x60, 0x2c, 0x4a, 0x6a, 0x67, 0x6c, 0x41, 0x27, 0x23, 0x30, 0x48, 0x6a, 0x49, 0x73, 0x26, 0x77, 0x75, 0x4d, 0x65, 0x5b, 0x34, 0x79, 0x67, 0x61, 0x5b, 0x5c, 0x2b, 0x71, 0x3f, 0x62, 0x51, 0x3a, 0x53, 0x42, 0x26, 0x6f, 0x36, 0x57, 0x3f, 0x2b, 0x34, 0x24, 0x30, 0x60, 0x55, 0x70, 0x65, 0x70, 0x57, 0x5d, 0x68, 0x36, 0x52, 0x5d, 0x3f, 0x6a, 0x3a, 0x33, 0x31, 0x6c, 0x4e, 0x57, 0x79, 0x49, 0x79, 0x69, 0x71, 0x6f, 0x70, 0x6a, 0x76, 0x4b, 0x2f, 0x33, 0x51, 0x68, 0x30, 0x2e, 0x77, 0x78, 0x55, 0x2f, 0x53, 0x52, 0x5e, 0x57, 0x60, 0x3b, 0x6f, 0x69, 0x61, 0x6c, 0x60, 0x5a, 0x34, 0x5a, 0x35, 0x4b, 0x28, 0x54, 0x32, 0x6a, 0x35, 0x36, 0x6d, 0x68, 0x47, 0x5c, 0x74, 0x2e, 0x5f, 0x6c, 0x6d, 0x55, 0x42, 0x77, 0x64, 0x7d, 0x53, 0x4d, 0x39, 0x2c, 0x41, 0x42, 0x23, 0x3a, 0x73, 0x40, 0x60, 0x5d, 0x38, 0x6d, 0x36, 0x56, 0x57, 0x2a, 0x28, 0x3d, 0x3b, 0x5c, 0x75, 0x35, 0x2d, 0x69, 0x2d, 0x44, 0x51, 0x27, 0x63, 0x66, 0x33, 0x46, 0x42, 0x2e, 0x36, 0x6b, 0x7b, 0x2c, 0x23, 0x3b, 0x5a, 0x50, 0x2a, 0x65, 0x28, 0x3b, 0x3c, 0x51, 0x3f, 0x4d, 0x63, 0x38, 0x25, 0x74, 0x2e, 0x51, 0x22, 0x31, 0x74, 0x35, 0x33, 0x23, 0x2d, 0x3f, 0x77, 0x26, 0x2c, 0x55, 0x6d, 0x27, 0x39, 0x79, 0x76, 0x63, 0x4b, 0x43, 0x4a, 0x3a, 0x6b, 0x59, 0x55, 0x65, 0x26, 0x2f, 0x3f, 0x56, 0x67, 0x5a, 0x77, 0x71, 0x22, 0x51, 0x2b, 0x6d, 0x4c, 0x2c, 0x57, 0x66, 0x76, 0x37, 0x70, 0x5f, 0x52, 0x29, 0x44, 0x52, 0x22, 0x57, 0x37, 0x27, 0x79, 0x29, 0x5c, 0x57, 0x3b, 0x54, 0x3c, 0x3f, 0x53, 0x35, 0x27, 0x5e, 0x7c, 0x49, 0x77, 0x57, 0x5a, 0x22, 0x76, 0x7c, 0x5b, 0x2f, 0x53, 0x5e, 0x55, 0x6d, 0x64, 0x67, 0x34, 0x41, 0x23, 0x76, 0x67, 0x23, 0x78, 0x6a, 0x63, 0x27, 0x68, 0x43, 0x7d, 0x58, 0x49, 0x2d, 0x79, 0x2e, 0x75, 0x60, 0x6b, 0x34, 0x48, 0x6f, 0x4a, 0x6c, 0x48, 0x40, 0x68, 0x5f, 0x35, 0x25, 0x6c, 0x38, 0x5c, 0x30, 0x32, 0x4c, 0x36, 0x31, 0x29, 0x74, 0x4a, 0x55, 0x56, 0x6d, 0x4e, 0x23, 0x54, 0x2e, 0x69, 0x78, 0x61, 0x76, 0x66, 0x22, 0x44, 0x73, 0x25, 0x44, 0x29, 0x2a, 0x28, 0x3b, 0x67, 0x48, 0x58, 0x37, 0x4a, 0x76, 0x76, 0x51, 0x4a, 0x61, 0x70, 0x51, 0x74, 0x40, 0x23, 0x29, 0x63, 0x69, 0x4a, 0x29, 0x23, 0x34, 0x6a, 0x3b, 0x25, 0x28, 0x54, 0x45, 0x33, 0x28, 0x44, 0x30, 0x61, 0x5b, 0x60, 0x51, 0x3f, 0x68, 0x50, 0x70, 0x3d, 0x58, 0x2e, 0x6e, 0x59, 0x5a, 0x62, 0x66, 0x4d, 0x7a, 0x2e, 0x37, 0x37, 0x3d, 0x7b, 0x74, 0x79, 0x48, 0x45, 0x77, 0x56, 0x33, 0x76, 0x71, 0x60, 0x74, 0x3f, 0x61, 0x22, 0x52, 0x51, 0x71, 0x69 }; uint32_t request3_len = sizeof(request3); uint8_t request4[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x75, 0x3e, 0x76, 0x3e, 0x66, 0x6b, 0x6b, 0x3e, 0x6d, 0x59, 0x38, 0x2b, 0x63, 0x4d, 0x2c, 0x73, 0x54, 0x57, 0x34, 0x25, 0x5b, 0x42, 0x7d, 0x5d, 0x37, 0x34, 0x2c, 0x79, 0x24, 0x4b, 0x74, 0x73, 0x25, 0x36, 0x73, 0x3a, 0x2c, 0x55, 0x69, 0x3c, 0x58, 0x67, 0x33, 0x53, 0x67, 0x5c, 0x61, 0x7b, 0x44, 0x2e, 0x42, 0x2d, 0x6b, 0x50, 0x55, 0x24, 0x70, 0x58, 0x60, 0x38, 0x42, 0x45, 0x70, 0x6d, 0x2f, 0x27, 0x27, 0x2c, 0x21, 0x6d, 0x57, 0x6e, 0x43, 0x3c, 0x5b, 0x27, 0x7a, 0x34, 0x49, 0x5a, 0x69, 0x30, 0x3f, 0x6f, 0x77, 0x70, 0x39, 0x2d, 0x51, 0x74, 0x4b, 0x25, 0x70, 0x51, 0x64, 0x4d, 0x75, 0x52, 0x5e, 0x3e, 0x37, 0x30, 0x5d, 0x3b, 0x2c, 0x72, 0x25, 0x6c, 0x6f, 0x79, 0x69, 0x3c, 0x5b, 0x73, 0x3d, 0x41, 0x28, 0x28, 0x64, 0x60, 0x4b, 0x7a, 0x2c, 0x4a, 0x6b, 0x3d, 0x2e, 0x6c, 0x7a, 0x54, 0x70, 0x61, 0x6f, 0x4b, 0x40, 0x28, 0x59, 0x31, 0x25, 0x21, 0x57, 0x79, 0x4b, 0x31, 0x6f, 0x4e, 0x71, 0x2b, 0x3c, 0x24, 0x30, 0x28, 0x3c, 0x61, 0x28, 0x4b, 0x35, 0x61, 0x4d, 0x55, 0x5e, 0x66, 0x34, 0x5f, 0x61, 0x70, 0x7b, 0x67, 0x51, 0x55, 0x68, 0x78, 0x26, 0x3a, 0x27, 0x4e, 0x71, 0x79, 0x4f, 0x67, 0x2c, 0x5a, 0x79, 0x75, 0x59, 0x3a, 0x33, 0x4a, 0x36, 0x71, 0x72, 0x6d, 0x49, 0x3e, 0x53, 0x59, 0x2b, 0x2b, 0x27, 0x4e, 0x50, 0x5d, 0x21, 0x55, 0x64, 0x4b, 0x72, 0x73, 0x25, 0x55, 0x26, 0x4f, 0x3a, 0x21, 0x54, 0x29, 0x4f, 0x64, 0x51, 0x59, 0x60, 0x7b, 0x7c, 0x6f, 0x3e, 0x65, 0x74, 0x6a, 0x5b, 0x52, 0x2c, 0x56, 0x4e, 0x45, 0x53, 0x4b, 0x7c, 0x38, 0x49, 0x4b, 0x4e, 0x4f, 0x4a, 0x47, 0x5e, 0x7c, 0x46, 0x3b, 0x67, 0x2e, 0x43, 0x79, 0x35, 0x55, 0x59, 0x6d, 0x38, 0x70, 0x2f, 0x59, 0x4f, 0x27, 0x63, 0x40, 0x66, 0x2d, 0x39, 0x4f, 0x3d, 0x2e, 0x4c, 0x67, 0x71, 0x7d, 0x34, 0x22, 0x52, 0x4e, 0x36, 0x7b, 0x2c, 0x39, 0x4d, 0x42, 0x60, 0x75, 0x74, 0x72, 0x4f, 0x72, 0x68, 0x3a, 0x51, 0x31, 0x2d, 0x21, 0x4a, 0x35, 0x47, 0x6d, 0x69, 0x3c, 0x50, 0x4c, 0x59, 0x66, 0x4c, 0x71, 0x24, 0x3a, 0x36, 0x67, 0x24, 0x5a, 0x59, 0x28, 0x7c, 0x21, 0x5e, 0x77, 0x68, 0x5e, 0x7b, 0x6e, 0x56, 0x62, 0x36, 0x29, 0x6f, 0x4f, 0x5d, 0x57, 0x56, 0x2b, 0x75, 0x2a, 0x2c, 0x69, 0x63, 0x51, 0x74, 0x6e, 0x5e, 0x46, 0x50, 0x28, 0x2c, 0x3b, 0x32, 0x53, 0x28, 0x78, 0x59, 0x72, 0x39, 0x5e, 0x44, 0x5c, 0x77, 0x60, 0x72, 0x44, 0x3b, 0x75, 0x68, 0x39, 0x55, 0x3e, 0x44, 0x50, 0x76, 0x3c, 0x48, 0x46, 0x43, 0x22, 0x56, 0x27, 0x21, 0x31, 0x33, 0x4a, 0x5a, 0x74, 0x41, 0x58, 0x3f, 0x39, 0x29, 0x71, 0x73, 0x30, 0x57, 0x70, 0x33, 0x62, 0x7b, 0x4a, 0x75, 0x3e, 0x4d, 0x4c, 0x4e, 0x55, 0x63, 0x38, 0x66, 0x7d, 0x68, 0x7d, 0x6f, 0x23, 0x55, 0x50, 0x3d, 0x34, 0x46, 0x5e, 0x2f, 0x55, 0x27, 0x62, 0x68, 0x7c, 0x6c, 0x21, 0x2b, 0x63, 0x4b, 0x47, 0x6b, 0x6a, 0x5b, 0x7b, 0x5c, 0x71, 0x37, 0x7c, 0x52, 0x2b, 0x2f, 0x4a, 0x47, 0x70, 0x78, 0x50, 0x2f, 0x75, 0x28, 0x4c, 0x60, 0x4c, 0x4c, 0x54, 0x6b, 0x68, 0x63, 0x4f, 0x47, 0x39, 0x2a, 0x70, 0x51, 0x7d, 0x28, 0x59, 0x52, 0x46, 0x4b, 0x38, 0x27, 0x49, 0x50, 0x5d, 0x25, 0x22, 0x5f, 0x48, 0x2c, 0x2f, 0x67, 0x59, 0x5d, 0x7d, 0x21, 0x3d, 0x72, 0x4f, 0x5c, 0x5b, 0x41, 0x47, 0x5f, 0x56, 0x69, 0x42, 0x55, 0x60, 0x68, 0x4b, 0x77, 0x44, 0x4c, 0x3b, 0x7d, 0x5a, 0x58, 0x43, 0x7a, 0x33, 0x22, 0x58, 0x58, 0x6f, 0x74, 0x53, 0x57, 0x6d, 0x6e, 0x29, 0x6b, 0x33, 0x71, 0x68, 0x29, 0x48, 0x67, 0x35, 0x52, 0x41, 0x6b, 0x36, 0x4f, 0x46, 0x31, 0x24, 0x73, 0x56, 0x40, 0x48, 0x37, 0x51, 0x24, 0x2a, 0x59, 0x21, 0x74, 0x76, 0x25, 0x2e, 0x4a, 0x74, 0x32, 0x29, 0x5f, 0x57, 0x7c, 0x58, 0x30, 0x2c, 0x7b, 0x70, 0x5b, 0x51, 0x73, 0x27, 0x4a, 0x28, 0x77, 0x2a, 0x43, 0x28, 0x2e, 0x32, 0x3d, 0x38, 0x36, 0x2e, 0x6b, 0x40, 0x6c, 0x76, 0x54, 0x66, 0x4a, 0x5c, 0x25, 0x62, 0x2e, 0x61, 0x48, 0x30, 0x28, 0x41, 0x40, 0x69, 0x3c, 0x39, 0x36, 0x4b, 0x64, 0x50, 0x76, 0x3d, 0x52, 0x50, 0x77, 0x33, 0x3b, 0x65, 0x59, 0x31, 0x5c, 0x48, 0x6a, 0x74, 0x78, 0x5b, 0x74, 0x60, 0x47, 0x27, 0x60, 0x22, 0x4a, 0x72, 0x25, 0x34, 0x5d, 0x3a, 0x21, 0x66, 0x61, 0x7b, 0x34, 0x41, 0x3b, 0x3a, 0x27, 0x44, 0x48, 0x7c, 0x7a, 0x74, 0x3a, 0x68, 0x59, 0x48, 0x61, 0x32, 0x49, 0x61, 0x40, 0x22, 0x33, 0x75, 0x29, 0x76, 0x5b, 0x24, 0x5b, 0x5c, 0x76, 0x5c, 0x28, 0x75, 0x36, 0x26, 0x2c, 0x65, 0x5e, 0x51, 0x7b, 0x3a, 0x7d, 0x4f, 0x35, 0x73, 0x6b, 0x5b, 0x5c, 0x37, 0x35, 0x6b, 0x41, 0x35, 0x40, 0x3a, 0x22, 0x28, 0x6c, 0x71, 0x46, 0x68, 0x7b, 0x66, 0x56, 0x24, 0x7c, 0x54, 0x28, 0x30, 0x22, 0x4e, 0x3c, 0x65, 0x69, 0x36, 0x44, 0x53, 0x3d, 0x6c, 0x5f, 0x73, 0x6c, 0x6f, 0x5e, 0x27, 0x23, 0x4e, 0x60, 0x45, 0x2f, 0x3d, 0x37, 0x28, 0x51, 0x29, 0x77, 0x6a, 0x6b, 0x2a, 0x2a, 0x51, 0x26, 0x4c, 0x4e, 0x71, 0x77, 0x73, 0x71, 0x2d, 0x5a, 0x2c, 0x23, 0x3d, 0x5f, 0x62, 0x63, 0x2e, 0x72, 0x2a, 0x75, 0x66, 0x43, 0x56, 0x5f, 0x21, 0x64, 0x66, 0x35, 0x3b, 0x7a, 0x45, 0x3f, 0x4f, 0x57, 0x22, 0x5a, 0x45, 0x65, 0x37, 0x58, 0x5b, 0x43, 0x66, 0x4f, 0x5d, 0x6e, 0x41, 0x41, 0x62, 0x5e, 0x39, 0x65, 0x6f, 0x43, 0x4b, 0x5e, 0x51, 0x42, 0x3f, 0x2d, 0x68, 0x4b, 0x6e, 0x46, 0x6f, 0x21, 0x44, 0x3c, 0x22, 0x46, 0x31, 0x31, 0x2e, 0x56, 0x2e, 0x77, 0x48, 0x68, 0x23, 0x4a, 0x36, 0x52, 0x5d, 0x61, 0x47, 0x71, 0x2e, 0x3a, 0x4a, 0x5b, 0x56, 0x6b, 0x52, 0x2a, 0x4c, 0x4f, 0x24, 0x34, 0x60, 0x70, 0x58, 0x7a, 0x76, 0x4b, 0x68, 0x24, 0x5f, 0x51, 0x6d, 0x75, 0x45, 0x48, 0x21, 0x53, 0x4d, 0x27, 0x75, 0x5f, 0x50, 0x3e, 0x40, 0x3f, 0x5e, 0x64, 0x41, 0x5f, 0x68, 0x48, 0x30, 0x71, 0x4b, 0x66, 0x2c, 0x2f, 0x76, 0x4b, 0x23, 0x46, 0x34, 0x50, 0x58, 0x52, 0x69, 0x2b, 0x6e, 0x7a, 0x33, 0x53, 0x43, 0x43, 0x35, 0x54, 0x30, 0x73, 0x63, 0x3b, 0x43, 0x52, 0x29, 0x45, 0x37, 0x71, 0x79, 0x5a, 0x26, 0x24, 0x72, 0x73, 0x4e, 0x44, 0x38, 0x5b, 0x71, 0x36, 0x3a, 0x4f, 0x5b, 0x71, 0x28, 0x71, 0x79, 0x72, 0x40, 0x6e, 0x51, 0x72, 0x29, 0x3d, 0x4f, 0x33, 0x22, 0x73, 0x5a, 0x30, 0x71, 0x58, 0x54, 0x59, 0x48, 0x29, 0x2b, 0x5c, 0x73, 0x6f, 0x4e, 0x60, 0x2a, 0x72, 0x39, 0x50, 0x59, 0x6f, 0x48, 0x3e, 0x62, 0x6c, 0x62, 0x49, 0x6c, 0x2c, 0x3f, 0x43, 0x3f, 0x32, 0x7c, 0x6f, 0x6c, 0x39, 0x26, 0x26, 0x7b, 0x5d, 0x65, 0x6f, 0x41, 0x7c, 0x42, 0x2b, 0x65, 0x6f, 0x3e, 0x7b, 0x69, 0x46, 0x4d, 0x68, 0x68, 0x5a, 0x33, 0x25, 0x5d, 0x6f, 0x48, 0x7c, 0x77, 0x7d, 0x3f, 0x4e, 0x30, 0x69, 0x65, 0x28, 0x2e, 0x34, 0x34, 0x41, 0x43, 0x5e, 0x30, 0x23, 0x3b, 0x60, 0x79, 0x5b, 0x26, 0x7c, 0x77, 0x3e, 0x43, 0x24, 0x31, 0x3a, 0x56, 0x24, 0x3c, 0x60, 0x3f, 0x60, 0x55, 0x6a, 0x68 }; uint32_t request4_len = sizeof(request4); uint8_t request5[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x69, 0x3e, 0x72, 0x44, 0x31, 0x6b, 0x28, 0x2f, 0x79, 0x37, 0x58, 0x5d, 0x5f, 0x68, 0x71, 0x47, 0x7a, 0x68, 0x7c, 0x6c, 0x65, 0x3c, 0x74, 0x67, 0x59, 0x5c, 0x3d, 0x28, 0x65, 0x28, 0x58, 0x74, 0x44, 0x62, 0x2e, 0x36, 0x54, 0x2f, 0x24, 0x34, 0x4b, 0x6d, 0x3a, 0x7b, 0x60, 0x71, 0x5a, 0x77, 0x4a, 0x27, 0x25, 0x70, 0x75, 0x56, 0x78, 0x73, 0x2e, 0x38, 0x6c, 0x70, 0x66, 0x7b, 0x7b, 0x2d, 0x78, 0x27, 0x65, 0x63, 0x58, 0x4f, 0x7d, 0x5c, 0x31, 0x3e, 0x36, 0x6e, 0x65, 0x61, 0x2e, 0x4e, 0x26, 0x68, 0x2b, 0x33, 0x7d, 0x54, 0x2c, 0x28, 0x47, 0x3a, 0x31, 0x47, 0x56, 0x32, 0x74, 0x51, 0x79, 0x65, 0x42, 0x45, 0x60, 0x55, 0x6f, 0x48, 0x61, 0x23, 0x72, 0x62, 0x74, 0x3a, 0x5a, 0x26, 0x2d, 0x41, 0x58, 0x62, 0x75, 0x4b, 0x37, 0x2e, 0x3f, 0x2a, 0x6e, 0x2e, 0x2c, 0x43, 0x6f, 0x53, 0x5f, 0x48, 0x7a, 0x53, 0x7b, 0x54, 0x28, 0x30, 0x2b, 0x7a, 0x34, 0x33, 0x28, 0x2b, 0x23, 0x23, 0x72, 0x38, 0x25, 0x30, 0x35, 0x66, 0x76, 0x46, 0x2a, 0x57, 0x7a, 0x60, 0x38, 0x5a, 0x26, 0x4f, 0x78, 0x43, 0x2c, 0x7d, 0x3d, 0x76, 0x7d, 0x66, 0x48, 0x7d, 0x3e, 0x59, 0x31, 0x58, 0x6b, 0x30, 0x76, 0x45, 0x6e, 0x70, 0x72, 0x5f, 0x3c, 0x70, 0x6d, 0x77, 0x42, 0x75, 0x42, 0x73, 0x68, 0x5e, 0x5f, 0x72, 0x2b, 0x2a, 0x70, 0x38, 0x7a, 0x4c, 0x58, 0x2e, 0x5e, 0x2d, 0x2d, 0x78, 0x67, 0x5a, 0x77, 0x34, 0x5a, 0x50, 0x76, 0x2d, 0x2b, 0x77, 0x37, 0x6e, 0x38, 0x2d, 0x7b, 0x44, 0x78, 0x67, 0x52, 0x57, 0x79, 0x43, 0x7d, 0x6d, 0x4d, 0x32, 0x23, 0x37, 0x51, 0x4b, 0x41, 0x60, 0x6e, 0x53, 0x4e, 0x78, 0x37, 0x37, 0x60, 0x56, 0x64, 0x52, 0x25, 0x46, 0x53, 0x5f, 0x2b, 0x56, 0x2b, 0x3b, 0x40, 0x37, 0x33, 0x37, 0x23, 0x43, 0x36, 0x6b, 0x6b, 0x5d, 0x35, 0x28, 0x7d, 0x6a, 0x2c, 0x68, 0x28, 0x4b, 0x4a, 0x6c, 0x27, 0x35, 0x51, 0x66, 0x30, 0x39, 0x28, 0x4d, 0x61, 0x2f, 0x64, 0x36, 0x59, 0x39, 0x68, 0x4b, 0x24, 0x51, 0x7b, 0x6e, 0x38, 0x49, 0x55, 0x72, 0x5f, 0x33, 0x5c, 0x26, 0x45, 0x2f, 0x71, 0x66, 0x33, 0x3d, 0x36, 0x68, 0x65, 0x48, 0x42, 0x40, 0x58, 0x61, 0x4f, 0x50, 0x70, 0x5e, 0x3c, 0x5d, 0x56, 0x43, 0x4c, 0x41, 0x45, 0x54, 0x76, 0x4b, 0x21, 0x25, 0x45, 0x4c, 0x5e, 0x58, 0x23, 0x7d, 0x34, 0x61, 0x5c, 0x53, 0x2a, 0x47, 0x37, 0x22, 0x6d, 0x31, 0x42, 0x6e, 0x22, 0x72, 0x62, 0x55, 0x59, 0x66, 0x28, 0x73, 0x55, 0x50, 0x5c, 0x6f, 0x52, 0x40, 0x3e, 0x3b, 0x44, 0x2a, 0x51, 0x3d, 0x4d, 0x47, 0x3a, 0x57, 0x3e, 0x29, 0x29, 0x7d, 0x40, 0x36, 0x41, 0x3f, 0x58, 0x77, 0x3b, 0x41, 0x2d, 0x64, 0x5a, 0x72, 0x7c, 0x7d, 0x30, 0x68, 0x54, 0x34, 0x40, 0x21, 0x7d, 0x2b, 0x2d, 0x2b, 0x6d, 0x5f, 0x49, 0x57, 0x68, 0x65, 0x79, 0x2c, 0x21, 0x41, 0x31, 0x55, 0x27, 0x4d, 0x78, 0x55, 0x2f, 0x61, 0x62, 0x78, 0x58, 0x25, 0x3a, 0x4b, 0x3e, 0x67, 0x44, 0x7c, 0x7d, 0x52, 0x3d, 0x3e, 0x3b, 0x62, 0x2d, 0x28, 0x48, 0x70, 0x2c, 0x79, 0x31, 0x5a, 0x5e, 0x3f, 0x6a, 0x30, 0x78, 0x41, 0x44, 0x60, 0x4e, 0x63, 0x63, 0x2e, 0x31, 0x79, 0x2b, 0x47, 0x57, 0x26, 0x22, 0x6a, 0x46, 0x43, 0x70, 0x30, 0x51, 0x7d, 0x21, 0x3c, 0x68, 0x74, 0x40, 0x5a, 0x6e, 0x71, 0x3f, 0x76, 0x73, 0x2e, 0x29, 0x3f, 0x6a, 0x55, 0x21, 0x72, 0x65, 0x75, 0x5e, 0x6b, 0x39, 0x6e, 0x3e, 0x76, 0x42, 0x41, 0x65, 0x3f, 0x2b, 0x37, 0x70, 0x7a, 0x7a, 0x29, 0x50, 0x66, 0x21, 0x67, 0x3f, 0x54, 0x32, 0x5f, 0x73, 0x27, 0x59, 0x6f, 0x39, 0x4b, 0x4e, 0x23, 0x54, 0x3b, 0x39, 0x21, 0x38, 0x41, 0x33, 0x44, 0x57, 0x6b, 0x51, 0x30, 0x6a, 0x76, 0x62, 0x2c, 0x5c, 0x5e, 0x49, 0x3e, 0x59, 0x38, 0x5e, 0x4a, 0x59, 0x77, 0x34, 0x25, 0x4f, 0x76, 0x6a, 0x68, 0x6f, 0x73, 0x7c, 0x3d, 0x2d, 0x64, 0x6c, 0x7a, 0x3d, 0x2c, 0x26, 0x28, 0x58, 0x2b, 0x4b, 0x45, 0x68, 0x38, 0x74, 0x63, 0x7b, 0x4a, 0x63, 0x52, 0x26, 0x54, 0x3c, 0x46, 0x77, 0x2d, 0x6b, 0x78, 0x63, 0x7b, 0x6a, 0x50, 0x26, 0x42, 0x62, 0x63, 0x65, 0x6b, 0x63, 0x54, 0x4d, 0x47, 0x59, 0x48, 0x2e, 0x60, 0x7c, 0x4d, 0x33, 0x4d, 0x61, 0x72, 0x76, 0x72, 0x21, 0x4d, 0x2b, 0x43, 0x58, 0x47, 0x4a, 0x36, 0x2d, 0x7b, 0x32, 0x72, 0x21, 0x78, 0x22, 0x38, 0x2c, 0x7a, 0x34, 0x44, 0x45, 0x66, 0x31, 0x7b, 0x37, 0x68, 0x62, 0x65, 0x62, 0x6d, 0x4e, 0x7c, 0x75, 0x38, 0x2a, 0x73, 0x27, 0x64, 0x33, 0x4f, 0x21, 0x41, 0x7c, 0x41, 0x3f, 0x60, 0x68, 0x34, 0x72, 0x5b, 0x38, 0x33, 0x6f, 0x65, 0x3e, 0x5a, 0x7d, 0x25, 0x49, 0x50, 0x60, 0x36, 0x59, 0x5e, 0x6b, 0x25, 0x66, 0x7a, 0x7d, 0x71, 0x40, 0x6c, 0x2c, 0x6e, 0x6a, 0x5a, 0x24, 0x5a, 0x76, 0x21, 0x67, 0x39, 0x4b, 0x4a, 0x31, 0x24, 0x66, 0x66, 0x2e, 0x58, 0x43, 0x46, 0x75, 0x6c, 0x47, 0x28, 0x4f, 0x21, 0x75, 0x77, 0x6f, 0x71, 0x48, 0x3f, 0x4d, 0x4c, 0x51, 0x37, 0x3b, 0x41, 0x4d, 0x41, 0x48, 0x28, 0x71, 0x24, 0x2f, 0x7a, 0x22, 0x49, 0x4a, 0x39, 0x44, 0x43, 0x68, 0x21, 0x3a, 0x34, 0x4e, 0x52, 0x7a, 0x60, 0x71, 0x61, 0x6d, 0x51, 0x58, 0x2a, 0x59, 0x4c, 0x4a, 0x59, 0x6b, 0x77, 0x78, 0x2e, 0x27, 0x78, 0x76, 0x48, 0x4f, 0x46, 0x79, 0x2c, 0x54, 0x42, 0x7b, 0x2c, 0x52, 0x41, 0x54, 0x2b, 0x2c, 0x33, 0x6b, 0x70, 0x77, 0x2e, 0x2e, 0x41, 0x25, 0x7a, 0x48, 0x6e, 0x71, 0x55, 0x6a, 0x43, 0x5a, 0x2c, 0x6c, 0x76, 0x6d, 0x71, 0x72, 0x4d, 0x76, 0x5b, 0x7b, 0x22, 0x4b, 0x45, 0x31, 0x30, 0x26, 0x53, 0x75, 0x3f, 0x26, 0x59, 0x36, 0x2f, 0x68, 0x4f, 0x34, 0x5e, 0x2b, 0x30, 0x63, 0x68, 0x7b, 0x32, 0x5e, 0x77, 0x7d, 0x7b, 0x53, 0x5f, 0x63, 0x53, 0x77, 0x7a, 0x7d, 0x35, 0x28, 0x3e, 0x41, 0x6f, 0x5b, 0x31, 0x78, 0x7b, 0x2b, 0x51, 0x23, 0x43, 0x46, 0x6a, 0x32, 0x32, 0x25, 0x45, 0x57, 0x43, 0x22, 0x50, 0x60, 0x32, 0x70, 0x2e, 0x79, 0x2e, 0x6b, 0x33, 0x67, 0x6c, 0x43, 0x5b, 0x3b, 0x68, 0x53, 0x53, 0x6a, 0x48, 0x59, 0x5f, 0x30, 0x72, 0x7d, 0x6b, 0x37, 0x24, 0x75, 0x52, 0x50, 0x2b, 0x75, 0x35, 0x24, 0x3b, 0x6e, 0x53, 0x56, 0x34, 0x23, 0x54, 0x65, 0x4f, 0x78, 0x3e, 0x46, 0x7d, 0x25, 0x3f, 0x2f, 0x49, 0x6b, 0x49, 0x47, 0x45, 0x24, 0x38, 0x3b, 0x68, 0x6c, 0x4f, 0x29, 0x21, 0x50, 0x32, 0x67, 0x47, 0x5a, 0x72, 0x76, 0x21, 0x39, 0x67, 0x3c, 0x72, 0x47, 0x43, 0x4a, 0x2e, 0x31, 0x32, 0x34, 0x3c, 0x53, 0x2d, 0x22, 0x5b, 0x5b, 0x6a, 0x77, 0x75, 0x31, 0x68, 0x30, 0x45, 0x43, 0x5f, 0x60, 0x5d, 0x56, 0x67, 0x66, 0x55, 0x6a, 0x72, 0x77, 0x7b, 0x44, 0x61, 0x22, 0x64, 0x36, 0x39, 0x6e, 0x44, 0x37, 0x54, 0x45, 0x46, 0x6f, 0x58, 0x35, 0x51, 0x3c, 0x62, 0x49, 0x3a, 0x50, 0x58, 0x56, 0x5d, 0x77, 0x6f, 0x56, 0x64, 0x7b, 0x49, 0x39, 0x21, 0x31, 0x2d, 0x5f, 0x56, 0x56, 0x33, 0x31, 0x69, 0x4a, 0x52, 0x62, 0x5b, 0x6e, 0x65, 0x7c, 0x3d, 0x31, 0x55, 0x3d, 0x75, 0x25, 0x61, 0x50, 0x71, 0x45, 0x29 }; uint32_t request5_len = sizeof(request5); uint8_t request6[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x5b, 0x56, 0x3d, 0x5a, 0x6b, 0x43, 0x73, 0x26, 0x65, 0x3b, 0x38, 0x79, 0x26, 0x5e, 0x60, 0x59, 0x40, 0x71, 0x7c, 0x72, 0x28, 0x29, 0x69, 0x32, 0x72, 0x5a, 0x6c, 0x55, 0x43, 0x65, 0x3f, 0x4a, 0x21, 0x66, 0x59, 0x30, 0x76, 0x39, 0x21, 0x69, 0x4b, 0x25, 0x5d, 0x6e, 0x5f, 0x24, 0x2b, 0x38, 0x70, 0x78, 0x35, 0x7d, 0x39, 0x36, 0x31, 0x72, 0x44, 0x49, 0x45, 0x3d, 0x25, 0x50, 0x24, 0x3b, 0x52, 0x27, 0x66, 0x46, 0x5d, 0x4f, 0x34, 0x50, 0x26, 0x5a, 0x25, 0x3e, 0x3f, 0x34, 0x4b, 0x35, 0x77, 0x3a, 0x3f, 0x3e, 0x23, 0x4e, 0x30, 0x23, 0x70, 0x72, 0x33, 0x34, 0x60, 0x2a, 0x4a, 0x32, 0x6e, 0x29, 0x54, 0x73, 0x5f, 0x26, 0x71, 0x3a, 0x78, 0x5d, 0x3f, 0x31, 0x48, 0x59, 0x61, 0x44, 0x5c, 0x38, 0x4f, 0x41, 0x73, 0x67, 0x62, 0x73, 0x33, 0x52, 0x77, 0x73, 0x57, 0x49, 0x7a, 0x59, 0x26, 0x21, 0x34, 0x38, 0x2b, 0x5f, 0x5f, 0x37, 0x74, 0x28, 0x46, 0x3d, 0x43, 0x42, 0x26, 0x66, 0x63, 0x37, 0x6d, 0x2a, 0x65, 0x3f, 0x71, 0x2d, 0x4c, 0x72, 0x29, 0x4b, 0x3a, 0x77, 0x64, 0x6a, 0x6b, 0x42, 0x70, 0x5c, 0x51, 0x38, 0x71, 0x25, 0x4c, 0x7c, 0x6f, 0x74, 0x71, 0x39, 0x71, 0x25, 0x3f, 0x62, 0x23, 0x45, 0x5f, 0x77, 0x59, 0x56, 0x56, 0x67, 0x78, 0x3a, 0x2e, 0x4e, 0x27, 0x59, 0x65, 0x2f, 0x64, 0x3c, 0x62, 0x40, 0x69, 0x52, 0x36, 0x49, 0x3e, 0x3b, 0x2c, 0x47, 0x4f, 0x3e, 0x61, 0x78, 0x2d, 0x45, 0x71, 0x3f, 0x7b, 0x55, 0x34, 0x36, 0x47, 0x5e, 0x36, 0x51, 0x3d, 0x5a, 0x4b, 0x75, 0x44, 0x72, 0x61, 0x44, 0x71, 0x4e, 0x42, 0x6a, 0x2c, 0x34, 0x40, 0x3b, 0x40, 0x31, 0x31, 0x75, 0x4b, 0x32, 0x71, 0x69, 0x3a, 0x5d, 0x31, 0x25, 0x53, 0x2a, 0x61, 0x54, 0x68, 0x2a, 0x76, 0x71, 0x57, 0x67, 0x56, 0x23, 0x7d, 0x70, 0x7d, 0x28, 0x57, 0x5f, 0x2f, 0x4c, 0x71, 0x2e, 0x40, 0x63, 0x49, 0x5b, 0x7c, 0x7b, 0x56, 0x76, 0x77, 0x46, 0x69, 0x56, 0x3d, 0x75, 0x31, 0x3b, 0x35, 0x40, 0x37, 0x2c, 0x51, 0x37, 0x49, 0x6a, 0x79, 0x68, 0x53, 0x31, 0x4c, 0x6f, 0x57, 0x4c, 0x48, 0x31, 0x6a, 0x30, 0x2b, 0x69, 0x30, 0x56, 0x58, 0x4b, 0x76, 0x3b, 0x60, 0x6d, 0x35, 0x4d, 0x74, 0x2f, 0x74, 0x2c, 0x54, 0x4f, 0x6e, 0x3f, 0x38, 0x56, 0x5c, 0x67, 0x2b, 0x4a, 0x35, 0x30, 0x67, 0x7d, 0x58, 0x24, 0x59, 0x54, 0x48, 0x2e, 0x28, 0x7d, 0x6e, 0x51, 0x55, 0x68, 0x56, 0x54, 0x59, 0x31, 0x4a, 0x65, 0x5a, 0x5e, 0x27, 0x76, 0x76, 0x65, 0x6d, 0x2f, 0x75, 0x63, 0x67, 0x52, 0x5e, 0x29, 0x58, 0x3d, 0x5c, 0x3f, 0x54, 0x7c, 0x67, 0x21, 0x6e, 0x75, 0x67, 0x35, 0x77, 0x31, 0x3d, 0x26, 0x3f, 0x60, 0x45, 0x2d, 0x2b, 0x45, 0x5d, 0x3f, 0x55, 0x73, 0x59, 0x4c, 0x5e, 0x6c, 0x30, 0x4a, 0x4e, 0x47, 0x55, 0x42, 0x6a, 0x4b, 0x32, 0x3c, 0x75, 0x6e, 0x36, 0x51, 0x5f, 0x4c, 0x68, 0x72, 0x72, 0x27, 0x3b, 0x51, 0x59, 0x7b, 0x68, 0x7b, 0x3b, 0x54, 0x35, 0x37, 0x7c, 0x44, 0x43, 0x36, 0x4c, 0x4f, 0x67, 0x62, 0x4e, 0x39, 0x4b, 0x7a, 0x49, 0x36, 0x68, 0x38, 0x4c, 0x4a, 0x64, 0x33, 0x35, 0x2f, 0x3e, 0x5c, 0x58, 0x61, 0x23, 0x5b, 0x50, 0x6e, 0x34, 0x44, 0x60, 0x28, 0x54, 0x41, 0x5c, 0x31, 0x53, 0x2d, 0x58, 0x58, 0x54, 0x28, 0x77, 0x51, 0x6f, 0x64, 0x4c, 0x68, 0x34, 0x79, 0x45, 0x66, 0x2c, 0x26, 0x77, 0x64, 0x5f, 0x6c, 0x3b, 0x71, 0x28, 0x4d, 0x68, 0x2a, 0x6b, 0x37, 0x6a, 0x34, 0x51, 0x27, 0x2a, 0x46, 0x3a, 0x2e, 0x35, 0x21, 0x21, 0x79, 0x51, 0x44, 0x58, 0x5d, 0x6f, 0x65, 0x6b, 0x76, 0x68, 0x3a, 0x43, 0x70, 0x36, 0x41, 0x6b, 0x56, 0x64, 0x75, 0x5b, 0x37, 0x24, 0x56, 0x7c, 0x6e, 0x6c, 0x41, 0x3a, 0x60, 0x56, 0x38, 0x55, 0x63, 0x77, 0x4d, 0x6e, 0x50, 0x3c, 0x3d, 0x7a, 0x44, 0x71, 0x42, 0x4b, 0x55, 0x75, 0x72, 0x61, 0x60, 0x65, 0x6f, 0x7a, 0x26, 0x64, 0x46, 0x67, 0x74, 0x29, 0x2a, 0x5b, 0x62, 0x41, 0x28, 0x62, 0x30, 0x34, 0x33, 0x40, 0x79, 0x7a, 0x38, 0x56, 0x38, 0x73, 0x22, 0x7a, 0x7d, 0x73, 0x2a, 0x2a, 0x28, 0x2b, 0x63, 0x27, 0x6f, 0x3d, 0x3e, 0x2c, 0x56, 0x23, 0x32, 0x4b, 0x3b, 0x58, 0x4d, 0x72, 0x4c, 0x49, 0x6f, 0x30, 0x76, 0x23, 0x21, 0x21, 0x3c, 0x49, 0x56, 0x7a, 0x56, 0x79, 0x2f, 0x50, 0x7a, 0x5b, 0x21, 0x21, 0x4a, 0x48, 0x61, 0x33, 0x52, 0x49, 0x2e, 0x30, 0x7d, 0x2c, 0x2d, 0x67, 0x23, 0x55, 0x62, 0x66, 0x52, 0x5a, 0x61, 0x75, 0x63, 0x3c, 0x39, 0x69, 0x41, 0x31, 0x6b, 0x4e, 0x6f, 0x25, 0x34, 0x74, 0x30, 0x21, 0x3a, 0x40, 0x72, 0x44, 0x40, 0x60, 0x4c, 0x53, 0x74, 0x42, 0x64, 0x44, 0x49, 0x76, 0x67, 0x21, 0x79, 0x36, 0x3c, 0x37, 0x70, 0x4f, 0x58, 0x29, 0x71, 0x2a, 0x3a, 0x4d, 0x5d, 0x67, 0x68, 0x52, 0x63, 0x23, 0x24, 0x4b, 0x21, 0x3f, 0x68, 0x69, 0x6c, 0x66, 0x66, 0x42, 0x28, 0x59, 0x35, 0x34, 0x6f, 0x2d, 0x6a, 0x25, 0x66, 0x34, 0x54, 0x5d, 0x50, 0x26, 0x41, 0x22, 0x4f, 0x34, 0x79, 0x3c, 0x50, 0x68, 0x2d, 0x5f, 0x7b, 0x63, 0x7d, 0x58, 0x2e, 0x73, 0x46, 0x2f, 0x54, 0x61, 0x27, 0x74, 0x45, 0x23, 0x72, 0x31, 0x7d, 0x63, 0x4b, 0x43, 0x5e, 0x44, 0x54, 0x2c, 0x38, 0x58, 0x24, 0x75, 0x6c, 0x50, 0x3c, 0x23, 0x5f, 0x35, 0x57, 0x4f, 0x7b, 0x2f, 0x57, 0x29, 0x73, 0x58, 0x2a, 0x66, 0x3e, 0x49, 0x42, 0x5a, 0x6b, 0x75, 0x6a, 0x38, 0x3f, 0x73, 0x44, 0x42, 0x46, 0x2d, 0x39, 0x66, 0x5b, 0x28, 0x3e, 0x63, 0x62, 0x53, 0x75, 0x65, 0x64, 0x79, 0x32, 0x35, 0x71, 0x22, 0x6a, 0x7b, 0x41, 0x2b, 0x26, 0x43, 0x79, 0x58, 0x6f, 0x71, 0x25, 0x24, 0x34, 0x72, 0x5b, 0x4a, 0x2c, 0x5c, 0x77, 0x23, 0x42, 0x27, 0x6a, 0x67, 0x51, 0x5f, 0x3c, 0x75, 0x2c, 0x3f, 0x43, 0x45, 0x5b, 0x48, 0x65, 0x6f, 0x6c, 0x27, 0x65, 0x21, 0x3e, 0x33, 0x37, 0x5f, 0x2b, 0x2e, 0x24, 0x22, 0x47, 0x4e, 0x33, 0x5b, 0x7b, 0x21, 0x3c, 0x53, 0x69, 0x2e, 0x31, 0x3d, 0x48, 0x57, 0x3a, 0x56, 0x48, 0x6b, 0x47, 0x5d, 0x33, 0x41, 0x6c, 0x66, 0x4c, 0x61, 0x67, 0x32, 0x69, 0x53, 0x2c, 0x2f, 0x3e, 0x36, 0x68, 0x37, 0x28, 0x40, 0x21, 0x76, 0x27, 0x44, 0x26, 0x24, 0x6a, 0x30, 0x75, 0x2a, 0x73, 0x48, 0x36, 0x52, 0x4a, 0x3b, 0x51, 0x4e, 0x2f, 0x23, 0x36, 0x4b, 0x49, 0x33, 0x5a, 0x70, 0x2c, 0x54, 0x5b, 0x67, 0x48, 0x53, 0x5d, 0x21, 0x3e, 0x6b, 0x52, 0x6a, 0x3c, 0x48, 0x29, 0x68, 0x27, 0x32, 0x75, 0x61, 0x7c, 0x51, 0x2e, 0x7b, 0x49, 0x2f, 0x5b, 0x3d, 0x74, 0x5a, 0x28, 0x26, 0x29, 0x2c, 0x30, 0x54, 0x74, 0x45, 0x55, 0x4a, 0x3d, 0x39, 0x35, 0x66, 0x56, 0x28, 0x6d, 0x6e, 0x38, 0x7b, 0x2b, 0x40, 0x31, 0x56, 0x61, 0x74, 0x2b, 0x79, 0x5f, 0x63, 0x51, 0x53, 0x52, 0x7d, 0x73, 0x4e, 0x2e, 0x45, 0x3b, 0x22, 0x28, 0x6c, 0x2b, 0x47, 0x21, 0x50, 0x2a, 0x7c, 0x45, 0x48, 0x57, 0x3e, 0x2f, 0x6d, 0x66, 0x6c, 0x51, 0x23, 0x6c, 0x37, 0x4d, 0x4b, 0x4b, 0x66, 0x55, 0x69, 0x2e, 0x4a, 0x69, 0x71, 0x7c, 0x71, 0x30, 0x5c, 0x43, 0x46, 0x63, 0x5a, 0x23, 0x75, 0x40 }; uint32_t request6_len = sizeof(request6); uint8_t request7[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x5d, 0x32, 0x55, 0x71, 0x51, 0x45, 0x4e, 0x54, 0x34, 0x21, 0x46, 0x77, 0x5e, 0x5b, 0x75, 0x62, 0x2b, 0x5c, 0x34, 0x26, 0x72, 0x2b, 0x2c, 0x64, 0x4b, 0x65, 0x56, 0x72, 0x31, 0x7d, 0x6a, 0x5f, 0x70, 0x26, 0x32, 0x29, 0x7d, 0x21, 0x5b, 0x3e, 0x5e, 0x53, 0x3d, 0x48, 0x5e, 0x2a, 0x4c, 0x37, 0x3d, 0x59, 0x79, 0x21, 0x4f, 0x56, 0x79, 0x2a, 0x4e, 0x28, 0x61, 0x7d, 0x2c, 0x58, 0x2f, 0x78, 0x5c, 0x3f, 0x5c, 0x42, 0x6d, 0x2f, 0x71, 0x54, 0x25, 0x31, 0x73, 0x38, 0x6c, 0x31, 0x5a, 0x2e, 0x42, 0x5b, 0x2d, 0x41, 0x24, 0x4c, 0x37, 0x40, 0x39, 0x7d, 0x2a, 0x67, 0x60, 0x6a, 0x7a, 0x62, 0x24, 0x4e, 0x3f, 0x2e, 0x69, 0x35, 0x28, 0x65, 0x77, 0x53, 0x23, 0x44, 0x59, 0x71, 0x31, 0x5c, 0x40, 0x5d, 0x3a, 0x27, 0x46, 0x55, 0x30, 0x56, 0x21, 0x74, 0x3e, 0x73, 0x41, 0x22, 0x52, 0x68, 0x40, 0x6c, 0x37, 0x3e, 0x62, 0x5a, 0x2e, 0x21, 0x23, 0x33, 0x27, 0x73, 0x68, 0x26, 0x60, 0x67, 0x70, 0x58, 0x50, 0x42, 0x58, 0x27, 0x3a, 0x35, 0x6f, 0x51, 0x62, 0x78, 0x25, 0x2c, 0x7b, 0x66, 0x34, 0x6a, 0x5a, 0x39, 0x60, 0x70, 0x41, 0x2d, 0x65, 0x26, 0x5a, 0x67, 0x58, 0x2d, 0x3e, 0x56, 0x6d, 0x30, 0x4b, 0x4d, 0x5d, 0x45, 0x41, 0x3d, 0x6e, 0x27, 0x4e, 0x5a, 0x7d, 0x2e, 0x62, 0x4d, 0x42, 0x70, 0x31, 0x24, 0x73, 0x5c, 0x78, 0x77, 0x50, 0x73, 0x27, 0x48, 0x3d, 0x35, 0x2c, 0x4b, 0x40, 0x2d, 0x25, 0x77, 0x5d, 0x3d, 0x6b, 0x50, 0x6f, 0x57, 0x73, 0x2f, 0x4f, 0x6e, 0x4c, 0x6e, 0x56, 0x7b, 0x55, 0x3c, 0x6d, 0x60, 0x47, 0x53, 0x56, 0x39, 0x3b, 0x51, 0x61, 0x71, 0x75, 0x73, 0x6b, 0x70, 0x58, 0x5f, 0x2c, 0x27, 0x74, 0x49, 0x2c, 0x2b, 0x53, 0x2d, 0x5b, 0x79, 0x43, 0x34, 0x39, 0x5a, 0x38, 0x3e, 0x2d, 0x66, 0x70, 0x3d, 0x49, 0x51, 0x29, 0x4d, 0x5d, 0x4c, 0x57, 0x4a, 0x2f, 0x41, 0x69, 0x56, 0x57, 0x77, 0x49, 0x58, 0x75, 0x28, 0x29, 0x4a, 0x6d, 0x54, 0x4f, 0x4f, 0x3f, 0x58, 0x5f, 0x58, 0x6f, 0x39, 0x22, 0x4d, 0x5d, 0x31, 0x75, 0x43, 0x2f, 0x7d, 0x31, 0x3d, 0x4c, 0x4d, 0x76, 0x74, 0x4d, 0x57, 0x3b, 0x56, 0x57, 0x48, 0x2b, 0x5d, 0x32, 0x67, 0x51, 0x6e, 0x60, 0x39, 0x6f, 0x64, 0x38, 0x37, 0x52, 0x4b, 0x52, 0x42, 0x32, 0x4f, 0x24, 0x53, 0x31, 0x6e, 0x4a, 0x68, 0x2f, 0x28, 0x2e, 0x27, 0x49, 0x75, 0x77, 0x75, 0x26, 0x47, 0x7c, 0x5d, 0x72, 0x5a, 0x77, 0x50, 0x2e, 0x6c, 0x27, 0x68, 0x6b, 0x7b, 0x27, 0x63, 0x21, 0x3d, 0x30, 0x2d, 0x5c, 0x67, 0x4d, 0x41, 0x79, 0x47, 0x42, 0x50, 0x6d, 0x32, 0x74, 0x39, 0x62, 0x4d, 0x5f, 0x65, 0x78, 0x4f, 0x67, 0x3a, 0x60, 0x26, 0x45, 0x61, 0x7c, 0x61, 0x63, 0x40, 0x46, 0x79, 0x52, 0x47, 0x57, 0x49, 0x53, 0x4c, 0x48, 0x36, 0x67, 0x47, 0x5c, 0x71, 0x50, 0x4d, 0x4f, 0x58, 0x26, 0x40, 0x6d, 0x54, 0x55, 0x67, 0x66, 0x23, 0x70, 0x23, 0x68, 0x70, 0x4d, 0x2c, 0x7a, 0x3d, 0x60, 0x51, 0x35, 0x64, 0x56, 0x2f, 0x26, 0x6d, 0x72, 0x6a, 0x59, 0x34, 0x3a, 0x73, 0x4b, 0x27, 0x33, 0x61, 0x26, 0x45, 0x61, 0x28, 0x74, 0x22, 0x54, 0x50, 0x2e, 0x39, 0x6a, 0x2c, 0x27, 0x59, 0x26, 0x73, 0x44, 0x71, 0x67, 0x4c, 0x37, 0x74, 0x2c, 0x63, 0x52, 0x2a, 0x60, 0x4f, 0x7b, 0x32, 0x39, 0x21, 0x79, 0x54, 0x79, 0x6d, 0x28, 0x27, 0x3a, 0x6a, 0x7d, 0x40, 0x6a, 0x4f, 0x4b, 0x46, 0x61, 0x36, 0x6a, 0x22, 0x3f, 0x77, 0x2d, 0x6a, 0x3b, 0x73, 0x71, 0x72, 0x3c, 0x21, 0x2e, 0x3f, 0x33, 0x25, 0x76, 0x64, 0x64, 0x70, 0x43, 0x32, 0x44, 0x73, 0x61, 0x51, 0x3c, 0x3b, 0x45, 0x3a, 0x68, 0x46, 0x5b, 0x6e, 0x36, 0x47, 0x4d, 0x38, 0x26, 0x4f, 0x5c, 0x7d, 0x73, 0x29, 0x24, 0x78, 0x44, 0x75, 0x40, 0x42, 0x41, 0x2a, 0x73, 0x2b, 0x24, 0x38, 0x51, 0x67, 0x36, 0x67, 0x2f, 0x70, 0x58, 0x54, 0x6e, 0x5d, 0x3b, 0x41, 0x59, 0x76, 0x7d, 0x2d, 0x40, 0x70, 0x29, 0x4a, 0x4a, 0x31, 0x79, 0x2c, 0x4e, 0x22, 0x31, 0x59, 0x31, 0x3c, 0x2f, 0x21, 0x29, 0x3f, 0x65, 0x6c, 0x38, 0x55, 0x4f, 0x27, 0x66, 0x66, 0x34, 0x45, 0x49, 0x41, 0x56, 0x24, 0x2e, 0x40, 0x36, 0x23, 0x5a, 0x46, 0x40, 0x23, 0x7b, 0x2d, 0x69, 0x54, 0x6c, 0x51, 0x58, 0x73, 0x56, 0x60, 0x5f, 0x60, 0x63, 0x5f, 0x77, 0x6a, 0x4c, 0x2c, 0x35, 0x39, 0x60, 0x73, 0x63, 0x3e, 0x2d, 0x55, 0x5a, 0x26, 0x4b, 0x43, 0x3b, 0x56, 0x33, 0x58, 0x74, 0x51, 0x4f, 0x5c, 0x2a, 0x44, 0x78, 0x66, 0x78, 0x71, 0x40, 0x29, 0x5e, 0x26, 0x57, 0x51, 0x49, 0x30, 0x29, 0x73, 0x38, 0x56, 0x6c, 0x41, 0x78, 0x3d, 0x61, 0x3d, 0x2c, 0x33, 0x46, 0x57, 0x54, 0x63, 0x3e, 0x79, 0x55, 0x4a, 0x7d, 0x2e, 0x2a, 0x3c, 0x77, 0x47, 0x35, 0x29, 0x5a, 0x6d, 0x69, 0x48, 0x6b, 0x73, 0x7d, 0x4f, 0x5f, 0x6f, 0x3a, 0x7a, 0x4e, 0x54, 0x59, 0x38, 0x62, 0x44, 0x72, 0x51, 0x57, 0x6a, 0x74, 0x54, 0x4f, 0x77, 0x6b, 0x66, 0x4a, 0x6b, 0x39, 0x29, 0x69, 0x60, 0x71, 0x52, 0x6a, 0x32, 0x66, 0x6c, 0x25, 0x76, 0x27, 0x7a, 0x2c, 0x38, 0x72, 0x4e, 0x5f, 0x40, 0x26, 0x74, 0x6a, 0x5e, 0x42, 0x38, 0x78, 0x34, 0x4f, 0x4f, 0x35, 0x27, 0x39, 0x62, 0x52, 0x61, 0x37, 0x54, 0x47, 0x38, 0x70, 0x31, 0x7a, 0x66, 0x69, 0x72, 0x24, 0x52, 0x2a, 0x2a, 0x78, 0x72, 0x2b, 0x2e, 0x2a, 0x57, 0x4a, 0x21, 0x52, 0x3c, 0x2a, 0x2f, 0x24, 0x58, 0x34, 0x3c, 0x42, 0x5c, 0x5b, 0x78, 0x27, 0x55, 0x63, 0x58, 0x3e, 0x26, 0x50, 0x2c, 0x72, 0x60, 0x36, 0x6c, 0x46, 0x58, 0x63, 0x59, 0x23, 0x2a, 0x2d, 0x63, 0x6a, 0x68, 0x69, 0x74, 0x3f, 0x49, 0x4f, 0x48, 0x4a, 0x3b, 0x59, 0x56, 0x77, 0x43, 0x6d, 0x57, 0x28, 0x5f, 0x39, 0x73, 0x28, 0x74, 0x3c, 0x4f, 0x43, 0x48, 0x6a, 0x57, 0x5d, 0x41, 0x73, 0x3f, 0x41, 0x7c, 0x65, 0x5e, 0x2d, 0x38, 0x72, 0x3a, 0x53, 0x3e, 0x33, 0x47, 0x69, 0x6a, 0x6e, 0x78, 0x67, 0x5d, 0x35, 0x3b, 0x3f, 0x23, 0x7c, 0x71, 0x3d, 0x7c, 0x3a, 0x3c, 0x75, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x80, 0x23, 0x00, 0xdf, 0xaf, 0xff, 0x33, 0x9b, 0x78, 0x70, 0x43, 0xc5, 0x0a, 0x4d, 0x98, 0x96, 0x02, 0x64, 0x92, 0xc1, 0xee, 0x70, 0x32 }; uint32_t request7_len = sizeof(request7); uint8_t request8[] = { 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x65, 0xc1, 0xef, 0x7b, 0xd6, 0xaa, 0xd6, 0x09, 0x21, 0xf6, 0xe7, 0xd1, 0x4c, 0xdf, 0x6a, 0x2d, 0x0a, 0xfb, 0x43, 0xea, 0xda, 0x07, 0x24, 0x84, 0x88, 0x52, 0x9e, 0xa8, 0xa1, 0x7f, 0x4b, 0x60, 0xec, 0x94, 0x57, 0x33, 0x06, 0x93, 0x92, 0x25, 0xd6, 0xac, 0xdc, 0x89, 0x68, 0x5e, 0xbb, 0x32, 0x2b, 0x17, 0x68, 0xf2, 0x06, 0xb7, 0x86, 0xac, 0x81, 0xfe, 0x52, 0x27, 0xf5, 0x80, 0x11, 0x0d, 0x4e, 0x2e, 0x1b, 0xa3, 0x44, 0x8a, 0x58, 0xed, 0xf3, 0x9c, 0xe9, 0x31, 0x01, 0x72, 0xa6, 0xab, 0xfa, 0xa8, 0x05, 0x00, 0x37, 0x60, 0x6b, 0x81, 0xef, 0xf4, 0x96, 0x9a, 0xf7, 0x67, 0x95, 0x27, 0x7a, 0x25, 0xef, 0x6f, 0x0e, 0xff, 0x2d, 0x15, 0x7f, 0x23, 0x1c, 0xa7, 0x56, 0x94, 0x4a, 0x18, 0x98, 0xc6, 0xd8, 0xd2, 0x29, 0x5b, 0x57, 0xb8, 0x5d, 0x3a, 0x93, 0x58, 0x45, 0x77, 0x36, 0xe3, 0xd1, 0x36, 0x87, 0xff, 0xe3, 0x94, 0x0f, 0x00, 0xe6, 0x7c, 0x1a, 0x92, 0xc1, 0x5f, 0x40, 0xc3, 0xa3, 0x25, 0xce, 0xd4, 0xaf, 0x39, 0xeb, 0x17, 0xcf, 0x22, 0x43, 0xd9, 0x0c, 0xce, 0x37, 0x86, 0x46, 0x54, 0xd6, 0xce, 0x00, 0x30, 0x36, 0xae, 0xf9, 0xb5, 0x2b, 0x11, 0xa0, 0xfe, 0xa3, 0x4b, 0x2e, 0x05, 0xbe, 0x54, 0xa9, 0xd8, 0xa5, 0x76, 0x83, 0x5b, 0x63, 0x01, 0x1c, 0xd4, 0x56, 0x72, 0xcd, 0xdc, 0x4a, 0x1d, 0x77, 0xda, 0x8a, 0x9e, 0xba, 0xcb, 0x6c, 0xe8, 0x19, 0x5d, 0x68, 0xef, 0x8e, 0xbc, 0x6a, 0x05, 0x53, 0x0b, 0xc7, 0xc5, 0x96, 0x84, 0x04, 0xd9, 0xda, 0x4c, 0x42, 0x31, 0xd9, 0xbd, 0x99, 0x06, 0xf7, 0xa3, 0x0a, 0x19, 0x49, 0x07, 0x77, 0xf0, 0xdb, 0x7c, 0x43, 0xfa, 0xb2, 0xad, 0xb0, 0xfa, 0x87, 0x52, 0xba, 0xc9, 0x94, 0x61, 0xdc, 0xcf, 0x16, 0xac, 0x0f, 0x4a, 0xa3, 0x6b, 0x5b, 0x6e, 0x27, 0x86, 0x1f, 0xfe, 0x4d, 0x28, 0x3a, 0xa5, 0x10, 0x54, 0x6d, 0xed, 0x53, 0xf9, 0x73, 0xc6, 0x6e, 0xa8, 0xc0, 0x97, 0xcf, 0x56, 0x3b, 0x61, 0xdf, 0xab, 0x83, 0x18, 0xe8, 0x09, 0xee, 0x6a, 0xb7, 0xf5, 0xc9, 0x62, 0x55, 0x2d, 0xc7, 0x0c, 0x0d, 0xa0, 0x22, 0xd8, 0xd4, 0xd6, 0xb2, 0x12, 0x21, 0xd7, 0x73, 0x3e, 0x41, 0xb0, 0x5c, 0xd4, 0xcf, 0x98, 0xf3, 0x70, 0xe6, 0x08, 0xe6, 0x2a, 0x4f, 0x24, 0x85, 0xe8, 0x74, 0xa8, 0x41, 0x5f, 0x0e, 0xfd, 0xf1, 0xf3, 0xbe, 0x9b, 0x14, 0xfd, 0xc0, 0x73, 0x11, 0xff, 0xa5, 0x5b, 0x06, 0x34, 0xc3, 0x6c, 0x28, 0x42, 0x07, 0xfe, 0x8a, 0xa5, 0xbe, 0x72, 0x7a, 0xf7, 0xfa, 0x25, 0xec, 0x35, 0x5e, 0x98, 0x71, 0x50, 0x60, 0x35, 0x76, 0x53, 0x40, 0x1a, 0x34, 0xa5, 0x99, 0x09, 0xa2, 0xc6, 0xca, 0xa5, 0xce, 0x08, 0x50, 0x45, 0xab, 0x8d, 0xfb, 0xe3, 0xb8, 0xe4, 0x8a, 0x61, 0x48, 0x14, 0x6e, 0xf7, 0x58, 0x71, 0xe5, 0x2e, 0xbc, 0x12, 0xd1, 0x25, 0xe9, 0x65, 0x7a, 0xa1, 0x27, 0xbe, 0x3b, 0x8b, 0xe8, 0xe7, 0xbc, 0xe1, 0x05, 0xe7, 0x92, 0xeb, 0xb9, 0xdf, 0x5d, 0x53, 0x74, 0xc0, 0x63, 0x97, 0x80, 0xb8, 0x3c, 0xae, 0xf3, 0xf2, 0x09, 0x12, 0x81, 0x6c, 0x69, 0x10, 0x6f, 0xf6, 0xbe, 0x03, 0x7b, 0x88, 0xcf, 0x26, 0x6b, 0x51, 0x06, 0x23, 0x68, 0x03, 0xa1, 0xb7, 0xd3, 0x0c, 0xca, 0xbf, 0x29, 0x01, 0xa9, 0x61, 0x34, 0x75, 0x98, 0x1e, 0x05, 0x59, 0xb3, 0x46, 0x44, 0xff, 0x2b, 0x98, 0x04, 0x88, 0x89, 0xfd, 0x7f, 0xd5, 0x19, 0x8a, 0xa6, 0xf3, 0xd9, 0x44, 0xd5, 0xf9, 0x3a, 0x3c, 0xec, 0xd9, 0x9b, 0x8c, 0x93, 0x93, 0x2b, 0x44, 0x86, 0x8b, 0x80, 0x83, 0x23, 0x00, 0xdf, 0xaf, 0xff, 0x33, 0x9b, 0x78, 0x70, 0x43, 0xf1, 0x55, 0x87, 0xb1, 0xa1, 0xb3, 0x8e, 0x79, 0x02, 0x70, 0x82, 0x6c, 0x0b, 0xc1, 0xef, 0x96, 0xf1, 0xef, 0xdd, 0xa2, 0x69, 0x86, 0xc7, 0x85, 0x09, 0x7e, 0xf0, 0x2f, 0x8e, 0xa0, 0x5f, 0xea, 0x39, 0x2e, 0x24, 0xf0, 0x82, 0x30, 0x26, 0xa8, 0xa1, 0x4f, 0xc6, 0x5c, 0xec, 0x94, 0x87, 0x52, 0x9b, 0x93, 0x92, 0xf3, 0xa3, 0x1b, 0xc7, 0x8f, 0x9e, 0xb3, 0xbb, 0x32, 0x2b, 0x17, 0x54, 0xf2, 0x06, 0x0c, 0x86, 0x92, 0x0f, 0xb8, 0xe0, 0x27, 0x50, 0xaa, 0xeb, 0xf5, 0x4e, 0x2b, 0x1b, 0xb2, 0x44, 0xe6, 0x58, 0x02, 0xd7, 0x65, 0xdc, 0x31, 0x01, 0xec, 0xa6, 0xab, 0xfa, 0xa8, 0x05, 0x00, 0x37, 0x60, 0x4f, 0xa1, 0x3c, 0x4f, 0x7a, 0x9a, 0x10, 0x67, 0x95, 0xc2, 0x5b, 0x25, 0xef, 0x76, 0x0e, 0xff, 0x2d, 0x15, 0x7f, 0x23, 0x1c, 0x77, 0x56, 0x94, 0x4a, 0x18, 0x98, 0xc6, 0xd8, 0xd2, 0x29, 0x44, 0x57, 0xb8, 0x40, 0x3a, 0x93, 0x58, 0x45, 0x77, 0x36, 0x36, 0x07, 0x35, 0x2a, 0xff, 0x00, 0x94, 0x5c, 0x80, 0xe6, 0x7c, 0x1a, 0x92, 0xc1, 0x5f, 0x40, 0xc3, 0xbc, 0xf8, 0xce, 0x05, 0x77, 0x39, 0x40, 0x17, 0xcf, 0x63, 0x43, 0x77, 0x27, 0xce, 0x37, 0x86, 0x46, 0x54, 0xd6, 0xce, 0x00, 0x30, 0x36, 0xae, 0x9f, 0x24, 0x2b, 0x5a, 0xa0, 0xfe, 0xa3, 0x4b, 0x2e, 0x7e, 0xf7, 0x54, 0xa9, 0xd8, 0xa5, 0x76, 0x83, 0x7b, 0x63, 0x01, 0x1c, 0xd4, 0x56, 0x17, 0x02, 0xdc, 0x4a, 0x89, 0x77, 0xda, 0x8f, 0x9e, 0xba, 0xcb, 0x37, 0xe8, 0x19, 0x5d, 0x68, 0x38, 0x8e, 0xbc, 0x6a, 0x05, 0x53, 0x0b, 0xc7, 0xc5, 0x96, 0x84, 0x5a, 0xd9, 0x6d, 0x4c, 0x42, 0x31, 0xd9, 0xf2, 0x99, 0x06, 0xf7, 0x0c, 0x99, 0xbe, 0x49, 0x07, 0x77, 0xf0, 0x8b, 0x7c, 0x43, 0xfa, 0xb2, 0xad, 0xb0, 0xfa, 0x87, 0x52, 0xba, 0xc9, 0x94, 0x61, 0xdc, 0xcf, 0x16, 0xac, 0x0f, 0x4a, 0xa3, 0x6b, 0x5b, 0x6e, 0x27, 0x86, 0x1f, 0xfe, 0x4d, 0x28, 0x3a, 0xa5, 0x10, 0x98, 0x6d, 0xed, 0x53, 0xf9, 0x73, 0xc6, 0xa5, 0xa8, 0xf7, 0x66, 0xcf, 0x56, 0x3b, 0x61, 0xdf, 0xab, 0x83, 0x18, 0xe8, 0x09, 0xee, 0x6a, 0xb7, 0xf5, 0xc9, 0x62, 0x55, 0x2d, 0xc7, 0x0c, 0x0d, 0xa0, 0x22, 0xd8, 0xd4, 0xd6, 0xb2, 0x12, 0x21, 0xd7, 0x73, 0x3e, 0x41, 0xb0, 0x5c, 0xd4, 0xcf, 0x98, 0xf3, 0x70, 0xe6, 0x08, 0xe6, 0x2a, 0x4f, 0x92, 0x85, 0xe8, 0x74, 0xa8, 0x41, 0x5f, 0x0e, 0xfd, 0xf1, 0xf3, 0xbe, 0x9b, 0x14, 0xfd, 0xc0, 0x73, 0x11, 0xff, 0xa5, 0x5b, 0x06, 0x34, 0xc3, 0x5d, 0x28, 0x42, 0x34, 0xfe, 0x8a, 0xa5, 0xbe, 0x72, 0x7a, 0xf7, 0xfa, 0x25, 0x2b, 0x35, 0x5e, 0x98, 0x71, 0x50, 0x2c, 0x35, 0x76, 0x53, 0x4e, 0x1a, 0x34, 0xa5, 0x99, 0x09, 0xa2, 0xc6, 0xca, 0xa5, 0xce, 0x08, 0x50, 0x45, 0xab, 0x8d, 0xfb, 0xe3, 0xb8, 0xe4, 0x8a, 0x61, 0x48, 0x14, 0x6e, 0xf7, 0x58, 0x71, 0xe5, 0x2e, 0xbc, 0x12, 0xd1, 0x25, 0xe9, 0x65, 0x7a, 0xa1, 0x27, 0xbe, 0x3b, 0x8b, 0xe8, 0xe7, 0xbc, 0x77, 0x05, 0xe7, 0x92, 0xeb, 0xb9, 0xdf, 0x5d, 0x53, 0x74, 0xc0, 0x63, 0x97, 0x80, 0xb8, 0x3c, 0xae, 0xf3, 0xf2, 0x09, 0x12, 0x81, 0x6c, 0x69, 0x10, 0x6f, 0xf6, 0xbe, 0x03, 0x7b, 0x88, 0xcf, 0x26, 0x6b, 0x51, 0x06, 0x23, 0x68, 0x03, 0xa1, 0xb7, 0xd3, 0x0c, 0xca, 0xbf, 0x29, 0x01, 0xa9, 0x61, 0x34, 0x75, 0x98, 0x1e, 0x6f, 0x59, 0xb3, 0x46, 0x44, 0xff, 0x2b, 0x98, 0x04, 0x88, 0x89, 0xfd, 0x1c, 0xd5, 0x19, 0x8a, 0xa6, 0xf3, 0xd9, 0x44, 0xd5, 0xf9, 0x79, 0x26, 0x46, 0xf7 }; uint32_t request8_len = sizeof(request8); uint8_t request9[] = { 0x05, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xbf, 0xa1, 0x12, 0x73, 0x23, 0x44, 0x86, 0x8b, 0x50, 0x6a, 0x40, 0x00 }; uint32_t request9_len = sizeof(request9); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); /* bind */ int r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 0) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; /* bind_ack */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 0) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; /* request1 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 1024 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh = 0; /* request2 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 2048 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh = 0; /* request3 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 3072 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh = 0; /* request4 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 4096 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh = 0; /* request5 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 5120) && dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL); if (result == 0) goto end; /* request6 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 6144 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh = 0; /* request7 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request7, request7_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 7168 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh = 0; /* request8 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request8, request8_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 8192 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh = 0; /* request9 */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request9, request9_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 8204 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh = 0; /* request1 again */ r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= ( (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 1024 && dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh == 1) && (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) ); if (result == 0) goto end; end: StreamTcpFreeConfig(TRUE); return result; #endif return 1; } /** * \test General test. */ int DCERPCParserTest05(void) { int result = 1; Flow f; int r = 0; uint8_t bind1[] = { 0x05, 0x00, 0x0b, 0x01, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind1_len = sizeof(bind1); uint8_t bind2[] = { 0x05, 0x00, 0x0b, 0x02, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x67, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind2_len = sizeof(bind2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } DCERPCUuidEntry *item = NULL; int m = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.uuid_list, next) { printf("%d ", m); printUUID("BIND",item); m++; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } item = NULL; m = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.uuid_list, next) { printf("%d ", m); printUUID("BIND",item); m++; } /* we will need this test later for fragged bind pdus. keep it */ result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test DCERPC fragmented bind PDU(one PDU which is frag'ed) */ int DCERPCParserTest06(void) { int result = 1; Flow f; int r = 0; uint8_t bind1[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc7, 0x70, 0x0d, 0x3e, 0x71, 0x37, 0x39, 0x0d, 0x3a, 0x4f, 0xd3, 0xdc, 0xca, 0x49, 0xe8, 0xa3, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x84, 0xb6, 0x55, 0x75, 0xdb, 0x9e, 0xba, 0x54, 0x56, 0xd3, 0x45, 0x10, 0xb7, 0x7a, 0x2a, 0xe2, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x6e, 0x39, 0x21, 0x24, 0x70, 0x6f, 0x41, 0x57, 0x54, 0x70, 0xb8, 0xc3, 0x5e, 0x89, 0x3b, 0x43, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x39, 0x6a, 0x86, 0x5d, 0x24, 0x0f, 0xd2, 0xf7, 0xb6, 0xce, 0x95, 0x9c, 0x54, 0x1d, 0x3a, 0xdb, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x12, 0xa5, 0xdd, 0xc5, 0x55, 0xce, 0xc3, 0x46, 0xbd, 0xa0, 0x94, 0x39, 0x3c, 0x0d, 0x9b, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x87, 0x1c, 0x8b, 0x6e, 0x11, 0xa8, 0x67, 0x98, 0xd4, 0x5d, 0xf6, 0x8a, 0x2f, 0x33, 0x24, 0x7b, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x9b, 0x82, 0x13, 0xd1, 0x28, 0xe0, 0x63, 0xf3, 0x62, 0xee, 0x76, 0x73, 0xf9, 0xac, 0x3d, 0x2e, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0xa9, 0xd4, 0x73, 0xf2, 0xed, 0xad, 0xe8, 0x82, 0xf8, 0xcf, 0x9d, 0x9f, 0x66, 0xe6, 0x43, 0x37, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x06, 0x2b, 0x85, 0x38, 0x4f, 0x73, 0x96, 0xb1, 0x73, 0xe1, 0x59, 0xbe, 0x9d, 0xe2, 0x6c, 0x07, 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60}; uint32_t bind1_len = sizeof(bind1); uint8_t bind2[] = { 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xbf, 0xfa, 0xbb, 0xa4, 0x9e, 0x5c, 0x80, 0x61, 0xb5, 0x8b, 0x79, 0x69, 0xa6, 0x32, 0x88, 0x77, 0x01, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x39, 0xa8, 0x2c, 0x39, 0x73, 0x50, 0x06, 0x8d, 0xf2, 0x37, 0x1e, 0x1e, 0xa8, 0x8f, 0x46, 0x98, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x91, 0x13, 0xd0, 0xa7, 0xef, 0xc4, 0xa7, 0x96, 0x0c, 0x4a, 0x0d, 0x29, 0x80, 0xd3, 0xfe, 0xbf, 0x00, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0xcc, 0x2b, 0x55, 0x1d, 0xd4, 0xa4, 0x0d, 0xfb, 0xcb, 0x6f, 0x86, 0x36, 0xa6, 0x57, 0xc3, 0x21, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x43, 0x7b, 0x07, 0xee, 0x85, 0xa8, 0xb9, 0x3a, 0x0f, 0xf9, 0x83, 0x70, 0xe6, 0x0b, 0x4f, 0x33, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x9c, 0x6a, 0x15, 0x8c, 0xd6, 0x9c, 0xa6, 0xc3, 0xb2, 0x9e, 0x62, 0x9f, 0x3d, 0x8e, 0x47, 0x73, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind2_len = sizeof(bind2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 420); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.ctxbytesprocessed == 40); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitems == 16); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitemsleft == 8); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.ctxbytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitems == 16); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitemsleft == 0); end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test DCERPC fragmented bind PDU(one PDU which is frag'ed). */ int DCERPCParserTest07(void) { int result = 1; Flow f; int r = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x0D, 0x0E }; uint32_t request2_len = sizeof(request2); uint8_t request3[] = { 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14 }; uint32_t request3_len = sizeof(request3); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 36); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); result &= (dcerpc_state->dcerpc.pdu_fragged = 1); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 38); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 14); result &= (dcerpc_state->dcerpc.pdu_fragged = 1); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 20); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test DCERPC fragmented bind PDU(one PDU which is frag'ed). */ int DCERPCParserTest08(void) { int result = 1; Flow f; int r = 0; uint8_t request[] = { 0x05, 0x02, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, }; uint32_t request_len = sizeof(request); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, request, request_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 0); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test DCERPC fragmented bind PDU(one PDU which is frag'ed). */ int DCERPCParserTest09(void) { int result = 1; Flow f; int r = 0; uint8_t request[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, }; uint32_t request_len = sizeof(request); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, request, request_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 36); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test DCERPC fragmented PDU. */ int DCERPCParserTest10(void) { int result = 1; Flow f; int r = 0; uint8_t fault[] = { 0x05, 0x00, 0x03, 0x03, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint32_t fault_len = sizeof(fault); uint8_t request1[] = { 0x05, 0x00 }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C }; uint32_t request2_len = sizeof(request2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, fault, fault_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 2); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test DCERPC fragmented PDU. */ int DCERPCParserTest11(void) { int result = 1; Flow f; int r = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x05, 0x00 }; uint32_t request2_len = sizeof(request2); uint8_t request3[] = { 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF }; uint32_t request3_len = sizeof(request3); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 2); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 14); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test DCERPC fragmented PDU. */ int DCERPCParserTest12(void) { int result = 1; Flow f; int r = 0; uint8_t bind_ack1[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, }; uint32_t bind_ack1_len = sizeof(bind_ack1); uint8_t bind_ack2[] = { 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack2_len = sizeof(bind_ack2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack1, bind_ack1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 24); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack2, bind_ack2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test Check if the parser accepts bind pdus that have context ids starting * from a non-zero value. */ int DCERPCParserTest13(void) { int result = 1; Flow f; int r = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitems == 1); if (result == 0) goto end; result = 0; uint8_t ctx_uuid_from_pcap[16] = { 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}; DCERPCUuidEntry *item = NULL; int internal_id = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.uuid_list, next) { int i = 0; /* check the interface uuid */ for (i = 0; i < 16; i++) { if (ctx_uuid_from_pcap[i] != item->uuid[i]) { result = 0; goto end; } } result = 1; result &= (item->internal_id == internal_id++); } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test Check for another endless loop with bind pdus. */ int DCERPCParserTest14(void) { int result = 1; Flow f; int r = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0xFF /* ka boom - endless loop */ }; uint32_t bind_len = sizeof(bind); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test Check for another endless loop for bind_ack pdus. */ int DCERPCParserTest15(void) { int result = 1; Flow f; int r = 0; uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0xfd, 0x04, 0x01, 0x00, 0x04, 0x00, 0x31, 0x33, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x01, 0x02, 0x03, 0x04, 0xFF }; uint32_t bind_ack_len = sizeof(bind_ack); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test Check for correct internal ids for bind_acks. */ int DCERPCParserTest16(void) { int result = 1; Flow f; int r = 0; uint8_t bind1[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x50, 0x08, 0x43, 0x95, 0x43, 0x5a, 0x8b, 0xb2, 0xf4, 0xc5, 0xb9, 0xee, 0x67, 0x55, 0x7c, 0x19, 0x00, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xda, 0xc2, 0xbc, 0x9b, 0x35, 0x2e, 0xd4, 0xc9, 0x1f, 0x85, 0x01, 0xe6, 0x4e, 0x5a, 0x5e, 0xd4, 0x04, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0xb2, 0x97, 0xcc, 0x14, 0x6f, 0x70, 0x0d, 0xa5, 0x33, 0xd7, 0xf4, 0xe3, 0x8e, 0xb2, 0x2a, 0x1e, 0x05, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x96, 0x4e, 0xa6, 0xf6, 0xb2, 0x4b, 0xae, 0xb3, 0x21, 0xf4, 0x97, 0x7c, 0xcd, 0xa7, 0x08, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0xbc, 0xc0, 0xf7, 0x71, 0x3f, 0x71, 0x54, 0x44, 0x22, 0xa8, 0x55, 0x0f, 0x98, 0x83, 0x1f, 0xfe, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0xbe, 0x52, 0xf2, 0x58, 0x4a, 0xc3, 0xb5, 0xd0, 0xba, 0xac, 0xda, 0xf0, 0x12, 0x99, 0x38, 0x6e, 0x04, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0xdb, 0xfa, 0x73, 0x01, 0xb3, 0x81, 0x01, 0xd4, 0x7f, 0xa0, 0x36, 0xb1, 0x97, 0xae, 0x29, 0x7f, 0x01, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x89, 0xbe, 0x41, 0x1d, 0x38, 0x75, 0xf5, 0xb5, 0xad, 0x27, 0x73, 0xf1, 0xb0, 0x7a, 0x28, 0x82, 0x05, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0xf6, 0x87, 0x09, 0x93, 0xb8, 0xa8, 0x20, 0xc4, 0xb8, 0x63, 0xe6, 0x95, 0xed, 0x59, 0xee, 0x3f, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x92, 0x77, 0x92, 0x68, 0x3e, 0xa4, 0xbc, 0x3f, 0x44, 0x33, 0x0e, 0xb8, 0x33, 0x0a, 0x2f, 0xdf, 0x01, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0xa1, 0x03, 0xd2, 0xa9, 0xd2, 0x16, 0xc9, 0x89, 0x67, 0x18, 0x3e, 0xb1, 0xee, 0x6b, 0xf9, 0x18, 0x02, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x2f, 0x09, 0x5e, 0x74, 0xec, 0xa0, 0xbb, 0xc1, 0x60, 0x18, 0xf1, 0x93, 0x04, 0x17, 0x11, 0xf9, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind1_len = sizeof(bind1); uint8_t bind_ack1[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0xc1, 0x2b, 0x00, 0x00, 0x0e, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack1_len = sizeof(bind_ack1); uint8_t bind2[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc7, 0x70, 0x0d, 0x3e, 0x71, 0x37, 0x39, 0x0d, 0x3a, 0x4f, 0xd3, 0xdc, 0xca, 0x49, 0xe8, 0xa3, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x84, 0xb6, 0x55, 0x75, 0xdb, 0x9e, 0xba, 0x54, 0x56, 0xd3, 0x45, 0x10, 0xb7, 0x7a, 0x2a, 0xe2, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x6e, 0x39, 0x21, 0x24, 0x70, 0x6f, 0x41, 0x57, 0x54, 0x70, 0xb8, 0xc3, 0x5e, 0x89, 0x3b, 0x43, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x39, 0x6a, 0x86, 0x5d, 0x24, 0x0f, 0xd2, 0xf7, 0xb6, 0xce, 0x95, 0x9c, 0x54, 0x1d, 0x3a, 0xdb, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x12, 0xa5, 0xdd, 0xc5, 0x55, 0xce, 0xc3, 0x46, 0xbd, 0xa0, 0x94, 0x39, 0x3c, 0x0d, 0x9b, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x87, 0x1c, 0x8b, 0x6e, 0x11, 0xa8, 0x67, 0x98, 0xd4, 0x5d, 0xf6, 0x8a, 0x2f, 0x33, 0x24, 0x7b, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x9b, 0x82, 0x13, 0xd1, 0x28, 0xe0, 0x63, 0xf3, 0x62, 0xee, 0x76, 0x73, 0xf9, 0xac, 0x3d, 0x2e, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0xa9, 0xd4, 0x73, 0xf2, 0xed, 0xad, 0xe8, 0x82, 0xf8, 0xcf, 0x9d, 0x9f, 0x66, 0xe6, 0x43, 0x37, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x06, 0x2b, 0x85, 0x38, 0x4f, 0x73, 0x96, 0xb1, 0x73, 0xe1, 0x59, 0xbe, 0x9d, 0xe2, 0x6c, 0x07, 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xbf, 0xfa, 0xbb, 0xa4, 0x9e, 0x5c, 0x80, 0x61, 0xb5, 0x8b, 0x79, 0x69, 0xa6, 0x32, 0x88, 0x77, 0x01, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x39, 0xa8, 0x2c, 0x39, 0x73, 0x50, 0x06, 0x8d, 0xf2, 0x37, 0x1e, 0x1e, 0xa8, 0x8f, 0x46, 0x98, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x91, 0x13, 0xd0, 0xa7, 0xef, 0xc4, 0xa7, 0x96, 0x0c, 0x4a, 0x0d, 0x29, 0x80, 0xd3, 0xfe, 0xbf, 0x00, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0xcc, 0x2b, 0x55, 0x1d, 0xd4, 0xa4, 0x0d, 0xfb, 0xcb, 0x6f, 0x86, 0x36, 0xa6, 0x57, 0xc3, 0x21, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x43, 0x7b, 0x07, 0xee, 0x85, 0xa8, 0xb9, 0x3a, 0x0f, 0xf9, 0x83, 0x70, 0xe6, 0x0b, 0x4f, 0x33, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x9c, 0x6a, 0x15, 0x8c, 0xd6, 0x9c, 0xa6, 0xc3, 0xb2, 0x9e, 0x62, 0x9f, 0x3d, 0x8e, 0x47, 0x73, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind2_len = sizeof(bind2); uint8_t bind_ack2[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0xc2, 0x2b, 0x00, 0x00, 0x0e, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack2_len = sizeof(bind_ack2); uint8_t bind3[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xa4, 0x7f, 0x8e, 0xc6, 0xef, 0x56, 0x9b, 0x63, 0x92, 0xfa, 0x08, 0xb3, 0x35, 0xe2, 0xa5, 0x81, 0x00, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x9f, 0xfc, 0x78, 0xd2, 0x5f, 0x16, 0x0b, 0xbc, 0xc6, 0xdb, 0x5d, 0xef, 0xde, 0x54, 0xa2, 0x6f, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x78, 0xb8, 0x96, 0xc7, 0x2f, 0xda, 0x11, 0x6b, 0xd1, 0x28, 0x68, 0xe1, 0xd6, 0x71, 0xac, 0x9d, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xcf, 0xf4, 0xd7, 0x37, 0x03, 0xda, 0xcc, 0xe3, 0x3e, 0x34, 0x7f, 0x67, 0x99, 0x91, 0x41, 0x3d, 0x01, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x48, 0xeb, 0x32, 0xf0, 0x27, 0xd5, 0x9d, 0xd0, 0x1e, 0xc6, 0x48, 0x46, 0x97, 0xe9, 0xdb, 0x09, 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x82, 0xec, 0x0d, 0x08, 0xf2, 0x8f, 0x22, 0x57, 0x42, 0x9b, 0xce, 0xa8, 0x74, 0x16, 0xc6, 0xec, 0x00, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x70, 0x44, 0xee, 0xc9, 0x30, 0x6b, 0xf4, 0x34, 0x1e, 0x3d, 0x35, 0x0f, 0xf7, 0xf7, 0x00, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x59, 0x04, 0x39, 0x3f, 0x59, 0x87, 0x14, 0x0e, 0x76, 0x8d, 0x17, 0xc2, 0x47, 0xfa, 0x67, 0x7f, 0x04, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x30, 0xd6, 0xed, 0x2e, 0x57, 0xfa, 0xf4, 0x72, 0x6c, 0x10, 0x0d, 0xe5, 0x51, 0x7f, 0xd0, 0x39, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xea, 0x8b, 0x84, 0x4d, 0x44, 0x43, 0xc1, 0x94, 0x75, 0xe2, 0x81, 0x48, 0xd8, 0x77, 0xd9, 0xce, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x89, 0x4f, 0xe7, 0x95, 0xa3, 0xc1, 0x62, 0x36, 0x26, 0x9e, 0x67, 0xdb, 0x2c, 0x52, 0x89, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x78, 0x56, 0x34, 0x12, 0x34, 0x12, 0xcd, 0xab, 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind3_len = sizeof(bind3); uint8_t bind_ack3[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x1a, 0x33, 0x00, 0x00, 0x0e, 0x00, 0x5c, 0x70, 0x69, 0x70, 0x65, 0x5c, 0x73, 0x70, 0x6f, 0x6f, 0x6c, 0x73, 0x73, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack3_len = sizeof(bind_ack3); TcpSession ssn; DCERPCUuidEntry *item = NULL; int count = 0; uint8_t accepted_uuids[3][16] = { {0x4b, 0x32, 0x4f, 0xc8, 0x16, 0x70, 0x01, 0xd3, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88}, {0x4b, 0x32, 0x4f, 0xc8, 0x16, 0x70, 0x01, 0xd3, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88}, {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0xab, 0xcd, 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab} }; uint16_t accepted_ctxids[3] = {12, 15, 11}; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack1, bind_ack1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { int i = 0; /* check the interface uuid */ for (i = 0; i < 16; i++) { if (accepted_uuids[0][i] != item->uuid[i]) { result = 0; goto end; } } if (accepted_ctxids[0] != item->ctxid) { result = 0; goto end; } count++; } if (count != 1) { result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { count++; } if (count != 0) { result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack2, bind_ack2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { int i = 0; /* check the interface uuid */ for (i = 0; i < 16; i++) { if (accepted_uuids[1][i] != item->uuid[i]) { result = 0; goto end; } } if (accepted_ctxids[1] != item->ctxid) { result = 0; goto end; } count++; } if (count != 1) { result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind3, bind3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { count++; } if (count != 0) { result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack3, bind_ack3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { int i = 0; /* check the interface uuid */ for (i = 0; i < 16; i++) { if (accepted_uuids[2][i] != item->uuid[i]) { result = 0; goto end; } } if (accepted_ctxids[2] != item->ctxid) { result = 0; goto end; } count++; } if (count != 1) { result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test Check for correct internal ids for bind_acks + alter_contexts */ int DCERPCParserTest17(void) { int result = 1; Flow f; int r = 0; uint8_t bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0xfd, 0x2c, 0x34, 0x6c, 0x3c, 0xce, 0x11, 0xa8, 0x93, 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_len = sizeof(bind); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x7d, 0xd8, 0x00, 0x00, 0x0d, 0x00, 0x5c, 0x70, 0x69, 0x70, 0x65, 0x5c, 0x6c, 0x6c, 0x73, 0x72, 0x70, 0x63, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t bind_ack_len = sizeof(bind_ack); uint8_t alter_context[] = { 0x05, 0x00, 0x0e, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xd0, 0x4c, 0x67, 0x57, 0x00, 0x52, 0xce, 0x11, 0xa8, 0x97, 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t alter_context_len = sizeof(alter_context); uint8_t alter_context_resp[] = { 0x05, 0x00, 0x0f, 0x03, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x7d, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; uint32_t alter_context_resp_len = sizeof(alter_context_resp); TcpSession ssn; DCERPCUuidEntry *item = NULL; int count = 0; uint8_t accepted_uuids[2][16] = { {0x57, 0x67, 0x4c, 0xd0, 0x52, 0x00, 0x11, 0xce, 0xa8, 0x97, 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d}, {0x34, 0x2c, 0xfd, 0x40, 0x3c, 0x6c, 0x11, 0xce, 0xa8, 0x93, 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d}, }; uint16_t accepted_ctxids[2] = {1, 0}; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { int i = 0; /* check the interface uuid */ for (i = 0; i < 16; i++) { if (accepted_uuids[1][i] != item->uuid[i]) { result = 0; goto end; } } if (accepted_ctxids[1] != item->ctxid) { result = 0; goto end; } count++; } if (count != 1) { result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, alter_context, alter_context_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { count++; } if (count != 1) { result = 0; goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, alter_context_resp, alter_context_resp_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { int i = 0; /* check the interface uuid */ for (i = 0; i < 16; i++) { if (accepted_uuids[count][i] != item->uuid[i]) { result = 0; goto end; } } if (accepted_ctxids[count] != item->ctxid) { result = 0; goto end; } count++; } if (count != 2) { result = 0; goto end; } end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } /** * \test DCERPC fragmented PDU. */ int DCERPCParserTest18(void) { int result = 1; Flow f; int r = 0; uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, }; uint32_t request1_len = sizeof(request1); uint8_t request2[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF }; uint32_t request2_len = sizeof(request2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 18); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 14); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.opnum == 2); end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } int DCERPCParserTest19(void) { int result = 0; Flow f; uint8_t dcerpcbind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2c, 0xd0, 0x28, 0xda, 0x76, 0x91, 0xf6, 0x6e, 0xcb, 0x0f, 0xbf, 0x85, 0xcd, 0x9b, 0xf6, 0x39, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x2c, 0x75, 0xce, 0x7e, 0x82, 0x3b, 0x06, 0xac, 0x1b, 0xf0, 0xf5, 0xb7, 0xa7, 0xf7, 0x28, 0xaf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0xe3, 0xb2, 0x10, 0xd1, 0xd0, 0x0c, 0xcc, 0x3d, 0x2f, 0x80, 0x20, 0x7c, 0xef, 0xe7, 0x09, 0xe0, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xde, 0x85, 0x70, 0xc4, 0x02, 0x7c, 0x60, 0x23, 0x67, 0x0c, 0x22, 0xbf, 0x18, 0x36, 0x79, 0x17, 0x01, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x41, 0x65, 0x29, 0x51, 0xaa, 0xe7, 0x7b, 0xa8, 0xf2, 0x37, 0x0b, 0xd0, 0x3f, 0xb3, 0x36, 0xed, 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x14, 0x96, 0x80, 0x01, 0x2e, 0x78, 0xfb, 0x5d, 0xb4, 0x3c, 0x14, 0xb3, 0x3d, 0xaa, 0x02, 0xfb, 0x06, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x3b, 0x04, 0x68, 0x3e, 0x63, 0xfe, 0x9f, 0xd8, 0x64, 0x55, 0xcd, 0xe7, 0x39, 0xaf, 0x98, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x16, 0x7a, 0x4f, 0x1b, 0xdb, 0x25, 0x92, 0x55, 0xdd, 0xae, 0x9e, 0x5b, 0x3e, 0x93, 0x66, 0x93, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0xe8, 0xa4, 0x8a, 0xcf, 0x95, 0x6c, 0xc7, 0x8f, 0x14, 0xcc, 0x56, 0xfc, 0x7b, 0x5f, 0x4f, 0xe8, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xd8, 0xda, 0xfb, 0xbc, 0xa2, 0x55, 0x6f, 0x5d, 0xc0, 0x2d, 0x88, 0x6f, 0x00, 0x17, 0x52, 0x8d, 0x06, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x3f, 0x17, 0x55, 0x0c, 0xf4, 0x23, 0x3c, 0xca, 0xe6, 0xa0, 0xaa, 0xcc, 0xb5, 0xe3, 0xf9, 0xce, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0xc9, 0x9f, 0x3e, 0x6e, 0x82, 0x0a, 0x2b, 0x28, 0x37, 0x78, 0xe1, 0x13, 0x70, 0x05, 0x38, 0x4d, 0x01, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x11, 0xaa, 0x4b, 0x15, 0xdf, 0xa6, 0x86, 0x3f, 0xfb, 0xe0, 0x09, 0xb7, 0xf8, 0x56, 0xd2, 0x3f, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0xee, 0x99, 0xc4, 0x25, 0x11, 0xe4, 0x95, 0x62, 0x29, 0xfa, 0xfd, 0x26, 0x57, 0x02, 0xf1, 0xce, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0xba, 0x81, 0x9e, 0x1a, 0xdf, 0x2b, 0xba, 0xe4, 0xd3, 0x17, 0x41, 0x60, 0x6d, 0x2d, 0x9e, 0x28, 0x03, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0xa0, 0x24, 0x03, 0x9a, 0xa9, 0x99, 0xfb, 0xbe, 0x49, 0x11, 0xad, 0x77, 0x30, 0xaa, 0xbc, 0xb6, 0x02, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x32, 0x04, 0x7e, 0xae, 0xec, 0x28, 0xd1, 0x55, 0x83, 0x4e, 0xc3, 0x47, 0x5d, 0x1d, 0xc6, 0x65, 0x02, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, 0xc6, 0xa4, 0x81, 0x48, 0x66, 0x2a, 0x74, 0x7d, 0x56, 0x6e, 0xc5, 0x1d, 0x19, 0xf2, 0xb5, 0xb6, 0x03, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0xcb, 0xae, 0xb3, 0xc0, 0x0c, 0xf4, 0xa4, 0x5e, 0x91, 0x72, 0xdd, 0x53, 0x24, 0x70, 0x89, 0x02, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0xb8, 0xd0, 0xa0, 0x1a, 0x5e, 0x7a, 0x2d, 0xfe, 0x35, 0xc6, 0x7d, 0x08, 0x0d, 0x33, 0x73, 0x18, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, }; uint8_t dcerpcbindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x6c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0xce, 0x47, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0xf6, 0x6e, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint32_t bindlen = sizeof(dcerpcbind); uint32_t bindacklen = sizeof(dcerpcbindack); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); int r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpcbind, bindlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); goto end; } DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { printf("no dcerpc state: "); goto end; } if (dcerpc_state->dcerpc.bytesprocessed == 0) { printf("request - dce parser bytesprocessed should not be 0.\n"); goto end; } r = AppLayerParse(NULL, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpcbindack, bindacklen); if (r == 0) { printf("dce parser didn't return fail\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); return result; } #endif /* UNITTESTS */ void DCERPCParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DCERPCParserTest01", DCERPCParserTest01, 1); UtRegisterTest("DCERPCParserTest02", DCERPCParserTest02, 1); UtRegisterTest("DCERPCParserTest03", DCERPCParserTest03, 1); UtRegisterTest("DCERPCParserTest04", DCERPCParserTest04, 1); UtRegisterTest("DCERPCParserTest05", DCERPCParserTest05, 1); UtRegisterTest("DCERPCParserTest06", DCERPCParserTest06, 1); UtRegisterTest("DCERPCParserTest07", DCERPCParserTest07, 1); UtRegisterTest("DCERPCParserTest08", DCERPCParserTest08, 1); UtRegisterTest("DCERPCParserTest09", DCERPCParserTest09, 1); UtRegisterTest("DCERPCParserTest10", DCERPCParserTest10, 1); UtRegisterTest("DCERPCParserTest11", DCERPCParserTest11, 1); UtRegisterTest("DCERPCParserTest12", DCERPCParserTest12, 1); UtRegisterTest("DCERPCParserTest13", DCERPCParserTest13, 1); UtRegisterTest("DCERPCParserTest14", DCERPCParserTest14, 1); UtRegisterTest("DCERPCParserTest15", DCERPCParserTest15, 1); UtRegisterTest("DCERPCParserTest16", DCERPCParserTest16, 1); UtRegisterTest("DCERPCParserTest17", DCERPCParserTest17, 1); UtRegisterTest("DCERPCParserTest18", DCERPCParserTest18, 1); UtRegisterTest("DCERPCParserTest19", DCERPCParserTest19, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/detect-engine-port.c0000644000000000000000000022165212253546156014676 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Ports part of the detection engine. * * \todo move this out of the detection plugin structure * \todo more unittesting * */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "flow-var.h" #include "util-cidr.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-rule-vars.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-siggroup.h" #include "detect-engine-port.h" #include "conf.h" #include "util-debug.h" #include "util-error.h" static int DetectPortCutNot(DetectPort *, DetectPort **); static int DetectPortCut(DetectEngineCtx *, DetectPort *, DetectPort *, DetectPort **); DetectPort *PortParse(char *str); int DetectPortIsValidRange(char *); /** Memory usage counters */ static uint32_t detect_port_memory = 0; static uint32_t detect_port_init_cnt = 0; static uint32_t detect_port_free_cnt = 0; /** * \brief Alloc a DetectPort structure and update counters * * \retval sgh Pointer to the newly created DetectPort on success; or NULL in * case of error. */ DetectPort *DetectPortInit(void) { DetectPort *dp = SCMalloc(sizeof(DetectPort)); if (unlikely(dp == NULL)) return NULL; memset(dp, 0, sizeof(DetectPort)); detect_port_memory += sizeof(DetectPort); detect_port_init_cnt++; return dp; } /** * \brief Free a DetectPort and its members * * \param dp Pointer to the DetectPort that has to be freed. */ void DetectPortFree(DetectPort *dp) { if (dp == NULL) return; /* only free the head if we have the original */ if (dp->sh != NULL && !(dp->flags & PORT_SIGGROUPHEAD_COPY)) { SigGroupHeadFree(dp->sh); } dp->sh = NULL; if (dp->dst_ph != NULL && !(dp->flags & PORT_GROUP_PORTS_COPY)) { DetectPortCleanupList(dp->dst_ph); } dp->dst_ph = NULL; //BUG_ON(dp->next != NULL); detect_port_memory -= sizeof(DetectPort); detect_port_free_cnt++; SCFree(dp); } /** * \brief Prints Memory statistics of the counters at detect-engine-port.[c,h] */ void DetectPortPrintMemory(void) { SCLogDebug(" * Port memory stats (DetectPort %" PRIuMAX "):", (uintmax_t)sizeof(DetectPort)); SCLogDebug(" - detect_port_memory %" PRIu32 "", detect_port_memory); SCLogDebug(" - detect_port_init_cnt %" PRIu32 "", detect_port_init_cnt); SCLogDebug(" - detect_port_free_cnt %" PRIu32 "", detect_port_free_cnt); SCLogDebug(" - outstanding ports %" PRIu32 "", detect_port_init_cnt - detect_port_free_cnt); SCLogDebug(" * Port memory stats done"); } /** * \brief Used to see if the exact same portrange exists in the list * * \param head Pointer to the DetectPort list head * \param dp DetectPort to search in the DetectPort list * * \retval returns a ptr to the match, or NULL if no match */ DetectPort *DetectPortLookup(DetectPort *head, DetectPort *dp) { DetectPort *cur; if (head != NULL) { for (cur = head; cur != NULL; cur = cur->next) { if (DetectPortCmp(cur, dp) == PORT_EQ) return cur; } } return NULL; } /** * \brief Helper function used to print the list of ports * present in this DetectPort list. * * \param head Pointer to the DetectPort list head */ void DetectPortPrintList(DetectPort *head) { DetectPort *cur; uint16_t cnt = 0; SCLogDebug("= list start:"); if (head != NULL) { for (cur = head; cur != NULL; cur = cur->next) { DetectPortPrint(cur); cnt++; } SCLogDebug(" "); } SCLogDebug("= list end (cnt %" PRIu32 ")", cnt); } /** * \brief Free a DetectPort list and each of its members * * \param head Pointer to the DetectPort list head */ void DetectPortCleanupList (DetectPort *head) { if (head == NULL) return; DetectPort *cur, *next; for (cur = head; cur != NULL; ) { next = cur->next; cur->next = NULL; DetectPortFree(cur); cur = next; } head = NULL; } /** * \brief Do a sorted insert, where the top of the list should be the biggest * port range. * * \todo XXX current sorting only works for overlapping ranges * * \param head Pointer to the DetectPort list head * \param dp Pointer to DetectPort to search in the DetectPort list * \retval 0 if dp is added correctly */ int DetectPortAdd(DetectPort **head, DetectPort *dp) { DetectPort *cur, *prev_cur = NULL; //SCLogDebug("DetectPortAdd: adding "); DetectPortPrint(ag); SCLogDebug(""); if (*head != NULL) { for (cur = *head; cur != NULL; cur = cur->next) { prev_cur = cur; int r = DetectPortCmp(dp,cur); if (r == PORT_EB) { /* insert here */ dp->prev = cur->prev; dp->next = cur; cur->prev = dp; if (*head == cur) { *head = dp; } else { dp->prev->next = dp; } return 0; } } dp->prev = prev_cur; if (prev_cur != NULL) prev_cur->next = dp; } else { *head = dp; } return 0; } /** * \brief Copy and insert the new DetectPort, with a copy list of sigs * * \param de_ctx Pointer to the current detection engine context * \param head Pointer to the DetectPort list head * \param new Pointer to DetectPort to search in the DetectPort list * * \retval 0 if dp is added correctly */ int DetectPortInsertCopy(DetectEngineCtx *de_ctx, DetectPort **head, DetectPort *new) { DetectPort *copy = DetectPortCopySingle(de_ctx,new); if (copy == NULL) return -1; return DetectPortInsert(de_ctx, head, copy); } /** * \brief function for inserting a port group object. This also makes sure * SigGroupContainer lists are handled correctly. * * \param de_ctx Pointer to the current detection engine context * \param head Pointer to the DetectPort list head * \param dp DetectPort to search in the DetectPort list * * \retval 1 inserted * \retval 0 not inserted, memory of new is freed * \retval -1 error * */ int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, DetectPort *new) { if (new == NULL) return 0; //BUG_ON(new->next != NULL); //BUG_ON(new->prev != NULL); /* see if it already exists or overlaps with existing ag's */ if (*head != NULL) { DetectPort *cur = NULL; int r = 0; for (cur = *head; cur != NULL; cur = cur->next) { r = DetectPortCmp(new,cur); BUG_ON(r == PORT_ER); /* if so, handle that */ if (r == PORT_EQ) { SCLogDebug("PORT_EQ %p %p", cur, new); /* exact overlap/match */ if (cur != new) { SigGroupHeadCopySigs(de_ctx, new->sh, &cur->sh); cur->cnt += new->cnt; DetectPortFree(new); return 0; } return 1; } else if (r == PORT_GT) { SCLogDebug("PORT_GT (cur->next %p)", cur->next); /* only add it now if we are bigger than the last * group. Otherwise we'll handle it later. */ if (cur->next == NULL) { SCLogDebug("adding GT"); /* put in the list */ new->prev = cur; cur->next = new; return 1; } } else if (r == PORT_LT) { SCLogDebug("PORT_LT"); /* see if we need to insert the ag anywhere */ /* put in the list */ if (cur->prev != NULL) cur->prev->next = new; new->prev = cur->prev; new->next = cur; cur->prev = new; /* update head if required */ if (*head == cur) { *head = new; } return 1; /* alright, those were the simple cases, * lets handle the more complex ones now */ } else { DetectPort *c = NULL; r = DetectPortCut(de_ctx, cur, new, &c); if (r == -1) goto error; r = DetectPortInsert(de_ctx, head, new); if (r == -1) goto error; if (c != NULL) { SCLogDebug("inserting C (%p)", c); if (SCLogDebugEnabled()) { DetectPortPrint(c); } r = DetectPortInsert(de_ctx, head, c); if (r == -1) goto error; } return 1; } } /* head is NULL, so get a group and set head to it */ } else { SCLogDebug("setting new head %p", new); *head = new; } return 1; error: /* XXX */ return -1; } /** * \brief Function that cuts port groups and merge them * * \param de_ctx Pointer to the current detection engine context * \param a pointer to DetectPort "a" * \param b pointer to DetectPort "b" * \param c pointer to DetectPort "c" * * \retval 0 ok * \retval -1 error * */ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, DetectPort *b, DetectPort **c) { uint32_t a_port1 = a->port; uint32_t a_port2 = a->port2; uint32_t b_port1 = b->port; uint32_t b_port2 = b->port2; DetectPort *tmp = NULL; /* default to NULL */ *c = NULL; int r = DetectPortCmp(a,b); BUG_ON(r != PORT_ES && r != PORT_EB && r != PORT_LE && r != PORT_GE); /* get a place to temporary put sigs lists */ tmp = DetectPortInit(); if (tmp == NULL) { goto error; } memset(tmp, 0, sizeof(DetectPort)); /** * We have 3 parts: [aaa[abab]bbb] * part a: a_port1 <-> b_port1 - 1 * part b: b_port1 <-> a_port2 * part c: a_port2 + 1 <-> b_port2 */ if (r == PORT_LE) { SCLogDebug("cut r == PORT_LE"); a->port = a_port1; a->port2 = b_port1 - 1; b->port = b_port1; b->port2 = a_port2; DetectPort *tmp_c; tmp_c = DetectPortInit(); if (tmp_c == NULL) { goto error; } *c = tmp_c; tmp_c->port = a_port2 + 1; tmp_c->port2 = b_port2; SigGroupHeadCopySigs(de_ctx,b->sh,&tmp_c->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); /* copy a to b */ tmp_c->cnt += b->cnt; b->cnt += a->cnt; /** * We have 3 parts: [bbb[baba]aaa] * part a: b_port1 <-> a_port1 - 1 * part b: a_port1 <-> b_port2 * part c: b_port2 + 1 <-> a_port2 */ } else if (r == PORT_GE) { SCLogDebug("cut r == PORT_GE"); a->port = b_port1; a->port2 = a_port1 - 1; b->port = a_port1; b->port2 = b_port2; DetectPort *tmp_c; tmp_c = DetectPortInit(); if (tmp_c == NULL) { goto error; } *c = tmp_c; tmp_c->port = b_port2 + 1; tmp_c->port2 = a_port2; /** * 'a' gets clean and then 'b' sigs * 'b' gets clean, then 'a' then 'b' sigs * 'c' gets 'a' sigs */ SigGroupHeadCopySigs(de_ctx,a->sh,&tmp->sh); /* store old a list */ SigGroupHeadClearSigs(a->sh); /* clean a list */ SigGroupHeadCopySigs(de_ctx,tmp->sh,&tmp_c->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx,b->sh,&a->sh); /* copy old b to a */ SigGroupHeadCopySigs(de_ctx,tmp->sh,&b->sh);/* prepend old a before b */ SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ tmp->cnt += a->cnt; a->cnt = 0; tmp_c->cnt += tmp->cnt; a->cnt += b->cnt; b->cnt += tmp->cnt; tmp->cnt = 0; /** * We have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] * part a: a_port1 <-> a_port2 * part b: a_port2 + 1 <-> b_port2 * * part a: b_port1 <-> a_port1 - 1 * part b: a_port1 <-> a_port2 * * 3 part [bbb[aaa]bbb] * becomes[aaa[bbb]ccc] * * part a: b_port1 <-> a_port1 - 1 * part b: a_port1 <-> a_port2 * part c: a_port2 + 1 <-> b_port2 */ } else if (r == PORT_ES) { SCLogDebug("cut r == PORT_ES"); if (a_port1 == b_port1) { SCLogDebug("1"); a->port = a_port1; a->port2 = a_port2; b->port = a_port2 + 1; b->port2 = b_port2; /** 'b' overlaps 'a' so 'a' needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx,b->sh,&a->sh); a->cnt += b->cnt; } else if (a_port2 == b_port2) { SCLogDebug("2"); a->port = b_port1; a->port2 = a_port1 - 1; b->port = a_port1; b->port2 = a_port2; /* [bbb[baba]] will be transformed into * [aaa][bbb] * steps: copy b sigs to tmp * a overlaps b, so copy a to b * clear a * copy tmp to a */ SigGroupHeadCopySigs(de_ctx,b->sh,&tmp->sh); /* store old a list */ tmp->cnt = b->cnt; SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); b->cnt += a->cnt; SigGroupHeadClearSigs(a->sh); /* clean a list */ SigGroupHeadCopySigs(de_ctx,tmp->sh,&a->sh);/* merge old a with b */ a->cnt = tmp->cnt; SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ } else { SCLogDebug("3"); a->port = b_port1; a->port2 = a_port1 - 1; b->port = a_port1; b->port2 = a_port2; DetectPort *tmp_c; tmp_c = DetectPortInit(); if (tmp_c == NULL) { goto error; } *c = tmp_c; tmp_c->port = a_port2 + 1; tmp_c->port2 = b_port2; /** * 'a' gets clean and then 'b' sigs * 'b' gets clean, then 'a' then 'b' sigs * 'c' gets 'b' sigs */ SigGroupHeadCopySigs(de_ctx,a->sh,&tmp->sh); /* store old a list */ SigGroupHeadClearSigs(a->sh); /* clean a list */ SigGroupHeadCopySigs(de_ctx,b->sh,&tmp_c->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx,b->sh,&a->sh); /* copy old b to a */ SigGroupHeadCopySigs(de_ctx,tmp->sh,&b->sh);/* merge old a with b */ SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ tmp->cnt += a->cnt; a->cnt = 0; tmp_c->cnt += b->cnt; a->cnt += b->cnt; b->cnt += tmp->cnt; tmp->cnt = 0; } /** * We have 2 or three parts: * * 2 part: [[baba]aaa] or [aaa[abab]] * part a: b_port1 <-> b_port2 * part b: b_port2 + 1 <-> a_port2 * * part a: a_port1 <-> b_port1 - 1 * part b: b_port1 <-> b_port2 * * 3 part [aaa[bbb]aaa] * becomes[aaa[bbb]ccc] * * part a: a_port1 <-> b_port2 - 1 * part b: b_port1 <-> b_port2 * part c: b_port2 + 1 <-> a_port2 */ } else if (r == PORT_EB) { SCLogDebug("cut r == PORT_EB"); if (a_port1 == b_port1) { SCLogDebug("1"); a->port = b_port1; a->port2 = b_port2; b->port = b_port2 + 1; b->port2 = a_port2; /** 'b' overlaps 'a' so 'a' needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx,b->sh,&tmp->sh); SigGroupHeadClearSigs(b->sh); SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); SigGroupHeadCopySigs(de_ctx,tmp->sh,&a->sh); SigGroupHeadClearSigs(tmp->sh); tmp->cnt += b->cnt; b->cnt = 0; b->cnt += a->cnt; a->cnt += tmp->cnt; tmp->cnt = 0; } else if (a_port2 == b_port2) { SCLogDebug("2"); a->port = a_port1; a->port2 = b_port1 - 1; b->port = b_port1; b->port2 = b_port2; /** 'a' overlaps 'b' so 'b' needs the 'a' sigs */ SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); b->cnt += a->cnt; } else { SCLogDebug("3"); a->port = a_port1; a->port2 = b_port1 - 1; b->port = b_port1; b->port2 = b_port2; DetectPort *tmp_c; tmp_c = DetectPortInit(); if (tmp_c == NULL) { goto error; } *c = tmp_c; tmp_c->port = b_port2 + 1; tmp_c->port2 = a_port2; SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); SigGroupHeadCopySigs(de_ctx,a->sh,&tmp_c->sh); b->cnt += a->cnt; tmp_c->cnt += a->cnt; } } if (tmp != NULL) { DetectPortFree(tmp); } return 0; error: if (tmp != NULL) DetectPortFree(tmp); return -1; } /** * \brief Function that cuts port groups implementing group negation * * \param a pointer to DetectPort "a" * \param b pointer to DetectPort "b" * * \retval 0 ok * \retval -1 error * */ static int DetectPortCutNot(DetectPort *a, DetectPort **b) { uint16_t a_port1 = a->port; uint16_t a_port2 = a->port2; /* default to NULL */ *b = NULL; if (a_port1 != 0x0000 && a_port2 != 0xFFFF) { a->port = 0x0000; a->port2 = a_port1 - 1; DetectPort *tmp_b; tmp_b = DetectPortInit(); if (tmp_b == NULL) { goto error; } tmp_b->port = a_port2 + 1; tmp_b->port2 = 0xFFFF; *b = tmp_b; } else if (a_port1 == 0x0000 && a_port2 != 0xFFFF) { a->port = a_port2 + 1; a->port2 = 0xFFFF; } else if (a_port1 != 0x0000 && a_port2 == 0xFFFF) { a->port = 0x0000; a->port2 = a_port1 - 1; } else { goto error; } return 0; error: return -1; } /** * \brief Function that compare port groups * * \param a pointer to DetectPort "a" * \param b pointer to DetectPort "b" * * \retval PORT_XX (Port enum value, XX is EQ, ES, EB, LE, etc) * \retval PORT_ER on error * */ int DetectPortCmp(DetectPort *a, DetectPort *b) { /* check any */ if ((a->flags & PORT_FLAG_ANY) && (b->flags & PORT_FLAG_ANY)) return PORT_EQ; if ((a->flags & PORT_FLAG_ANY) && !(b->flags & PORT_FLAG_ANY)) return PORT_LT; if (!(a->flags & PORT_FLAG_ANY) && (b->flags & PORT_FLAG_ANY)) return PORT_GT; uint16_t a_port1 = a->port; uint16_t a_port2 = a->port2; uint16_t b_port1 = b->port; uint16_t b_port2 = b->port2; /* PORT_EQ */ if (a_port1 == b_port1 && a_port2 == b_port2) { //SCLogDebug("PORT_EQ"); return PORT_EQ; /* PORT_ES */ } else if (a_port1 >= b_port1 && a_port1 <= b_port2 && a_port2 <= b_port2) { //SCLogDebug("PORT_ES"); return PORT_ES; /* PORT_EB */ } else if (a_port1 <= b_port1 && a_port2 >= b_port2) { //SCLogDebug("PORT_EB"); return PORT_EB; } else if (a_port1 < b_port1 && a_port2 < b_port2 && a_port2 >= b_port1) { //SCLogDebug("PORT_LE"); return PORT_LE; } else if (a_port1 < b_port1 && a_port2 < b_port2) { //SCLogDebug("PORT_LT"); return PORT_LT; } else if (a_port1 > b_port1 && a_port1 <= b_port2 && a_port2 > b_port2) { //SCLogDebug("PORT_GE"); return PORT_GE; } else if (a_port1 > b_port2) { //SCLogDebug("PORT_GT"); return PORT_GT; } else { /* should be unreachable */ BUG_ON(1); } return PORT_ER; } /** * \brief Function that return a copy of DetectPort src * * \param de_ctx Pointer to the current Detection Engine Context * \param src Pointer to a DetectPort group to copy * * \retval Pointer to a DetectPort instance (copy of src) * \retval NULL on error * */ DetectPort *DetectPortCopy(DetectEngineCtx *de_ctx, DetectPort *src) { if (src == NULL) return NULL; DetectPort *dst = DetectPortInit(); if (dst == NULL) { goto error; } dst->port = src->port; dst->port2 = src->port2; if (src->next != NULL) { dst->next = DetectPortCopy(de_ctx, src->next); if (dst->next != NULL) { dst->next->prev = dst; } } return dst; error: return NULL; } /** * \brief Function that return a copy of DetectPort src sigs * * \param de_ctx Pointer to the current Detection Engine Context * \param src Pointer to a DetectPort group to copy * * \retval Pointer to a DetectPort instance (copy of src) * \retval NULL on error * */ DetectPort *DetectPortCopySingle(DetectEngineCtx *de_ctx,DetectPort *src) { if (src == NULL) return NULL; DetectPort *dst = DetectPortInit(); if (dst == NULL) { goto error; } dst->port = src->port; dst->port2 = src->port2; SigGroupHeadCopySigs(de_ctx,src->sh,&dst->sh); return dst; error: return NULL; } /** * \brief Function Match to Match a port against a DetectPort group * * \param dp Pointer to DetectPort group where we try to match the port * \param port To compare/match * * \retval 1 if port is in the range (it match) * \retval 0 if port is not in the range * */ int DetectPortMatch(DetectPort *dp, uint16_t port) { if (port >= dp->port && port <= dp->port2) { return 1; } return 0; } /** * \brief Helper function that print the DetectPort info * \retval none */ void DetectPortPrint(DetectPort *dp) { if (dp == NULL) return; if (dp->flags & PORT_FLAG_ANY) { SCLogDebug("=> port %p: ANY", dp); // printf("ANY"); } else { SCLogDebug("=> port %p %" PRIu32 "-%" PRIu32 "", dp, dp->port, dp->port2); // printf("%" PRIu32 "-%" PRIu32 "", dp->port, dp->port2); } } /** * \brief Function that find the group matching address in a group head * * \param dp Pointer to DetectPort group where we try to find the group * \param port port to search/lookup * * \retval Pointer to the DetectPort group of our port if it matched * \retval NULL if port is not in the list * */ DetectPort * DetectPortLookupGroup(DetectPort *dp, uint16_t port) { DetectPort *p = dp; if (dp == NULL) return NULL; for ( ; p != NULL; p = p->next) { if (DetectPortMatch(p,port) == 1) { //SCLogDebug("match, port %" PRIu32 ", dp ", port); //DetectPortPrint(p); SCLogDebug(""); return p; } } return NULL; } /** * \brief Function to join the source group to the target and its members * * \param de_ctx Pointer to the current Detection Engine Context * \param target Pointer to DetectPort group where the source is joined * \param source Pointer to DetectPort group that will join into the target * * \retval -1 on error * \retval 0 on success * */ int DetectPortJoin(DetectEngineCtx *de_ctx, DetectPort *target, DetectPort *source) { if (target == NULL || source == NULL) return -1; target->cnt += source->cnt; SigGroupHeadCopySigs(de_ctx,source->sh,&target->sh); if (source->port < target->port) target->port = source->port; if (source->port2 > target->port2) target->port2 = source->port2; return 0; } /******************* parsing routines ************************/ /** * \brief Wrapper function that call the internal/real function * to insert the new DetectPort * \param head Pointer to the head of the DetectPort group list * \param new Pointer to the new DetectPort group list * * \retval 1 inserted * \retval 0 not inserted, memory of new is freed * \retval -1 error */ static int DetectPortParseInsert(DetectPort **head, DetectPort *new) { return DetectPortInsert(NULL, head, new); } /** * \brief Function to parse and insert the string in the DetectPort head list * * \param head Pointer to the head of the DetectPort group list * \param s Pointer to the port string * * \retval 0 on success * \retval -1 on error */ static int DetectPortParseInsertString(DetectPort **head, char *s) { DetectPort *ad = NULL, *ad_any = NULL; int r = 0; char port_any = FALSE; SCLogDebug("head %p, *head %p, s %s", head, *head, s); /** parse the address */ ad = PortParse(s); if (ad == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT," failed to parse port \"%s\"",s); return -1; } if (ad->flags & PORT_FLAG_ANY) { port_any = TRUE; } /** handle the not case, we apply the negation then insert the part(s) */ if (ad->flags & PORT_FLAG_NOT) { DetectPort *ad2 = NULL; if (DetectPortCutNot(ad, &ad2) < 0) { goto error; } /** normally a 'not' will result in two ad's unless the 'not' is on the * start or end of the address space(e.g. 0.0.0.0 or 255.255.255.255) */ if (ad2 != NULL) { if (DetectPortParseInsert(head, ad2) < 0) { if (ad2 != NULL) SCFree(ad2); goto error; } } } r = DetectPortParseInsert(head, ad); if (r < 0) goto error; /** if any, insert 0.0.0.0/0 and ::/0 as well */ if (r == 1 && port_any == TRUE) { SCLogDebug("inserting 0:65535 as port is \"any\""); ad_any = PortParse("0:65535"); if (ad_any == NULL) goto error; if (DetectPortParseInsert(head, ad_any) < 0) goto error; } return 0; error: SCLogError(SC_ERR_PORT_PARSE_INSERT_STRING,"DetectPortParseInsertString error"); if (ad != NULL) DetectPortCleanupList(ad); if (ad_any != NULL) DetectPortCleanupList(ad_any); return -1; } /** * \brief Parses a port string and updates the 2 port heads with the * port groups. * * \todo We don't seem to be handling negated cases, like [port,![!port,port]], * since we pass around negate without keeping a count of ! with depth. * Can solve this by keeping a count of the negations with depth, so that * an even no of negations would count as no negation and an odd no of * negations would count as a negation. * * \param gh Pointer to the port group head that should hold port ranges * that are not negated. * \param ghn Pointer to the port group head that should hold port ranges * that are negated. * \param s Pointer to the character string holding the port to be * parsed. * \param negate Flag that indicates if the receieved address string is negated * or not. 0 if it is not, 1 it it is. * * \retval 0 On successfully parsing. * \retval -1 On failure. */ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, int negate) { size_t u = 0; size_t x = 0; int o_set = 0, n_set = 0, d_set = 0; int range = 0; int depth = 0; size_t size = strlen(s); char address[1024] = ""; char *rule_var_port = NULL; char *temp_rule_var_port = NULL; int r = 0; SCLogDebug("head %p, *head %p, negate %d", head, *head, negate); for (u = 0, x = 0; u < size && x < sizeof(address); u++) { address[x] = s[u]; x++; if (s[u] == ':') range = 1; if (range == 1 && s[u] == '!') { SCLogError(SC_ERR_NEGATED_VALUE_IN_PORT_RANGE,"Can't have a negated value in a range."); return -1; } else if (!o_set && s[u] == '!') { SCLogDebug("negation encountered"); n_set = 1; x--; } else if (s[u] == '[') { if (!o_set) { o_set = 1; x = 0; } depth++; } else if (s[u] == ']') { if (depth == 1) { address[x - 1] = '\0'; SCLogDebug("Parsed port from DetectPortParseDo - %s", address); x = 0; r = DetectPortParseDo(head, nhead, address, negate? negate: n_set); if (r == -1) goto error; n_set = 0; } depth--; range = 0; } else if (depth == 0 && s[u] == ',') { if (o_set == 1) { o_set = 0; } else if (d_set == 1) { address[x - 1] = '\0'; rule_var_port = SCRuleVarsGetConfVar(address, SC_RULE_VARS_PORT_GROUPS); if (rule_var_port == NULL) goto error; if (strlen(rule_var_port) == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "variable %s resolved " "to nothing. This is likely a misconfiguration. " "Note that a negated port needs to be quoted, " "\"!$HTTP_PORTS\" instead of !$HTTP_PORTS. See issue #295.", s); goto error; } temp_rule_var_port = rule_var_port; if (negate == 1 || n_set == 1) { temp_rule_var_port = SCMalloc(strlen(rule_var_port) + 3); if (unlikely(temp_rule_var_port == NULL)) goto error; snprintf(temp_rule_var_port, strlen(rule_var_port) + 3, "[%s]", rule_var_port); } r = DetectPortParseDo(head, nhead, temp_rule_var_port, (negate + n_set) % 2);//negate? negate: n_set); if (r == -1) goto error; d_set = 0; n_set = 0; if (temp_rule_var_port != rule_var_port) SCFree(temp_rule_var_port); } else { address[x - 1] = '\0'; SCLogDebug("Parsed port from DetectPortParseDo - %s", address); if (negate == 0 && n_set == 0) { r = DetectPortParseInsertString(head, address); } else { r = DetectPortParseInsertString(nhead, address); } if (r == -1) goto error; n_set = 0; } x = 0; range = 0; } else if (depth == 0 && s[u] == '$') { d_set = 1; } else if (depth == 0 && u == size-1) { range = 0; if (x == 1024) { address[x - 1] = '\0'; } else { address[x] = '\0'; } SCLogDebug("%s", address); x = 0; if (d_set == 1) { rule_var_port = SCRuleVarsGetConfVar(address, SC_RULE_VARS_PORT_GROUPS); if (rule_var_port == NULL) goto error; if (strlen(rule_var_port) == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "variable %s resolved " "to nothing. This is likely a misconfiguration. " "Note that a negated port needs to be quoted, " "\"!$HTTP_PORTS\" instead of !$HTTP_PORTS. See issue #295.", s); goto error; } temp_rule_var_port = rule_var_port; if ((negate + n_set) % 2) { temp_rule_var_port = SCMalloc(strlen(rule_var_port) + 3); if (unlikely(temp_rule_var_port == NULL)) goto error; snprintf(temp_rule_var_port, strlen(rule_var_port) + 3, "[%s]", rule_var_port); } r = DetectPortParseDo(head, nhead, temp_rule_var_port, (negate + n_set) % 2); if (r == -1) goto error; d_set = 0; if (temp_rule_var_port != rule_var_port) SCFree(temp_rule_var_port); } else { if (!((negate + n_set) % 2)) { r = DetectPortParseInsertString(head,address); } else { r = DetectPortParseInsertString(nhead,address); } if (r == -1) goto error; } n_set = 0; } } if (depth > 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "not every port block was " "properly closed in \"%s\", %d missing closing brackets (]). " "Note: problem might be in a variable.", s, depth); goto error; } else if (depth < 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "not every port block was " "properly opened in \"%s\", %d missing opening brackets ([). " "Note: problem might be in a variable.", s, depth*-1); goto error; } return 0; error: return -1; } /** * \brief Check if the port group list covers the complete port space. * \retval 0 no * \retval 1 yes */ int DetectPortIsCompletePortSpace(DetectPort *p) { uint16_t next_port = 0; if (p == NULL) return 0; if (p->port != 0x0000) return 0; /* if we're ending with 0xFFFF while we know we started with 0x0000 it's the complete space */ if (p->port2 == 0xFFFF) return 1; next_port = p->port2 + 1; p = p->next; for ( ; p != NULL; p = p->next) { if (p->port != next_port) return 0; if (p->port2 == 0xFFFF) return 1; next_port = p->port2 + 1; } return 0; } /** * \brief Helper function for the parsing process * * \param head Pointer to the head of the DetectPort group list * \param nhead Pointer to the new head of the DetectPort group list * * \retval 0 on success * \retval -1 on error */ int DetectPortParseMergeNotPorts(DetectPort **head, DetectPort **nhead) { DetectPort *ad = NULL; DetectPort *ag, *ag2; int r = 0; /** check if the full port space is negated */ if (DetectPortIsCompletePortSpace(*nhead) == 1) { SCLogError(SC_ERR_COMPLETE_PORT_SPACE_NEGATED,"Complete port space is negated"); goto error; } /** * step 0: if the head list is empty, but the nhead list isn't * we have a pure not thingy. In that case we add a 0:65535 * first. */ if (*head == NULL && *nhead != NULL) { SCLogDebug("inserting 0:65535 into head"); r = DetectPortParseInsertString(head,"0:65535"); if (r < 0) { goto error; } } /** step 1: insert our ghn members into the gh list */ for (ag = *nhead; ag != NULL; ag = ag->next) { /** work with a copy of the ad so we can easily clean up * the ghn group later. */ ad = DetectPortCopy(NULL, ag); if (ad == NULL) { goto error; } r = DetectPortParseInsert(head, ad); if (r < 0) { goto error; } ad = NULL; } /** step 2: pull the address blocks that match our 'not' blocks */ for (ag = *nhead; ag != NULL; ag = ag->next) { SCLogDebug("ag %p", ag); DetectPortPrint(ag); for (ag2 = *head; ag2 != NULL; ) { SCLogDebug("ag2 %p", ag2); DetectPortPrint(ag2); r = DetectPortCmp(ag, ag2); if (r == PORT_EQ || r == PORT_EB) { /* XXX more ??? */ if (ag2->prev == NULL) { *head = ag2->next; } else { ag2->prev->next = ag2->next; } if (ag2->next != NULL) { ag2->next->prev = ag2->prev; } /** store the next ptr and remove the group */ DetectPort *next_ag2 = ag2->next; DetectPortFree(ag2); ag2 = next_ag2; } else { ag2 = ag2->next; } } } for (ag2 = *head; ag2 != NULL; ag2 = ag2->next) { SCLogDebug("ag2 %p", ag2); DetectPortPrint(ag2); } if (*head == NULL) { SCLogError(SC_ERR_NO_PORTS_LEFT_AFTER_MERGE,"no ports left after merging ports with negated ports"); goto error; } return 0; error: if (ad != NULL) DetectPortFree(ad); return -1; } int DetectPortTestConfVars(void) { SCLogDebug("Testing port conf vars for any misconfigured values"); ConfNode *port_vars_node = ConfGetNode("vars.port-groups"); if (port_vars_node == NULL) { return 0; } ConfNode *seq_node; TAILQ_FOREACH(seq_node, &port_vars_node->head, next) { SCLogDebug("Testing %s - %s\n", seq_node->name, seq_node->val); DetectPort *gh = DetectPortInit(); if (gh == NULL) { goto error; } DetectPort *ghn = NULL; if (seq_node->val == NULL) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Port var \"%s\" probably has a sequence(something " "in brackets) value set without any quotes. Please " "quote it using \"..\".", seq_node->name); goto error; } int r = DetectPortParseDo(&gh, &ghn, seq_node->val, /* start with negate no */0); if (r < 0) { goto error; } if (DetectPortIsCompletePortSpace(ghn)) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Port var - \"%s\" has the complete Port range negated " "with it's value \"%s\". Port space range is NIL. " "Probably have a !any or a port range that supplies " "a NULL address range", seq_node->name, seq_node->val); goto error; } if (gh != NULL) DetectPortFree(gh); if (ghn != NULL) DetectPortFree(ghn); } return 0; error: return -1; } /** * \brief Function for parsing port strings * * \param head Pointer to the head of the DetectPort group list * \param str Pointer to the port string * * \retval 0 on success * \retval -1 on error */ int DetectPortParse(DetectPort **head, char *str) { int r; SCLogDebug("Port string to be parsed - str %s", str); /* negate port list */ DetectPort *nhead = NULL; r = DetectPortParseDo(head, &nhead, str,/* start with negate no */0); if (r < 0) goto error; SCLogDebug("head %p %p, nhead %p", head, *head, nhead); /* merge the 'not' address groups */ if (DetectPortParseMergeNotPorts(head, &nhead) < 0) goto error; /* free the temp negate head */ DetectPortCleanupList(nhead); return 0; error: DetectPortCleanupList(nhead); return -1; } /** * \brief Helper function for parsing port strings * * \param str Pointer to the port string * * \retval DetectPort pointer of the parse string on success * \retval NULL on error */ DetectPort *PortParse(char *str) { char *port2 = NULL; DetectPort *dp = NULL; char *portdup = SCStrdup(str); if (unlikely(portdup == NULL)) { return NULL; } dp = DetectPortInit(); if (dp == NULL) goto error; /* XXX better input validation */ /* we dup so we can put a nul-termination in it later */ char *port = portdup; /* handle the negation case */ if (port[0] == '!') { dp->flags |= PORT_FLAG_NOT; port++; } /* see if the address is an ipv4 or ipv6 address */ if ((port2 = strchr(port, ':')) != NULL) { /* 80:81 range format */ port2[0] = '\0'; port2++; if(DetectPortIsValidRange(port)) dp->port = atoi(port); else goto error; if (strcmp(port2, "") != 0) { if (DetectPortIsValidRange(port2)) dp->port2 = atoi(port2); else goto error; } else { dp->port2 = 65535; } /* a > b is illegal, a == b is ok */ if (dp->port > dp->port2) goto error; } else { if (strcasecmp(port,"any") == 0) { dp->port = 0; dp->port2 = 65535; } else if(DetectPortIsValidRange(port)){ dp->port = dp->port2 = atoi(port); } else { goto error; } } SCFree(portdup); return dp; error: if (dp != NULL) DetectPortCleanupList(dp); if (portdup) SCFree(portdup); return NULL; } /** * \brief Helper function to check if a parsed port is in the valid range * of available ports * * \param str Pointer to the port string * * \retval 1 if port is in the valid range * \retval 0 if invalid */ int DetectPortIsValidRange(char *port){ if(atoi(port) >= 0 && atoi(port) <= 65535) return 1; else return 0; } /********************** End parsing routines ********************/ /********************* Hash function routines *******************/ #define PORT_HASH_SIZE 1024 /** * \brief Generate a hash for a DetectPort group * * \param ht HashListTable * \param data Pointer to the DetectPort * \param datalen sizeof data (not used here atm) * * \retval uint32_t the value of the generated hash */ uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datalen) { DetectPort *p = (DetectPort *)data; uint32_t hash = p->port * p->port2; return hash % ht->array_size; } /** * \brief Function that return if the two DetectPort groups are equal or not * * \param data1 Pointer to the DetectPort 1 * \param len1 sizeof data 1 (not used here atm) * \param data2 Pointer to the DetectPort 2 * \param len2 sizeof data 2 (not used here atm) * * \retval 1 if the DetectPort groups are equal * \retval 0 if not equal */ char DetectPortCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { DetectPort *p1 = (DetectPort *)data1; DetectPort *p2 = (DetectPort *)data2; if (p1->port2 == p2->port2 && p1->port == p2->port && p1->flags == p2->flags) return 1; return 0; } void DetectPortFreeFunc(void *p) { DetectPort *dp = (DetectPort *)p; DetectPortFree(dp); } /** * \brief Function that initialize the HashListTable of destination DetectPort * * \param de_ctx Pointer to the current DetectionEngineContext * * \retval 0 HashListTable initialization succes * \retval -1 Error */ int DetectPortDpHashInit(DetectEngineCtx *de_ctx) { de_ctx->dport_hash_table = HashListTableInit(PORT_HASH_SIZE, DetectPortHashFunc, DetectPortCompareFunc, DetectPortFreeFunc); if (de_ctx->dport_hash_table == NULL) goto error; return 0; error: return -1; } /** * \brief Function that free the HashListTable of destination DetectPort * * \param de_ctx Pointer to the current DetectionEngineCtx */ void DetectPortDpHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->dport_hash_table == NULL) return; HashListTableFree(de_ctx->dport_hash_table); de_ctx->dport_hash_table = NULL; } /** * \brief Function that reset the HashListTable of destination DetectPort * (Free and Initialize it) * * \param de_ctx Pointer to the current DetectionEngineCtx */ void DetectPortDpHashReset(DetectEngineCtx *de_ctx) { DetectPortDpHashFree(de_ctx); DetectPortDpHashInit(de_ctx); } /** * \brief Function that add a destination DetectPort into the hashtable * * \param de_ctx Pointer to the current DetectionEngineCtx * \param p Pointer to the DetectPort to add */ int DetectPortDpHashAdd(DetectEngineCtx *de_ctx, DetectPort *p) { return HashListTableAdd(de_ctx->dport_hash_table, (void *)p, 0); } /** * \brief Function that search a destination DetectPort in the hashtable * * \param de_ctx Pointer to the current DetectionEngineCtx * \param p Pointer to the DetectPort to search */ DetectPort *DetectPortDpHashLookup(DetectEngineCtx *de_ctx, DetectPort *p) { DetectPort *rp = HashListTableLookup(de_ctx->dport_hash_table, (void *)p, 0); return rp; } /** * \brief Function that initialize the HashListTable of source DetectPort * * \param de_ctx Pointer to the current DetectionEngineContext * * \retval 0 HashListTable initialization succes * \retval -1 Error */ int DetectPortSpHashInit(DetectEngineCtx *de_ctx) { de_ctx->sport_hash_table = HashListTableInit(PORT_HASH_SIZE, DetectPortHashFunc, DetectPortCompareFunc, DetectPortFreeFunc); if (de_ctx->sport_hash_table == NULL) goto error; return 0; error: return -1; } /** * \brief Function that free the HashListTable of source DetectPort * * \param de_ctx Pointer to the current DetectionEngineCtx */ void DetectPortSpHashFree(DetectEngineCtx *de_ctx) { if (de_ctx->sport_hash_table == NULL) return; HashListTableFree(de_ctx->sport_hash_table); de_ctx->sport_hash_table = NULL; } /** * \brief Function that reset the HashListTable of source DetectPort * (Free and Initialize it) * * \param de_ctx Pointer to the current DetectionEngineCtx */ void DetectPortSpHashReset(DetectEngineCtx *de_ctx) { DetectPortSpHashFree(de_ctx); DetectPortSpHashInit(de_ctx); } /** * \brief Function that add a source DetectPort into the hashtable * * \param de_ctx Pointer to the current DetectionEngineCtx * \param p Pointer to the DetectPort to add */ int DetectPortSpHashAdd(DetectEngineCtx *de_ctx, DetectPort *p) { return HashListTableAdd(de_ctx->sport_hash_table, (void *)p, 0); } /** * \brief Function that search a source DetectPort in the hashtable * * \param de_ctx Pointer to the current DetectionEngineCtx * \param p Pointer to the DetectPort to search */ DetectPort *DetectPortSpHashLookup(DetectEngineCtx *de_ctx, DetectPort *p) { DetectPort *rp = HashListTableLookup(de_ctx->sport_hash_table, (void *)p, 0); return rp; } /*---------------------- Unittests -------------------------*/ #ifdef UNITTESTS /** * \test Check if a DetectPort is properly allocated */ int PortTestParse01 (void) { DetectPort *dd = NULL; int r = DetectPortParse(&dd,"80"); if (r == 0) { DetectPortFree(dd); return 1; } return 0; } /** * \test Check if two ports are properly allocated in the DetectPort group */ int PortTestParse02 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"80"); if (r == 0) { r = DetectPortParse(&dd,"22"); if (r == 0) { result = 1; } DetectPortCleanupList(dd); return result; } return result; } /** * \test Check if two port ranges are properly allocated in the DetectPort group */ int PortTestParse03 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"80:88"); if (r == 0) { r = DetectPortParse(&dd,"85:100"); if (r == 0) { result = 1; } DetectPortCleanupList(dd); return result; } return result; } /** * \test Check if a negated port range is properly allocated in the DetectPort */ int PortTestParse04 (void) { DetectPort *dd = NULL; int r = DetectPortParse(&dd,"!80:81"); if (r == 0) { DetectPortCleanupList(dd); return 1; } return 0; } /** * \test Check if a negated port range is properly fragmented in the allowed * real groups, ex !80:81 should allow 0:79 and 82:65535 */ int PortTestParse05 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"!80:81"); if (r != 0) goto end; if (dd->next == NULL) goto end; if (dd->port != 0 || dd->port2 != 79) goto end; if (dd->next->port != 82 || dd->next->port2 != 65535) goto end; DetectPortCleanupList(dd); result = 1; end: return result; } /** * \test Check if we copy a DetectPort correctly */ int PortTestParse06 (void) { DetectPort *dd = NULL, *copy = NULL; int result = 0; int r = DetectPortParse(&dd,"22"); if (r != 0) goto end; r = DetectPortParse(&dd,"80"); if (r != 0) goto end; r = DetectPortParse(&dd,"143"); if (r != 0) goto end; copy = DetectPortCopy(NULL,dd); if (copy == NULL) goto end; if (DetectPortCmp(dd,copy) != PORT_EQ) goto end; if (copy->next == NULL) goto end; if (DetectPortCmp(dd->next,copy->next) != PORT_EQ) goto end; if (copy->next->next == NULL) goto end; if (DetectPortCmp(dd->next->next,copy->next->next) != PORT_EQ) goto end; if (copy->port != 22 || copy->next->port != 80 || copy->next->next->port != 143) goto end; result = 1; end: if (copy != NULL) DetectPortCleanupList(copy); if (dd != NULL) DetectPortCleanupList(dd); return result; } /** * \test Check if a negated port range is properly fragmented in the allowed * real groups */ int PortTestParse07 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"!21:902"); if (r != 0) goto end; if (dd->next == NULL) goto end; if (dd->port != 0 || dd->port2 != 20) goto end; if (dd->next->port != 903 || dd->next->port2 != 65535) goto end; DetectPortCleanupList(dd); result = 1; end: return result; } /** * \test Check if we dont allow invalid port range specification */ int PortTestParse08 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"[80:!80]"); if (r == 0) goto end; DetectPortCleanupList(dd); result = 1; end: return result; } /** * \test Check if we autocomplete correctly an open range */ int PortTestParse09 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"1024:"); if (r != 0) goto end; if (dd == NULL) goto end; if (dd->port != 1024 || dd->port2 != 0xffff) goto end; DetectPortCleanupList(dd); result = 1; end: return result; } /** * \test Test we don't allow a port that is too big */ int PortTestParse10 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"77777777777777777777777777777777777777777777"); if (r != 0) { result = 1 ; goto end; } DetectPortFree(dd); end: return result; } /** * \test Test second port of range being too big */ int PortTestParse11 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"1024:65536"); if (r != 0) { result = 1 ; goto end; } DetectPortFree(dd); end: return result; } /** * \test Test second port of range being just right */ int PortTestParse12 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"1024:65535"); if (r != 0) { goto end; } DetectPortFree(dd); result = 1 ; end: return result; } /** * \test Test first port of range being too big */ int PortTestParse13 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"65536:65535"); if (r != 0) { result = 1 ; goto end; } DetectPortFree(dd); end: return result; } /** * \test Test merging port groups */ int PortTestParse14 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParseInsertString(&dd, "0:100"); if (r != 0) goto end; r = DetectPortParseInsertString(&dd, "1000:65535"); if (r != 0 || dd->next == NULL) goto end; result = 1; result &= (dd->port == 0) ? 1 : 0; result &= (dd->port2 == 100) ? 1 : 0; result &= (dd->next->port == 1000) ? 1 : 0; result &= (dd->next->port2 == 65535) ? 1 : 0; DetectPortFree(dd); end: return result; } /** * \test Test merging negated port groups */ int PortTestParse15 (void) { DetectPort *dd = NULL; int result = 0; int r = DetectPortParse(&dd,"![0:100,1000:3000]"); if (r != 0 || dd->next == NULL) goto end; result = 1; result &= (dd->port == 101) ? 1 : 0; result &= (dd->port2 == 999) ? 1 : 0; result &= (dd->next->port == 3001) ? 1 : 0; result &= (dd->next->port2 == 65535) ? 1 : 0; DetectPortFree(dd); end: return result; } /** * \test Test parse, copy and cmp functions */ int PortTestParse16 (void) { DetectPort *dd = NULL, *copy = NULL; int result = 0; int r = DetectPortParse(&dd,"22"); if (r != 0) goto end; r = DetectPortParse(&dd,"80"); if (r != 0) goto end; r = DetectPortParse(&dd,"143"); if (r != 0) goto end; copy = DetectPortCopy(NULL,dd); if (copy == NULL) goto end; if (DetectPortCmp(dd,copy) != PORT_EQ) goto end; if (copy->next == NULL) goto end; if (DetectPortCmp(dd->next,copy->next) != PORT_EQ) goto end; if (copy->next->next == NULL) goto end; if (DetectPortCmp(dd->next->next,copy->next->next) != PORT_EQ) goto end; if (copy->port != 22 || copy->next->port != 80 || copy->next->next->port != 143) goto end; if (copy->next->prev != copy) goto end; result = 1; end: if (copy != NULL) DetectPortCleanupList(copy); if (dd != NULL) DetectPortCleanupList(dd); return result; } /** * \test Test general functions */ int PortTestFunctions01(void) { DetectPort *head = NULL; DetectPort *dp1= NULL; int result = 0; /* Parse */ int r = DetectPortParse(&head,"![0:100,1000:65535]"); if (r != 0 || head->next != NULL) goto end; /* We should have only one DetectPort */ if (!(head->port == 101)) goto end; if (!(head->port2 == 999)) goto end; if (!(head->next == NULL)) goto end; r = DetectPortParse(&dp1,"2000:3000"); if (r != 0 || dp1->next != NULL) goto end; if (!(dp1->port == 2000)) goto end; if (!(dp1->port2 == 3000)) goto end; /* Add */ r = DetectPortAdd(&head, dp1); if (r != 0 || head->next == NULL) goto end; if (!(head->port == 101)) goto end; if (!(head->port2 == 999)) goto end; if (!(head->next->port == 2000)) goto end; if (!(head->next->port2 == 3000)) goto end; /* Match */ if (!DetectPortMatch(head, 150)) goto end; if (DetectPortMatch(head->next, 1500)) goto end; if ((DetectPortMatch(head, 3500))) goto end; if ((DetectPortMatch(head, 50))) goto end; result = 1; end: if (dp1 != NULL) DetectPortFree(dp1); if (head != NULL) DetectPortFree(head); return result; } /** * \test Test general functions */ int PortTestFunctions02(void) { DetectPort *head = NULL; DetectPort *dp1= NULL; DetectPort *dp2= NULL; int result = 0; /* Parse */ int r = DetectPortParse(&head, "![0:100,1000:65535]"); if (r != 0 || head->next != NULL) goto end; r = DetectPortParse(&dp1, "!200:300"); if (r != 0 || dp1->next == NULL) goto end; /* Merge Nots */ r = DetectPortParseMergeNotPorts(&head, &dp1); if (r != 0 || head->next != NULL) goto end; r = DetectPortParse(&dp2, "!100:500"); if (r != 0 || dp2->next == NULL) goto end; /* Merge Nots */ r = DetectPortParseMergeNotPorts(&head, &dp2); if (r != 0 || head->next != NULL) goto end; if (!(head->port == 200)) goto end; if (!(head->port2 == 300)) goto end; result = 1; end: if (dp1 != NULL) DetectPortFree(dp1); if (dp2 != NULL) DetectPortFree(dp2); if (head != NULL) DetectPortFree(head); return result; } /** * \test Test general functions */ int PortTestFunctions03(void) { DetectPort *dp1= NULL; DetectPort *dp2= NULL; DetectPort *dp3= NULL; int result = 0; int r = DetectPortParse(&dp1, "200:300"); if (r != 0) goto end; r = DetectPortParse(&dp2, "250:300"); if (r != 0) goto end; /* Cut */ DetectPortCut(NULL, dp1, dp2, &dp3); if (r != 0) goto end; if (!(dp1->port == 200)) goto end; if (!(dp1->port2 == 249)) goto end; if (!(dp2->port == 250)) goto end; if (!(dp2->port2 == 300)) goto end; dp1->port = 0; dp1->port2 = 500; dp2->port = 250; dp2->port2 = 750; /* Cut */ DetectPortCut(NULL, dp1, dp2, &dp3); if (r != 0) goto end; if (!(dp1->port == 0)) goto end; if (!(dp1->port2 == 249)) goto end; if (!(dp2->port == 250)) goto end; if (!(dp2->port2 == 500)) goto end; if (!(dp3->port == 501)) goto end; if (!(dp3->port2 == 750)) goto end; result = 1; end: if (dp1 != NULL) DetectPortFree(dp1); if (dp2 != NULL) DetectPortFree(dp2); if (dp3 != NULL) DetectPortFree(dp3); return result; } /** * \test Test general functions */ int PortTestFunctions04(void) { DetectPort *dp1= NULL; DetectPort *dp2= NULL; int result = 0; int r = DetectPortParse(&dp1, "200:300"); if (r != 0) goto end; dp2 = DetectPortInit(); /* Cut Not */ DetectPortCutNot(dp1, &dp2); if (r != 0) goto end; if (!(dp1->port == 0)) goto end; if (!(dp1->port2 == 199)) goto end; if (!(dp2->port == 301)) goto end; if (!(dp2->port2 == 65535)) goto end; result = 1; end: if (dp1 != NULL) DetectPortFree(dp1); if (dp2 != NULL) DetectPortFree(dp2); return result; } /** * \test Test general functions */ static int PortTestFunctions05(void) { DetectPort *dp1 = NULL; DetectPort *dp2 = NULL; DetectPort *dp3 = NULL; int result = 0; int r = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature s[2]; memset(s,0x00,sizeof(s)); s[0].num = 0; s[1].num = 1; r = DetectPortParse(&dp1, "1024:65535"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; } SigGroupHeadAppendSig(de_ctx, &dp1->sh, &s[0]); r = DetectPortParse(&dp2, "any"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; } SigGroupHeadAppendSig(de_ctx, &dp2->sh, &s[1]); SCLogDebug("dp1"); DetectPortPrint(dp1); SCLogDebug("dp2"); DetectPortPrint(dp2); DetectPortInsert(de_ctx, &dp3, dp1); DetectPortInsert(de_ctx, &dp3, dp2); if (dp3 == NULL) goto end; SCLogDebug("dp3"); DetectPort *x = dp3; for ( ; x != NULL; x = x->next) { DetectPortPrint(x); //SigGroupHeadPrintSigs(de_ctx, x->sh); } DetectPort *one = dp3; DetectPort *two = dp3->next; int sig = 0; if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'two', but it shouldn't: ", sig); goto end; } result = 1; end: if (dp1 != NULL) DetectPortFree(dp1); if (dp2 != NULL) DetectPortFree(dp2); return result; } /** * \test Test general functions */ static int PortTestFunctions06(void) { DetectPort *dp1 = NULL; DetectPort *dp2 = NULL; DetectPort *dp3 = NULL; int result = 0; int r = 0; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature s[2]; memset(s,0x00,sizeof(s)); s[0].num = 0; s[1].num = 1; r = DetectPortParse(&dp1, "1024:65535"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; } SigGroupHeadAppendSig(de_ctx, &dp1->sh, &s[0]); r = DetectPortParse(&dp2, "any"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; } SigGroupHeadAppendSig(de_ctx, &dp2->sh, &s[1]); SCLogDebug("dp1"); DetectPortPrint(dp1); SCLogDebug("dp2"); DetectPortPrint(dp2); DetectPortInsert(de_ctx, &dp3, dp2); DetectPortInsert(de_ctx, &dp3, dp1); if (dp3 == NULL) goto end; SCLogDebug("dp3"); DetectPort *x = dp3; for ( ; x != NULL; x = x->next) { DetectPortPrint(x); //SigGroupHeadPrintSigs(de_ctx, x->sh); } DetectPort *one = dp3; DetectPort *two = dp3->next; int sig = 0; if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'one', but it shouldn't: ", sig); goto end; } sig = 1; if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { printf("sig %d part of 'two', but it shouldn't: ", sig); goto end; } result = 1; end: if (dp1 != NULL) DetectPortFree(dp1); if (dp2 != NULL) DetectPortFree(dp2); return result; } /** * \test Test packet Matches * \param raw_eth_pkt pointer to the ethernet packet * \param pktsize size of the packet * \param sig pointer to the signature to test * \param sid sid number of the signature * \retval return 1 if match * \retval return 0 if not */ int PortTestMatchReal(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, uint32_t sid) { int result = 0; FlowInitConfig(FLOW_QUIET); Packet *p = UTHBuildPacketFromEth(raw_eth_pkt, pktsize); result = UTHPacketMatchSig(p, sig); FlowShutdown(); return result; } /** * \brief Wrapper for PortTestMatchReal */ int PortTestMatchRealWrp(char *sig, uint32_t sid) { /* Real HTTP packeth doing a GET method * tcp.sport=47370 tcp.dport=80 * ip.src=192.168.28.131 ip.dst=192.168.1.1 */ uint8_t raw_eth_pkt[] = { 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c, 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00, 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06, 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8, 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2, 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18, 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45, 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50, 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f, 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e, 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d, 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67, 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a, 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30, 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55, 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20, 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20, 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72, 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e, 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b, 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39, 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75, 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34, 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79, 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f, 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34, 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74, 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68, 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c, 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f, 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d, 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63, 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d, 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c, 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e, 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61, 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75, 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30, 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65, 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64, 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69, 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74, 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65, 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38, 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74, 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e, 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e, 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d, 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33, 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e, 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20, 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69, 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end raw_eth_pkt */ return PortTestMatchReal(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), sig, sid); } /** * \test Check if we match a dest port */ int PortTestMatchReal01() { /* tcp.sport=47370 tcp.dport=80 */ char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\"; content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we match a source port */ int PortTestMatchReal02() { char *sig = "alert tcp any 47370 -> any any (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we match both of them */ int PortTestMatchReal03() { char *sig = "alert tcp any 47370 -> any 80 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we negate dest ports correctly */ int PortTestMatchReal04() { char *sig = "alert tcp any any -> any !80 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; } /** * \test Check if we negate source ports correctly */ int PortTestMatchReal05() { char *sig = "alert tcp any !47370 -> any any (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; } /** * \test Check if we negate both ports correctly */ int PortTestMatchReal06() { char *sig = "alert tcp any !47370 -> any !80 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; } /** * \test Check if we match a dest port range */ int PortTestMatchReal07() { char *sig = "alert tcp any any -> any 70:100 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we match a source port range */ int PortTestMatchReal08() { char *sig = "alert tcp any 47000:50000 -> any any (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we match both port ranges */ int PortTestMatchReal09() { char *sig = "alert tcp any 47000:50000 -> any 70:100 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we negate a dest port range */ int PortTestMatchReal10() { char *sig = "alert tcp any any -> any !70:100 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; } /** * \test Check if we negate a source port range */ int PortTestMatchReal11() { char *sig = "alert tcp any !47000:50000 -> any any (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; } /** * \test Check if we negate both port ranges */ int PortTestMatchReal12() { char *sig = "alert tcp any !47000:50000 -> any !70:100 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; } /** * \test Check if we autocomplete ranges correctly */ int PortTestMatchReal13() { char *sig = "alert tcp any 47000:50000 -> any !81: (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we autocomplete ranges correctly */ int PortTestMatchReal14() { char *sig = "alert tcp any !48000:50000 -> any :100 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we autocomplete ranges correctly */ int PortTestMatchReal15() { char *sig = "alert tcp any :50000 -> any 81:100 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; } /** * \test Check if we separate ranges correctly */ int PortTestMatchReal16() { char *sig = "alert tcp any 100: -> any ![0:79,81:65535] (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we separate ranges correctly */ int PortTestMatchReal17() { char *sig = "alert tcp any ![0:39999,48000:50000] -> any ![0:80,82:65535] " "(msg:\"Nothing..\"; content:\"GET\"; sid:1;)"; return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; } /** * \test Check if we separate ranges correctly */ int PortTestMatchReal18() { char *sig = "alert tcp any ![0:39999,48000:50000] -> any 80 (msg:\"Nothing" " at all\"; content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } /** * \test Check if we separate ranges correctly */ int PortTestMatchReal19() { char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\";" " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } static int PortTestMatchDoubleNegation(void) { int result = 0; DetectPort *head = NULL, *nhead = NULL; if (DetectPortParseDo(&head, &nhead, "![!80]", 0) == -1) return result; result = (head != NULL); result = (nhead == NULL); return result; } #endif /* UNITTESTS */ void DetectPortTests(void) { #ifdef UNITTESTS UtRegisterTest("PortTestParse01", PortTestParse01, 1); UtRegisterTest("PortTestParse02", PortTestParse02, 1); UtRegisterTest("PortTestParse03", PortTestParse03, 1); UtRegisterTest("PortTestParse04", PortTestParse04, 1); UtRegisterTest("PortTestParse05", PortTestParse05, 1); UtRegisterTest("PortTestParse06", PortTestParse06, 1); UtRegisterTest("PortTestParse07", PortTestParse07, 1); UtRegisterTest("PortTestParse08", PortTestParse08, 1); UtRegisterTest("PortTestParse09", PortTestParse09, 1); UtRegisterTest("PortTestParse10", PortTestParse10, 1); UtRegisterTest("PortTestParse11", PortTestParse11, 1); UtRegisterTest("PortTestParse12", PortTestParse12, 1); UtRegisterTest("PortTestParse13", PortTestParse13, 1); UtRegisterTest("PortTestParse14", PortTestParse14, 1); UtRegisterTest("PortTestParse15", PortTestParse15, 1); UtRegisterTest("PortTestParse16", PortTestParse16, 1); UtRegisterTest("PortTestFunctions01", PortTestFunctions01, 1); UtRegisterTest("PortTestFunctions02", PortTestFunctions02, 1); UtRegisterTest("PortTestFunctions03", PortTestFunctions03, 1); UtRegisterTest("PortTestFunctions04", PortTestFunctions04, 1); UtRegisterTest("PortTestFunctions05", PortTestFunctions05, 1); UtRegisterTest("PortTestFunctions06", PortTestFunctions06, 1); UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01, 1); UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02, 1); UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03, 1); UtRegisterTest("PortTestMatchReal04", PortTestMatchReal04, 1); UtRegisterTest("PortTestMatchReal05", PortTestMatchReal05, 1); UtRegisterTest("PortTestMatchReal06", PortTestMatchReal06, 1); UtRegisterTest("PortTestMatchReal07", PortTestMatchReal07, 1); UtRegisterTest("PortTestMatchReal08", PortTestMatchReal08, 1); UtRegisterTest("PortTestMatchReal09", PortTestMatchReal09, 1); UtRegisterTest("PortTestMatchReal10", PortTestMatchReal10, 1); UtRegisterTest("PortTestMatchReal11", PortTestMatchReal11, 1); UtRegisterTest("PortTestMatchReal12", PortTestMatchReal12, 1); UtRegisterTest("PortTestMatchReal13", PortTestMatchReal13, 1); UtRegisterTest("PortTestMatchReal14", PortTestMatchReal14, 1); UtRegisterTest("PortTestMatchReal15", PortTestMatchReal15, 1); UtRegisterTest("PortTestMatchReal16", PortTestMatchReal16, 1); UtRegisterTest("PortTestMatchReal17", PortTestMatchReal17, 1); UtRegisterTest("PortTestMatchReal18", PortTestMatchReal18, 1); UtRegisterTest("PortTestMatchReal19", PortTestMatchReal19, 1); UtRegisterTest("PortTestMatchDoubleNegation", PortTestMatchDoubleNegation, 1); #endif /* UNITTESTS */ } suricata-1.4.7/src/util-file.c0000644000000000000000000004733712253546156013101 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * \author Pablo Rincon * */ #include "suricata-common.h" #include "suricata.h" #include "debug.h" #include "flow.h" #include "stream.h" #include "util-hash.h" #include "util-debug.h" #include "util-memcmp.h" #include "util-print.h" #include "app-layer-parser.h" #include "util-validate.h" /** \brief switch to force magic checks on all files * regardless of the rules. */ static int g_file_force_magic = 0; /** \brief switch to force md5 calculation on all files * regardless of the rules. */ static int g_file_force_md5 = 0; /** \brief switch to force tracking off all files * regardless of the rules. */ static int g_file_force_tracking = 0; /* prototypes */ static void FileFree(File *); static void FileDataFree(FileData *); void FileForceMagicEnable(void) { g_file_force_magic = 1; } void FileForceMd5Enable(void) { g_file_force_md5 = 1; } int FileForceMagic(void) { return g_file_force_magic; } int FileForceMd5(void) { return g_file_force_md5; } void FileForceTrackingEnable(void) { g_file_force_tracking = 1; } int FileMagicSize(void) { /** \todo make this size configurable */ return 512; } static int FileAppendFileDataFilePtr(File *ff, FileData *ffd) { SCEnter(); if (ff == NULL) { SCReturnInt(-1); } if (ff->chunks_tail == NULL) { ff->chunks_head = ffd; ff->chunks_tail = ffd; } else { ff->chunks_tail->next = ffd; ff->chunks_tail = ffd; } #ifdef DEBUG ff->chunks_cnt++; if (ff->chunks_cnt > ff->chunks_cnt_max) ff->chunks_cnt_max = ff->chunks_cnt; #endif #ifdef HAVE_NSS if (ff->md5_ctx) HASH_Update(ff->md5_ctx, ffd->data, ffd->len); #endif SCReturnInt(0); } static int FileAppendFileData(FileContainer *ffc, FileData *ffd) { SCEnter(); if (ffc == NULL) { SCReturnInt(-1); } if (FileAppendFileDataFilePtr(ffc->tail, ffd) == -1) { SCReturnInt(-1); } SCReturnInt(0); } static void FilePruneFile(File *file) { SCEnter(); SCLogDebug("file %p, file->chunks_cnt %"PRIu64, file, file->chunks_cnt); if (!(file->flags & FILE_NOMAGIC)) { /* need magic but haven't set it yet, bail out */ if (file->magic == NULL) SCReturn; else SCLogDebug("file->magic %s", file->magic); } else { SCLogDebug("file->flags & FILE_NOMAGIC == true"); } /* okay, we now know we can prune */ FileData *fd = file->chunks_head; while (fd != NULL) { SCLogDebug("fd %p", fd); if (file->flags & FILE_NOSTORE || fd->stored == 1) { file->chunks_head = fd->next; if (file->chunks_tail == fd) file->chunks_tail = fd->next; FileDataFree(fd); fd = file->chunks_head; #ifdef DEBUG file->chunks_cnt--; SCLogDebug("file->chunks_cnt %"PRIu64, file->chunks_cnt); #endif } else if (fd->stored == 0) { fd = NULL; break; } } SCReturn; } void FilePrune(FileContainer *ffc) { File *file; for (file = ffc->head; file != NULL; file = file->next) { FilePruneFile(file); } } /** * \brief allocate a FileContainer * * \retval new newly allocated FileContainer * \retval NULL error */ FileContainer *FileContainerAlloc(void) { FileContainer *new = SCMalloc(sizeof(FileContainer)); if (unlikely(new == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating mem"); return NULL; } memset(new, 0, sizeof(FileContainer)); new->head = new->tail = NULL; return new; } /** * \brief Recycle a FileContainer * * \param ffc FileContainer */ void FileContainerRecycle(FileContainer *ffc) { if (ffc == NULL) return; File *cur = ffc->head; File *next = NULL; for (;cur != NULL; cur = next) { next = cur->next; FileFree(cur); } ffc->head = ffc->tail = NULL; } /** * \brief Free a FileContainer * * \param ffc FileContainer */ void FileContainerFree(FileContainer *ffc) { if (ffc == NULL) return; File *ptr = ffc->head; File *next = NULL; for (;ptr != NULL; ptr = next) { next = ptr->next; FileFree(ptr); } ffc->head = ffc->tail = NULL; SCFree(ffc); } /** * \internal * * \brief allocate a FileData chunk and set it up * * \param data data chunk to store in the FileData * \param data_len lenght of the data * * \retval new FileData object */ static FileData *FileDataAlloc(uint8_t *data, uint32_t data_len) { FileData *new = SCMalloc(sizeof(FileData)); if (unlikely(new == NULL)) { return NULL; } memset(new, 0, sizeof(FileData)); new->data = SCMalloc(data_len); if (new->data == NULL) { SCFree(new); return NULL; } new->len = data_len; memcpy(new->data, data, data_len); new->next = NULL; return new; } /** * \internal * * \brief free a FileData object * * \param ffd the flow file data object to free */ static void FileDataFree(FileData *ffd) { if (ffd == NULL) return; if (ffd->data != NULL) { SCFree(ffd->data); } SCFree(ffd); } /** * \brief Alloc a new File * * \param name character array containing the name (not a string) * \param name_len length in bytes of the name * * \retval new File object or NULL on error */ static File *FileAlloc(uint8_t *name, uint16_t name_len) { File *new = SCMalloc(sizeof(File)); if (unlikely(new == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating mem"); return NULL; } memset(new, 0, sizeof(File)); new->name = SCMalloc(name_len); if (new->name == NULL) { SCFree(new); return NULL; } new->name_len = name_len; memcpy(new->name, name, name_len); return new; } static void FileFree(File *ff) { if (ff == NULL) return; if (ff->name != NULL) SCFree(ff->name); /* magic returned by libmagic is strdup'd by MagicLookup. */ if (ff->magic != NULL) SCFree(ff->magic); if (ff->chunks_head != NULL) { FileData *ffd = ff->chunks_head; while (ffd != NULL) { FileData *next_ffd = ffd->next; FileDataFree(ffd); ffd = next_ffd; } } #ifdef HAVE_NSS if (ff->md5_ctx) HASH_Destroy(ff->md5_ctx); #endif SCLogDebug("ff chunks_cnt %"PRIu64", chunks_cnt_max %"PRIu64, ff->chunks_cnt, ff->chunks_cnt_max); SCFree(ff); } void FileContainerAdd(FileContainer *ffc, File *ff) { if (ffc->head == NULL || ffc->tail == NULL) { ffc->head = ffc->tail = ff; } else { ffc->tail->next = ff; ffc->tail = ff; } } /** * \brief Tag a file for storing * * \param ff The file to store */ int FileStore(File *ff) { ff->flags |= FILE_STORE; SCReturnInt(0); } /** * \brief Set the TX id for a file * * \param ff The file to store * \param txid the tx id */ int FileSetTx(File *ff, uint16_t txid) { SCLogDebug("ff %p txid %"PRIu16, ff, txid); if (ff != NULL) ff->txid = txid; SCReturnInt(0); } /** * \brief check if we have stored enough * * \param ff file * * \retval 0 limit not reached yet * \retval 1 limit reached */ static int FileStoreNoStoreCheck(File *ff) { SCEnter(); if (ff == NULL) { SCReturnInt(0); } if (ff->flags & FILE_NOSTORE) { if (ff->state == FILE_STATE_OPENED && ff->size >= (uint64_t)FileMagicSize()) { SCReturnInt(1); } } SCReturnInt(0); } /** * \brief Store a chunk of file data in the flow. The open "flowfile" * will be used. * * \param ffc the container * \param data data chunk * \param data_len data chunk len * * \retval 0 ok * \retval -1 error * \retval -2 no store for this file */ int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) { SCEnter(); if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) { SCReturnInt(-1); } if (ffc->tail->state != FILE_STATE_OPENED) { if (ffc->tail->flags & FILE_NOSTORE) { SCReturnInt(-2); } SCReturnInt(-1); } ffc->tail->size += data_len; SCLogDebug("file size is now %"PRIu64, ffc->tail->size); if (FileStoreNoStoreCheck(ffc->tail) == 1) { #ifdef HAVE_NSS /* no storage but forced md5 */ if (ffc->tail->md5_ctx) { if (ffc->tail->md5_ctx) HASH_Update(ffc->tail->md5_ctx, data, data_len); SCReturnInt(0); } #endif if (g_file_force_tracking || (!(ffc->tail->flags & FILE_NOTRACK))) SCReturnInt(0); ffc->tail->state = FILE_STATE_TRUNCATED; SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED"); SCReturnInt(-2); } SCLogDebug("appending %"PRIu32" bytes", data_len); FileData *ffd = FileDataAlloc(data, data_len); if (ffd == NULL) { ffc->tail->state = FILE_STATE_ERROR; SCReturnInt(-1); } /* append the data */ if (FileAppendFileData(ffc, ffd) < 0) { ffc->tail->state = FILE_STATE_ERROR; FileDataFree(ffd); SCReturnInt(-1); } SCReturnInt(0); } /** * \brief Open a new File * * \param ffc flow container * \param name filename character array * \param name_len filename len * \param data initial data * \param data_len initial data len * \param flags open flags * * \retval ff flowfile object * * \note filename is not a string, so it's not nul terminated. */ File *FileOpenFile(FileContainer *ffc, uint8_t *name, uint16_t name_len, uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); //PrintRawDataFp(stdout, name, name_len); File *ff = FileAlloc(name, name_len); if (ff == NULL) { SCReturnPtr(NULL, "File"); } if (flags & FILE_STORE) { ff->flags |= FILE_STORE; } else if (flags & FILE_NOSTORE) { SCLogDebug("not storing this file"); ff->flags |= FILE_NOSTORE; } if (flags & FILE_NOMAGIC) { SCLogDebug("not doing magic for this file"); ff->flags |= FILE_NOMAGIC; } if (flags & FILE_NOMD5) { SCLogDebug("not doing md5 for this file"); ff->flags |= FILE_NOMD5; } #ifdef HAVE_NSS if (!(ff->flags & FILE_NOMD5) || g_file_force_md5) { ff->md5_ctx = HASH_Create(HASH_AlgMD5); if (ff->md5_ctx != NULL) { HASH_Begin(ff->md5_ctx); } } #endif ff->state = FILE_STATE_OPENED; SCLogDebug("flowfile state transitioned to FILE_STATE_OPENED"); FileContainerAdd(ffc, ff); if (data != NULL) { //PrintRawDataFp(stdout, data, data_len); ff->size += data_len; SCLogDebug("file size is now %"PRIu64, ff->size); FileData *ffd = FileDataAlloc(data, data_len); if (ffd == NULL) { ff->state = FILE_STATE_ERROR; SCReturnPtr(NULL, "File"); } /* append the data */ if (FileAppendFileData(ffc, ffd) < 0) { ff->state = FILE_STATE_ERROR; FileDataFree(ffd); SCReturnPtr(NULL, "File"); } } SCReturnPtr(ff, "File"); } static int FileCloseFilePtr(File *ff, uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); if (ff == NULL) { SCReturnInt(-1); } if (ff->state != FILE_STATE_OPENED) { SCReturnInt(-1); } ff->size += data_len; SCLogDebug("file size is now %"PRIu64, ff->size); if (data != NULL) { //PrintRawDataFp(stdout, data, data_len); if (ff->flags & FILE_NOSTORE) { #ifdef HAVE_NSS /* no storage but md5 */ if (ff->md5_ctx) HASH_Update(ff->md5_ctx, data, data_len); #endif } else { FileData *ffd = FileDataAlloc(data, data_len); if (ffd == NULL) { ff->state = FILE_STATE_ERROR; SCReturnInt(-1); } /* append the data */ if (FileAppendFileDataFilePtr(ff, ffd) < 0) { ff->state = FILE_STATE_ERROR; FileDataFree(ffd); SCReturnInt(-1); } } } if (flags & FILE_TRUNCATED) { ff->state = FILE_STATE_TRUNCATED; SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED"); if (flags & FILE_NOSTORE) { SCLogDebug("not storing this file"); ff->flags |= FILE_NOSTORE; } } else { ff->state = FILE_STATE_CLOSED; SCLogDebug("flowfile state transitioned to FILE_STATE_CLOSED"); #ifdef HAVE_NSS if (ff->md5_ctx) { unsigned int len = 0; HASH_End(ff->md5_ctx, ff->md5, &len, sizeof(ff->md5)); ff->flags |= FILE_MD5; } #endif } SCReturnInt(0); } /** * \brief Close a File * * \param ffc the container * \param data final data if any * \param data_len data len if any * \param flags flags * * \retval 0 ok * \retval -1 error */ int FileCloseFile(FileContainer *ffc, uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); if (ffc == NULL || ffc->tail == NULL) { SCReturnInt(-1); } if (FileCloseFilePtr(ffc->tail, data, data_len, flags) == -1) { SCReturnInt(-1); } SCReturnInt(0); } /** * \brief disable file storage for a flow * * \param f *LOCKED* flow * \param direction flow direction */ void FileDisableStoring(Flow *f, uint8_t direction) { File *ptr = NULL; SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) f->flags |= FLOW_FILE_NO_STORE_TS; else f->flags |= FLOW_FILE_NO_STORE_TC; FileContainer *ffc = AppLayerGetFilesFromFlow(f, direction); if (ffc != NULL) { for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { /* if we're already storing, we'll continue */ if (!(ptr->flags & FILE_STORE)) { SCLogDebug("not storing this file"); ptr->flags |= FILE_NOSTORE; } } } SCReturn; } /** * \brief disable file magic lookups for this flow * * \param f *LOCKED* flow * \param direction flow direction */ void FileDisableMagic(Flow *f, uint8_t direction) { File *ptr = NULL; SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) f->flags |= FLOW_FILE_NO_MAGIC_TS; else f->flags |= FLOW_FILE_NO_MAGIC_TC; FileContainer *ffc = AppLayerGetFilesFromFlow(f, direction); if (ffc != NULL) { for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { SCLogDebug("disabling magic for file %p from direction %s", ptr, direction == STREAM_TOSERVER ? "toserver":"toclient"); ptr->flags |= FILE_NOMAGIC; } } SCReturn; } /** * \brief disable file md5 calc for this flow * * \param f *LOCKED* flow * \param direction flow direction */ void FileDisableMd5(Flow *f, uint8_t direction) { File *ptr = NULL; SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) f->flags |= FLOW_FILE_NO_MD5_TS; else f->flags |= FLOW_FILE_NO_MD5_TC; FileContainer *ffc = AppLayerGetFilesFromFlow(f, direction); if (ffc != NULL) { for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { SCLogDebug("disabling md5 for file %p from direction %s", ptr, direction == STREAM_TOSERVER ? "toserver":"toclient"); ptr->flags |= FILE_NOMD5; #ifdef HAVE_NSS /* destroy any ctx we may have so far */ if (ptr->md5_ctx != NULL) { HASH_Destroy(ptr->md5_ctx); ptr->md5_ctx = NULL; } #endif } } SCReturn; } /** * \brief disable file size tracking for this flow * * \param f *LOCKED* flow * \param direction flow direction */ void FileDisableFilesize(Flow *f, uint8_t direction) { File *ptr = NULL; SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) f->flags |= FLOW_FILE_NO_SIZE_TS; else f->flags |= FLOW_FILE_NO_SIZE_TC; FileContainer *ffc = AppLayerGetFilesFromFlow(f, direction); if (ffc != NULL) { for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { SCLogDebug("disabling size tracking for file %p from direction %s", ptr, direction == STREAM_TOSERVER ? "toserver":"toclient"); ptr->flags |= FILE_NOTRACK; } } SCReturn; } /** * \brief set no store flag, close file if needed * * \param ff file */ void FileDisableStoringForFile(File *ff) { SCEnter(); if (ff == NULL) { SCReturn; } SCLogDebug("not storing this file"); ff->flags |= FILE_NOSTORE; if (ff->state == FILE_STATE_OPENED && ff->size >= (uint64_t)FileMagicSize()) { (void)FileCloseFilePtr(ff, NULL, 0, (FILE_TRUNCATED|FILE_NOSTORE)); } } /** * \brief disable file storing for files in a transaction * * \param f *LOCKED* flow * \param direction flow direction * \param tx_id transaction id */ void FileDisableStoringForTransaction(Flow *f, uint8_t direction, uint16_t tx_id) { File *ptr = NULL; DEBUG_ASSERT_FLOW_LOCKED(f); SCEnter(); FileContainer *ffc = AppLayerGetFilesFromFlow(f, direction); if (ffc != NULL) { for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { if (ptr->txid == tx_id) { if (ptr->flags & FILE_STORE) { /* weird, already storing -- let it continue*/ SCLogDebug("file is already being stored"); } else { FileDisableStoringForFile(ptr); } } } } SCReturn; } /** * \brief flag a file with id "file_id" to be stored. * * \param fc file store * \param file_id the file's id */ void FileStoreFileById(FileContainer *fc, uint16_t file_id) { File *ptr = NULL; SCEnter(); if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { if (ptr->file_id == file_id) { ptr->flags |= FILE_STORE; } } } } void FileStoreAllFilesForTx(FileContainer *fc, uint16_t tx_id) { File *ptr = NULL; SCEnter(); if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { if (ptr->txid == tx_id) { ptr->flags |= FILE_STORE; } } } } void FileStoreAllFiles(FileContainer *fc) { File *ptr = NULL; SCEnter(); if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { ptr->flags |= FILE_STORE; } } } void FileTruncateAllOpenFiles(FileContainer *fc) { File *ptr = NULL; SCEnter(); if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { if (ptr->state == FILE_STATE_OPENED) { FileCloseFilePtr(ptr, NULL, 0, FILE_TRUNCATED); } } } } suricata-1.4.7/src/decode-sctp.h0000644000000000000000000000324012253546156013367 00000000000000/* Copyright (C) 2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Eric Leblond */ #ifndef __DECODE_SCTP_H__ #define __DECODE_SCTP_H__ /** size of the packet header without any chunk headers */ #define SCTP_HEADER_LEN 12 /* XXX RAW* needs to be really 'raw', so no ntohs there */ #define SCTP_GET_RAW_SRC_PORT(sctph) ntohs((sctph)->sh_sport) #define SCTP_GET_RAW_DST_PORT(sctph) ntohs((sctph)->sh_dport) #define SCTP_GET_SRC_PORT(p) SCTP_GET_RAW_SRC_PORT(p->sctph) #define SCTP_GET_DST_PORT(p) SCTP_GET_RAW_DST_PORT(p->sctph) typedef struct SCTPHdr_ { uint16_t sh_sport; /* source port */ uint16_t sh_dport; /* destination port */ uint32_t sh_vtag; /* verification tag, defined per flow */ uint32_t sh_sum; /* checksum, computed via crc32 */ } SCTPHdr; #define CLEAR_SCTP_PACKET(p) { \ (p)->sctph = NULL; \ } while (0) void DecodeSCTPRegisterTests(void); #endif /* __DECODE_SCTP_H__ */ suricata-1.4.7/src/util-misc.c0000644000000000000000000005261112253546156013104 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "config.h" #include "suricata.h" #include "util-byte.h" #include "util-debug.h" #include "util-unittest.h" /* size string parsing API */ static int ParseSizeString(const char *size, double *res) { #define PARSE_REGEX "^\\s*(\\d+(?:.\\d+)?)\\s*([a-zA-Z]{2})?\\s*$" pcre *parse_regex; pcre_extra *parse_regex_study; const char *eb; int eo; int opts = 0; #define MAX_SUBSTRINGS 30 int pcre_exec_ret; int r; int ov[MAX_SUBSTRINGS]; int retval = 0; *res = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset " "%" PRId32 ": %s", PARSE_REGEX, eo, eb); retval = -2; goto end; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); retval = -2; goto end; } pcre_exec_ret = pcre_exec(parse_regex, parse_regex_study, size, strlen(size), 0, 0, ov, MAX_SUBSTRINGS); if (!(pcre_exec_ret == 2 || pcre_exec_ret == 3)) { SCLogError(SC_ERR_PCRE_MATCH, "invalid size argument - %s. Valid size " "argument should be in the format - \n" "xxx <- indicates it is just bytes\n" "xxxkb or xxxKb or xxxKB or xxxkB <- indicates kilobytes\n" "xxxmb or xxxMb or xxxMB or xxxmB <- indicates megabytes\n" "xxxgb or xxxGb or xxxGB or xxxgB <- indicates gigabytes.\n", size); retval = -2; goto end; } const char *str_ptr; r = pcre_get_substring((char *)size, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (r < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); retval = -2; goto end; } char *endptr; errno = 0; *res = strtod(str_ptr, &endptr); if (errno == ERANGE) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range"); retval = -1; goto end; } else if (endptr == str_ptr) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value"); retval = -1; goto end; } pcre_free_substring(str_ptr); if (pcre_exec_ret == 3) { r = pcre_get_substring((char *)size, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (r < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); retval = -2; goto end; } if (strcasecmp(str_ptr, "kb") == 0) { *res *= 1024; } else if (strcasecmp(str_ptr, "mb") == 0) { *res *= 1024 * 1024; } else if (strcasecmp(str_ptr, "gb") == 0) { *res *= 1024 * 1024 * 1024; } else { /* not possible */ BUG_ON(1); } } retval = 0; end: return retval; } int ParseSizeStringU8(const char *size, uint8_t *res) { double temp_res = 0; *res = 0; int r = ParseSizeString(size, &temp_res); if (r < 0) return r; if (temp_res > UINT8_MAX) return -1; *res = temp_res; return 0; } int ParseSizeStringU16(const char *size, uint16_t *res) { double temp_res = 0; *res = 0; int r = ParseSizeString(size, &temp_res); if (r < 0) return r; if (temp_res > UINT16_MAX) return -1; *res = temp_res; return 0; } int ParseSizeStringU32(const char *size, uint32_t *res) { double temp_res = 0; *res = 0; int r = ParseSizeString(size, &temp_res); if (r < 0) return r; if (temp_res > UINT32_MAX) return -1; *res = temp_res; return 0; } int ParseSizeStringU64(const char *size, uint64_t *res) { double temp_res = 0; *res = 0; int r = ParseSizeString(size, &temp_res); if (r < 0) return r; if (temp_res > UINT64_MAX) return -1; *res = temp_res; return 0; } /*********************************Unittests********************************/ #ifdef UNITTESTS int UtilMiscParseSizeStringTest01(void) { const char *str; double result; /* no space */ str = "10"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10) { goto error; } str = "10kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10Kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10KB"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10mb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024 * 1024) { goto error; } str = "10gb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10737418240UL) { goto error; } /* space start */ str = " 10"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10) { goto error; } str = " 10kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10Kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10KB"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10mb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024 * 1024) { goto error; } str = " 10gb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10737418240) { goto error; } /* space end */ str = "10 "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10) { goto error; } str = "10kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10Kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10KB "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10mb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024 * 1024) { goto error; } str = "10gb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10737418240) { goto error; } /* space start - space end */ str = " 10 "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10) { goto error; } str = " 10kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10Kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10KB "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10mb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024 * 1024) { goto error; } str = " 10gb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10737418240) { goto error; } /* space between number and scale */ /* no space */ str = "10"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10) { goto error; } str = "10 kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10 Kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10 KB"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10 mb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024 * 1024) { goto error; } str = "10 gb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10737418240) { goto error; } /* space start */ str = " 10"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10) { goto error; } str = " 10 kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10 Kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10 KB"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10 mb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024 * 1024) { goto error; } str = " 10 gb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10737418240) { goto error; } /* space end */ str = "10 "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10) { goto error; } str = "10 kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10 Kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10 KB "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = "10 mb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024 * 1024) { goto error; } str = "10 gb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10737418240) { goto error; } /* space start - space end */ str = " 10 "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10) { goto error; } str = " 10 kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10 Kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10 KB "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024) { goto error; } str = " 10 mb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10 * 1024 * 1024) { goto error; } str = " 10 gb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10737418240) { goto error; } /* no space */ str = "10.5"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5) { goto error; } str = "10.5kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5Kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5KB"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5mb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024) { goto error; } str = "10.5gb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024 * 1024) { goto error; } /* space start */ str = " 10.5"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5) { goto error; } str = " 10.5kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5Kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5KB"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5mb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024) { goto error; } str = " 10.5gb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024 * 1024) { goto error; } /* space end */ str = "10.5 "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5) { goto error; } str = "10.5kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5Kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5KB "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5mb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024) { goto error; } str = "10.5gb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024 * 1024) { goto error; } /* space start - space end */ str = " 10.5 "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5) { goto error; } str = " 10.5kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5Kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5KB "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5mb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024) { goto error; } str = " 10.5gb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024 * 1024) { goto error; } /* space between number and scale */ /* no space */ str = "10.5"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5) { goto error; } str = "10.5 kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5 Kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5 KB"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5 mb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024) { goto error; } str = "10.5 gb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024 * 1024) { goto error; } /* space start */ str = " 10.5"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5) { goto error; } str = " 10.5 kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5 Kb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5 KB"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5 mb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024) { goto error; } str = " 10.5 gb"; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024 * 1024) { goto error; } /* space end */ str = "10.5 "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5) { goto error; } str = "10.5 kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5 Kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5 KB "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = "10.5 mb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024) { goto error; } str = "10.5 gb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024 * 1024) { goto error; } /* space start - space end */ str = " 10.5 "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5) { goto error; } str = " 10.5 kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5 Kb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5 KB "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024) { goto error; } str = " 10.5 mb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024) { goto error; } str = " 10.5 gb "; result = 0; if (ParseSizeString(str, &result) > 0) { goto error; } if (result != 10.5 * 1024 * 1024 * 1024) { goto error; } return 1; error: return 0; } #endif /* UNITTESTS */ void UtilMiscRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("UtilMiscParseSizeStringTest01", UtilMiscParseSizeStringTest01, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/runmode-ipfw.h0000644000000000000000000000207612253546156013617 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien */ #ifndef __RUNMODE_IPFW_H__ #define __RUNMODE_IPFW_H__ int RunModeIpsIPFWAuto(DetectEngineCtx *); int RunModeIpsIPFWAutoFp(DetectEngineCtx *); int RunModeIpsIPFWWorker(DetectEngineCtx *); void RunModeIpsIPFWRegister(void); const char *RunModeIpsIPFWGetDefaultMode(void); #endif /* __RUNMODE_IPFW_H__ */ suricata-1.4.7/src/app-layer-smb2.h0000644000000000000000000000462012253546156013733 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Kirby Kuehl */ #ifndef __APP_LAYER_SMB2_H__ #define __APP_LAYER_SMB2_H__ #include "suricata-common.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-nbss.h" #include "flow.h" #include "stream.h" typedef struct SMB2Hdr { uint32_t Protocol; /**< Contains 0xFE,'SMB' */ uint16_t StructureSize; uint16_t CreditCharge; uint32_t Status; uint16_t Command; uint16_t CreditRequestResponse; uint32_t Flags; uint32_t NextCommand; uint64_t MessageId; uint32_t ProcessId; uint32_t TreeId; uint64_t SessionId; uint8_t Signature[16]; } SMB2Hdr; #define SMB2_HDR_LEN 64 typedef struct SMB2State_ { NBSSHdr nbss; SMB2Hdr smb2; uint16_t bytesprocessed; } SMB2State; /** from http://msdn.microsoft.com/en-us/library/cc246528(PROT.13).aspx */ #define SMB2_NEGOTIATE 0x0000 #define SMB2_SESSION_SETUP 0x0001 #define SMB2_LOGOFF 0x0002 #define SMB2_TREE_CONNECT 0x0003 #define SMB2_TREE_DISCONNECT 0x0004 #define SMB2_CREATE 0x0005 #define SMB2_CLOSE 0x0006 #define SMB2_FLUSH 0x0007 #define SMB2_READ 0x0008 #define SMB2_WRITE 0x0009 #define SMB2_LOCK 0x000A #define SMB2_IOCTL 0x000B #define SMB2_CANCEL 0x000C #define SMB2_ECHO 0x000D #define SMB2_QUERY_DIRECTORY 0x000E #define SMB2_CHANGE_NOTIFY 0x000F #define SMB2_QUERY_INFO 0x0010 #define SMB2_SET_INFO 0x0011 #define SMB2_OPLOCK_BREAK 0x0012 void RegisterSMB2Parsers(void); void SMB2ParserRegisterTests(void); #endif /* __APP_LAYER_SMB2_H__ */ suricata-1.4.7/src/app-layer.c0000644000000000000000000002611612253546156013071 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Generic App-layer functions */ #include "suricata-common.h" #include "app-layer.h" #include "app-layer-detect-proto.h" #include "stream-tcp-reassemble.h" #include "stream-tcp-private.h" #include "flow.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "util-profiling.h" #include "util-validate.h" //#define PRINT extern uint8_t engine_mode; /** \brief Get the active app layer proto from the packet * \param p packet pointer with a LOCKED flow * \retval alstate void pointer to the state * \retval proto (ALPROTO_UNKNOWN if no proto yet) */ uint16_t AppLayerGetProtoFromPacket(Packet *p) { SCEnter(); if (p == NULL || p->flow == NULL) { SCReturnUInt(ALPROTO_UNKNOWN); } DEBUG_ASSERT_FLOW_LOCKED(p->flow); SCLogDebug("p->flow->alproto %"PRIu16"", p->flow->alproto); SCReturnUInt(p->flow->alproto); } /** \brief Get the active app layer state from the packet * \param p packet pointer with a LOCKED flow * \retval alstate void pointer to the state * \retval NULL in case we have no state */ void *AppLayerGetProtoStateFromPacket(Packet *p) { SCEnter(); if (p == NULL || p->flow == NULL) { SCReturnPtr(NULL, "void"); } DEBUG_ASSERT_FLOW_LOCKED(p->flow); SCLogDebug("p->flow->alproto %"PRIu16"", p->flow->alproto); SCLogDebug("p->flow %p", p->flow); SCReturnPtr(p->flow->alstate, "void"); } /** \brief Get the active app layer state from the flow * \param f flow pointer to a LOCKED flow * \retval alstate void pointer to the state * \retval NULL in case we have no state */ void *AppLayerGetProtoStateFromFlow(Flow *f) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); if (f == NULL) { SCReturnPtr(NULL, "void"); } SCLogDebug("f->alproto %"PRIu16"", f->alproto); SCReturnPtr(f->alstate, "void"); } /** global app layer detection context */ extern AlpProtoDetectCtx alp_proto_ctx; /** * \brief Handle a chunk of TCP data * * If the protocol is yet unknown, the proto detection code is run first. * * \param dp_ctx Thread app layer detect context * \param f Flow * \param ssn TCP Session * \param data ptr to reassembled data * \param data_len length of the data chunk * \param flags control flags * * \retval 0 ok * \retval -1 error */ int AppLayerHandleTCPData(AlpProtoDetectThreadCtx *dp_ctx, Flow *f, TcpSession *ssn, uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); int r = 0; #if DEBUG BUG_ON(f == NULL); BUG_ON(ssn == NULL); #endif SCLogDebug("data_len %u flags %02X", data_len, flags); if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { /* if we don't know the proto yet and we have received a stream * initializer message, we run proto detection. * We receive 2 stream init msgs (one for each direction) but we * only run the proto detection once. */ if (f->alproto == ALPROTO_UNKNOWN && (flags & STREAM_GAP)) { ssn->flags |= STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED; SCLogDebug("ALPROTO_UNKNOWN flow %p, due to GAP in stream start", f); StreamTcpSetSessionNoReassemblyFlag(ssn, 0); } else if (f->alproto == ALPROTO_UNKNOWN && (flags & STREAM_START)) { SCLogDebug("Stream initializer (len %" PRIu32 ")", data_len); #ifdef PRINT if (data_len > 0) { printf("=> Init Stream Data (app layer) -- start %s%s\n", flags & STREAM_TOCLIENT ? "toclient" : "", flags & STREAM_TOSERVER ? "toserver" : ""); PrintRawDataFp(stdout, data, data_len); printf("=> Init Stream Data -- end\n"); } #endif PACKET_PROFILING_APP_PD_START(dp_ctx); f->alproto = AppLayerDetectGetProto(&alp_proto_ctx, dp_ctx, f, data, data_len, flags, IPPROTO_TCP); PACKET_PROFILING_APP_PD_END(dp_ctx); if (f->alproto != ALPROTO_UNKNOWN) { ssn->flags |= STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED; PACKET_PROFILING_APP_START(dp_ctx, f->alproto); r = AppLayerParse(dp_ctx->alproto_local_storage[f->alproto], f, f->alproto, flags, data, data_len); PACKET_PROFILING_APP_END(dp_ctx, f->alproto); } else { if ((f->flags & FLOW_TS_PM_PP_ALPROTO_DETECT_DONE) && (f->flags & FLOW_TC_PM_PP_ALPROTO_DETECT_DONE)) { FlowSetSessionNoApplayerInspectionFlag(f); ssn->flags |= STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED; } } } else { SCLogDebug("stream data (len %" PRIu32 " alproto " "%"PRIu16" (flow %p)", data_len, f->alproto, f); #ifdef PRINT if (data_len > 0) { printf("=> Stream Data (app layer) -- start %s%s\n", flags & STREAM_TOCLIENT ? "toclient" : "", flags & STREAM_TOSERVER ? "toserver" : ""); PrintRawDataFp(stdout, data, data_len); printf("=> Stream Data -- end\n"); } #endif /* if we don't have a data object here we are not getting it * a start msg should have gotten us one */ if (f->alproto != ALPROTO_UNKNOWN) { PACKET_PROFILING_APP_START(dp_ctx, f->alproto); r = AppLayerParse(dp_ctx->alproto_local_storage[f->alproto], f, f->alproto, flags, data, data_len); PACKET_PROFILING_APP_END(dp_ctx, f->alproto); } else { SCLogDebug(" smsg not start, but no l7 data? Weird"); } } } else { SCLogDebug("FLOW_AL_NO_APPLAYER_INSPECTION is set"); } SCReturnInt(r); } /** * \brief Attach a stream message to the TCP session for inspection * in the detection engine. * * \param dp_ctx Thread app layer detect context * \param smsg Stream message * * \retval 0 ok * \retval -1 error */ int AppLayerHandleTCPMsg(AlpProtoDetectThreadCtx *dp_ctx, StreamMsg *smsg) { SCEnter(); #ifdef PRINT printf("=> Stream Data (raw reassembly) -- start %s%s\n", smsg->flags & STREAM_TOCLIENT ? "toclient" : "", smsg->flags & STREAM_TOSERVER ? "toserver" : ""); PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); printf("=> Stream Data -- end\n"); #endif SCLogDebug("smsg %p", smsg); BUG_ON(smsg->flow == NULL); TcpSession *ssn = smsg->flow->protoctx; if (ssn != NULL) { SCLogDebug("storing smsg %p in the tcp session", smsg); /* store the smsg in the tcp stream */ if (smsg->flags & STREAM_TOSERVER) { SCLogDebug("storing smsg in the to_server"); /* put the smsg in the stream list */ if (ssn->toserver_smsg_head == NULL) { ssn->toserver_smsg_head = smsg; ssn->toserver_smsg_tail = smsg; smsg->next = NULL; smsg->prev = NULL; } else { StreamMsg *cur = ssn->toserver_smsg_tail; cur->next = smsg; smsg->prev = cur; smsg->next = NULL; ssn->toserver_smsg_tail = smsg; } } else { SCLogDebug("storing smsg in the to_client"); /* put the smsg in the stream list */ if (ssn->toclient_smsg_head == NULL) { ssn->toclient_smsg_head = smsg; ssn->toclient_smsg_tail = smsg; smsg->next = NULL; smsg->prev = NULL; } else { StreamMsg *cur = ssn->toclient_smsg_tail; cur->next = smsg; smsg->prev = cur; smsg->next = NULL; ssn->toclient_smsg_tail = smsg; } } FlowDeReference(&smsg->flow); } else { /* no ssn ptr */ /* if there is no ssn ptr we won't * be inspecting this msg in detect * so return it to the pool. */ FlowDeReference(&smsg->flow); /* return the used message to the queue */ StreamMsgReturnToPool(smsg); } SCReturnInt(0); } /** * \brief Handle a app layer UDP message * * If the protocol is yet unknown, the proto detection code is run first. * * \param dp_ctx Thread app layer detect context * \param f unlocked flow * \param p UDP packet * * \retval 0 ok * \retval -1 error */ int AppLayerHandleUdp(AlpProtoDetectThreadCtx *dp_ctx, Flow *f, Packet *p) { SCEnter(); int r = 0; if (f == NULL) { SCReturnInt(r); } FLOWLOCK_WRLOCK(f); uint8_t flags = 0; if (p->flowflags & FLOW_PKT_TOSERVER) { flags |= STREAM_TOSERVER; } else { flags |= STREAM_TOCLIENT; } /* if we don't know the proto yet and we have received a stream * initializer message, we run proto detection. * We receive 2 stream init msgs (one for each direction) but we * only run the proto detection once. */ if (f->alproto == ALPROTO_UNKNOWN && !(f->flags & FLOW_ALPROTO_DETECT_DONE)) { SCLogDebug("Detecting AL proto on udp mesg (len %" PRIu32 ")", p->payload_len); f->alproto = AppLayerDetectGetProto(&alp_proto_ctx, dp_ctx, f, p->payload, p->payload_len, flags, IPPROTO_UDP); if (f->alproto != ALPROTO_UNKNOWN) { f->flags |= FLOW_ALPROTO_DETECT_DONE; r = AppLayerParse(dp_ctx->alproto_local_storage[f->alproto], f, f->alproto, flags, p->payload, p->payload_len); } else { f->flags |= FLOW_ALPROTO_DETECT_DONE; SCLogDebug("ALPROTO_UNKNOWN flow %p", f); } } else { SCLogDebug("stream data (len %" PRIu32 " ), alproto " "%"PRIu16" (flow %p)", p->payload_len, f->alproto, f); /* if we don't have a data object here we are not getting it * a start msg should have gotten us one */ if (f->alproto != ALPROTO_UNKNOWN) { r = AppLayerParse(dp_ctx->alproto_local_storage[f->alproto], f, f->alproto, flags, p->payload, p->payload_len); } else { SCLogDebug("udp session has started, but failed to detect alproto " "for l7"); } } FLOWLOCK_UNLOCK(f); SCReturnInt(r); } suricata-1.4.7/src/util-clock.h0000644000000000000000000000233212253546156013244 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __UTIL_CLOCK_H__ #define __UTIL_CLOCK_H__ #include /* Feel free to add more macros */ #define CLOCK_INIT clock_t clo1, clo2; clo1 = clo2 = 0; #define CLOCK_START clo1 = clock() #define CLOCK_END clo2 = clock() #define CLOCK_PRINT_SEC printf("Seconds spent: %.4fs\n", ((clo2 - clo1)/(double)CLOCKS_PER_SEC)) #define GET_CLOCK_END_SECS ((clo1 - clo2)/(double)CLOCKS_PER_SEC) #endif /*__UTIL_CLOCK_H__ */ suricata-1.4.7/src/detect-depth.h0000644000000000000000000000163312253546156013553 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_DEPTH_H__ #define __DETECT_DEPTH_H__ /* prototypes */ void DetectDepthRegister (void); #endif /* __DETECT_DEPTH_H__ */ suricata-1.4.7/src/detect-noalert.c0000644000000000000000000000307312253546156014106 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Implements the noalert keyword */ #include "suricata-common.h" #include "detect.h" #include "util-debug.h" static int DetectNoalertSetup (DetectEngineCtx *, Signature *, char *); void DetectNoalertRegister (void) { sigmatch_table[DETECT_NOALERT].name = "noalert"; sigmatch_table[DETECT_NOALERT].Match = NULL; sigmatch_table[DETECT_NOALERT].Setup = DetectNoalertSetup; sigmatch_table[DETECT_NOALERT].Free = NULL; sigmatch_table[DETECT_NOALERT].RegisterTests = NULL; sigmatch_table[DETECT_NOALERT].flags |= SIGMATCH_NOOPT; } static int DetectNoalertSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr) { if (nullstr != NULL) { SCLogError(SC_ERR_INVALID_VALUE, "nocase has no value"); return -1; } s->flags |= SIG_FLAG_NOALERT; return 0; } suricata-1.4.7/src/runmodes.c0000644000000000000000000003524312253546156013034 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** \file * * \author Victor Julien * * Pre-cooked threading runmodes. */ #include "suricata-common.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "tm-threads.h" #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" #include "util-byte.h" #include "util-affinity.h" #include "conf.h" #include "queue.h" #include "runmodes.h" #include "util-unittest.h" #include "alert-fastlog.h" #include "alert-prelude.h" #include "alert-unified2-alert.h" #include "alert-debuglog.h" #include "log-httplog.h" #include "output.h" #include "cuda-packet-batcher.h" #include "source-pfring.h" int debuglog_enabled = 0; /** * \brief Holds description for a runmode. */ typedef struct RunMode_ { /* the runmode type */ int runmode; const char *name; const char *description; /* runmode function */ int (*RunModeFunc)(DetectEngineCtx *); } RunMode; typedef struct RunModes_ { int no_of_runmodes; RunMode *runmodes; } RunModes; /** * A list of output modules that will be active for the run mode. */ typedef struct RunModeOutput_ { TmModule *tm_module; OutputCtx *output_ctx; TAILQ_ENTRY(RunModeOutput_) entries; } RunModeOutput; TAILQ_HEAD(, RunModeOutput_) RunModeOutputs = TAILQ_HEAD_INITIALIZER(RunModeOutputs); static RunModes runmodes[RUNMODE_MAX]; static char *active_runmode; /** * \internal * \brief Translate a runmode mode to a printale string. * * \param runmode Runmode to be converted into a printable string. * * \retval string Printable string. */ static const char *RunModeTranslateModeToName(int runmode) { switch (runmode) { case RUNMODE_PCAP_DEV: return "PCAP_DEV"; case RUNMODE_PCAP_FILE: return "PCAP_FILE"; case RUNMODE_PFRING: #ifdef HAVE_PFRING return "PFRING"; #else return "PFRING(DISABLED)"; #endif case RUNMODE_NFQ: return "NFQ"; case RUNMODE_IPFW: return "IPFW"; case RUNMODE_ERF_FILE: return "ERF_FILE"; case RUNMODE_DAG: return "ERF_DAG"; case RUNMODE_NAPATECH: return "NAPATECH"; case RUNMODE_UNITTEST: return "UNITTEST"; case RUNMODE_AFP_DEV: return "AF_PACKET_DEV"; case RUNMODE_UNIX_SOCKET: return "UNIX_SOCKET"; default: SCLogError(SC_ERR_UNKNOWN_RUN_MODE, "Unknown runtime mode. Aborting"); exit(EXIT_FAILURE); } } /** * \internal * \brief Dispatcher function for runmodes. Calls the required runmode function * based on runmode + runmode_custom_id. * * \param runmode The runmode type. * \param runmode_customd_id The runmode custom id. * \param de_ctx Detection Engine Context. */ static RunMode *RunModeGetCustomMode(int runmode, const char *custom_mode) { int i; for (i = 0; i < runmodes[runmode].no_of_runmodes; i++) { if (strcmp(runmodes[runmode].runmodes[i].name, custom_mode) == 0) return &runmodes[runmode].runmodes[i]; } return NULL; } /** * Return the running mode * * The returned string must not be freed. * * \return a string containing the current running mode */ char *RunmodeGetActive(void) { return active_runmode; } /** * Return the running mode * * The returned string must not be freed. * * \return a string containing the current running mode */ const char *RunModeGetMainMode(void) { int mainmode = RunmodeGetCurrent(); return RunModeTranslateModeToName(mainmode); } /** * \brief Register all runmodes in the engine. */ void RunModeRegisterRunModes(void) { memset(runmodes, 0, sizeof(runmodes)); RunModeIdsPcapRegister(); RunModeFilePcapRegister(); RunModeIdsPfringRegister(); RunModeIpsNFQRegister(); RunModeIpsIPFWRegister(); RunModeErfFileRegister(); RunModeErfDagRegister(); RunModeNapatechRegister(); RunModeIdsAFPRegister(); RunModeUnixSocketRegister(); #ifdef UNITTESTS UtRunModeRegister(); #endif return; } /** * \brief Lists all registered runmodes. */ void RunModeListRunmodes(void) { printf("------------------------------------- Runmodes -------------------" "-----------------------\n"); printf("| %-17s | %-17s | %-10s \n", "RunMode Type", "Custom Mode ", "Descripition"); printf("|-----------------------------------------------------------------" "-----------------------\n"); int i = RUNMODE_UNKNOWN + 1; int j = 0; for ( ; i < RUNMODE_MAX; i++) { int mode_displayed = 0; for (j = 0; j < runmodes[i].no_of_runmodes; j++) { if (mode_displayed == 1) { printf("| ----------------------------------------------" "-----------------------\n"); RunMode *runmode = &runmodes[i].runmodes[j]; printf("| %-17s | %-17s | %-27s \n", "", runmode->name, runmode->description); } else { RunMode *runmode = &runmodes[i].runmodes[j]; printf("| %-17s | %-17s | %-27s \n", RunModeTranslateModeToName(runmode->runmode), runmode->name, runmode->description); } if (mode_displayed == 0) mode_displayed = 1; } printf("|-----------------------------------------------------------------" "-----------------------\n"); } return; } void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_ctx) { if (custom_mode == NULL) { char *val = NULL; if (ConfGet("runmode", &val) != 1) { custom_mode = NULL; } else { custom_mode = val; } } if (custom_mode == NULL) { switch (runmode) { case RUNMODE_PCAP_DEV: custom_mode = RunModeIdsGetDefaultMode(); break; case RUNMODE_PCAP_FILE: custom_mode = RunModeFilePcapGetDefaultMode(); break; #ifdef HAVE_PFRING case RUNMODE_PFRING: custom_mode = RunModeIdsPfringGetDefaultMode(); break; #endif case RUNMODE_NFQ: custom_mode = RunModeIpsNFQGetDefaultMode(); break; case RUNMODE_IPFW: custom_mode = RunModeIpsIPFWGetDefaultMode(); break; case RUNMODE_ERF_FILE: custom_mode = RunModeErfFileGetDefaultMode(); break; case RUNMODE_DAG: custom_mode = RunModeErfDagGetDefaultMode(); break; case RUNMODE_NAPATECH: custom_mode = RunModeNapatechGetDefaultMode(); break; case RUNMODE_AFP_DEV: custom_mode = RunModeAFPGetDefaultMode(); break; case RUNMODE_UNIX_SOCKET: custom_mode = RunModeUnixSocketGetDefaultMode(); break; default: SCLogError(SC_ERR_UNKNOWN_RUN_MODE, "Unknown runtime mode. Aborting"); exit(EXIT_FAILURE); } } else { /* if (custom_mode == NULL) */ /* Add compability with old 'worker' name */ if (!strcmp("worker", custom_mode)) { SCLogWarning(SC_ERR_RUNMODE, "'worker' mode have been renamed " "to 'workers', please modify your setup."); custom_mode = SCStrdup("workers"); if (unlikely(custom_mode == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup custom mode"); exit(EXIT_FAILURE); } } } RunMode *mode = RunModeGetCustomMode(runmode, custom_mode); if (mode == NULL) { SCLogError(SC_ERR_RUNMODE, "The custom type \"%s\" doesn't exist " "for this runmode type \"%s\". Please use --list-runmodes to " "see available custom types for this runmode", custom_mode, RunModeTranslateModeToName(runmode)); exit(EXIT_FAILURE); } /* Export the custom mode */ active_runmode = SCStrdup(custom_mode); if (unlikely(active_runmode == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup active mode"); exit(EXIT_FAILURE); } mode->RunModeFunc(de_ctx); return; } /** * \brief Registers a new runmode. * * \param runmode Runmode type. * \param name Custom mode for this specific runmode type. Within each * runmode type, each custom name is a primary key. * \param description Description for this runmode. * \param RunModeFunc The function to be run for this runmode. */ void RunModeRegisterNewRunMode(int runmode, const char *name, const char *description, int (*RunModeFunc)(DetectEngineCtx *)) { if (RunModeGetCustomMode(runmode, name) != NULL) { SCLogError(SC_ERR_RUNMODE, "A runmode by this custom name has already " "been registered. Please use an unique name"); return; } runmodes[runmode].runmodes = SCRealloc(runmodes[runmode].runmodes, (runmodes[runmode].no_of_runmodes + 1) * sizeof(RunMode)); if (runmodes[runmode].runmodes == NULL) { exit(EXIT_FAILURE); } RunMode *mode = &runmodes[runmode].runmodes[runmodes[runmode].no_of_runmodes]; runmodes[runmode].no_of_runmodes++; mode->runmode = runmode; mode->name = SCStrdup(name); mode->description = SCStrdup(description); mode->RunModeFunc = RunModeFunc; return; } /** * Cleanup the run mode. */ void RunModeShutDown(void) { /* Close any log files. */ RunModeOutput *output; while ((output = TAILQ_FIRST(&RunModeOutputs))) { SCLogDebug("Shutting down output %s.", output->tm_module->name); TAILQ_REMOVE(&RunModeOutputs, output, entries); if (output->output_ctx != NULL && output->output_ctx->DeInit != NULL) output->output_ctx->DeInit(output->output_ctx); SCFree(output); } } /** * Initialize the output modules. */ void RunModeInitializeOutputs(void) { ConfNode *outputs = ConfGetNode("outputs"); if (outputs == NULL) { /* No "outputs" section in the configuration. */ return; } ConfNode *output, *output_config; TmModule *tm_module; const char *enabled; TAILQ_FOREACH(output, &outputs->head, next) { if (strcmp(output->val, "stats") == 0) continue; output_config = ConfNodeLookupChild(output, output->val); if (output_config == NULL) { /* Shouldn't happen. */ SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to lookup configuration child node: fast"); exit(1); } enabled = ConfNodeLookupChildValue(output_config, "enabled"); if (enabled == NULL || !ConfValIsTrue(enabled)) { continue; } if (strncmp(output->val, "unified-", sizeof("unified-") - 1) == 0) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Unified1 is no longer supported," " use Unified2 instead " "(see https://redmine.openinfosecfoundation.org/issues/353" " for an explanation)"); continue; } else if (strcmp(output->val, "alert-prelude") == 0) { #ifndef PRELUDE SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Prelude support not compiled in. Reconfigure/" "recompile with --enable-prelude to add Prelude " "support."); continue; #endif } OutputModule *module = OutputGetModuleByConfName(output->val); if (module == NULL) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "No output module named %s, ignoring", output->val); continue; } OutputCtx *output_ctx = NULL; if (module->InitFunc != NULL) { output_ctx = module->InitFunc(output_config); if (output_ctx == NULL) { /* In most cases the init function will have logged the * error. Maybe we should exit on init errors? */ continue; } } tm_module = TmModuleGetByName(module->name); if (tm_module == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "TmModuleGetByName for %s failed", module->name); exit(EXIT_FAILURE); } if (strcmp(tmm_modules[TMM_ALERTDEBUGLOG].name, tm_module->name) == 0) debuglog_enabled = 1; RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); if (unlikely(runmode_output == NULL)) return; runmode_output->tm_module = tm_module; runmode_output->output_ctx = output_ctx; TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); } } /** * Setup the outputs for this run mode. * * \param tv The ThreadVars for the thread the outputs will be * appended to. */ void SetupOutputs(ThreadVars *tv) { RunModeOutput *output; TAILQ_FOREACH(output, &RunModeOutputs, entries) { tv->cap_flags |= output->tm_module->cap_flags; TmSlotSetFuncAppend(tv, output->tm_module, output->output_ctx); } } float threading_detect_ratio = 1; /** * Initialize the output modules. */ void RunModeInitialize(void) { threading_set_cpu_affinity = FALSE; if ((ConfGetBool("threading.set-cpu-affinity", &threading_set_cpu_affinity)) == 0) { threading_set_cpu_affinity = FALSE; } /* try to get custom cpu mask value if needed */ if (threading_set_cpu_affinity == TRUE) { AffinitySetupLoadFromConfig(); } if ((ConfGetFloat("threading.detect-thread-ratio", &threading_detect_ratio)) != 1) { threading_detect_ratio = 1; } SCLogDebug("threading.detect-thread-ratio %f", threading_detect_ratio); } suricata-1.4.7/src/detect-tos.c0000644000000000000000000002403012253546156013243 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata-common.h" #include "threads.h" #include "decode.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-tos.h" #include "app-layer-protos.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" #include "util-byte.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #define PARSE_REGEX "^\\s*(!?\\s*[0-9]{1,3}|!?\\s*[xX][0-9a-fA-F]{1,2})\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectTosSetup(DetectEngineCtx *, Signature *, char *); static int DetectTosMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); static void DetectTosRegisterTests(void); static void DetectTosFree(void *); #define DETECT_IPTOS_MIN 0 #define DETECT_IPTOS_MAX 255 /** * \brief Register Tos keyword. */ void DetectTosRegister(void) { sigmatch_table[DETECT_TOS].name = "tos"; sigmatch_table[DETECT_TOS].Match = DetectTosMatch; sigmatch_table[DETECT_TOS].Setup = DetectTosSetup; sigmatch_table[DETECT_TOS].Free = DetectTosFree; sigmatch_table[DETECT_TOS].RegisterTests = DetectTosRegisterTests; const char *eb; int eo; int opts = 0; parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); if (parse_regex == NULL) { SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at " "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); goto error; } parse_regex_study = pcre_study(parse_regex, 0, &eb); if (eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); goto error; } return; error: return; } /** * \brief Match function for tos keyword. * * \param tv ThreadVars instance. * \param det_ctx Pointer to the detection thread ctx. * \param p Pointer to the packet. * \param m Pointer to the SigMatch containing the tos data. * * \retval 0 no match * \retval 1 match */ int DetectTosMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) { DetectTosData *tosd = (DetectTosData *)sm->ctx; int result = 0; if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) { return 0; } if (tosd->tos == IPV4_GET_IPTOS(p)) { SCLogDebug("tos match found for %d\n", tosd->tos); result = 1; } return (tosd->negated ^ result); } DetectTosData *DetectTosParse(char *arg) { DetectTosData *tosd = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, arg, strlen(arg), 0, 0, ov, MAX_SUBSTRINGS); if (ret != 2) { SCLogError(SC_ERR_PCRE_MATCH, "invalid tos option - %s. " "The tos option value must be in the range " "%u - %u", arg, DETECT_IPTOS_MIN, DETECT_IPTOS_MAX); goto error; } const char *str_ptr; res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } int64_t tos = 0; int negated = 0; if (*str_ptr == '!') { str_ptr++; negated = 1; } while (isspace((unsigned char)*str_ptr)) str_ptr++; if (*str_ptr == 'x' || *str_ptr == 'X') { int r = ByteExtractStringSigned(&tos, 16, 0, str_ptr + 1); if (r < 0) { goto error; } } else { int r = ByteExtractStringSigned(&tos, 10, 0, str_ptr); if (r < 0) { goto error; } } if (!(tos >= DETECT_IPTOS_MIN && tos <= DETECT_IPTOS_MAX)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid tos argument - " "%s. The tos option value must be in the range " "%u - %u", str_ptr, DETECT_IPTOS_MIN, DETECT_IPTOS_MAX); goto error; } tosd = SCMalloc(sizeof(DetectTosData)); if (unlikely(tosd == NULL)) goto error; tosd->tos = (uint8_t)tos; tosd->negated = negated; return tosd; error: if (tosd != NULL) DetectTosFree(tosd); return NULL; } /** * \brief Setup function for tos argument. Parse the argument and * add it into the sig. * * \param de_ctx Detection Engine Context instance. * \param s Pointer to the signature. * \param arg Argument to be parsed. * * \retval 0 on Success. * \retval -1 on Failure. */ int DetectTosSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectTosData *tosd; SigMatch *sm; tosd = DetectTosParse(arg); if (tosd == 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_TOS; sm->ctx = (void *)tosd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; return 0; error: return -1; } /** * \brief Free data allocated by the tos keyword. * * \param tosd Data to be freed. */ void DetectTosFree(void *tosd) { SCFree(tosd); } /********************************Unittests***********************************/ #ifdef UNITTESTS int DetectTosTest01(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("12"); if (tosd != NULL && tosd->tos == 12 && !tosd->negated) { DetectTosFree(tosd); return 1; } return 0; } int DetectTosTest02(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("123"); if (tosd != NULL && tosd->tos == 123 && !tosd->negated) { DetectTosFree(tosd); return 1; } return 0; } int DetectTosTest03(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse(" 12 "); if (tosd != NULL && tosd->tos == 12 && !tosd->negated) { DetectTosFree(tosd); return 1; } return 0; } int DetectTosTest04(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("256"); if (tosd != NULL) { DetectTosFree(tosd); return 0; } return 1; } int DetectTosTest05(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("boom"); if (tosd != NULL) { DetectTosFree(tosd); return 0; } return 1; } int DetectTosTest06(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("x12"); if (tosd != NULL && tosd->tos == 0x12 && !tosd->negated) { DetectTosFree(tosd); return 1; } return 0; } int DetectTosTest07(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("X12"); if (tosd != NULL && tosd->tos == 0x12 && !tosd->negated) { DetectTosFree(tosd); return 1; } return 0; } int DetectTosTest08(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("x121"); if (tosd != NULL) { DetectTosFree(tosd); return 0; } return 1; } int DetectTosTest09(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("!12"); if (tosd != NULL && tosd->tos == 12 && tosd->negated) { DetectTosFree(tosd); return 1; } return 0; } int DetectTosTest10(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse("!x12"); if (tosd != NULL && tosd->tos == 0x12 && tosd->negated) { DetectTosFree(tosd); return 1; } return 0; } int DetectTosTest11(void) { DetectTosData *tosd = NULL; tosd = DetectTosParse(" ! 12"); if (tosd != NULL && tosd->tos == 12 && tosd->negated) { DetectTosFree(tosd); return 1; } return 0; } int DetectTosTest12(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) goto end; IPV4_SET_RAW_IPTOS(p->ip4h, 10); char *sigs[4]; sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; tos:10; sid:1;)"; sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; tos:!10; sid:2;)"; sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; tos:20; sid:3;)"; sigs[3]= "alert ip any any -> any any (msg:\"Testing id 3\"; tos:!20; sid:4;)"; uint32_t sid[4] = {1, 2, 3, 4}; uint32_t results[1][4] = { {1, 0, 0, 1}, }; result = UTHGenericTest(&p, 1, sigs, sid, (uint32_t *) results, 4); UTHFreePackets(&p, 1); end: return result; } #endif void DetectTosRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectTosTest01", DetectTosTest01, 1); UtRegisterTest("DetectTosTest02", DetectTosTest02, 1); UtRegisterTest("DetectTosTest03", DetectTosTest03, 1); UtRegisterTest("DetectTosTest04", DetectTosTest04, 1); UtRegisterTest("DetectTosTest05", DetectTosTest05, 1); UtRegisterTest("DetectTosTest06", DetectTosTest06, 1); UtRegisterTest("DetectTosTest07", DetectTosTest07, 1); UtRegisterTest("DetectTosTest08", DetectTosTest08, 1); UtRegisterTest("DetectTosTest09", DetectTosTest09, 1); UtRegisterTest("DetectTosTest10", DetectTosTest10, 1); UtRegisterTest("DetectTosTest11", DetectTosTest11, 1); UtRegisterTest("DetectTosTest12", DetectTosTest12, 1); #endif return; } suricata-1.4.7/src/app-layer-smtp.c0000644000000000000000000033245612253546156014061 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include "suricata.h" #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-smtp.h" #include "util-debug.h" #include "util-byte.h" #include "util-unittest.h" #include "util-byte.h" #include "util-unittest-helper.h" #include "util-memcmp.h" #include "flow-util.h" #include "detect-engine.h" #include "detect-engine-state.h" #include "detect-parse.h" #include "conf.h" #include "decode-events.h" #define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510 #define SMTP_COMMAND_BUFFER_STEPS 5 /* we are in process of parsing a fresh command. Just a placeholder. If we * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */ #define SMTP_PARSER_STATE_COMMAND_MODE 0x00 /* we are in mode of parsing a command's data. Used when we are parsing tls * or accepting the rfc 2822 mail after DATA command */ #define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01 /* Used when we are still in the process of parsing a server command. Used * with multi-line replies and the stream is fragmented before all the lines * for a response is seen */ #define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02 /* Used to indicate that the parser has seen the first reply */ #define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04 /* Used to indicate that the parser is parsing a multiline reply */ #define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08 /* Various SMTP commands * We currently have var-ified just STARTTLS and DATA, since we need to them * for state transitions. The rest are just indicate as OTHER_CMD. Other * commands would be introduced as and when needed */ #define SMTP_COMMAND_STARTTLS 1 #define SMTP_COMMAND_DATA 2 #define SMTP_COMMAND_BDAT 3 /* not an actual command per se, but the mode where we accept the mail after * DATA has it's own reply code for completion, from the server. We give this * stage a pseudo command of it's own, so that we can add this to the command * buffer to match with the reply */ #define SMTP_COMMAND_DATA_MODE 4 /* All other commands are represented by this var */ #define SMTP_COMMAND_OTHER_CMD 5 /* Different EHLO extensions. Not used now. */ #define SMTP_EHLO_EXTENSION_PIPELINING #define SMTP_EHLO_EXTENSION_SIZE #define SMTP_EHLO_EXTENSION_DSN #define SMTP_EHLO_EXTENSION_STARTTLS #define SMTP_EHLO_EXTENSION_8BITMIME SCEnumCharMap smtp_decoder_event_table[ ] = { { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY }, { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST", SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST }, { "MAX_COMMAND_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED }, { "MAX_REPLY_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED }, { "INVALID_PIPELINED_SEQUENCE", SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE }, { "BDAT_CHUNK_LEN_EXCEEDED", SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED }, { "NO_SERVER_WELCOME_MESSAGE", SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE }, { "TLS_REJECTED", SMTP_DECODER_EVENT_TLS_REJECTED }, { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED }, { NULL, -1 }, }; #define SMTP_MPM MPM_AC static MpmCtx *smtp_mpm_ctx = NULL; MpmThreadCtx *smtp_mpm_thread_ctx; /* smtp reply codes. If an entry is made here, please make a simultaneous * entry in smtp_reply_map */ enum { SMTP_REPLY_211, SMTP_REPLY_214, SMTP_REPLY_220, SMTP_REPLY_221, SMTP_REPLY_250, SMTP_REPLY_251, SMTP_REPLY_252, SMTP_REPLY_354, SMTP_REPLY_421, SMTP_REPLY_450, SMTP_REPLY_451, SMTP_REPLY_452, SMTP_REPLY_455, SMTP_REPLY_500, SMTP_REPLY_501, SMTP_REPLY_502, SMTP_REPLY_503, SMTP_REPLY_504, SMTP_REPLY_550, SMTP_REPLY_551, SMTP_REPLY_552, SMTP_REPLY_553, SMTP_REPLY_554, SMTP_REPLY_555, }; SCEnumCharMap smtp_reply_map[ ] = { { "211", SMTP_REPLY_211 }, { "214", SMTP_REPLY_214 }, { "220", SMTP_REPLY_220 }, { "221", SMTP_REPLY_221 }, { "250", SMTP_REPLY_250 }, { "251", SMTP_REPLY_251 }, { "252", SMTP_REPLY_252 }, { "354", SMTP_REPLY_354 }, { "421", SMTP_REPLY_421 }, { "450", SMTP_REPLY_450 }, { "451", SMTP_REPLY_451 }, { "452", SMTP_REPLY_452 }, { "455", SMTP_REPLY_455 }, { "500", SMTP_REPLY_500 }, { "501", SMTP_REPLY_501 }, { "502", SMTP_REPLY_502 }, { "503", SMTP_REPLY_503 }, { "504", SMTP_REPLY_504 }, { "550", SMTP_REPLY_550 }, { "551", SMTP_REPLY_551 }, { "552", SMTP_REPLY_552 }, { "553", SMTP_REPLY_553 }, { "554", SMTP_REPLY_554 }, { "555", SMTP_REPLY_555 }, { NULL, -1 }, }; //static void SMTPParserReset(void) //{ // return; //} /** * \internal * \brief Get the next line from input. It doesn't do any length validation. * * \param state The smtp state. * * \retval 0 On suceess. * \retval -1 Either when we don't have any new lines to supply anymore or * on failure. */ static int SMTPGetLine(SMTPState *state) { SCEnter(); /* we have run out of input */ if (state->input_len <= 0) return -1; /* toserver */ if (state->direction == 0) { if (state->ts_current_line_lf_seen == 1) { /* we have seen the lf for the previous line. Clear the parser * details to parse new line */ state->ts_current_line_lf_seen = 0; if (state->ts_current_line_db == 1) { state->ts_current_line_db = 0; SCFree(state->ts_db); state->ts_db = NULL; state->ts_db_len = 0; state->current_line = NULL; state->current_line_len = 0; } } uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len); if (lf_idx == NULL) { /* fragmented lines. Decoder event for special cases. Not all * fragmented lines should be treated as a possible evasion * attempt. With multi payload smtp chunks we can have valid * cases of fragmentation. But within the same segment chunk * if we see fragmentation then it's definitely something you * should alert about */ if (state->ts_current_line_db == 0) { state->ts_db = SCMalloc(state->input_len); if (state->ts_db == NULL) { return -1; } state->ts_current_line_db = 1; memcpy(state->ts_db, state->input, state->input_len); state->ts_db_len = state->input_len; } else { state->ts_db = SCRealloc(state->ts_db, (state->ts_db_len + state->input_len)); if (state->ts_db == NULL) { return -1; } memcpy(state->ts_db + state->ts_db_len, state->input, state->input_len); state->ts_db_len += state->input_len; } /* else */ state->input += state->input_len; state->input_len = 0; return -1; } else { state->ts_current_line_lf_seen = 1; if (state->ts_current_line_db == 1) { state->ts_db = SCRealloc(state->ts_db, (state->ts_db_len + (lf_idx + 1 - state->input))); if (state->ts_db == NULL) { return -1; } memcpy(state->ts_db + state->ts_db_len, state->input, (lf_idx + 1 - state->input)); state->ts_db_len += (lf_idx + 1 - state->input); if (state->ts_db_len > 1 && state->ts_db[state->ts_db_len - 2] == 0x0D) { state->ts_db_len -= 2; state->current_line_delimiter_len = 2; } else { state->ts_db_len -= 1; state->current_line_delimiter_len = 1; } state->current_line = state->ts_db; state->current_line_len = state->ts_db_len; } else { state->current_line = state->input; state->current_line_len = lf_idx - state->input; if (state->input != lf_idx && *(lf_idx - 1) == 0x0D) { state->current_line_len--; state->current_line_delimiter_len = 2; } else { state->current_line_delimiter_len = 1; } } state->input_len -= (lf_idx - state->input) + 1; state->input = (lf_idx + 1); return 0; } /* toclient */ } else { if (state->tc_current_line_lf_seen == 1) { /* we have seen the lf for the previous line. Clear the parser * details to parse new line */ state->tc_current_line_lf_seen = 0; if (state->tc_current_line_db == 1) { state->tc_current_line_db = 0; SCFree(state->tc_db); state->tc_db = NULL; state->tc_db_len = 0; state->current_line = NULL; state->current_line_len = 0; } } uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len); if (lf_idx == NULL) { /* fragmented lines. Decoder event for special cases. Not all * fragmented lines should be treated as a possible evasion * attempt. With multi payload smtp chunks we can have valid * cases of fragmentation. But within the same segment chunk * if we see fragmentation then it's definitely something you * should alert about */ if (state->tc_current_line_db == 0) { state->tc_db = SCMalloc(state->input_len); if (state->tc_db == NULL) { return -1; } state->tc_current_line_db = 1; memcpy(state->tc_db, state->input, state->input_len); state->tc_db_len = state->input_len; } else { state->tc_db = SCRealloc(state->tc_db, (state->tc_db_len + state->input_len)); if (state->tc_db == NULL) { return -1; } memcpy(state->tc_db + state->tc_db_len, state->input, state->input_len); state->tc_db_len += state->input_len; } /* else */ state->input += state->input_len; state->input_len = 0; return -1; } else { state->tc_current_line_lf_seen = 1; if (state->tc_current_line_db == 1) { state->tc_db = SCRealloc(state->tc_db, (state->tc_db_len + (lf_idx + 1 - state->input))); if (state->tc_db == NULL) { return -1; } memcpy(state->tc_db + state->tc_db_len, state->input, (lf_idx + 1 - state->input)); state->tc_db_len += (lf_idx + 1 - state->input); if (state->tc_db_len > 1 && state->tc_db[state->tc_db_len - 2] == 0x0D) { state->tc_db_len -= 2; state->current_line_delimiter_len = 2; } else { state->tc_db_len -= 1; state->current_line_delimiter_len = 1; } state->current_line = state->tc_db; state->current_line_len = state->tc_db_len; } else { state->current_line = state->input; state->current_line_len = lf_idx - state->input; if (state->input != lf_idx && *(lf_idx - 1) == 0x0D) { state->current_line_len--; state->current_line_delimiter_len = 2; } else { state->current_line_delimiter_len = 1; } } state->input_len -= (lf_idx - state->input) + 1; state->input = (lf_idx + 1); return 0; } /* else - if (lf_idx == NULL) */ } } static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f) { SCEnter(); if (state->cmds_cnt >= state->cmds_buffer_len) { int increment = SMTP_COMMAND_BUFFER_STEPS; if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) { increment = USHRT_MAX - state->cmds_buffer_len; } state->cmds = SCRealloc(state->cmds, sizeof(uint8_t) * (state->cmds_buffer_len + increment)); if (state->cmds == NULL) { SCLogDebug("SCRalloc failure"); return -1; } state->cmds_buffer_len += increment; } if (state->cmds_cnt >= 1 && ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) || (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) { /* decoder event */ AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE); /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP, * STARTTLS as the last command in pipelined mode */ } /** \todo decoder event */ if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) { SCLogDebug("command buffer overflow"); return -1; } state->cmds[state->cmds_cnt] = command; state->cmds_cnt++; return 0; } static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f, AppLayerParserState *pstate) { SCEnter(); state->bdat_chunk_idx += (state->current_line_len + state->current_line_delimiter_len); if (state->bdat_chunk_idx > state->bdat_chunk_len) { state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; /* decoder event */ AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED); SCReturnInt(-1); } else if (state->bdat_chunk_idx == state->bdat_chunk_len) { state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; } SCReturnInt(0); } static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, AppLayerParserState *pstate) { SCEnter(); if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { /* looks like are still waiting for a confirmination from the server */ return 0; } if (state->current_line_len == 1 && state->current_line[0] == '.') { state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; /* kinda like a hack. The mail sent in DATA mode, would be * acknowledged with a reply. We insert a dummy command to * the command buffer to be used by the reply handler to match * the reply received */ SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f); } return 0; } static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f, AppLayerParserState *pstate) { return 0; } static int SMTPProcessReply(SMTPState *state, Flow *f, AppLayerParserState *pstate) { SCEnter(); uint64_t reply_code = 0; PatternMatcherQueue *pmq = state->thread_local_data; /* the reply code has to contain at least 3 bytes, to hold the 3 digit * reply code */ if (state->current_line_len < 3) { /* decoder event */ AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_INVALID_REPLY); return -1; } if (state->current_line_len >= 4) { if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) { if (state->current_line[3] != '-') { state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; } } else { if (state->current_line[3] == '-') { state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; } } } else { if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) { state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; } } /* I don't like this pmq reset here. We'll devise a method later, that * should make the use of the mpm very efficient */ PmqReset(pmq); int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, smtp_mpm_thread_ctx, pmq, state->current_line, 3); if (mpm_cnt == 0) { /* set decoder event - reply code invalid */ AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_INVALID_REPLY); SCLogDebug("invalid reply code %02x %02x %02x", state->current_line[0], state->current_line[1], state->current_line[2]); SCReturnInt(-1); } reply_code = smtp_reply_map[pmq->pattern_id_array[0]].enum_value; if (state->cmds_idx == state->cmds_cnt) { /* decoder event - unable to match reply with request */ SCLogDebug("unable to match reply with request"); SCReturnInt(-1); } /* kinda hack needed for us. Our parser logs commands, to be * matched against server replies. SMTP is normally accompanied by a * toclient welcome message, which would have had no command to * accompany it with. And also alproto detection sees to it that the * toserver stream is the first one to be processed by the app layer. * Hence check the first reply and if it is a welcome message(220), * leave without matching it against any buffered command */ if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; if (reply_code == SMTP_REPLY_220) { return 0; } else { /* set decoder event - first reply from server not a welcome message */ AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE); } } if (state->cmds[state->cmds_idx] == SMTP_COMMAND_STARTTLS) { if (reply_code == SMTP_REPLY_220) { /* we are entering STARRTTLS data mode */ state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; pstate->flags |= APP_LAYER_PARSER_DONE; pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION; pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY; } else { /* decoder event */ AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_TLS_REJECTED); } } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) { if (reply_code == SMTP_REPLY_354) { /* Next comes the mail for the DATA command in toserver direction */ state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; } else { /* decoder event */ AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED); } } else { /* we don't care for any other command for now */ /* check if reply falls in the valid list of replies for SMTP. If not * decoder event */ } /* if it is a multi-line reply, we need to move the index only once for all * the line of the reply. We unset the multiline flag on the last * line of the multiline reply, following which we increment the index */ if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) { state->cmds_idx++; } /* if we have matched all the buffered commands, reset the cnt and index */ if (state->cmds_idx == state->cmds_cnt) { state->cmds_cnt = 0; state->cmds_idx = 0; } return 0; } static int SMTPParseCommandBDAT(SMTPState *state) { SCEnter(); int i = 4; while (i < state->current_line_len) { if (state->current_line[i] != ' ') { break; } i++; } if (i == 4) { /* decoder event */ return -1; } if (i == state->current_line_len) { /* decoder event */ return -1; } uint8_t *endptr = NULL; state->bdat_chunk_len = strtoul((const char *)state->current_line + i, (char **)&endptr, 10); if (endptr == state->current_line + i) { /* decoder event */ return -1; } return 0; } static int SMTPProcessRequest(SMTPState *state, Flow *f, AppLayerParserState *pstate) { SCEnter(); /* there are 2 commands that can push it into this COMMAND_DATA mode - * STARTTLS and DATA */ if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { int r = 0; if (state->current_line_len >= 8 && SCMemcmpLowercase("starttls", state->current_line, 8) == 0) { state->current_command = SMTP_COMMAND_STARTTLS; } else if (state->current_line_len >= 4 && SCMemcmpLowercase("data", state->current_line, 4) == 0) { state->current_command = SMTP_COMMAND_DATA; } else if (state->current_line_len >= 4 && SCMemcmpLowercase("bdat", state->current_line, 4) == 0) { r = SMTPParseCommandBDAT(state); if (r == -1) { SCReturnInt(-1); } state->current_command = SMTP_COMMAND_BDAT; state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; } else { state->current_command = SMTP_COMMAND_OTHER_CMD; } /* Every command is inserted into a command buffer, to be matched * against reply(ies) sent by the server */ if (SMTPInsertCommandIntoCommandBuffer(state->current_command, state, f) == -1) { SCReturnInt(-1); } SCReturnInt(r); } switch (state->current_command) { case SMTP_COMMAND_STARTTLS: return SMTPProcessCommandSTARTTLS(state, f, pstate); case SMTP_COMMAND_DATA: return SMTPProcessCommandDATA(state, f, pstate); case SMTP_COMMAND_BDAT: return SMTPProcessCommandBDAT(state, f, pstate); default: /* we have nothing to do with any other command at this instant. * Just let it go through */ SCReturnInt(0); } } static int SMTPParse(int direction, Flow *f, SMTPState *state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, PatternMatcherQueue *local_data, AppLayerParserResult *output) { SCEnter(); state->input = input; state->input_len = input_len; state->direction = direction; state->thread_local_data = local_data; /* toserver */ if (direction == 0) { while (SMTPGetLine(state) >= 0) { if (SMTPProcessRequest(state, f, pstate) == -1) SCReturnInt(-1); } /* toclient */ } else { while (SMTPGetLine(state) >= 0) { if (SMTPProcessReply(state, f, pstate) == -1) SCReturnInt(-1); } } SCReturnInt(0); } static int SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SCEnter(); /* first arg 0 is toserver */ return SMTPParse(0, f, alstate, pstate, input, input_len, local_data, output); } static int SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, void *local_data, AppLayerParserResult *output) { SCEnter(); /* first arg 1 is toclient */ return SMTPParse(1, f, alstate, pstate, input, input_len, local_data, output); return 0; } /** * \internal * \brief Function to allocate SMTP state memory. */ static void *SMTPStateAlloc(void) { SMTPState *smtp_state = SCMalloc(sizeof(SMTPState)); if (unlikely(smtp_state == NULL)) return NULL; memset(smtp_state, 0, sizeof(SMTPState)); smtp_state->cmds = SCMalloc(sizeof(uint8_t) * SMTP_COMMAND_BUFFER_STEPS); if (smtp_state->cmds == NULL) { SCFree(smtp_state); return NULL; } smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS; return smtp_state; } static void *SMTPLocalStorageAlloc(void) { /* needed by the mpm */ PatternMatcherQueue *pmq = SCMalloc(sizeof(PatternMatcherQueue)); if (unlikely(pmq == NULL)) { exit(EXIT_FAILURE); } PmqSetup(pmq, 0, sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 2); return pmq; } static void SMTPLocalStorageFree(void *pmq) { if (pmq != NULL) { PmqFree(pmq); SCFree(pmq); } return; } /** * \internal * \brief Function to free SMTP state memory. */ static void SMTPStateFree(void *p) { SMTPState *smtp_state = (SMTPState *)p; if (smtp_state->cmds != NULL) { SCFree(smtp_state->cmds); } if (smtp_state->ts_current_line_db) { SCFree(smtp_state->ts_db); } if (smtp_state->tc_current_line_db) { SCFree(smtp_state->tc_db); } SCFree(smtp_state); return; } static void SMTPSetMpmState(void) { smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx)); if (unlikely(smtp_mpm_ctx == NULL)) { exit(EXIT_FAILURE); } memset(smtp_mpm_ctx, 0, sizeof(MpmCtx)); smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx)); if (unlikely(smtp_mpm_thread_ctx == NULL)) { exit(EXIT_FAILURE); } memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); mpm_table[SMTP_MPM].InitCtx(smtp_mpm_ctx, -1); mpm_table[SMTP_MPM].InitThreadCtx(smtp_mpm_ctx, smtp_mpm_thread_ctx, 0); uint32_t i = 0; for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) { SCEnumCharMap *map = &smtp_reply_map[i]; mpm_table[SMTP_MPM].AddPatternNocase(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3 /* reply codes always 3 bytes */, 0 /* now defunct option */, 0 /* now defunct option */, i /* pattern id */, 0 /* no sid */, 0 /* no flags */); } mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx); } /** * \brief Register the SMPT Protocol parser. */ void RegisterSMTPParsers(void) { char *proto_name = "smtp"; AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0, STREAM_TOSERVER); AppLayerRegisterStateFuncs(ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree); AppLayerRegisterProto(proto_name, ALPROTO_SMTP, STREAM_TOSERVER, SMTPParseClientRecord); AppLayerRegisterProto(proto_name, ALPROTO_SMTP, STREAM_TOCLIENT, SMTPParseServerRecord); AppLayerDecoderEventsModuleRegister(ALPROTO_SMTP, smtp_decoder_event_table); AppLayerRegisterLocalStorageFunc(ALPROTO_SMTP, SMTPLocalStorageAlloc, SMTPLocalStorageFree); SMTPSetMpmState(); return; } /***************************************Unittests******************************/ #ifdef UNITTESTS /* * \test Test STARTTLS. */ int SMTPParserTest01(void) { int result = 0; Flow f; int r = 0; /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ uint8_t welcome_reply[] = { 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, 0x0d, 0x0a }; uint32_t welcome_reply_len = sizeof(welcome_reply); /* EHLO [192.168.0.158] */ uint8_t request1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a }; uint32_t request1_len = sizeof(request1); /* 250-mx.google.com at your service, [117.198.115.50] * 250-SIZE 35882577 * 250-8BITMIME * 250-STARTTLS * 250 ENHANCEDSTATUSCODES */ uint8_t reply1[] = { 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e, 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35, 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, 0x0a }; uint32_t reply1_len = sizeof(reply1); /* STARTTLS */ uint8_t request2[] = { 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, 0x0d, 0x0a }; uint32_t request2_len = sizeof(request2); /* 220 2.0.0 Ready to start TLS */ uint8_t reply2[] = { 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a }; uint32_t reply2_len = sizeof(reply2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) || !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /** * \test Test multiple DATA commands(full mail transactions). */ int SMTPParserTest02(void) { int result = 0; Flow f; int r = 0; /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ uint8_t welcome_reply[] = { 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, 0x0d, 0x0a }; uint32_t welcome_reply_len = sizeof(welcome_reply); /* EHLO boo.com */ uint8_t request1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request1_len = sizeof(request1); /* 250-mx.google.com at your service, [117.198.115.50] * 250-SIZE 35882577 * 250-8BITMIME * 250-STARTTLS * 250 ENHANCEDSTATUSCODES */ uint8_t reply1[] = { 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a }; uint32_t reply1_len = sizeof(reply1); /* MAIL FROM:asdff@asdf.com */ uint8_t request2[] = { 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request2_len = sizeof(request2); /* 250 2.1.0 Ok */ uint8_t reply2[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a }; uint32_t reply2_len = sizeof(reply2); /* RCPT TO:bimbs@gmail.com */ uint8_t request3[] = { 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request3_len = sizeof(request3); /* 250 2.1.5 Ok */ uint8_t reply3[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a }; uint32_t reply3_len = sizeof(reply3); /* DATA */ uint8_t request4[] = { 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a }; uint32_t request4_len = sizeof(request4); /* 354 End data with .|| */ uint8_t reply4[] = { 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d, 0x0a }; uint32_t reply4_len = sizeof(reply4); /* FROM:asdff@asdf.com */ uint8_t request5_1[] = { 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request5_1_len = sizeof(request5_1); /* TO:bimbs@gmail.com */ uint8_t request5_2[] = { 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request5_2_len = sizeof(request5_2); /* */ uint8_t request5_3[] = { 0x0d, 0x0a }; uint32_t request5_3_len = sizeof(request5_3); /* this is test mail1 */ uint8_t request5_4[] = { 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x31, 0x0d, 0x0a }; uint32_t request5_4_len = sizeof(request5_4); /* . */ uint8_t request5_5[] = { 0x2e, 0x0d, 0x0a }; uint32_t request5_5_len = sizeof(request5_5); /* 250 2.0.0 Ok: queued as 6A1AF20BF2 */ uint8_t reply5[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42, 0x46, 0x32, 0x0d, 0x0a }; uint32_t reply5_len = sizeof(reply5); /* MAIL FROM:asdfg@asdf.com */ uint8_t request6[] = { 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request6_len = sizeof(request6); /* 250 2.1.0 Ok */ uint8_t reply6[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a }; uint32_t reply6_len = sizeof(reply6); /* RCPT TO:bimbs@gmail.com */ uint8_t request7[] = { 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request7_len = sizeof(request7); /* 250 2.1.5 Ok */ uint8_t reply7[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a }; uint32_t reply7_len = sizeof(reply7); /* DATA */ uint8_t request8[] = { 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a }; uint32_t request8_len = sizeof(request8); /* 354 End data with .|| */ uint8_t reply8[] = { 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d, 0x0a }; uint32_t reply8_len = sizeof(reply8); /* FROM:asdfg@gmail.com */ uint8_t request9_1[] = { 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request9_1_len = sizeof(request9_1); /* TO:bimbs@gmail.com */ uint8_t request9_2[] = { 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request9_2_len = sizeof(request9_2); /* */ uint8_t request9_3[] = { 0x0d, 0x0a }; uint32_t request9_3_len = sizeof(request9_3); /* this is test mail2 */ uint8_t request9_4[] = { 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x32, 0x0d, 0x0a }; uint32_t request9_4_len = sizeof(request9_4); /* . */ uint8_t request9_5[] = { 0x2e, 0x0d, 0x0a }; uint32_t request9_5_len = sizeof(request9_5); /* 250 2.0.0 Ok: queued as 28CFF20BF2 */ uint8_t reply9[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42, 0x46, 0x32, 0x0d, 0x0a }; uint32_t reply9_len = sizeof(reply9); /* QUIT */ uint8_t request10[] = { 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a }; uint32_t request10_len = sizeof(request10); /* 221 2.0.0 Bye */ uint8_t reply10[] = { 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a }; uint32_t reply10_len = sizeof(reply10); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_DATA || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4, reply4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_1, request5_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_2, request5_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_3, request5_3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_4, request5_4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_5, request5_5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply5, reply5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply6, reply6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request7, request7_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply7, reply7_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request8, request8_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_DATA || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply8, reply8_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_1, request9_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_2, request9_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_3, request9_3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_4, request9_4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_5, request9_5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply9, reply9_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request10, request10_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply10, reply10_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /** * \test Testing parsing pipelined commands. */ int SMTPParserTest03(void) { int result = 0; Flow f; int r = 0; /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ uint8_t welcome_reply[] = { 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a }; uint32_t welcome_reply_len = sizeof(welcome_reply); /* EHLO boo.com */ uint8_t request1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0a }; uint32_t request1_len = sizeof(request1); /* 250-poona_slack_vm1.localdomain * 250-PIPELINING * 250-SIZE 10240000 * 250-VRFY * 250-ETRN * 250-ENHANCEDSTATUSCODES * 250-8BITMIME * 250 DSN */ uint8_t reply1[] = { 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a }; uint32_t reply1_len = sizeof(reply1); /* MAIL FROM:pbsf@asdfs.com * RCPT TO:pbsf@asdfs.com * DATA */ uint8_t request2[] = { 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a }; uint32_t request2_len = sizeof(request2); /* 250 2.1.0 Ok * 250 2.1.5 Ok * 354 End data with .|| */ uint8_t reply2[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d, 0x0a }; uint32_t reply2_len = sizeof(reply2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD || smtp_state->cmds[2] != SMTP_COMMAND_DATA || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /* * \test Test smtp with just delimter instead of . */ int SMTPParserTest04(void) { int result = 0; Flow f; int r = 0; /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ uint8_t welcome_reply[] = { 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a }; uint32_t welcome_reply_len = sizeof(welcome_reply); /* EHLO boo.com */ uint8_t request1[] = { 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a }; uint32_t request1_len = sizeof(request1); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /* * \test Test STARTTLS fail. */ int SMTPParserTest05(void) { int result = 0; Flow f; int r = 0; /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ uint8_t welcome_reply[] = { 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a }; uint32_t welcome_reply_len = sizeof(welcome_reply); /* EHLO boo.com */ uint8_t request1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request1_len = sizeof(request1); /* 250-poona_slack_vm1.localdomain * 250-PIPELINING * 250-SIZE 10240000 * 250-VRFY * 250-ETRN * 250-ENHANCEDSTATUSCODES * 250-8BITMIME * 250 DSN */ uint8_t reply1[] = { 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a }; uint32_t reply1_len = sizeof(reply1); /* STARTTLS */ uint8_t request2[] = { 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, 0x0d, 0x0a }; uint32_t request2_len = sizeof(request2); /* 502 5.5.2 Error: command not recognized */ uint8_t reply2[] = { 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e, 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63, 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d, 0x0a }; uint32_t reply2_len = sizeof(reply2); /* QUIT */ uint8_t request3[] = { 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a }; uint32_t request3_len = sizeof(request3); /* 221 2.0.0 Bye */ uint8_t reply3[] = { 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a }; uint32_t reply3_len = sizeof(reply3); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) || (f.flags & FLOW_NO_APPLAYER_INSPECTION) || (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /** * \test Test multiple DATA commands(full mail transactions). */ int SMTPParserTest06(void) { int result = 0; Flow f; int r = 0; uint8_t welcome_reply[] = { 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30, 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30, 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f, 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b, 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69, 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e, 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f, 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62, 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35, 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d, 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a }; uint32_t welcome_reply_len = sizeof(welcome_reply); uint8_t request1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63, 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69, 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d, 0x0a }; uint32_t request1_len = sizeof(request1); uint8_t reply1[] = { 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30, 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30, 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f, 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31, 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31, 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39, 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69, 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55, 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55, 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b, 0x0d, 0x0a }; uint32_t reply1_len = sizeof(reply1); /* MAIL FROM:asdff@asdf.com */ uint8_t request2[] = { 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request2_len = sizeof(request2); /* 250 2.1.0 Ok */ uint8_t reply2[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a }; uint32_t reply2_len = sizeof(reply2); /* RCPT TO:bimbs@gmail.com */ uint8_t request3[] = { 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; uint32_t request3_len = sizeof(request3); /* 250 2.1.5 Ok */ uint8_t reply3[] = { 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a }; uint32_t reply3_len = sizeof(reply3); /* BDAT 51 */ uint8_t request4[] = { 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d, 0x0a, }; uint32_t request4_len = sizeof(request4); uint8_t request5[] = { 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a, }; uint32_t request5_len = sizeof(request5); uint8_t request6[] = { 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, 0x66, 0x0d, 0x0a, }; uint32_t request6_len = sizeof(request6); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_BDAT || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE) || smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE) || smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 32) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN || smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 51) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /* * \test Test retrieving lines when frag'ed. */ int SMTPParserTest07(void) { int result = 0; Flow f; int r = 0; const char *request1_str = "EHLO boo.com"; /* EHLO boo.com */ uint8_t request1_1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, }; int32_t request1_1_len = sizeof(request1_1); /* */ uint8_t request1_2[] = { 0x0a }; int32_t request1_2_len = sizeof(request1_2); /* EHLO boo.com */ uint8_t request2[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, }; int32_t request2_len = sizeof(request2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->current_line != NULL || smtp_state->current_line_len != 0 || smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != request1_1_len || memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 || smtp_state->current_line != smtp_state->ts_db || smtp_state->current_line_len != smtp_state->ts_db_len) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || smtp_state->current_line == NULL || smtp_state->current_line_len != (int32_t)strlen(request1_str) || memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /* * \test Test retrieving lines when frag'ed. */ int SMTPParserTest08(void) { int result = 0; Flow f; int r = 0; const char *request1_str = "EHLO boo.com"; /* EHLO boo.com */ uint8_t request1_1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, }; int32_t request1_1_len = sizeof(request1_1); /* */ uint8_t request1_2[] = { 0x0d, 0x0a }; int32_t request1_2_len = sizeof(request1_2); /* EHLO boo.com */ uint8_t request2[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, }; int32_t request2_len = sizeof(request2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->current_line != NULL || smtp_state->current_line_len != 0 || smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != request1_1_len || memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 || smtp_state->current_line != smtp_state->ts_db || smtp_state->current_line_len != smtp_state->ts_db_len) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || smtp_state->current_line == NULL || smtp_state->current_line_len != (int32_t)strlen(request1_str) || memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /* * \test Test retrieving lines when frag'ed. */ int SMTPParserTest09(void) { int result = 0; Flow f; int r = 0; const char *request1_str = "EHLO boo.com"; /* EHLO boo. */ uint8_t request1_1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, }; int32_t request1_1_len = sizeof(request1_1); /* com */ uint8_t request1_2[] = { 0x63, 0x6f, 0x6d, 0x0d, 0x0a }; int32_t request1_2_len = sizeof(request1_2); /* EHLO boo.com */ uint8_t request2[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, }; int32_t request2_len = sizeof(request2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->current_line != NULL || smtp_state->current_line_len != 0 || smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != request1_1_len || memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 || smtp_state->current_line != smtp_state->ts_db || smtp_state->current_line_len != smtp_state->ts_db_len) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || smtp_state->current_line == NULL || smtp_state->current_line_len != (int32_t)strlen(request1_str) || memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /* * \test Test retrieving lines when frag'ed. */ int SMTPParserTest10(void) { int result = 0; Flow f; int r = 0; const char *request1_str = ""; /* EHLO boo. */ uint8_t request1_1[] = { 0x0d, }; int32_t request1_1_len = sizeof(request1_1); /* com */ uint8_t request1_2[] = { 0x0a, }; int32_t request1_2_len = sizeof(request1_2); const char *request2_str = "EHLO boo.com"; /* EHLO boo.com */ uint8_t request2[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, }; int32_t request2_len = sizeof(request2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->current_line != NULL || smtp_state->current_line_len != 0 || smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != request1_1_len || memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 || smtp_state->current_line != smtp_state->ts_db || smtp_state->current_line_len != smtp_state->ts_db_len) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || smtp_state->current_line == NULL || smtp_state->current_line_len != (int32_t)strlen(request2_str) || memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } /* * \test Test retrieving lines when frag'ed. */ int SMTPParserTest11(void) { int result = 0; Flow f; int r = 0; const char *request1_str = ""; /* EHLO boo. */ uint8_t request1[] = { 0x0a, }; int32_t request1_len = sizeof(request1); const char *request2_str = "EHLO boo.com"; /* EHLO boo.com */ uint8_t request2[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, }; int32_t request2_len = sizeof(request2); TcpSession ssn; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } if (smtp_state->current_line == NULL || smtp_state->current_line_len != 0 || smtp_state->ts_current_line_db == 1 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); goto end; } if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || smtp_state->current_line == NULL || smtp_state->current_line_len != (int32_t)strlen(request2_str) || memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) { printf("smtp parser in inconsistent state\n"); goto end; } result = 1; end: StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); SMTPLocalStorageFree(thread_local_data); return result; } int SMTPParserTest12(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; SMTPState *smtp_state = NULL; int r = 0; /* EHLO boo.com */ uint8_t request1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, }; int32_t request1_len = sizeof(request1); /* 388 */ uint8_t reply1[] = { 0x31, 0x38, 0x38, 0x0d, 0x0a, }; uint32_t reply1_len = sizeof(reply1); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SMTP; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any " "(msg:\"SMTP event handling\"; " "app-layer-event: smtp.invalid_reply; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, request1, request1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); goto end; } smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched. It shouldn't match: "); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT, reply1, reply1_len); if (r == 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match. Should have matched: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); SMTPLocalStorageFree(thread_local_data); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } int SMTPParserTest13(void) { int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; Flow f; TcpSession ssn; DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; SMTPState *smtp_state = NULL; int r = 0; /* EHLO boo.com */ uint8_t request1[] = { 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, }; int32_t request1_len = sizeof(request1); /* 250 */ uint8_t reply1[] = { 0x32, 0x35, 0x30, 0x0d, 0x0a, }; uint32_t reply1_len = sizeof(reply1); /* MAIL FROM:pbsf@asdfs.com * RCPT TO:pbsf@asdfs.com * DATA * STARTTLS */ uint8_t request2[] = { 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, 0x0d, 0x0a }; uint32_t request2_len = sizeof(request2); memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SMTP; StreamTcpInitConfig(TRUE); void *thread_local_data = SMTPLocalStorageAlloc(); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"SMTP event handling\"; " "app-layer-event: " "smtp.invalid_pipelined_sequence; " "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, request1, request1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); goto end; } smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched. It shouldn't match: "); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched. It shouldn't match: "); goto end; } r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match. Should have matched: "); goto end; } result = 1; end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); SMTPLocalStorageFree(thread_local_data); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void SMTPParserRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SMTPParserTest01", SMTPParserTest01, 1); UtRegisterTest("SMTPParserTest02", SMTPParserTest02, 1); UtRegisterTest("SMTPParserTest03", SMTPParserTest03, 1); UtRegisterTest("SMTPParserTest04", SMTPParserTest04, 1); UtRegisterTest("SMTPParserTest05", SMTPParserTest05, 1); UtRegisterTest("SMTPParserTest06", SMTPParserTest06, 1); UtRegisterTest("SMTPParserTest07", SMTPParserTest07, 1); UtRegisterTest("SMTPParserTest08", SMTPParserTest08, 1); UtRegisterTest("SMTPParserTest09", SMTPParserTest09, 1); UtRegisterTest("SMTPParserTest10", SMTPParserTest10, 1); UtRegisterTest("SMTPParserTest11", SMTPParserTest11, 1); UtRegisterTest("SMTPParserTest12", SMTPParserTest12, 1); UtRegisterTest("SMTPParserTest13", SMTPParserTest13, 1); #endif /* UNITTESTS */ return; } suricata-1.4.7/src/detect-engine-hrhhd.c0000644000000000000000000021471012253546156015004 00000000000000/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \ingroup httplayer * * @{ */ /** \file * * \author Anoop Saldanha * * \brief Handle HTTP host header. * HRHHD - Http Raw Host Header Data * */ #include "suricata-common.h" #include "suricata.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" #include "flow-util.h" #include "util-debug.h" #include "util-print.h" #include "flow.h" #include "app-layer-parser.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" #include "detect-engine-hrhhd.h" int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, uint8_t flags) { htp_tx_t *tx = NULL; uint32_t cnt = 0; int idx; /* we need to lock because the buffers are not actually true buffers * but are ones that point to a buffer given by libhtp */ FLOWLOCK_RDLOCK(f); if (htp_state == NULL) { SCLogDebug("no HTTP state"); goto end; } if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { SCLogDebug("HTP state has no conn(p)"); goto end; } idx = AppLayerTransactionGetInspectId(f); if (idx == -1) { goto end; } int size = (int)list_size(htp_state->connp->conn->transactions); for (; idx < size; idx++) { uint8_t *hname; uint32_t hname_len; tx = list_get(htp_state->connp->conn->transactions, idx); if (tx == NULL) continue; if (tx->parsed_uri_incomplete == NULL || tx->parsed_uri_incomplete->hostname == NULL) { htp_header_t *h = NULL; h = (htp_header_t *)table_getc(tx->request_headers, "Host"); if (h == NULL) { SCLogDebug("HTTP host header not present in this request"); continue; } hname = (uint8_t *)bstr_ptr(h->value); hname_len = bstr_len(h->value); } else { hname = (uint8_t *)bstr_ptr(tx->parsed_uri_incomplete->hostname); if (hname == NULL) continue; hname_len = bstr_len(tx->parsed_uri_incomplete->hostname); } cnt += HttpHRHPatternSearch(det_ctx, hname, hname_len, flags); } end: FLOWLOCK_UNLOCK(f); return cnt; } /** * \brief Do the http_header content inspection for a signature. * * \param de_ctx Detection engine context. * \param det_ctx Detection engine thread context. * \param s Signature to inspect. * \param f Flow. * \param flags App layer flags. * \param state App layer state. * * \retval 0 No match. * \retval 1 Match. */ int DetectEngineInspectHttpHRH(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, tx_id); uint8_t *hname; uint32_t hname_len; if (tx == NULL) return 0; if (tx->parsed_uri_incomplete == NULL || tx->parsed_uri_incomplete->hostname == NULL) { htp_header_t *h = NULL; h = (htp_header_t *)table_getc(tx->request_headers, "Host"); if (h == NULL) { SCLogDebug("HTTP host header not present in this request"); return 0; } hname = (uint8_t *)bstr_ptr(h->value); hname_len = bstr_len(h->value); } else { hname = (uint8_t *)bstr_ptr(tx->parsed_uri_incomplete->hostname); if (hname == NULL) return 0; hname_len = bstr_len(tx->parsed_uri_incomplete->hostname); } det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRHHDMATCH], f, hname, hname_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, NULL); if (r == 1) return 1; return 0; } /***********************************Unittests**********************************/ #ifdef UNITTESTS /** * \test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest01(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"CONNECT\"; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest02(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"CO\"; depth:4; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest03(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:!\"ECT\"; depth:4; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest04(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"ECT\"; depth:4; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest05(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:!\"CON\"; depth:4; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest06(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"ECT\"; offset:3; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest07(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:!\"CO\"; offset:3; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest08(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:!\"ECT\"; offset:3; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest09(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"CON\"; offset:3; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest10(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"CO\"; http_raw_host; " "content:\"EC\"; within:4; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest11(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"CO\"; http_raw_host; " "content:!\"EC\"; within:3; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest12(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"CO\"; http_raw_host; " "content:\"EC\"; within:3; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest13(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"CO\"; http_raw_host; " "content:!\"EC\"; within:4; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest14(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"CO\"; http_raw_host; " "content:\"EC\"; distance:2; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest15(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"CO\"; http_raw_host; " "content:!\"EC\"; distance:3; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest16(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"CO\"; http_raw_host; " "content:\"EC\"; distance:3; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } /** * \test Test that the http_raw_host header content matches against a http request * which holds the content. */ static int DetectEngineHttpHRHTest17(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: CONNECT\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"CO\"; http_raw_host; " "content:!\"EC\"; distance:2; http_raw_host; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest18(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.kaboom.com:8080\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"kaboom\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest19(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.kaboom.com:8080\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"kaboom\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest20(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" "Host: www.kaboom.com:8080\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"8080\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but it should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest21(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"kaboom\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest22(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"kaboom\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest23(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"8080\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but it shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest24(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" "Host: www.rabbit.com\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"kaboom\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't match but it should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest25(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" "Host: www.rabbit.com\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http_raw_host header test\"; " "content:\"rabbit\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sid 1 matched but it shouldn't have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest26(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://[fdaf:222d::2342]/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"2342\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } static int DetectEngineHttpHRHTest27(void) { TcpSession ssn; Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; uint8_t http_buf[] = "GET http://[fdaf:222d::2342]:8080/index.html HTTP/1.0\r\n" "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_HTTP; StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http host header test\"; " "content:\"2342\"; http_raw_host; nocase; " "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; goto end; } http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); result = 0; goto end; } /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { printf("sid 1 didn't match but should have: "); goto end; } result = 1; end: if (de_ctx != NULL) SigGroupCleanup(de_ctx); if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); return result; } #endif /* UNITTESTS */ void DetectEngineHttpHRHRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpHRHTest01", DetectEngineHttpHRHTest01, 1); UtRegisterTest("DetectEngineHttpHRHTest02", DetectEngineHttpHRHTest02, 1); UtRegisterTest("DetectEngineHttpHRHTest03", DetectEngineHttpHRHTest03, 1); UtRegisterTest("DetectEngineHttpHRHTest04", DetectEngineHttpHRHTest04, 1); UtRegisterTest("DetectEngineHttpHRHTest05", DetectEngineHttpHRHTest05, 1); UtRegisterTest("DetectEngineHttpHRHTest06", DetectEngineHttpHRHTest06, 1); UtRegisterTest("DetectEngineHttpHRHTest07", DetectEngineHttpHRHTest07, 1); UtRegisterTest("DetectEngineHttpHRHTest08", DetectEngineHttpHRHTest08, 1); UtRegisterTest("DetectEngineHttpHRHTest09", DetectEngineHttpHRHTest09, 1); UtRegisterTest("DetectEngineHttpHRHTest10", DetectEngineHttpHRHTest10, 1); UtRegisterTest("DetectEngineHttpHRHTest11", DetectEngineHttpHRHTest11, 1); UtRegisterTest("DetectEngineHttpHRHTest12", DetectEngineHttpHRHTest12, 1); UtRegisterTest("DetectEngineHttpHRHTest13", DetectEngineHttpHRHTest13, 1); UtRegisterTest("DetectEngineHttpHRHTest14", DetectEngineHttpHRHTest14, 1); UtRegisterTest("DetectEngineHttpHRHTest15", DetectEngineHttpHRHTest15, 1); UtRegisterTest("DetectEngineHttpHRHTest16", DetectEngineHttpHRHTest16, 1); UtRegisterTest("DetectEngineHttpHRHTest17", DetectEngineHttpHRHTest17, 1); UtRegisterTest("DetectEngineHttpHRHTest18", DetectEngineHttpHRHTest18, 1); UtRegisterTest("DetectEngineHttpHRHTest19", DetectEngineHttpHRHTest19, 1); UtRegisterTest("DetectEngineHttpHRHTest20", DetectEngineHttpHRHTest20, 1); UtRegisterTest("DetectEngineHttpHRHTest21", DetectEngineHttpHRHTest21, 1); UtRegisterTest("DetectEngineHttpHRHTest22", DetectEngineHttpHRHTest22, 1); UtRegisterTest("DetectEngineHttpHRHTest23", DetectEngineHttpHRHTest23, 1); UtRegisterTest("DetectEngineHttpHRHTest24", DetectEngineHttpHRHTest24, 1); UtRegisterTest("DetectEngineHttpHRHTest25", DetectEngineHttpHRHTest25, 1); UtRegisterTest("DetectEngineHttpHRHTest26", DetectEngineHttpHRHTest26, 1); UtRegisterTest("DetectEngineHttpHRHTest27", DetectEngineHttpHRHTest27, 1); #endif /* UNITTESTS */ return; } /** * @} */ suricata-1.4.7/src/cuda-packet-batcher.c0000644000000000000000000015570312253546156014773 00000000000000/** * Copyright (c) 2010 Open Information Security Foundation. * * \author Anoop Saldanha * * \todo * 1 Implement a gpu version of aho-corasick. That should get rid of a * lot of post processing and pattern_chopping, and we don't have to * deal with one or two byte patterns. (currently in process) * 2 Use texture/shared memory. This should be handled along with 1 and 6. * 3 Currently a lot of packets(~17k) are getting stuck on the detection * thread, which is a major bottleneck. Introduce bypass detection * threads for these 15k non buffered packets and check how the alerts * are affected by this(out of sequence handling by detection threads). * 4 Test the use of mapped memory(if possible anywhere). * 5 Check parallelising memcopies with kernel execution. * 6 Test this feature - Rearrange the packet stream(either on cpu or gpu), * where each block in the gpu can access the packet with non-coalesced * reads. * 2 packets p1 -> aabb ccdd * p2 -> eeff gghh * * stream -> aabbeeffccddgghh. * * Modify the block size to 16 threads for CC < 2.0 devices and 32 for * for >= 2.0. * * The rearrangement of packet stream can be done on the gpu, with no * perf degradation, using coalesced reads. Padding packets need to * be addressed though. * (Need to give more thought to this task). * * -- Feel free to pick any task from the agenda, but please * drop a mail to dev mailing list(or directly to the dev team). Better * yet, open a feature request on our bug/feature tracker * (https://redmine.openinfosecfoundation.org/issues). Will be a mess if * 2 or more devs end up working on the same task or related tasks. */ /* compile in, only if we have a CUDA enabled on this machine */ #ifdef __SC_CUDA_SUPPORT__ #include "suricata-common.h" #include "suricata.h" #include "detect.h" #include "decode.h" #include "flow.h" #include "data-queue.h" #include "threads.h" #include "threadvars.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "cuda-packet-batcher.h" #include "conf.h" #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" #include "util-mpm-b2g-cuda.h" #include "util-cuda-handlers.h" #include "detect-engine-address.h" #include "detect-engine-port.h" #include "detect-engine.h" #include "detect-parse.h" #include "tm-threads.h" #include "tmqh-packetpool.h" #include "util-mpm.h" /* \todo Make this user configurable through our yaml file. Also provide options * where this can be dynamically updated based on the traffic */ #define SC_CUDA_PB_BATCHER_ALARM_TIME 1 /* holds the inq and outq between the cuda-packet-batcher TM and the cuda b2g mpm * dispatcher thread */ static Tmq *tmq_inq = NULL; static Tmq *tmq_outq = NULL; /* holds the packet inq between the batcher TM and, the TM feeding it packets * in the runmode sequence. We will need this to implement the alarm. We will * have a SIG_ALRM delivered every SC_CUDA_PB_BATCHER_ALARM_TIME seconds, after * which we willf set a flag informing the batcher TM to queue the buffer to the * GPU and wake the batcher thread, in case it is waiting on a conditional for a * packet from the previous TM in the runmode */ static Tmq *tmq_batcher_inq = NULL; /* used to indicate if we want to stop buffering the packets anymore. We * we will need this while we want to shut the engine down * \todo give a better description */ static int run_batcher = 1; /* indicates the maximum no of packets we are ready to buffer. Theoretically the * maximum value held by this var can't exceed the value held by * "max_pending_packets". Either ways we should make this user configurable like * SC_CUDA_PB_BATCHER_ALARM_TIME. Also allow dynamic updates to this value based * on the traffic * \todo make this user configurable, as well allow dynamic update of this * variable based on the traffic seen */ static uint32_t buffer_packet_threshhold = 0; /* the profile used by the cuda batcher */ static MpmCudaConf *profile = NULL; /* flag used by the SIG_ALRM handler to indicate that the batcher TM should queue * the buffer to be processed by the Cuda Mpm B2g Batcher Thread for further * processing on the GPU */ static int queue_buffer = 0; /* struct to configure the SIG_ALRM frequency. */ static struct itimerval itimer = {{0, 0}, {0, 0}}; static int unittest_mode = 0; /** * \internal * \brief The SIG_ALRM handler. We will set the "queue_buffer" flag thus * informing the batcher TM that it needs to queue the buffer. We * also signal the cond var for the batcher TM inq(the one it * receives packets from), incase it is waiting on the conditional * for a new packet from the previous TM in the runmodes list. * * \param signum The signal number that this function just woke up to. In * our case it is SIG_ALRM. */ static void SCCudaPBSetQueueBufferFlag(int signum) { SCLogDebug("Cuda Packet Batche alarm generated after %f seconds. Set the" "queue_buffer flag and signal the cuda TM inq.", profile->batching_timeout); queue_buffer = 1; SCCondSignal(&((&trans_q[tmq_batcher_inq->id])->cond_q)); return; } /** * \internal. * \brief Set the SIG_ALRM handler */ static void SCCudaPBSetBatcherAlarmTimeHandler() { struct sigaction action; SCLogDebug("Setting the SIGALRM handler for the Cuda Batcher TM"); action.sa_handler = SCCudaPBSetQueueBufferFlag; sigemptyset(&(action.sa_mask)); sigaddset(&(action.sa_mask), SIGALRM); action.sa_flags = 0; sigaction(SIGALRM, &action, 0); itimer.it_value.tv_sec = profile->batching_timeout; itimer.it_value.tv_usec = (profile->batching_timeout - (int32_t) profile->batching_timeout) * 1000000; return; } /** * \internal * \brief Reset the batcher alarm. */ static inline void SCCudaPBResetBatcherAlarm() { queue_buffer = 0; /* if we are running unittests, don't set the alarm handler. It will only * cause a seg fault if the tests take too long */ if (!unittest_mode) { /* \todo We could update itimer dynamically based on the traffic */ setitimer(ITIMER_REAL, &itimer, NULL); } } /** * \internal * \brief Used to retrieve the Signature Group Head for a packet. * * \param de_ctx Pointer the detection engine context to search for the * sgh for an incoming packet. * \param p Pointer to the incoming packet for which we will have to * search for a sgh. * * \retval sgh Pointer to the relevant matching sgh for the Packet. */ static SigGroupHead *SCCudaPBGetSgh(DetectEngineCtx *de_ctx, Packet *p) { int f; SigGroupHead *sgh = NULL; /* select the flow_gh */ if (p->flowflags & FLOW_PKT_TOCLIENT) f = 0; else f = 1; /* find the right mpm instance */ DetectAddress *ag = DetectAddressLookupInHead(de_ctx->flow_gh[f].src_gh[p->proto], &p->src); if (ag != NULL) { /* source group found, lets try a dst group */ ag = DetectAddressLookupInHead(ag->dst_gh,&p->dst); if (ag != NULL) { if (ag->port == NULL) { SCLogDebug("we don't have ports"); sgh = ag->sh; } else { SCLogDebug("we have ports"); DetectPort *sport = DetectPortLookupGroup(ag->port,p->sp); if (sport != NULL) { DetectPort *dport = DetectPortLookupGroup(sport->dst_ph, p->dp); if (dport != NULL) { sgh = dport->sh; } else { SCLogDebug("no dst port group found for the packet with dp %"PRIu16, p->dp); } } else { SCLogDebug("no src port group found for the packet with sp %"PRIu16, p->sp); } } } else { SCLogDebug("no dst address group found for the packet"); } } else { SCLogDebug("no src address group found for the packet"); } return sgh; } /** * \internal * \brief Handles the queuing of the buffer from this batcher TM to the cuda * mpm b2g dispatcher TM. * * \tctx The batcher thread context that holds the current operational buffer * which has to be buffered by this function. */ static void SCCudaPBQueueBuffer(SCCudaPBThreadCtx *tctx) { SCCudaPBPacketsBuffer *pb = (SCCudaPBPacketsBuffer *)tctx->curr_pb; uint32_t nop_in_buffer = pb->nop_in_buffer; uint32_t *packets_offset_buffer = pb->packets_offset_buffer; uint32_t offset = *(packets_offset_buffer + nop_in_buffer - 1); SCCudaPBPacketDataForGPU *last_packet = (SCCudaPBPacketDataForGPU *)(pb->packets_buffer + offset); /* if we have no packets buffered in so far, get out */ if (pb->nop_in_buffer == 0) { SCLogDebug("No packets buffered in so far in the cuda buffer. Returning"); return; } /* calculate the total length of all the packets buffered in */ pb->packets_buffer_len = pb->packets_offset_buffer[pb->nop_in_buffer - 1] + sizeof(SCCudaPBPacketDataForGPUNonPayload) + last_packet->payload_len; pb->packets_total_payload_len = pb->packets_payload_offset_buffer[pb->nop_in_buffer - 1] + last_packet->payload_len; /* enqueue the buffer in the outq to be consumed by the dispatcher TM */ SCDQDataQueue *dq_outq = &data_queues[tmq_outq->id]; SCMutexLock(&dq_outq->mutex_q); SCDQDataEnqueue(dq_outq, (SCDQGenericQData *)tctx->curr_pb); SCCondSignal(&dq_outq->cond_q); SCMutexUnlock(&dq_outq->mutex_q); while (run_batcher) { /* dequeue a new buffer */ SCDQDataQueue *dq_inq = &data_queues[tmq_inq->id]; SCMutexLock(&dq_inq->mutex_q); if (dq_inq->len == 0) { /* if we have no data in queue, wait... */ SCCondWait(&dq_inq->cond_q, &dq_inq->mutex_q); } if (run_batcher == 0) { break; } if (dq_inq->len > 0) { tctx->curr_pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(dq_inq); tctx->curr_pb->nop_in_buffer = 0; tctx->curr_pb->packets_buffer_len = 0; tctx->curr_pb->packets_total_payload_len = 0; SCMutexUnlock(&dq_inq->mutex_q); SCLogDebug("Dequeued a new packet buffer for the cuda batcher TM"); break; } else { /* Should only happen on signals. */ SCMutexUnlock(&dq_inq->mutex_q); SCLogDebug("Unable to Relooping in the quest to dequeue new buffer"); } } /* while (run_batcher) */ return; } /** * \brief Custom slot function used by the Batcher TM. * * \param td Pointer to the ThreadVars instance. In this case the batcher TM's * ThreadVars instance. */ void *SCCudaPBTmThreadsSlot1(void *td) { ThreadVars *tv = (ThreadVars *)td; TmSlot *s = (TmSlot *)tv->tm_slots; Packet *p = NULL; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ SCSetThreadName(tv->name); if (tv->thread_setup_flags != 0) { TmThreadSetupOptions(tv); } SCLogDebug("%s starting", tv->name); if (s->SlotThreadInit != NULL) { void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); } SC_ATOMIC_SET(s->slot_data, slot_data); } memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); TmThreadsSetFlag(tv, THV_INIT_DONE); while(run) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); TmThreadTestThreadUnPaused(tv); /* input a packet */ p = tv->tmqh_in(tv); if (p == NULL) { SCLogDebug("packet is NULL for TM: %s", tv->name); /* the only different between the actual Slot1 function in * tm-threads.c and this custom Slot1 function is this call * here. We need to make the call here, even if we don't * receive a packet from the previous stage in the runmodes. * This is needed in cases where the SIG_ALRM handler * wants us to queue the buffer to the GPU and ends up waking * the Batcher TM(which is waiting on a cond from the previous * feeder TM). Please handle the NULL packet case in the * function that you now call */ r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), NULL, NULL); } else { r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), NULL, NULL); /* handle error */ if (r == TM_ECODE_FAILED) { TmqhOutputPacketpool(tv, p); TmThreadsSetFlag(tv, THV_FAILED); break; } /* output the packet */ tv->tmqh_out(tv, p); } if (TmThreadsCheckFlag(tv, THV_KILL)) { SCPerfSyncCounters(tv, 0); run = 0; } } TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); if (s->SlotThreadExitPrintStats != NULL) { s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); } if (s->SlotThreadDeinit != NULL) { r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } } SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); } /** * \brief Used to de-allocate an instance of SCCudaPBPacketsBuffer. * * \param pb Pointer to the SCCudaPacketsBuffer instance to be de-alloced. */ void SCCudaPBDeAllocSCCudaPBPacketsBuffer(SCCudaPBPacketsBuffer *pb) { if (pb == NULL) return; if (pb->packets_buffer != NULL) { if (SCCudaMemFreeHost(pb->packets_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "packets_buffer"); } } if (pb->packets_offset_buffer != NULL) { if (SCCudaMemFreeHost(pb->packets_offset_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "packets_offset_buffer"); } } if (pb->packets_payload_offset_buffer != NULL) { if (SCCudaMemFreeHost(pb->packets_payload_offset_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory " "packets_payload_offset_buffer"); } } if (pb->packets_address_buffer != NULL) SCFree(pb->packets_address_buffer); SCFree(pb); return; } /** * \brief Allocates a new instance of SCCudaPBPacketsBuffer. * * \param pb The newly created instance of SCCudaPBPacketsBuffer. */ SCCudaPBPacketsBuffer *SCCudaPBAllocSCCudaPBPacketsBuffer(void) { SCCudaPBPacketsBuffer *pb = SCMalloc(sizeof(SCCudaPBPacketsBuffer)); if (unlikely(pb == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(pb, 0, sizeof(SCCudaPBPacketsBuffer)); /* Register new module, needed for some unit tests */ if (SCCudaHlGetModuleHandle("SC_CUDA_PACKET_BATCHER") == -1) { SCCudaHlRegisterModule("SC_CUDA_PACKET_BATCHER"); } /* the buffer for the packets to be sent over to the gpu. We allot space for * profile->packet_buffer_limit packets, assuming a size of * profile->packet_size_limit for each packet */ SCCudaHlModuleData *data = NULL; data = SCCudaHlGetModuleData(SCCudaHlGetModuleHandle("SC_CUDA_PACKET_BATCHER")); if (data == NULL) { SCLogDebug("Module not registered. To avail the benefits of this " "registration facility, first register a module using " "context using SCCudaHlRegisterModule(), after which you " "can call this function"); return NULL; } if (SCCudaHlGetCudaContext(&data->cuda_context, "mpm", data->handle) == -1) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Error getting cuda context"); return NULL; } if (SCCudaCtxPushCurrent(data->cuda_context) == -1) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Error pushing cuda context to allocate memory"); } if (profile->page_locked) { if (SCCudaMemHostAlloc((void**)&pb->packets_buffer, profile->packet_buffer_limit * (profile->packet_size_limit + sizeof(SCCudaPBPacketDataForGPUNonPayload)), CU_MEMHOSTALLOC_PORTABLE | CU_MEMHOSTALLOC_WRITECOMBINED) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error allocating page-locked memory"); exit(EXIT_FAILURE); } } else { pb->packets_buffer = SCMalloc(profile->packet_buffer_limit * (profile->packet_size_limit + sizeof(SCCudaPBPacketDataForGPUNonPayload))); if (pb->packets_buffer == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } } memset(pb->packets_buffer, 0, profile->packet_buffer_limit * (profile->packet_size_limit + sizeof(SCCudaPBPacketDataForGPUNonPayload))); if (profile->page_locked) { /* used to hold the offsets of the buffered packets in the packets_buffer */ if (SCCudaMemHostAlloc((void**)&pb->packets_offset_buffer, sizeof(uint32_t) * profile->packet_buffer_limit, CU_MEMHOSTALLOC_PORTABLE | CU_MEMHOSTALLOC_WRITECOMBINED) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error allocating page-locked memory"); exit(EXIT_FAILURE); } } else { pb->packets_offset_buffer = SCMalloc(sizeof(uint32_t) * profile->packet_buffer_limit); if (pb->packets_offset_buffer == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } } memset(pb->packets_offset_buffer, 0, sizeof(uint32_t) * profile->packet_buffer_limit); if (profile->page_locked) { /* used to hold the offsets of the packets payload */ if (SCCudaMemHostAlloc((void**)&pb->packets_payload_offset_buffer, sizeof(uint32_t) * profile->packet_buffer_limit, CU_MEMHOSTALLOC_PORTABLE | CU_MEMHOSTALLOC_WRITECOMBINED) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error allocating page-locked memory"); exit(EXIT_FAILURE); } } else { pb->packets_payload_offset_buffer = SCMalloc(sizeof(uint32_t) * profile->packet_buffer_limit); if (pb->packets_payload_offset_buffer == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } } memset(pb->packets_payload_offset_buffer, 0, sizeof(uint32_t) * profile->packet_buffer_limit); SCLogDebug("Allocated pagelocked CUDA memory"); if (SCCudaCtxPopCurrent(NULL) == -1) { SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Could not pop cuda context"); } /* used to hold the packet addresses for all the packets buffered inside * packets_buffer */ pb->packets_address_buffer = SCMalloc(sizeof(Packet *) * profile->packet_buffer_limit); if (pb->packets_address_buffer == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(pb->packets_address_buffer, 0, sizeof(Packet *) * profile->packet_buffer_limit); return pb; } /** * \brief Registration function for the Cuda Packet Batcher TM. */ void TmModuleCudaPacketBatcherRegister(void) { tmm_modules[TMM_CUDA_PACKET_BATCHER].name = "CudaPacketBatcher"; tmm_modules[TMM_CUDA_PACKET_BATCHER].ThreadInit = SCCudaPBThreadInit; tmm_modules[TMM_CUDA_PACKET_BATCHER].Func = SCCudaPBBatchPackets; tmm_modules[TMM_CUDA_PACKET_BATCHER].ThreadExitPrintStats = SCCudaPBThreadExitStats; tmm_modules[TMM_CUDA_PACKET_BATCHER].ThreadDeinit = SCCudaPBThreadDeInit; tmm_modules[TMM_CUDA_PACKET_BATCHER].RegisterTests = SCCudaPBRegisterTests; return; } /** * \brief The cuda batcher TM init function. * * \param tv The cuda packet batcher TM ThreadVars instance. * \param initdata The initialization data needed by this cuda batcher TM. * \param data Pointer to a ponter memory location that would be updated * with the newly created thread ctx instance. * * \retval TM_ECODE_OK On success. * \retval TM_ECODE_FAILED On failure. */ TmEcode SCCudaPBThreadInit(ThreadVars *tv, void *initdata, void **data) { SCCudaPBThreadCtx *tctx = NULL; if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid argument. initdata NULL " "for the cuda batcher TM init thread function"); return TM_ECODE_FAILED; } tctx = SCMalloc(sizeof(SCCudaPBThreadCtx)); if (unlikely(tctx == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } memset(tctx, 0, sizeof(SCCudaPBThreadCtx)); /* the detection engine context. We will need it to retrieve the sgh, * when we start receiving and batching the packets */ tctx->de_ctx = initdata; /* the first packet buffer from the queue */ tctx->curr_pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(&data_queues[tmq_inq->id]); /* register new module */ SCCudaHlRegisterModule("SC_CUDA_PACKET_BATCHER"); *data = tctx; /* we will need the cuda packet batcher TM's inq for further use later. Read * the comments associated with this var definition, for its use */ tmq_batcher_inq = tv->inq; /* set the SIG_ALRM handler */ SCCudaPBSetBatcherAlarmTimeHandler(); /* Set the alarm time limit during which the batcher thread would * buffer packets */ SCCudaPBResetBatcherAlarm(); return TM_ECODE_OK; } /** * \brief Batches packets into the packets buffer. * * \param tv Pointer to the ThreadVars instance, in this case the cuda packet * batcher TM's TV instance. * \param p Pointer the the packet to be buffered. * \param data Pointer the the batcher TM thread ctx. * \param pq Pointer to the packetqueue. We don't need this. * * \retval TM_ECODE_OK On success. * \retval TM_ECODE_FAILED On failure. */ TmEcode SCCudaPBBatchPackets(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *post_pq) { #define ALIGN_UP(offset, alignment) \ (offset) = ((offset) + (alignment) - 1) & ~((alignment) - 1) SCCudaPBThreadCtx *tctx = data; /* ah. we have been signalled that we crossed the time limit within which we * need to buffer packets. Let us queue the buffer to the GPU */ if (queue_buffer) { SCLogDebug("Cuda packet buffer TIME limit exceeded. Buffering packet " "buffer and reseting the alarm"); SCCudaPBQueueBuffer(tctx); SCCudaPBResetBatcherAlarm(); } /* this is possible, since we are using a custom slot function that calls this * function, even if it receives no packet from the packet queue */ if (p == NULL) { SCLogDebug("packet NULL inside Cuda batcher TM"); return TM_ECODE_OK; } /* we set it for every incoming packet. We will set this depending on whether * we end up buffering the packet or not */ p->cuda_mpm_enabled = 0; /* packets that are too big are handled by the cpu */ if (p->payload_len > SC_CUDA_PB_MAX_PAYLOAD_SIZE) { SCLogDebug("p->payload_len %"PRIu16" > %d, inspecting on the CPU.", p->payload_len, SC_CUDA_PB_MAX_PAYLOAD_SIZE); return TM_ECODE_OK; } /* the packets buffer */ SCCudaPBPacketsBuffer *pb = (SCCudaPBPacketsBuffer *)tctx->curr_pb; /* the previous packet which has been buffered into the packets_buffer */ SCCudaPBPacketDataForGPU *prev_buff_packet = NULL; /* holds the position in the packets_buffer where the curr packet would * be buffered in */ SCCudaPBPacketDataForGPU *curr_packet = NULL; /* the sgh to which the incoming packet belongs */ SigGroupHead *sgh = NULL; if (p->flow != NULL) { /* Get the stored sgh from the flow (if any). Make sure we're not using * the sgh for icmp error packets part of the same stream. */ if (p->proto == p->flow->proto) { /* filter out icmp */ if (p->flowflags & FLOW_PKT_TOSERVER && p->flow->flags & FLOW_SGH_TOSERVER) { sgh = p->flow->sgh_toserver; } else if (p->flowflags & FLOW_PKT_TOCLIENT && p->flow->flags & FLOW_SGH_TOCLIENT) { sgh = p->flow->sgh_toclient; } } } if (sgh == NULL) { /* get the signature group head to which this packet belongs. If it belongs * to no sgh, we don't need to buffer this packet. * \todo Get rid of this, once we get the sgh from the flow */ sgh = SCCudaPBGetSgh(tctx->de_ctx, p); if (sgh == NULL) { SCLogDebug("No SigGroupHead match for this packet"); return TM_ECODE_OK; } } /* if the payload is less than the maximum content length in this sgh we * don't need to run the PM on this packet. Chuck the packet out */ if (sgh->mpm_content_maxlen > p->payload_len) { SCLogDebug("not mpm-inspecting as pkt payload is smaller than " "the largest content length we need to match"); return TM_ECODE_OK; } MpmCtx *mpm_ctx = NULL; if (p->proto == IPPROTO_TCP) { if (p->flowflags & FLOW_PKT_TOSERVER) mpm_ctx = sgh->mpm_proto_tcp_ctx_ts; else mpm_ctx = sgh->mpm_proto_tcp_ctx_tc; } else if (p->proto == IPPROTO_UDP) { if (p->flowflags & FLOW_PKT_TOSERVER) mpm_ctx = sgh->mpm_proto_udp_ctx_ts; else mpm_ctx = sgh->mpm_proto_udp_ctx_tc; } else { mpm_ctx = sgh->mpm_proto_other_ctx; } /* if one of these conditions fail we don't have to run the mpm on this * packet. Firstly if the payload_len is == 0, we don't have a payload * to match against. Next if we don't have a mpm_context against this * sgh, indicating we don't have any patterns in this sgh, again we don't * have anything to run the PM against. Finally if the flow doesn't want * to analyze packets for this flow, we can chuck this packet out as well */ if ( !(p->payload_len > 0 && mpm_ctx != NULL && !(p->flags & PKT_NOPAYLOAD_INSPECTION)) ) { SCLogDebug("Either p->payload_len <= 0 or mpm_ctx for the packet is NULL " "or PKT_NOPAYLOAD_INSPECTION set for this packet"); return TM_ECODE_OK; } /* the cuda b2g context */ B2gCudaCtx *ctx = mpm_ctx->ctx; /* if we have a 1 byte search kernel set we don't buffer this packet for * cuda matching and instead run this non-cuda mpm function to be run on * the packet */ if (ctx->Search == B2gCudaSearch1) { SCLogDebug("The packet has a one byte patterns. run mpm " "separately"); return TM_ECODE_OK; } #ifdef B2G_CUDA_SEARCH2 /* if we have a 2 byte search kernel set we don't buffer this packet for * cuda matching and instead run this non-cuda mpm function to be run on the * packet */ if (ctx->Search == B2gCudaSearch2) { SCLogDebug("The packet has two byte patterns. run mpm " "separately"); return TM_ECODE_OK; } #endif /* we have passed all the criterions for buffering the packet. Set the * flag indicating that the packet goes through cuda mpm */ p->cuda_mpm_enabled = 1; /* first packet to be buffered in */ if (pb->nop_in_buffer == 0) { curr_packet = (SCCudaPBPacketDataForGPU *)pb->packets_buffer; /* buffer is not empty */ } else { prev_buff_packet = (SCCudaPBPacketDataForGPU *)(pb->packets_buffer + pb->packets_offset_buffer[pb->nop_in_buffer - 1]); curr_packet = (SCCudaPBPacketDataForGPU *)((uint8_t *)prev_buff_packet + sizeof(SCCudaPBPacketDataForGPUNonPayload) + prev_buff_packet->payload_len) ; int diff = (int)((uint8_t *)curr_packet - pb->packets_buffer); /* \todo Feel it is the wrong option taken by nvidia by setting CUdeviceptr * to unsigned int. Keep this option for now. We will get back to this * once nvidia responds to the filed bug */ ALIGN_UP(diff, sizeof(CUdeviceptr)); curr_packet = (SCCudaPBPacketDataForGPU *)(pb->packets_buffer + diff); } /* store the data in the packets_buffer for this packet, which would be passed * over to the GPU for processing */ curr_packet->m = ((B2gCudaCtx *)(mpm_ctx->ctx))->m; curr_packet->table = ((B2gCudaCtx *)(mpm_ctx->ctx))->cuda_B2G; curr_packet->payload_len = p->payload_len; memcpy(curr_packet->payload, p->payload, p->payload_len); /* store the address of the packet just buffered at the same index. The * dispatcher thread will need this address to communicate the results back * to the packet */ pb->packets_address_buffer[pb->nop_in_buffer] = p; /* if it is the first packet to be buffered, the offset is 0. If it is not, * then take the offset for the buffer from curr_packet */ if (pb->nop_in_buffer == 0) { pb->packets_offset_buffer[pb->nop_in_buffer] = 0; pb->packets_payload_offset_buffer[pb->nop_in_buffer] = 0; } else { pb->packets_offset_buffer[pb->nop_in_buffer] = (uint8_t *)curr_packet - pb->packets_buffer; pb->packets_payload_offset_buffer[pb->nop_in_buffer] = pb->packets_payload_offset_buffer[pb->nop_in_buffer - 1] + prev_buff_packet->payload_len; } /* indicates the no of packets added so far into the buffer */ pb->nop_in_buffer++; /* we have hit the threshhold for the total no of packets held in the buffer. * We will change this in the future, instead relying on the remaining space * left in the buffer or we have been informed that we have hit the time limit * to queue the buffer */ if ( (pb->nop_in_buffer == buffer_packet_threshhold) || queue_buffer) { SCLogDebug("Either we have hit the threshold limit for packets(i.e. we " "have %d packets limit) OR we have exceeded the buffering " "time limit. Buffering the packet buffer and reseting the " "alarm.", buffer_packet_threshhold); SCCudaPBQueueBuffer(tctx); SCCudaPBResetBatcherAlarm(); } return TM_ECODE_OK; } void SCCudaPBThreadExitStats(ThreadVars *tv, void *data) { return; } /** * \brief The thread de-init function for the cuda packet batcher TM. * * \param tv Pointer to the cuda packet batcher TM ThreadVars instance. * \param data Pointer the the Thread ctx for the cuda packet batcher TM. * * \retval TM_ECODE_OK On success. * \retval TM_ECODE_FAILED On failure. Although we won't be returning this here. */ TmEcode SCCudaPBThreadDeInit(ThreadVars *tv, void *data) { SCCudaPBThreadCtx *tctx = data; if (tctx != NULL) { if (tctx->curr_pb != NULL) { if (SCCudaHlPushCudaContextFromModule("SC_CUDA_PACKET_BATCHER") == -1){ SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Failed to push cuda context from module"); } SCCudaPBDeAllocSCCudaPBPacketsBuffer(tctx->curr_pb); tctx->curr_pb = NULL; if (SCCudaCtxPopCurrent(NULL) == -1){ SCLogError(SC_ERR_CUDA_ERROR, "Failed to pop cuda context"); } if (SCCudaHlDeRegisterModule("SC_CUDA_PACKET_BATCHER") == -1){ SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Failed to deregister module"); } } SCFree(tctx); } return TM_ECODE_OK; } /** * \brief Sets up the queues and buffers needed by the cuda batcher TM function. */ void SCCudaPBSetUpQueuesAndBuffers(void) { /* the b2g dispatcher thread would have to use the reverse for incoming * and outgoing queues */ char *inq_name = "cuda_batcher_mpm_inqueue"; char *outq_name = "cuda_batcher_mpm_outqueue"; int i = 0; /* set the incoming queue for the cuda_packet_batcher TM and the cuda B2g * dispatcher */ tmq_inq = TmqGetQueueByName(inq_name); if (tmq_inq == NULL) { tmq_inq = TmqCreateQueue(inq_name); if (tmq_inq == NULL) { return; } } tmq_inq->reader_cnt++; tmq_inq->writer_cnt++; /* set the outgoing queue from the cuda_packet_batcher TM and the cuda B2g * dispatcher */ tmq_outq = TmqGetQueueByName(outq_name); if (tmq_outq == NULL) { tmq_outq = TmqCreateQueue(outq_name); if (tmq_outq == NULL) { return; } } tmq_outq->reader_cnt++; tmq_outq->writer_cnt++; /* Register a new module to be used by the packet batcher to allocate * page-locked memory */ SCCudaHlRegisterModule("SC_CUDA_PACKET_BATCHER"); profile = SCCudaHlGetProfile("mpm"); /* allocate the packet buffer */ /* \todo need to work out the right no of packet buffers that we need to * queue. I doubt we will need more than 4(as long as we don't run it on * low traffic line). We don't want to get into the business of creating * new ones, when we run out of buffers, since malloc for a huge chunk * like this will take time. We need to figure out a value based on * various other parameters like alarm time and buffer threshold value */ for (i = 0; i < profile->packet_buffers; i++) { if (profile->page_locked) { SCLogDebug("Allocating \"%d\" page_locked cuda packet buffers", profile->packet_buffers); } else { SCLogDebug("Allocating \"%d\" non-page_locked cuda packet buffers", profile->packet_buffers); } SCCudaPBPacketsBuffer *pb = SCCudaPBAllocSCCudaPBPacketsBuffer(); /* dump the buffer into the inqueue for this batcher TM. the batcher * thread would be the first consumer for these buffers */ SCDQDataEnqueue(&data_queues[tmq_inq->id], (SCDQGenericQData *)pb); } /* \todo This needs to be changed ASAP. This can't exceed max_pending_packets. * Also we need to make this user configurable and allow dynamic updaes * based on live traffic */ buffer_packet_threshhold = profile->packet_buffer_limit; return; } /** * \brief Clean up all the buffers queued in. Need to write more on this. */ void SCCudaPBCleanUpQueuesAndBuffers(void) { SCCudaPBPacketsBuffer *pb = NULL; SCDQDataQueue *dq = NULL; if (tmq_inq == NULL || tmq_outq == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments. tmq_inq or " "tmq_outq NULL"); return; } if (SCCudaHlPushCudaContextFromModule("SC_CUDA_PACKET_BATCHER") == -1){ SCLogError(SC_ERR_CUDA_HANDLER_ERROR, "Could not push cuda context from module"); } /* clean all the buffers present in the inq */ dq = &data_queues[tmq_inq->id]; SCMutexLock(&dq->mutex_q); while ( (pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(dq)) != NULL) { if (pb->packets_buffer != NULL) { if (profile->page_locked) { if (SCCudaMemFreeHost(pb->packets_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "packets_buffer"); } } else { SCFree(pb->packets_buffer); } } if (pb->packets_offset_buffer != NULL) { if (profile->page_locked) { if (SCCudaMemFreeHost(pb->packets_offset_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "packets_offset_buffer"); } } else { SCFree(pb->packets_offset_buffer); } } if (pb->packets_payload_offset_buffer != NULL) { if (profile->page_locked) { if (SCCudaMemFreeHost(pb->packets_payload_offset_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "packets_payload_offset_buffer"); } } else { SCFree(pb->packets_payload_offset_buffer); } } SCFree(pb); } SCMutexUnlock(&dq->mutex_q); SCCondSignal(&dq->cond_q); /* clean all the buffers present in the outq */ dq = &data_queues[tmq_outq->id]; SCMutexLock(&dq->mutex_q); while ( (pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(dq)) != NULL) { if (pb->packets_buffer != NULL) { if (SCCudaMemFreeHost(pb->packets_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "packets_buffer"); } } if (pb->packets_offset_buffer != NULL) { if (SCCudaMemFreeHost(pb->packets_offset_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "packets_offset_buffer"); } } if (pb->packets_payload_offset_buffer != NULL) { if (SCCudaMemFreeHost(pb->packets_payload_offset_buffer) == -1) { SCLogError(SC_ERR_CUDA_ERROR, "Error deallocating pagelocked memory: " "packets_payload_offset_buffer"); } } SCFree(pb); } if (SCCudaCtxPopCurrent(NULL) == -1){ SCLogError(SC_ERR_CUDA_ERROR, "Could not pop cuda context"); } SCMutexUnlock(&dq->mutex_q); SCCondSignal(&dq->cond_q); return; } /** * \brief Function used to set the packet threshhold limit in the packets buffer. * * \param threshhold_override The threshhold limit for the packets_buffer. */ void SCCudaPBSetBufferPacketThreshhold(uint32_t threshhold_override) { buffer_packet_threshhold = threshhold_override; return; } /** * \brief Function used to set the profile for cuda packet batcher. Used * for unittests alone. */ void SCCudaPBSetProfile(char *profile_name) { profile = SCCudaHlGetProfile("mpm"); return; } /** * \brief Used to inform the cuda packet batcher that packet batching shouldn't * be done anymore and set the flag to indicate this. We also need to * signal the cuda batcher data inq, in case it is waiting on the inq * for a new free packet buffer. */ void SCCudaPBKillBatchingPackets(void) { run_batcher = 0; SCDQDataQueue *dq = &data_queues[tmq_inq->id]; SCCondSignal(&dq->cond_q); return; } void SCCudaPBRunningTests(int status) { unittest_mode = status; } /***********************************Unittests**********************************/ #ifdef UNITTESTS int SCCudaPBTest01(void) { #define ALIGN_UP(offset, alignment) \ (offset) = ((offset) + (alignment) - 1) & ~((alignment) - 1) uint8_t raw_eth[] = { 0x00, 0x25, 0x00, 0x9e, 0xfa, 0xfe, 0x00, 0x02, 0xcf, 0x74, 0xfe, 0xe1, 0x08, 0x00, 0x45, 0x00, 0x01, 0xcc, 0xcb, 0x91, 0x00, 0x00, 0x34, 0x06, 0xdf, 0xa8, 0xd1, 0x55, 0xe3, 0x67, 0xc0, 0xa8, 0x64, 0x8c, 0x00, 0x50, 0xc0, 0xb7, 0xd1, 0x11, 0xed, 0x63, 0x81, 0xa9, 0x9a, 0x05, 0x80, 0x18, 0x00, 0x75, 0x0a, 0xdd, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x09, 0x8a, 0x06, 0xd0, 0x12, 0x21, 0x2a, 0x3b, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x33, 0x30, 0x32, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x30, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x67, 0x77, 0x73, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x31, 0x38, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x65, 0x71, 0x75, 0x69, 0x76, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x0a, 0x3c, 0x48, 0x31, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x31, 0x3e, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x0a, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x41, 0x3e, 0x2e, 0x0d, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0d, 0x0a }; int result = 0; SCCudaPBThreadCtx *tctx = NULL; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars tv; ThreadVars tv_cuda_PB; DetectEngineCtx *de_ctx = NULL; SCCudaPBPacketsBuffer *pb = NULL; SCCudaPBPacketDataForGPU *buff_packet = NULL; SCDQDataQueue *dq = NULL; uint32_t i = 0; char *strings[] = {"test_one", "test_two", "test_three", "test_four", "test_five", "test_six", "test_seven", "test_eight", "test_nine", "test_ten"}; uint32_t packets_payload_offset_buffer[sizeof(strings)/sizeof(char *)]; memset(packets_payload_offset_buffer, 0, sizeof(packets_payload_offset_buffer)); uint32_t packets_offset_buffer[sizeof(strings)/sizeof(char *)]; memset(packets_offset_buffer, 0, sizeof(packets_offset_buffer)); uint32_t packets_total_payload_len = 0; uint32_t packets_buffer_len = 0; for (i = 0; i < sizeof(strings)/sizeof(char *); i++) { packets_total_payload_len += strlen(strings[i]); } for (i = 1; i < sizeof(strings)/sizeof(char *); i++) { packets_payload_offset_buffer[i] = packets_payload_offset_buffer[i - 1] + strlen(strings[i - 1]); packets_offset_buffer[i] = packets_offset_buffer[i - 1] + sizeof(SCCudaPBPacketDataForGPUNonPayload) + strlen(strings[i - 1]); ALIGN_UP(packets_offset_buffer[i], sizeof(CUdeviceptr)); } packets_buffer_len += packets_offset_buffer[(sizeof(strings)/sizeof(char *)) - 1] + sizeof(SCCudaPBPacketDataForGPUNonPayload) + strlen(strings[(sizeof(strings)/sizeof(char *)) - 1]); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&tv_cuda_PB, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth), NULL); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G_CUDA; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Bamboo\"; " "content:\"test\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("signature parsing failed\n"); goto end; } SigGroupBuild(de_ctx); result = 1; SCCudaPBSetUpQueuesAndBuffers(); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 10); SCCudaPBRunningTests(1); SCCudaPBThreadInit(&tv_cuda_PB, de_ctx, (void *)&tctx); SCCudaPBSetBufferPacketThreshhold(sizeof(strings)/sizeof(char *)); p->payload = (uint8_t *)strings[0]; p->payload_len = strlen(strings[0]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[1]; p->payload_len = strlen(strings[1]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[2]; p->payload_len = strlen(strings[2]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[3]; p->payload_len = strlen(strings[3]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[4]; p->payload_len = strlen(strings[4]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[5]; p->payload_len = strlen(strings[5]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[6]; p->payload_len = strlen(strings[6]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[7]; p->payload_len = strlen(strings[7]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[8]; p->payload_len = strlen(strings[8]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); p->payload = (uint8_t *)strings[9]; p->payload_len = strlen(strings[9]); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 1); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 8); dq = &data_queues[tmq_outq->id]; pb = (SCCudaPBPacketsBuffer *)SCDQDataDequeue(dq); if (pb == NULL) { result = 0; goto end; } result &= (dq->len == 0); result &= (pb->nop_in_buffer == 10); if (result == 0) goto end; for (i = 0; i < pb->nop_in_buffer; i++) { buff_packet = (SCCudaPBPacketDataForGPU *)(pb->packets_buffer + pb->packets_offset_buffer[i]); result &= (strlen(strings[i]) == buff_packet->payload_len); result &= (memcmp(strings[i], buff_packet->payload, buff_packet->payload_len) == 0); if (result == 0) goto end; result &= (packets_payload_offset_buffer[i] == pb->packets_payload_offset_buffer[i]); result &= (packets_offset_buffer[i] == pb->packets_offset_buffer[i]); } result &= (packets_total_payload_len == pb->packets_total_payload_len); result &= (packets_buffer_len == pb->packets_buffer_len); end: SCCudaPBCleanUpQueuesAndBuffers(); if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } SCCudaPBThreadDeInit(NULL, tctx); SCFree(p); return result; } int SCCudaPBTest02(void) { uint8_t raw_eth[] = { 0x00, 0x25, 0x00, 0x9e, 0xfa, 0xfe, 0x00, 0x02, 0xcf, 0x74, 0xfe, 0xe1, 0x08, 0x00, 0x45, 0x00, 0x01, 0xcc, 0xcb, 0x91, 0x00, 0x00, 0x34, 0x06, 0xdf, 0xa8, 0xd1, 0x55, 0xe3, 0x67, 0xc0, 0xa8, 0x64, 0x8c, 0x00, 0x50, 0xc0, 0xb7, 0xd1, 0x11, 0xed, 0x63, 0x81, 0xa9, 0x9a, 0x05, 0x80, 0x18, 0x00, 0x75, 0x0a, 0xdd, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x09, 0x8a, 0x06, 0xd0, 0x12, 0x21, 0x2a, 0x3b, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x33, 0x30, 0x32, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x31, 0x34, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x30, 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x67, 0x77, 0x73, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x31, 0x38, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x65, 0x71, 0x75, 0x69, 0x76, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x0a, 0x3c, 0x48, 0x31, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x48, 0x31, 0x3e, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x0a, 0x3c, 0x41, 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x41, 0x3e, 0x2e, 0x0d, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0d, 0x0a }; int result = 0; const char *string = NULL; SCCudaPBThreadCtx *tctx = NULL; Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; DecodeThreadVars dtv; ThreadVars tv; ThreadVars tv_cuda_PB; DetectEngineCtx *de_ctx = NULL; SCCudaPBPacketsBuffer *pb = NULL; SCDQDataQueue *dq = NULL; memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&tv, 0, sizeof(ThreadVars)); memset(&tv_cuda_PB, 0, sizeof(ThreadVars)); FlowInitConfig(FLOW_QUIET); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth), NULL); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->mpm_matcher = MPM_B2G_CUDA; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any 5555 -> any any (msg:\"Bamboo\"; " "content:\"test\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("signature parsing failed\n"); goto end; } SigGroupBuild(de_ctx); SCCudaPBSetUpQueuesAndBuffers(); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 10); SCCudaPBRunningTests(1); SCCudaPBThreadInit(&tv_cuda_PB, de_ctx, (void *)&tctx); result = 1; string = "test_one"; p->payload = (uint8_t *)string; p->payload_len = strlen(string); SCCudaPBBatchPackets(NULL, p, tctx, NULL, NULL); dq = &data_queues[tmq_outq->id]; result &= (dq->len == 0); dq = &data_queues[tmq_inq->id]; result &= (dq->len == 9); pb = tctx->curr_pb; result &= (pb->nop_in_buffer == 0); end: SCCudaPBCleanUpQueuesAndBuffers(); if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); } SCCudaPBThreadDeInit(NULL, tctx); SCFree(p); return result; } #endif /* UNITTESTS */ void SCCudaPBRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCCudaPBTest01", SCCudaPBTest01, 1); UtRegisterTest("SCCudaPBTest02", SCCudaPBTest02, 1); #endif return; } #endif /* __SC_CUDA_SUPPORT__ */ suricata-1.4.7/src/util-var.c0000644000000000000000000000543412253546156012742 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien * * Generic variable utility functions */ #include "suricata-common.h" #include "detect.h" #include "util-var.h" #include "flow-var.h" #include "flow-bit.h" #include "flow-alert-sid.h" #include "pkt-var.h" #include "util-debug.h" void GenericVarFree(GenericVar *gv) { if (gv == NULL) return; SCLogDebug("gv %p, gv->type %" PRIu32 "", gv, gv->type); GenericVar *next_gv = gv->next; switch (gv->type) { case DETECT_FLOWBITS: { FlowBit *fb = (FlowBit *)gv; //printf("GenericVarFree: fb %p, removing\n", fb); FlowBitFree(fb); break; } case DETECT_FLOWALERTSID: { FlowAlertSid *fb = (FlowAlertSid *)gv; SCLogDebug("fb %p, removing", fb); FlowAlertSidFree(fb); break; } case DETECT_FLOWVAR: { FlowVar *fv = (FlowVar *)gv; FlowVarFree(fv); break; } case DETECT_PKTVAR: { PktVar *pv = (PktVar *)gv; PktVarFree(pv); break; } default: { printf("ERROR: GenericVarFree unknown type %" PRIu32 "\n", gv->type); break; } } GenericVarFree(next_gv); } void GenericVarAppend(GenericVar **list, GenericVar *gv) { gv->next = NULL; if (*list == NULL) { *list = gv; } else { GenericVar *tgv = *list; while(tgv) { if (tgv->next == NULL) { tgv->next = gv; return; } tgv = tgv->next; } } } void GenericVarRemove(GenericVar **list, GenericVar *gv) { if (*list == NULL) return; GenericVar *listgv = *list, *prevgv = NULL; while (listgv != NULL) { if (listgv == gv) { if (prevgv == NULL) *list = gv->next; else prevgv->next = gv->next; return; } prevgv = listgv; listgv = listgv->next; } } suricata-1.4.7/src/detect-rawbytes.h0000644000000000000000000000164712253546156014314 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_RAWBYTES_H__ #define __DETECT_RAWBYTES_H__ /* prototypes */ void DetectRawbytesRegister (void); #endif /* __DETECT_RAWBYTES_H__ */ suricata-1.4.7/src/detect-engine-file.c0000644000000000000000000001613512253546156014627 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #include "suricata-common.h" #include "decode.h" #include "detect.h" #include "detect-engine.h" #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-filestore.h" #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" #include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" #include "detect-engine-hrud.h" #include "detect-engine-dcepayload.h" #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "app-layer-parser.h" #include "app-layer-protos.h" #include "app-layer-htp.h" #include "app-layer-smb.h" #include "app-layer-dcerpc-common.h" #include "app-layer-dcerpc.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "util-profiling.h" /** * \brief Inspect the file inspecting keywords. * * \param tv thread vars * \param det_ctx detection engine thread ctx * \param f flow * \param s signature to inspect * * \retval 0 no match * \retval 1 match * \retval 2 can't match * \retval 3 can't match filestore signature * * \note flow is not locked at this time */ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Flow *f, Signature *s, uint8_t flags, FileContainer *ffc) { SigMatch *sm = NULL; int r = 0; int match = 0; int store_r = 0; SCLogDebug("file inspection... %p", ffc); if (ffc != NULL) { File *file = ffc->head; for (; file != NULL; file = file->next) { SCLogDebug("file"); if (file->state == FILE_STATE_NONE) { SCLogDebug("file state FILE_STATE_NONE"); continue; } if (file->txid < det_ctx->tx_id) { SCLogDebug("file->txid < det_ctx->tx_id == %u < %u", file->txid, det_ctx->tx_id); continue; } if (file->txid > det_ctx->tx_id) { SCLogDebug("file->txid > det_ctx->tx_id == %u > %u", file->txid, det_ctx->tx_id); break; } if ((s->file_flags & FILE_SIG_NEED_FILENAME) && file->name == NULL) { SCLogDebug("sig needs filename, but we don't have any"); r = 0; break; } if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file->chunks_head == NULL) { SCLogDebug("sig needs file content, but we don't have any"); r = 0; break; } if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file->chunks_head == NULL) { SCLogDebug("sig needs file content, but we don't have any"); r = 0; break; } if ((s->file_flags & FILE_SIG_NEED_MD5) && (!(file->flags & FILE_MD5))) { SCLogDebug("sig needs file md5, but we don't have any"); r = 0; break; } if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) { SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED"); r = 0; break; } /* run the file match functions. */ for (sm = s->sm_lists[DETECT_SM_LIST_FILEMATCH]; sm != NULL; sm = sm->next) { SCLogDebug("sm %p, sm->next %p", sm, sm->next); if (sigmatch_table[sm->type].FileMatch != NULL) { match = sigmatch_table[sm->type]. FileMatch(tv, det_ctx, f, flags, file, s, sm); if (match == 0) { r = 2; break; } else if (sm->next == NULL) { r = 1; break; } } } /* continue inspection for other files as we may want to store * those as well. We'll return 1 (match) regardless of their * results though */ if (r == 1) store_r = 1; /* if this is a filestore sig, and the sig can't match * return 3 so we can distinguish */ if ((s->flags & SIG_FLAG_FILESTORE) && r == 2) r = 3; /* continue, this file may (or may not) be unable to match * maybe we have more that can :) */ } } else { /* if we have a filestore sm with a scope > file (so tx, ssn) we * run it here */ sm = s->sm_lists[DETECT_SM_LIST_FILEMATCH]; if (sm != NULL && sm->next == NULL && sm->type == DETECT_FILESTORE && sm->ctx != NULL) { DetectFilestoreData *fd = sm->ctx; if (fd->scope > FILESTORE_SCOPE_DEFAULT) { match = sigmatch_table[sm->type]. FileMatch(tv, det_ctx, f, flags, /* no file */NULL, s, sm); if (match == 1) { r = 1; } } } } if (store_r == 1) r = 1; SCReturnInt(r); } /** * \brief Inspect the file inspecting keywords against the HTTP transactions. * * \param tv thread vars * \param det_ctx detection engine thread ctx * \param f flow * \param s signature to inspect * \param alstate state * \param flags direction flag * * \retval 0 no match * \retval 1 match * \retval 2 can't match * \retval 3 can't match filestore signature * * \note flow should be locked when this function's called. */ int DetectFileInspectHttp(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, void *alstate, int tx_id) { int r = 0; FileContainer *ffc; HtpState *htp_state = (HtpState *)alstate; if (flags & STREAM_TOCLIENT) ffc = htp_state->files_tc; else ffc = htp_state->files_ts; /* inspect files for this transaction */ det_ctx->tx_id = (uint16_t)tx_id; int match = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); if (match == 1) { r = 1; } else if (match == 2) { if (r != 1) { SCLogDebug("sid %u can't match on this transaction", s->id); r = 2; } } else if (match == 3) { if (r != 1) { SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); r = 3; } } return r; } suricata-1.4.7/src/data-queue.h0000644000000000000000000000412112253546156013227 00000000000000/** * Copyright (c) 2009, 2010 Open Information Security Foundation. * * \author Anoop Saldanha * * \file Generic queues. Any instance that wants to get itself on the generic * queue, would have to implement the template struct SCDQGenericQData_ * defined below. */ #ifndef __DATA_QUEUE_H__ #define __DATA_QUEUE_H__ #include "threads.h" /** * \brief Generic template for any data structure that wants to be on the * queue. Any other data structure that wants to be on the queue * needs to use this template and define its own members from * onwards. */ typedef struct SCDQGenericQData_ { /* this is needed when we want to supply a list of data items */ struct SCDQGenericQData_ *next; struct SCDQGenericQData_ *prev; /* if we want to consider this pointer as the head of a list, this var * holds the no of elements in the list. Else it holds a . */ //uint16_t len; /* in case this data instance is the head of a list, we can refer the * bottomost instance directly using this var */ //struct SCDQGenericaQData *bot; /* any other data structure that wants to be on the queue can implement * its own memebers from here on, in its structure definition. Just note * that the first 2 members should always be next and prev in the same * order */ // } SCDQGenericQData; /** * \brief The data queue to hold instances that implement the template * SCDQGenericQData. */ typedef struct SCDQDataQueue_ { /* holds the item at the top of the queue */ SCDQGenericQData *top; /* holds the item at the bottom of the queue */ SCDQGenericQData *bot; /* no of items currently in the queue */ uint16_t len; #ifdef DBG_PERF uint16_t dbg_maxlen; #endif /* DBG_PERF */ SCMutex mutex_q; SCCondT cond_q; } SCDQDataQueue; void SCDQDataEnqueue(SCDQDataQueue *, SCDQGenericQData *); SCDQGenericQData *SCDQDataDequeue(SCDQDataQueue *); #endif /* __DATA_QUEUE_H__ */ suricata-1.4.7/src/log-droplog.h0000644000000000000000000000162712253546156013431 00000000000000/* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Gurvinder Singh * */ #ifndef ALERT_DROPLOG_H #define ALERT_DROPLOG_H void TmModuleLogDropLogRegister(void); #endif /* ALERT_DROPLOG_H */ suricata-1.4.7/src/source-nfq.h0000644000000000000000000000444412253546156013266 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __SOURCE_NFQ_H__ #define __SOURCE_NFQ_H__ #ifdef NFQ #include "threads.h" #ifdef OS_WIN32 #include #else #include /* for NF_ACCEPT */ #endif #include #define NFQ_MAX_QUEUE 16 /* idea: set the recv-thread id in the packet to * select an verdict-queue */ typedef struct NFQPacketVars_ { int id; /* this nfq packets id */ uint16_t nfq_index; /* index in NFQ array */ uint32_t mark; uint32_t ifi; uint32_t ifo; uint16_t hw_protocol; } NFQPacketVars; typedef struct NFQQueueVars_ { struct nfq_handle *h; #ifndef OS_WIN32 struct nfnl_handle *nh; int fd; #else HANDLE fd; OVERLAPPED ovr; #endif uint8_t use_mutex; /* 2 threads deal with the queue handle, so add a mutex */ struct nfq_q_handle *qh; SCMutex mutex_qh; /* this one should be not changing after init */ uint16_t queue_num; /* position into the NFQ queue var array */ uint16_t nfq_index; #ifdef DBG_PERF int dbg_maxreadsize; #endif /* DBG_PERF */ /* counters */ uint32_t pkts; uint64_t bytes; uint32_t errs; uint32_t accepted; uint32_t dropped; uint32_t replaced; } NFQQueueVars; typedef struct NFQGlobalVars_ { char unbind; } NFQGlobalVars; void NFQInitConfig(char quiet); int NFQRegisterQueue(char *queue); int NFQGetQueueCount(void); void *NFQGetQueue(int number); int NFQGetQueueNum(int number); void *NFQGetThread(int number); #endif /* NFQ */ #endif /* __SOURCE_NFQ_H__ */ suricata-1.4.7/src/detect-engine.h0000644000000000000000000000703612253546156013717 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DETECT_ENGINE_H__ #define __DETECT_ENGINE_H__ #include "detect.h" #include "tm-threads.h" typedef struct DetectEngineAppInspectionEngine_ { uint16_t alproto; uint16_t dir; int32_t sm_list; uint32_t inspect_flags; uint32_t match_flags; int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, int32_t tx_id); struct DetectEngineAppInspectionEngine_ *next; } DetectEngineAppInspectionEngine; extern DetectEngineAppInspectionEngine *app_inspection_engine[ALPROTO_MAX][2]; /* prototypes */ void DetectEngineRegisterAppInspectionEngines(void); void DetectEngineSpawnLiveRuleSwapMgmtThread(void); DetectEngineCtx *DetectEngineCtxInit(void); DetectEngineCtx *DetectEngineGetGlobalDeCtx(void); void DetectEngineCtxFree(DetectEngineCtx *); TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *); /* faster as a macro than a inline function on my box -- VJ */ #define DetectEngineGetMaxSigId(de_ctx) ((de_ctx)->signum) void DetectEngineResetMaxSigId(DetectEngineCtx *); void DetectEngineRegisterTests(void); /** * \brief Registers an app inspection engine. * * \param alproto App layer protocol for which we will register the engine. * \param direction The direction for the engine. 0 - toserver; 1- toclient. * \param sm_list The SigMatch list against which the engine works. * \param inspect_flags The inspection flags to be used by de_state * against the engine. * \param match_flags The match flags to be used by de_state in tandem with * the inpsect_flags. * \param Callback The engine callback. */ void DetectEngineRegisterAppInspectionEngine(uint16_t alproto, uint16_t direction, int32_t sm_list, uint32_t inspect_flags, uint32_t match_flags, int (*Callback)(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Signature *sig, Flow *f, uint8_t flags, void *alstate, int32_t tx_id), DetectEngineAppInspectionEngine *list[][2]); #endif /* __DETECT_ENGINE_H__ */ suricata-1.4.7/src/debug.h0000644000000000000000000000156412253546156012272 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __DEBUG_H__ #define __DEBUG_H__ #ifdef DEBUG #endif /* DEBUG */ #endif /* __DEBUG_H__ */ suricata-1.4.7/src/tmqh-flow.h0000644000000000000000000000260212253546156013114 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __TMQH_FLOW_H__ #define __TMQH_FLOW_H__ typedef struct TmqhFlowMode_ { PacketQueue *q; SC_ATOMIC_DECLARE(uint64_t, total_packets); SC_ATOMIC_DECLARE(uint64_t, total_flows); } TmqhFlowMode; /** \brief Ctx for the flow queue handler * \param size number of queues to output to * \param queues array of queue id's this flow handler outputs to */ typedef struct TmqhFlowCtx_ { uint16_t size; uint16_t last; TmqhFlowMode *queues; SC_ATOMIC_DECLARE(uint16_t, round_robin_idx); } TmqhFlowCtx; void TmqhFlowRegister (void); void TmqhFlowRegisterTests(void); #endif /* __TMQH_FLOW_H__ */ suricata-1.4.7/src/flow.h0000644000000000000000000004000112253546156012140 00000000000000/* Copyright (C) 2007-2012 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Victor Julien */ #ifndef __FLOW_H__ #define __FLOW_H__ #include "decode.h" #include "util-var.h" #include "util-atomic.h" #include "detect-tag.h" #define FLOW_QUIET TRUE #define FLOW_VERBOSE FALSE #define TOSERVER 0 #define TOCLIENT 1 /* per flow flags */ /** At least on packet from the source address was seen */ #define FLOW_TO_SRC_SEEN 0x00000001 /** At least on packet from the destination address was seen */ #define FLOW_TO_DST_SEEN 0x00000002 // vacany 1x /** no magic on files in this flow */ #define FLOW_FILE_NO_MAGIC_TS 0x00000008 #define FLOW_FILE_NO_MAGIC_TC 0x00000010 /** Flow was inspected against IP-Only sigs in the toserver direction */ #define FLOW_TOSERVER_IPONLY_SET 0x00000020 /** Flow was inspected against IP-Only sigs in the toclient direction */ #define FLOW_TOCLIENT_IPONLY_SET 0x00000040 /** Packet belonging to this flow should not be inspected at all */ #define FLOW_NOPACKET_INSPECTION 0x00000080 /** Packet payloads belonging to this flow should not be inspected */ #define FLOW_NOPAYLOAD_INSPECTION 0x00000100 /** All packets in this flow should be dropped */ #define FLOW_ACTION_DROP 0x00000200 /** All packets in this flow should be accepted */ #define FLOW_ACTION_PASS 0x00000400 /** Sgh for toserver direction set (even if it's NULL) */ #define FLOW_SGH_TOSERVER 0x00000800 /** Sgh for toclient direction set (even if it's NULL) */ #define FLOW_SGH_TOCLIENT 0x00001000 /** packet to server direction has been logged in drop file (only in IPS mode) */ #define FLOW_TOSERVER_DROP_LOGGED 0x00002000 /** packet to client direction has been logged in drop file (only in IPS mode) */ #define FLOW_TOCLIENT_DROP_LOGGED 0x00004000 /** alproto detect done. Right now we need it only for udp */ #define FLOW_ALPROTO_DETECT_DONE 0x00008000 #define FLOW_NO_APPLAYER_INSPECTION 0x00010000 /** Pattern matcher alproto detection done */ #define FLOW_TS_PM_ALPROTO_DETECT_DONE 0x00020000 /** Probing parser alproto detection done */ #define FLOW_TS_PP_ALPROTO_DETECT_DONE 0x00040000 /** Both pattern matcher and probing parser alproto detection done */ #define FLOW_TS_PM_PP_ALPROTO_DETECT_DONE 0x00080000 /** Pattern matcher alproto detection done */ #define FLOW_TC_PM_ALPROTO_DETECT_DONE 0x00100000 /** Probing parser alproto detection done */ #define FLOW_TC_PP_ALPROTO_DETECT_DONE 0x00200000 /** Both pattern matcher and probing parser alproto detection done */ #define FLOW_TC_PM_PP_ALPROTO_DETECT_DONE 0x00400000 #define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00800000 /** even if the flow has files, don't store 'm */ #define FLOW_FILE_NO_STORE_TS 0x01000000 #define FLOW_FILE_NO_STORE_TC 0x02000000 /** flow is ipv4 */ #define FLOW_IPV4 0x04000000 /** flow is ipv6 */ #define FLOW_IPV6 0x08000000 /** no md5 on files in this flow */ #define FLOW_FILE_NO_MD5_TS 0x10000000 #define FLOW_FILE_NO_MD5_TC 0x20000000 /** no size tracking of files in this flow */ #define FLOW_FILE_NO_SIZE_TS 0x40000000 #define FLOW_FILE_NO_SIZE_TC 0x80000000 #define FLOW_IS_IPV4(f) \ (((f)->flags & FLOW_IPV4) == FLOW_IPV4) #define FLOW_IS_IPV6(f) \ (((f)->flags & FLOW_IPV6) == FLOW_IPV6) #define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa) do { \ (pa)->family = AF_INET; \ (pa)->addr_data32[0] = (fa)->addr_data32[0]; \ } while (0) #define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa) do { \ (pa)->family = AF_INET; \ (pa)->addr_data32[0] = (fa)->addr_data32[0]; \ (pa)->addr_data32[1] = (fa)->addr_data32[1]; \ (pa)->addr_data32[2] = (fa)->addr_data32[2]; \ (pa)->addr_data32[3] = (fa)->addr_data32[3]; \ } while (0) /* 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 FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, a) do { \ (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \ (a)->addr_data32[1] = 0; \ (a)->addr_data32[2] = 0; \ (a)->addr_data32[3] = 0; \ } while (0) #define FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, a) do { \ (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \ (a)->addr_data32[1] = 0; \ (a)->addr_data32[2] = 0; \ (a)->addr_data32[3] = 0; \ } while (0) /* clear the address structure by setting all fields to 0 */ #define FLOW_CLEAR_ADDR(a) do { \ (a)->addr_data32[0] = 0; \ (a)->addr_data32[1] = 0; \ (a)->addr_data32[2] = 0; \ (a)->addr_data32[3] = 0; \ } while (0) /* Set the IPv6 addressesinto the Addrs of the Packet. * Make sure p->ip6h is initialized and validated. */ #define FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, a) do { \ (a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \ (a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \ (a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \ (a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \ } while (0) #define FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, a) do { \ (a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \ (a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \ (a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \ (a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \ } while (0) /* pkt flow flags */ #define FLOW_PKT_TOSERVER 0x01 #define FLOW_PKT_TOCLIENT 0x02 #define FLOW_PKT_ESTABLISHED 0x04 #define FLOW_PKT_STATELESS 0x08 #define FLOW_PKT_TOSERVER_IPONLY_SET 0x10 #define FLOW_PKT_TOCLIENT_IPONLY_SET 0x20 /** \todo only used by flow keyword internally. */ #define FLOW_PKT_NOSTREAM 0x40 /** \todo only used by flow keyword internally. */ #define FLOW_PKT_ONLYSTREAM 0x80 /** Mutex or RWLocks for the flow. */ //#define FLOWLOCK_RWLOCK #define FLOWLOCK_MUTEX #ifdef FLOWLOCK_RWLOCK #ifdef FLOWLOCK_MUTEX #error Cannot enable both FLOWLOCK_RWLOCK and FLOWLOCK_MUTEX #endif #endif #ifdef FLOWLOCK_RWLOCK #define FLOWLOCK_INIT(fb) SCRWLockInit(&(fb)->r, NULL) #define FLOWLOCK_DESTROY(fb) SCRWLockDestroy(&(fb)->r) #define FLOWLOCK_RDLOCK(fb) SCRWLockRDLock(&(fb)->r) #define FLOWLOCK_WRLOCK(fb) SCRWLockWRLock(&(fb)->r) #define FLOWLOCK_TRYRDLOCK(fb) SCRWLockTryRDLock(&(fb)->r) #define FLOWLOCK_TRYWRLOCK(fb) SCRWLockTryWRLock(&(fb)->r) #define FLOWLOCK_UNLOCK(fb) SCRWLockUnlock(&(fb)->r) #elif defined FLOWLOCK_MUTEX #define FLOWLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL) #define FLOWLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m) #define FLOWLOCK_RDLOCK(fb) SCMutexLock(&(fb)->m) #define FLOWLOCK_WRLOCK(fb) SCMutexLock(&(fb)->m) #define FLOWLOCK_TRYRDLOCK(fb) SCMutexTrylock(&(fb)->m) #define FLOWLOCK_TRYWRLOCK(fb) SCMutexTrylock(&(fb)->m) #define FLOWLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m) #else #error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX #endif /* global flow config */ typedef struct FlowCnf_ { uint32_t hash_rand; uint32_t hash_size; uint64_t memcap; uint32_t max_flows; uint32_t prealloc; uint32_t timeout_new; uint32_t timeout_est; uint32_t emerg_timeout_new; uint32_t emerg_timeout_est; uint32_t emergency_recovery; } FlowConfig; /* Hash key for the flow hash */ typedef struct FlowKey_ { Address src, dst; Port sp, dp; uint8_t proto; uint8_t recursion_level; } FlowKey; typedef struct FlowAddress_ { union { uint32_t address_un_data32[4]; /* type-specific field */ uint16_t address_un_data16[8]; /* type-specific field */ uint8_t address_un_data8[16]; /* type-specific field */ } address; } FlowAddress; #define addr_data32 address.address_un_data32 #define addr_data16 address.address_un_data16 #define addr_data8 address.address_un_data8 /** * \brief Flow data structure. * * The flow is a global data structure that is created for new packets of a * flow and then looked up for the following packets of a flow. * * Locking * * The flow is updated/used by multiple packets at the same time. This is why * there is a flow-mutex. It's a mutex and not a spinlock because some * operations on the flow can be quite expensive, thus spinning would be * too expensive. * * The flow "header" (addresses, ports, proto, recursion level) are static * after the initialization and remain read-only throughout the entire live * of a flow. This is why we can access those without protection of the lock. */ typedef struct Flow_ { /* flow "header", used for hashing and flow lookup. Static after init, * so safe to look at without lock */ FlowAddress src, dst; union { Port sp; /**< tcp/udp source port */ uint8_t type; /**< icmp type */ }; union { Port dp; /**< tcp/udp destination port */ uint8_t code; /**< icmp code */ }; uint8_t proto; uint8_t recursion_level; /* end of flow "header" */ /** how many pkts and stream msgs are using the flow *right now*. This * variable is atomic so not protected by the Flow mutex "m". * * On receiving a packet the counter is incremented while the flow * bucked is locked, which is also the case on timeout pruning. */ SC_ATOMIC_DECLARE(unsigned short, use_cnt); /** flow queue id, used with autofp */ SC_ATOMIC_DECLARE(int, autofp_tmqh_flow_qid); uint32_t probing_parser_toserver_al_proto_masks; uint32_t probing_parser_toclient_al_proto_masks; uint32_t flags; /* ts of flow init and last update */ int32_t lastts_sec; #ifdef FLOWLOCK_RWLOCK SCRWLock r; #elif defined FLOWLOCK_MUTEX SCMutex m; #else #error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX #endif /** protocol specific data pointer, e.g. for TcpSession */ void *protoctx; /** mapping to Flow's protocol specific protocols for timeouts and state and free functions. */ uint8_t protomap; uint8_t pad0; uint16_t alproto; /**< \brief application level protocol */ /** detection engine ctx id used to inspect this flow. Set at initial * inspection. If it doesn't match the currently in use de_ctx, the * de_state and stored sgh ptrs are reset. */ uint32_t de_ctx_id; /** application level storage ptrs. * */ void *alparser; /**< parser internal state */ void *alstate; /**< application layer state */ /** detection engine state */ struct DetectEngineState_ *de_state; /** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag * has been set. */ struct SigGroupHead_ *sgh_toclient; /** toserver sgh for this flow. Only use when FLOW_SGH_TOSERVER flow flag * has been set. */ struct SigGroupHead_ *sgh_toserver; /** List of tags of this flow (from "tag" keyword of type "session") */ void *tag_list; /* pointer to the var list */ GenericVar *flowvar; SCMutex de_state_m; /**< mutex lock for the de_state object */ /** hash list pointers, protected by fb->s */ struct Flow_ *hnext; /* hash list */ struct Flow_ *hprev; struct FlowBucket_ *fb; /** queue list pointers, protected by queue mutex */ struct Flow_ *lnext; /* list */ struct Flow_ *lprev; struct timeval startts; #ifdef DEBUG uint32_t todstpktcnt; uint32_t tosrcpktcnt; uint64_t bytecnt; #endif } Flow; enum { FLOW_STATE_NEW = 0, FLOW_STATE_ESTABLISHED, FLOW_STATE_CLOSED, }; typedef struct FlowProto_ { uint32_t new_timeout; uint32_t est_timeout; uint32_t closed_timeout; uint32_t emerg_new_timeout; uint32_t emerg_est_timeout; uint32_t emerg_closed_timeout; void (*Freefunc)(void *); int (*GetProtoState)(void *); } FlowProto; void FlowHandlePacket (ThreadVars *, Packet *); void FlowInitConfig (char); void FlowPrintQueueInfo (void); void FlowShutdown(void); void FlowSetIPOnlyFlag(Flow *, char); void FlowSetIPOnlyFlagNoLock(Flow *, char); void FlowIncrUsecnt(Flow *); void FlowDecrUsecnt(Flow *); void FlowRegisterTests (void); int FlowSetProtoTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t); int FlowSetProtoEmergencyTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t); int FlowSetProtoFreeFunc (uint8_t , void (*Free)(void *)); int FlowSetFlowStateFunc (uint8_t , int (*GetProtoState)(void *)); void FlowUpdateQueue(Flow *); struct FlowQueue_; int FlowUpdateSpareFlows(void); static inline void FlowLockSetNoPacketInspectionFlag(Flow *); static inline void FlowSetNoPacketInspectionFlag(Flow *); static inline void FlowLockSetNoPayloadInspectionFlag(Flow *); static inline void FlowSetNoPayloadInspectionFlag(Flow *); static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *); int FlowGetPacketDirection(Flow *, Packet *); void FlowCleanupAppLayer(Flow *); /** ----- Inline functions ----- */ /** \brief Set the No Packet Inspection Flag after locking the flow. * * \param f Flow to set the flag in */ static inline void FlowLockSetNoPacketInspectionFlag(Flow *f) { SCEnter(); SCLogDebug("flow %p", f); FLOWLOCK_WRLOCK(f); f->flags |= FLOW_NOPACKET_INSPECTION; FLOWLOCK_UNLOCK(f); SCReturn; } /** \brief Set the No Packet Inspection Flag without locking the flow. * * \param f Flow to set the flag in */ static inline void FlowSetNoPacketInspectionFlag(Flow *f) { SCEnter(); SCLogDebug("flow %p", f); f->flags |= FLOW_NOPACKET_INSPECTION; SCReturn; } /** \brief Set the No payload inspection Flag after locking the flow. * * \param f Flow to set the flag in */ static inline void FlowLockSetNoPayloadInspectionFlag(Flow *f) { SCEnter(); SCLogDebug("flow %p", f); FLOWLOCK_WRLOCK(f); f->flags |= FLOW_NOPAYLOAD_INSPECTION; FLOWLOCK_UNLOCK(f); SCReturn; } /** \brief Set the No payload inspection Flag without locking the flow. * * \param f Flow to set the flag in */ static inline void FlowSetNoPayloadInspectionFlag(Flow *f) { SCEnter(); SCLogDebug("flow %p", f); f->flags |= FLOW_NOPAYLOAD_INSPECTION; SCReturn; } /** \brief set flow flag to disable app layer inspection * * \param f *LOCKED* flow */ static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *f) { f->flags |= FLOW_NO_APPLAYER_INSPECTION; } #define FlowReference(dst_f_ptr, f) do { \ if ((f) != NULL) { \ FlowIncrUsecnt((f)); \ *(dst_f_ptr) = f; \ } \ } while (0) #define FlowDeReference(src_f_ptr) do { \ if (*(src_f_ptr) != NULL) { \ FlowDecrUsecnt(*(src_f_ptr)); \ *(src_f_ptr) = NULL; \ } \ } while (0) int FlowClearMemory(Flow *,uint8_t ); #endif /* __FLOW_H__ */ suricata-1.4.7/src/util-enum.c0000644000000000000000000000502512253546156013112 00000000000000/* Copyright (C) 2007-2010 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #include #include #include "util-enum.h" /** * \brief Maps a string name to an enum value from the supplied table. Please * specify the last element of any map table with a {NULL, -1}. If * missing, you will be welcomed with a segfault :) * * \param enum_name Character string that has to be mapped to an enum value * from the table * \param table Enum-Char table, from which the mapping is retrieved * * \retval result The enum_value for the enum_name string or -1 on failure */ int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table) { int result = -1; if (enum_name == NULL || table == NULL) { printf("Invalid argument(s) passed into SCMapEnumNameToValue\n"); return -1; } for (; table->enum_name != NULL; table++) { if (strcasecmp(table->enum_name, enum_name) == 0) { result = table->enum_value; break; } } return result; } /** * \brief Maps an enum value to a string name, from the supplied table * * \param enum_value Enum_value that has to be mapped to a string_value * from the table * \param table Enum-Char table, from which the mapping is retrieved * * \retval result The enum_name for the enum_value supplied or NULL on failure */ const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table) { if (table == NULL) { printf("Invalid argument(s) passed into SCMapEnumValueToName\n"); return NULL; } for (; table->enum_name != NULL; table++) { if (table->enum_value == enum_value) { return table->enum_name; } } printf("A enum by the value %d doesn't exist in this table\n", enum_value); return NULL; } suricata-1.4.7/install-sh0000755000000000000000000003325512253546173012251 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # 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. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$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 $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # 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. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: suricata-1.4.7/config.sub0000755000000000000000000010535412253546173012230 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-08-10' # This file 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 3 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, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or1k-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: suricata-1.4.7/threshold.config0000644000000000000000000000316312253546156013424 00000000000000# Thresholding: # # This feature is used to reduce the number of logged alerts for noisy rules. # Thresholding commands limit the number of times a particular event is logged # during a specified time interval. # # The syntax is the following: # # threshold gen_id , sig_id , type , track , count , seconds # # event_filter gen_id , sig_id , type , track , count , seconds # # suppress gen_id , sig_id # suppress gen_id , sig_id , track , ip # # The options are documented at https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Global-Thresholds # # Please note that thresholding can also be set inside a signature. The interaction between rule based thresholds # and global thresholds is documented here: # https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Global-Thresholds#Global-thresholds-vs-rule-thresholds # Limit to 10 alerts every 10 seconds for each source host #threshold gen_id 0, sig_id 0, type threshold, track by_src, count 10, seconds 10 # Limit to 1 alert every 10 seconds for signature with sid 2404000 #threshold gen_id 1, sig_id 2404000, type threshold, track by_dst, count 1, seconds 10 # Avoid to alert on f-secure update # Example taken from http://blog.inliniac.net/2012/03/07/f-secure-av-updates-and-suricata-ips/ #suppress gen_id 1, sig_id 2009557, track by_src, ip 217.110.97.128/25 #suppress gen_id 1, sig_id 2012086, track by_src, ip 217.110.97.128/25 #suppress gen_id 1, sig_id 2003614, track by_src, ip 217.110.97.128/25 suricata-1.4.7/classification.config0000644000000000000000000000671512253546156014431 00000000000000# $Id$ # classification.config taken from Snort 2.8.5.3. Snort is governed by the GPLv2 # # The following includes information for prioritizing rules # # Each classification includes a shortname, a description, and a default # priority for that classification. # # This allows alerts to be classified and prioritized. You can specify # what priority each classification has. Any rule can override the default # priority for that rule. # # Here are a few example rules: # # alert TCP any any -> any 80 (msg: "EXPLOIT ntpdx overflow"; # dsize: > 128; classtype:attempted-admin; priority:10; # # alert TCP any any -> any 25 (msg:"SMTP expn root"; flags:A+; \ # content:"expn root"; nocase; classtype:attempted-recon;) # # The first rule will set its type to "attempted-admin" and override # the default priority for that type to 10. # # The second rule set its type to "attempted-recon" and set its # priority to the default for that type. # # # config classification:shortname,short description,priority # config classification: not-suspicious,Not Suspicious Traffic,3 config classification: unknown,Unknown Traffic,3 config classification: bad-unknown,Potentially Bad Traffic, 2 config classification: attempted-recon,Attempted Information Leak,2 config classification: successful-recon-limited,Information Leak,2 config classification: successful-recon-largescale,Large Scale Information Leak,2 config classification: attempted-dos,Attempted Denial of Service,2 config classification: successful-dos,Denial of Service,2 config classification: attempted-user,Attempted User Privilege Gain,1 config classification: unsuccessful-user,Unsuccessful User Privilege Gain,1 config classification: successful-user,Successful User Privilege Gain,1 config classification: attempted-admin,Attempted Administrator Privilege Gain,1 config classification: successful-admin,Successful Administrator Privilege Gain,1 # NEW CLASSIFICATIONS config classification: rpc-portmap-decode,Decode of an RPC Query,2 config classification: shellcode-detect,Executable code was detected,1 config classification: string-detect,A suspicious string was detected,3 config classification: suspicious-filename-detect,A suspicious filename was detected,2 config classification: suspicious-login,An attempted login using a suspicious username was detected,2 config classification: system-call-detect,A system call was detected,2 config classification: tcp-connection,A TCP connection was detected,4 config classification: trojan-activity,A Network Trojan was detected, 1 config classification: unusual-client-port-connection,A client was using an unusual port,2 config classification: network-scan,Detection of a Network Scan,3 config classification: denial-of-service,Detection of a Denial of Service Attack,2 config classification: non-standard-protocol,Detection of a non-standard protocol or event,2 config classification: protocol-command-decode,Generic Protocol Command Decode,3 config classification: web-application-activity,access to a potentially vulnerable web application,2 config classification: web-application-attack,Web Application Attack,1 config classification: misc-activity,Misc activity,3 config classification: misc-attack,Misc Attack,2 config classification: icmp-event,Generic ICMP event,3 config classification: kickass-porn,SCORE! Get the lotion!,1 config classification: policy-violation,Potential Corporate Privacy Violation,1 config classification: default-login-attempt,Attempt to login by a default username and password,2 suricata-1.4.7/Makefile.in0000644000000000000000000007016312253546173012311 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in mkinstalldirs $(srcdir)/suricata.yaml.in \ COPYING ChangeLog config.guess config.sub install-sh missing \ ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac 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 = suricata.yaml CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-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 \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = libhtp src qa rules doc contrib scripts DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ 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 ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = ChangeLog COPYING LICENSE suricata.yaml.in \ classification.config threshold.config \ reference.config @BUILD_LIBHTP_TRUE@HTP_DIR = libhtp SUBDIRS = $(HTP_DIR) src qa rules doc contrib scripts all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__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) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(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) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 suricata.yaml: $(top_builddir)/config.status $(srcdir)/suricata.yaml.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt # 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. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ 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; \ ($(am__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" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ 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 || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -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__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_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) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(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 \ && cd "$$am__cwd" \ || exit 1 $(am__post_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: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 html-am: info: info-recursive info-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: 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: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ dist-xz 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-am uninstall \ uninstall-am install-data-am: @echo "Run 'make install-conf' if you want to install initial configuration files. Or 'make install-full' to install configuration and rules"; install-full: install install-conf install-rules install-conf: install -d "$(e_sysconfdir)" @test -e "$(e_sysconfdir)/suricata.yaml" || install -m 600 "$(top_srcdir)/suricata.yaml" "$(e_sysconfdir)" @test -e "$(e_sysconfdir)/classification.config" || install -m 600 "$(top_srcdir)/classification.config" "$(e_sysconfdir)" @test -e "$(e_sysconfdir)/reference.config" || install -m 600 "$(top_srcdir)/reference.config" "$(e_sysconfdir)" @test -e "$(e_sysconfdir)/threshold.config" || install -m 600 "$(top_srcdir)/threshold.config" "$(e_sysconfdir)" install -d "$(e_logfilesdir)" install -d "$(e_rundir)" install -m 770 -d "$(e_localstatedir)" install-rules: install -d "$(e_sysconfrulesdir)" wget -qO - http://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz | tar -x -z -C "$(e_sysconfdir)" -f - @test -e "$(e_sysconfrulesdir)decoder-events.rules" || install -m 600 "$(top_srcdir)/rules/decoder-events.rules" "$(e_sysconfrulesdir)" @test -e "$(e_sysconfrulesdir)stream-events.rules" || install -m 600 "$(top_srcdir)/rules/stream-events.rules" "$(e_sysconfrulesdir)" @test -e "$(e_sysconfrulesdir)smtp-events.rules" || install -m 600 "$(top_srcdir)/rules/smtp-events.rules" "$(e_sysconfrulesdir)" @test -e "$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(e_sysconfrulesdir)" @echo "" @echo "You can now start suricata by running as root something like '$(bindir)/suricata -c $(e_sysconfdir)/suricata.yaml -i eth0'." @echo "" @echo "If a library like libhtp.so is not found, you can run suricata with:" @echo "'LD_LIBRARY_PATH="$(prefix)/lib" "$(bindir)/suricata" -c "$(e_sysconfdir)/suricata.yaml" -i eth0'." @echo "" @echo "While rules are installed now, it's highly recommended to use a rule manager for maintaining rules." @echo "The two most common are Oinkmaster and Pulledpork. For a guide see:" @echo "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Rule_Management_with_Oinkmaster" # 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: suricata-1.4.7/LICENSE0000644000000000000000000004310312253546156011244 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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. Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. , 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 Lesser General Public License instead of this License. suricata-1.4.7/missing0000755000000000000000000001533112253546173011637 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2012-06-26.16; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 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, see . # 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 case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'automa4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: suricata-1.4.7/Makefile.am0000644000000000000000000000476612253546156012307 00000000000000# not a GNU package. You can remove this line, if # have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = foreign 1.4 ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = ChangeLog COPYING LICENSE suricata.yaml.in \ classification.config threshold.config \ reference.config if BUILD_LIBHTP HTP_DIR = libhtp endif SUBDIRS = $(HTP_DIR) src qa rules doc contrib scripts install-data-am: @echo "Run 'make install-conf' if you want to install initial configuration files. Or 'make install-full' to install configuration and rules"; install-full: install install-conf install-rules install-conf: install -d "$(e_sysconfdir)" @test -e "$(e_sysconfdir)/suricata.yaml" || install -m 600 "$(top_srcdir)/suricata.yaml" "$(e_sysconfdir)" @test -e "$(e_sysconfdir)/classification.config" || install -m 600 "$(top_srcdir)/classification.config" "$(e_sysconfdir)" @test -e "$(e_sysconfdir)/reference.config" || install -m 600 "$(top_srcdir)/reference.config" "$(e_sysconfdir)" @test -e "$(e_sysconfdir)/threshold.config" || install -m 600 "$(top_srcdir)/threshold.config" "$(e_sysconfdir)" install -d "$(e_logfilesdir)" install -d "$(e_rundir)" install -m 770 -d "$(e_localstatedir)" install-rules: install -d "$(e_sysconfrulesdir)" wget -qO - http://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz | tar -x -z -C "$(e_sysconfdir)" -f - @test -e "$(e_sysconfrulesdir)decoder-events.rules" || install -m 600 "$(top_srcdir)/rules/decoder-events.rules" "$(e_sysconfrulesdir)" @test -e "$(e_sysconfrulesdir)stream-events.rules" || install -m 600 "$(top_srcdir)/rules/stream-events.rules" "$(e_sysconfrulesdir)" @test -e "$(e_sysconfrulesdir)smtp-events.rules" || install -m 600 "$(top_srcdir)/rules/smtp-events.rules" "$(e_sysconfrulesdir)" @test -e "$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(e_sysconfrulesdir)" @echo "" @echo "You can now start suricata by running as root something like '$(bindir)/suricata -c $(e_sysconfdir)/suricata.yaml -i eth0'." @echo "" @echo "If a library like libhtp.so is not found, you can run suricata with:" @echo "'LD_LIBRARY_PATH="$(prefix)/lib" "$(bindir)/suricata" -c "$(e_sysconfdir)/suricata.yaml" -i eth0'." @echo "" @echo "While rules are installed now, it's highly recommended to use a rule manager for maintaining rules." @echo "The two most common are Oinkmaster and Pulledpork. For a guide see:" @echo "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Rule_Management_with_Oinkmaster" suricata-1.4.7/configure0000755000000000000000000230310412253546172012146 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="configure.ac" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" enable_option_checking=no ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS e_magic_file e_localstatedir e_sysconfrulesdir e_sysconfdir e_logfilesdir e_rundir e_logdir HAVE_GIT_CMD LUAJIT_LIBS LUAJIT_CFLAGS BUILD_CUDA_FALSE BUILD_CUDA_TRUE pkgpyexecdir pyexecdir pkgpythondir pythondir PYTHON_PLATFORM PYTHON_EXEC_PREFIX PYTHON_PREFIX PYTHON_VERSION PYTHON NVCC BUILD_LIBHTP_FALSE BUILD_LIBHTP_TRUE subdirs LIBHTPMAXVERSION_LIBS LIBHTPMAXVERSION_CFLAGS LIBHTPMINVERSION_LIBS LIBHTPMINVERSION_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG HAVE_PCAP_CONFIG LIBPRELUDE_CONFIG_PREFIX LIBPRELUDE_PREFIX LIBPRELUDE_LIBS LIBPRELUDE_LDFLAGS LIBPRELUDE_PTHREAD_CFLAGS LIBPRELUDE_CFLAGS LIBPRELUDE_CONFIG BUILD_UNITTESTS_FALSE BUILD_UNITTESTS_TRUE LIBOBJS HAVE_PYTHON_FALSE HAVE_PYTHON_TRUE HAVE_PYTHON_CONFIG HAVE_COCCINELLE_FALSE HAVE_COCCINELLE_TRUE HAVE_COCCINELLE_CONFIG HAVE_PKG_CONFIG CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock enable_largefile enable_gccprotect enable_gccprofile enable_gccmarch_native enable_unittests enable_old_barnyard2 enable_debug enable_debug_validation enable_profiling enable_profiling_locks enable_ipfw with_libpcre_includes with_libpcre_libraries with_libyaml_includes with_libyaml_libraries with_libpthread_includes with_libpthread_libraries with_libjansson_includes with_libjansson_libraries enable_unix_socket enable_nfqueue with_libnfnetlink_includes with_libnfnetlink_libraries with_libnetfilter_queue_includes with_libnetfilter_queue_libraries with_netfilterforwin_includes enable_prelude with_libprelude_prefix with_libnet_includes with_libnet_libraries enable_pfring with_libpfring_includes with_libpfring_libraries with_libpcap_includes with_libpcap_libraries enable_af_packet enable_non_bundled_htp with_libhtp_includes with_libhtp_libraries enable_cuda with_cuda_includes with_cuda_libraries with_cuda_nvcc with_libcap_ng_includes with_libcap_ng_libraries enable_dag with_dag_includes with_dag_libraries with_libnspr_includes with_libnspr_libraries with_libnss_includes with_libnss_libraries with_libmagic_includes with_libmagic_libraries enable_napatech with_napatech_includes with_napatech_libraries enable_luajit with_libluajit_includes with_libluajit_libraries enable_geoip with_libgeoip_includes with_libgeoip_libraries ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR LIBHTPMINVERSION_CFLAGS LIBHTPMINVERSION_LIBS LIBHTPMAXVERSION_CFLAGS LIBHTPMAXVERSION_LIBS PYTHON LUAJIT_CFLAGS LUAJIT_LIBS' ac_subdirs_all='libhtp' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-largefile omit support for large files --enable-gccprotect Detect and use gcc hardening options --enable-gccprofile Enable gcc profile info i.e -pg flag is set --enable-gccmarch-native Enable gcc march=native gcc 4.2 and later only --enable-unittests Enable compilation of the unit tests --enable-old-barnyard2 Use workaround for old barnyard2 in unified2 output --enable-debug Enable debug output --enable-debug-validation Enable (debug) validation code output --enable-profiling Enable performance profiling --enable-profiling-locks Enable performance profiling for locks --enable-ipfw Enable FreeBSD IPFW support for inline IDP --enable-unix-socket Enable unix socket [default=test] --enable-nfqueue Enable NFQUEUE support for inline IDP --enable-prelude Enable Prelude support for alerts --enable-pfring Enable Native PF_RING support --enable-af-packet Enable AF_PACKET support [default=yes] --enable-non-bundled-htp Enable the use of an already installed version of htp --enable-cuda Enable experimental CUDA pattern matching --enable-dag Enable DAG capture --enable-napatech Enabled Napatech Devices --enable-luajit Enable Luajit support --enable-geoip Enable GeoIP support Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-libpcre-includes=DIR libpcre include directory --with-libpcre-libraries=DIR libpcre library directory --with-libyaml-includes=DIR libyaml include directory --with-libyaml-libraries=DIR libyaml library directory --with-libpthread-includes=DIR libpthread include directory --with-libpthread-libraries=DIR libpthread library directory --with-libjansson-includes=DIR libjansson include directory --with-libjansson-libraries=DIR libjansson library directory --with-libnfnetlink-includes=DIR libnfnetlink include directory --with-libnfnetlink-libraries=DIR libnfnetlink library directory --with-libnetfilter_queue-includes=DIR libnetfilter_queue include directory --with-libnetfilter_queue-libraries=DIR libnetfilter_queue library directory --with-netfilterforwin-includes=DIR netfilterforwin include directory --with-libprelude-prefix=PFX Prefix where libprelude is installed (optional) --with-libnet-includes=DIR libnet include directory --with-libnet-libraries=DIR libnet library directory --with-libpfring-includes=DIR libpfring include directory --with-libpfring-libraries=DIR libpfring library directory --with-libpcap-includes=DIR libpcap include directory --with-libpcap-libraries=DIR libpcap library directory --with-libhtp-includes=DIR libhtp include directory --with-libhtp-libraries=DIR libhtp library directory --with-cuda-includes=DIR cuda include directory --with-cuda-libraries=DIR cuda library directory --with-cuda-nvcc=DIR cuda nvcc compiler directory --with-libcap_ng-includes=DIR libcap_ng include directory --with-libcap_ng-libraries=DIR libcap_ng library directory --with-dag-includes=DIR dagapi include directory --with-dag-libraries=DIR dagapi library directory --with-libnspr-includes=DIR libnspr include directory --with-libnspr-libraries=DIR libnspr library directory --with-libnss-includes=DIR libnss include directory --with-libnss-libraries=DIR libnss library directory --with-libmagic-includes=DIR libmagic include directory --with-libmagic-libraries=DIR libmagic library directory --with-napatech-includes=DIR napatech include directory --with-napatech-libraries=DIR napatech library directory --with-libluajit-includes=DIR libluajit include directory --with-libluajit-libraries=DIR libluajit library directory --with-libgeoip-includes=DIR libgeoip include directory --with-libgeoip-libraries=DIR libgeoip library directory Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path LIBHTPMINVERSION_CFLAGS C compiler flags for LIBHTPMINVERSION, overriding pkg-config LIBHTPMINVERSION_LIBS linker flags for LIBHTPMINVERSION, overriding pkg-config LIBHTPMAXVERSION_CFLAGS C compiler flags for LIBHTPMAXVERSION, overriding pkg-config LIBHTPMAXVERSION_LIBS linker flags for LIBHTPMAXVERSION, overriding pkg-config PYTHON the Python interpreter LUAJIT_CFLAGS C compiler flags for LUAJIT, overriding pkg-config LUAJIT_LIBS linker flags for LUAJIT, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" am__api_version='1.13' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE=suricata VERSION=1.4.7 cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' CFLAGS="${CFLAGS} -DRELEASE" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; } if ${ac_cv_prog_cc_c99+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy. static void test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str; int number; float fnumber; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. test_varargs ("s, d' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c99" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 $as_echo "$ac_cv_prog_cc_c99" >&6; } ;; esac if test "x$ac_cv_prog_cc_c99" != xno; then : fi case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: if test `basename $CC` = "clang"; then CFLAGS="$CFLAGS -Wextra -Werror-implicit-function-declaration" { $as_echo "$as_me:${as_lineno-$LINENO}: checking clang __sync_bool_compare_and_swap" >&5 $as_echo_n "checking clang __sync_bool_compare_and_swap... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { unsigned int i = 0; (void)__sync_bool_compare_and_swap(&i, 1, 1); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1" >>confdefs.h $as_echo "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1" >>confdefs.h $as_echo "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1" >>confdefs.h $as_echo "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test `basename $CC` = "gcc"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking gcc version" >&5 $as_echo_n "checking gcc version... " >&6; } gccver=$($CC -dumpversion) gccvermajor=$(echo $gccver | cut -d . -f1) gccverminor=$(echo $gccver | cut -d . -f2) gccvernum=$(expr $gccvermajor "*" 100 + $gccverminor) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gccver" >&5 $as_echo "$gccver" >&6; } if test "$gccvernum" -ge "400"; then CFLAGS="$CFLAGS -Wextra -Werror-implicit-function-declaration" # remove optimization options that break our code # VJ 2010/06/27: no-tree-pre added. It breaks ringbuffers code. CFLAGS="$CFLAGS -fno-tree-pre" else CFLAGS="$CFLAGS -W" fi fi CFLAGS="$CFLAGS -Wall -fno-strict-aliasing" CFLAGS="$CFLAGS -Wno-unused-parameter" CFLAGS="$CFLAGS -std=gnu99" # Checks for programs. for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_HAVE_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $HAVE_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_HAVE_PKG_CONFIG="$HAVE_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_HAVE_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_HAVE_PKG_CONFIG" && ac_cv_path_HAVE_PKG_CONFIG=""no"" ;; esac fi HAVE_PKG_CONFIG=$ac_cv_path_HAVE_PKG_CONFIG if test -n "$HAVE_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_PKG_CONFIG" >&5 $as_echo "$HAVE_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$HAVE_PKG_CONFIG" = "no"; then echo echo " ERROR! pkg-config not found, go get it " echo " http://pkg-config.freedesktop.org/wiki/ " echo " or install from your distribution " echo exit 1 fi # Extract the first word of "spatch", so it can be a program name with args. set dummy spatch; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_HAVE_COCCINELLE_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $HAVE_COCCINELLE_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_HAVE_COCCINELLE_CONFIG="$HAVE_COCCINELLE_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_HAVE_COCCINELLE_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_HAVE_COCCINELLE_CONFIG" && ac_cv_path_HAVE_COCCINELLE_CONFIG=""no"" ;; esac fi HAVE_COCCINELLE_CONFIG=$ac_cv_path_HAVE_COCCINELLE_CONFIG if test -n "$HAVE_COCCINELLE_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_COCCINELLE_CONFIG" >&5 $as_echo "$HAVE_COCCINELLE_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$HAVE_COCCINELLE_CONFIG" = "no"; then echo echo " Warning! spatch not found, you will not be " echo " able to run code checking with coccinelle " echo " get it from http://coccinelle.lip6.fr " echo " or install from your distribution " echo fi if test "$HAVE_COCCINELLE_CONFIG" != "no"; then HAVE_COCCINELLE_TRUE= HAVE_COCCINELLE_FALSE='#' else HAVE_COCCINELLE_TRUE='#' HAVE_COCCINELLE_FALSE= fi # Extract the first word of "python", so it can be a program name with args. set dummy python; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_HAVE_PYTHON_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $HAVE_PYTHON_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_HAVE_PYTHON_CONFIG="$HAVE_PYTHON_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_HAVE_PYTHON_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_HAVE_PYTHON_CONFIG" && ac_cv_path_HAVE_PYTHON_CONFIG=""no"" ;; esac fi HAVE_PYTHON_CONFIG=$ac_cv_path_HAVE_PYTHON_CONFIG if test -n "$HAVE_PYTHON_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_PYTHON_CONFIG" >&5 $as_echo "$HAVE_PYTHON_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$HAVE_PYTHON_CONFIG" = "no"; then echo echo " Warning! python not found, you will not be " echo " able to install surictasc unix socket client " echo enable_python="no" else enable_python="yes" fi if test "$HAVE_PYTHON_CONFIG" != "no"; then HAVE_PYTHON_TRUE= HAVE_PYTHON_FALSE='#' else HAVE_PYTHON_TRUE='#' HAVE_PYTHON_FALSE= fi # Checks for libraries. # Checks for header files. for ac_header in arpa/inet.h assert.h ctype.h errno.h fcntl.h inttypes.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in getopt.h do : ac_fn_c_check_header_mongrel "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default" if test "x$ac_cv_header_getopt_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETOPT_H 1 _ACEOF fi done for ac_header in limits.h netdb.h netinet/in.h poll.h sched.h signal.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in stdarg.h stdint.h stdio.h stdlib.h string.h sys/ioctl.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in syslog.h sys/prctl.h sys/socket.h sys/stat.h sys/syscall.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/time.h time.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/socket.h net/if.h sys/mman.h linux/if_arp.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_SYS_SOCKET_H #include #include #endif " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in windows.h winsock2.h ws2tcpip.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#define _X86_ " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in w32api/winbase.h do : ac_fn_c_check_header_compile "$LINENO" "w32api/winbase.h" "ac_cv_header_w32api_winbase_h" "#define _X86_ #include " if test "x$ac_cv_header_w32api_winbase_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_W32API_WINBASE_H 1 _ACEOF fi done # Checks for typedefs, structures, and compiler characteristics. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int32_t" >&5 $as_echo_n "checking for int32_t... " >&6; } if ${ac_cv_c_int32_t+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_int32_t=no for ac_type in 'int32_t' 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 1))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 1) < ($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 2))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else case $ac_type in int32_t) ac_cv_c_int32_t=yes ;; *) ac_cv_c_int32_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_int32_t" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_int32_t" >&5 $as_echo "$ac_cv_c_int32_t" >&6; } case $ac_cv_c_int32_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int32_t $ac_cv_c_int32_t _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint16_t" >&5 $as_echo_n "checking for uint16_t... " >&6; } if ${ac_cv_c_uint16_t+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_uint16_t=no for ac_type in 'uint16_t' 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) -1 >> (16 - 1) == 1)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in uint16_t) ac_cv_c_uint16_t=yes ;; *) ac_cv_c_uint16_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_uint16_t" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_uint16_t" >&5 $as_echo "$ac_cv_c_uint16_t" >&6; } case $ac_cv_c_uint16_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define uint16_t $ac_cv_c_uint16_t _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint32_t" >&5 $as_echo_n "checking for uint32_t... " >&6; } if ${ac_cv_c_uint32_t+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_uint32_t=no for ac_type in 'uint32_t' 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) -1 >> (32 - 1) == 1)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in uint32_t) ac_cv_c_uint32_t=yes ;; *) ac_cv_c_uint32_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_uint32_t" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_uint32_t" >&5 $as_echo "$ac_cv_c_uint32_t" >&6; } case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) $as_echo "#define _UINT32_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint32_t $ac_cv_c_uint32_t _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint64_t" >&5 $as_echo_n "checking for uint64_t... " >&6; } if ${ac_cv_c_uint64_t+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_uint64_t=no for ac_type in 'uint64_t' 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) -1 >> (64 - 1) == 1)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in uint64_t) ac_cv_c_uint64_t=yes ;; *) ac_cv_c_uint64_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_uint64_t" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_uint64_t" >&5 $as_echo "$ac_cv_c_uint64_t" >&6; } case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) $as_echo "#define _UINT64_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint64_t $ac_cv_c_uint64_t _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint8_t" >&5 $as_echo_n "checking for uint8_t... " >&6; } if ${ac_cv_c_uint8_t+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_uint8_t=no for ac_type in 'uint8_t' 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) -1 >> (8 - 1) == 1)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in uint8_t) ac_cv_c_uint8_t=yes ;; *) ac_cv_c_uint8_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_uint8_t" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_uint8_t" >&5 $as_echo "$ac_cv_c_uint8_t" >&6; } case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) $as_echo "#define _UINT8_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint8_t $ac_cv_c_uint8_t _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 $as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } if ${ac_cv_header_stdbool_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef bool "error: bool is not defined" #endif #ifndef false "error: false is not defined" #endif #if false "error: false is not 0" #endif #ifndef true "error: true is not defined" #endif #if true != 1 "error: true is not 1" #endif #ifndef __bool_true_false_are_defined "error: __bool_true_false_are_defined is not defined" #endif struct s { _Bool s: 1; _Bool t; } s; char a[true == 1 ? 1 : -1]; char b[false == 0 ? 1 : -1]; char c[__bool_true_false_are_defined == 1 ? 1 : -1]; char d[(bool) 0.5 == true ? 1 : -1]; /* See body of main program for 'e'. */ char f[(_Bool) 0.0 == false ? 1 : -1]; char g[true]; char h[sizeof (_Bool)]; char i[sizeof s.t]; enum { j = false, k = true, l = false * true, m = true * 256 }; /* The following fails for HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ _Bool n[m]; char o[sizeof n == m * sizeof n[0] ? 1 : -1]; char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; /* Catch a bug in an HP-UX C compiler. See http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html */ _Bool q = true; _Bool *pq = &q; int main () { bool e = &s; *pq |= q; *pq |= ! q; /* Refer to every declared value, to avoid compiler optimizations. */ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + !m + !n + !o + !p + !q + !pq); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdbool_h=yes else ac_cv_header_stdbool_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 $as_echo "$ac_cv_header_stdbool_h" >&6; } ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE__BOOL 1 _ACEOF fi if test $ac_cv_header_stdbool_h = yes; then $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h fi # Checks for library functions. for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if ${ac_cv_func_malloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 $as_echo_n "checking for GNU libc compatible realloc... " >&6; } if ${ac_cv_func_realloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_realloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *realloc (); #endif int main () { return ! realloc (0, 0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_realloc_0_nonnull=yes else ac_cv_func_realloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 $as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } if test $ac_cv_func_realloc_0_nonnull = yes; then : $as_echo "#define HAVE_REALLOC 1" >>confdefs.h else $as_echo "#define HAVE_REALLOC 0" >>confdefs.h case " $LIBOBJS " in *" realloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS realloc.$ac_objext" ;; esac $as_echo "#define realloc rpl_realloc" >>confdefs.h fi for ac_func in gettimeofday memset strcasecmp strchr strdup strerror strncasecmp strtol strtoul memchr do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # Add large file support # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi #check for os { $as_echo "$as_me:${as_lineno-$LINENO}: checking host os" >&5 $as_echo_n "checking host os... " >&6; } # If no host os was detected, try with uname if test -z "$host" ; then host="`uname`" fi echo -n "installation for $host OS... " e_magic_file="/usr/share/file/magic" case "$host" in *-*-*freebsd*) CFLAGS="${CFLAGS} -DOS_FREEBSD" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet11" LDFLAGS="${LDFLAGS} -L/usr/local/lib -L/usr/local/lib/libnet11" e_magic_file="/usr/share/misc/magic" ;; *-*-openbsd5.1) CFLAGS="${CFLAGS} -D__OpenBSD__ -fgnu89-inline" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet-1.1" LDFLAGS="${LDFLAGS} -L/usr/local/lib -I/usr/local/lib/libnet-1.1" e_magic_file="/usr/local/share/misc/magic.mgc" ;; *-*-openbsd5.2) CFLAGS="${CFLAGS} -D__OpenBSD__" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet-1.1" LDFLAGS="${LDFLAGS} -L/usr/local/lib -I/usr/local/lib/libnet-1.1" e_magic_file="/usr/local/share/misc/magic.mgc" ;; *-*-openbsd*) CFLAGS="${CFLAGS} -D__OpenBSD__ -fgnu89-inline" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet-1.1" LDFLAGS="${LDFLAGS} -L/usr/local/lib -I/usr/local/lib/libnet-1.1" e_magic_file="/usr/local/share/file/magic.mgc" ;; *darwin*|*Darwin*) CFLAGS="${CFLAGS} -DOS_DARWIN" CPPFLAGS="${CPPFLAGS} -I/opt/local/include" LDFLAGS="${LDFLAGS} -L/opt/local/lib" ;; *-*-linux*) #for now do nothing ;; *-*-mingw32*) CFLAGS="${CFLAGS} -DOS_WIN32" LDFLAGS="${LDFLAGS} -lws2_32" WINDOWS_PATH="yes" ;; *-*-cygwin) WINDOWS_PATH="yes" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unsupported OS this may or may not work" >&5 $as_echo "$as_me: WARNING: unsupported OS this may or may not work" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } #Enable support for gcc compile time security options. There is no great way to do detection of valid cflags that I have found #AX_CFLAGS_GCC_OPTION don't seem to do a better job than the code below and are a pain because of extra m4 files etc. #These flags seem to be supported on CentOS 5+, Ubuntu 8.04+, and FedoreCore 11+ #Options are taken from https://wiki.ubuntu.com/CompilerFlags # Check whether --enable-gccprotect was given. if test "${enable_gccprotect+set}" = set; then : enableval=$enable_gccprotect; else enable_gccprotect=no fi if test "x$enable_gccprotect" = "xyes"; then : #buffer overflow protection { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fstack-protector" >&5 $as_echo_n "checking for -fstack-protector... " >&6; } TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -fstack-protector" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : SECCFLAGS="${SECCFLAGS} -fstack-protector" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="${TMPCFLAGS}" #compile-time best-practices errors for certain libc functions, provides checks of buffer lengths and memory regions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -D_FORTIFY_SOURCE=2" >&5 $as_echo_n "checking for -D_FORTIFY_SOURCE=2... " >&6; } TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -D_FORTIFY_SOURCE=2" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : SECCFLAGS="${SECCFLAGS} -D_FORTIFY_SOURCE=2" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${TMPCFLAGS}" #compile-time warnings about misuse of format strings { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wformat -Wformat-security" >&5 $as_echo_n "checking for -Wformat -Wformat-security... " >&6; } TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wformat -Wformat-security" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : SECCFLAGS="${SECCFLAGS} -Wformat -Wformat-security" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${TMPCFLAGS}" #provides a read-only relocation table area in the final ELF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -z relro" >&5 $as_echo_n "checking for -z relro... " >&6; } TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z relro" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : SECLDFLAGS="${SECLDFLAGS} -z relro" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="${TMPLDFLAGS}" #forces all relocations to be resolved at run-time { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -z now" >&5 $as_echo_n "checking for -z now... " >&6; } TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z now" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : SECLDFLAGS="${SECLDFLAGS} -z now" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="${TMPLDFLAGS}" CFLAGS="${CFLAGS} ${SECCFLAGS}" LDFLAGS="${LDFLAGS} ${SECLDFLAGS}" fi #enable profile generation # Check whether --enable-gccprofile was given. if test "${enable_gccprofile+set}" = set; then : enableval=$enable_gccprofile; else enable_gccprofile=no fi if test "x$enable_gccprofile" = "xyes"; then : CFLAGS="${CFLAGS} -pg" fi #enable gcc march=native gcc 4.2 or later # Check whether --enable-gccmarch_native was given. if test "${enable_gccmarch_native+set}" = set; then : enableval=$enable_gccmarch_native; else enable_gccmarch_native=yes fi if test "x$enable_gccmarch_native" = "xyes"; then : if test `basename $CC` = "clang"; then OFLAGS="$CFLAGS" CFLAGS="$CFLAGS -march=native" { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking if $CC supports -march=native" >&5 $as_echo_n "checking checking if $CC supports -march=native... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } CFLAGS="$OFLAGS -march=native" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$OFLAGS" enable_gccmarch_native=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test `basename $CC` = "gcc"; then case $host in *darwin*|*Darwin*) if test "$gccvernum" -ge "403"; then CFLAGS="$CFLAGS -march=native" else enable_gccmarch_native=no fi ;; *) if test "$gccvernum" -ge "402"; then CFLAGS="$CFLAGS -march=native" fi ;; esac fi fi # options # enable the running of unit tests # Check whether --enable-unittests was given. if test "${enable_unittests+set}" = set; then : enableval=$enable_unittests; else enable_unittests=no fi if test "x$enable_unittests" = "xyes"; then : UT_ENABLED="yes" CFLAGS="${CFLAGS} -DUNITTESTS" fi if test "x$enable_unittests" = "xyes"; then BUILD_UNITTESTS_TRUE= BUILD_UNITTESTS_FALSE='#' else BUILD_UNITTESTS_TRUE='#' BUILD_UNITTESTS_FALSE= fi # enable workaround for old barnyard2 for unified alert output # Check whether --enable-old-barnyard2 was given. if test "${enable_old_barnyard2+set}" = set; then : enableval=$enable_old_barnyard2; else enable_old_barnyard2=no fi if test "x$enable_old_barnyard2" = "xyes"; then : CFLAGS="${CFLAGS} -DHAVE_OLD_BARNYARD2" fi # enable debug output # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; else enable_debug=no fi if test "x$enable_debug" = "xyes"; then : CFLAGS="${CFLAGS} -DDEBUG" fi # enable debug validation functions & macro's output # Check whether --enable-debug-validation was given. if test "${enable_debug_validation+set}" = set; then : enableval=$enable_debug_validation; else enable_debug_validation=no fi if test "x$enable_debug_validation" = "xyes"; then : CFLAGS="${CFLAGS} -DDEBUG_VALIDATION" fi # profiling support # Check whether --enable-profiling was given. if test "${enable_profiling+set}" = set; then : enableval=$enable_profiling; else enable_profiling=no fi if test "x$enable_profiling" = "xyes"; then : case "$host" in *-*-openbsd*) as_fn_error $? "profiling is not supported on OpenBSD" "$LINENO" 5 ;; *) CFLAGS="${CFLAGS} -DPROFILING" ;; esac fi # profiling support, locking # Check whether --enable-profiling-locks was given. if test "${enable_profiling_locks+set}" = set; then : enableval=$enable_profiling_locks; else enable_profiling_locks=no fi if test "x$enable_profiling_locks" = "xyes"; then : CFLAGS="${CFLAGS} -DPROFILING -DPROFILE_LOCKING" fi # enable support for IPFW # Check whether --enable-ipfw was given. if test "${enable_ipfw+set}" = set; then : enableval=$enable_ipfw; else enable_ipfw=no fi if test "x$enable_ipfw" = "xyes"; then : CFLAGS="$CFLAGS -DIPFW" fi # libraries #libpcre # Check whether --with-libpcre_includes was given. if test "${with_libpcre_includes+set}" = set; then : withval=$with_libpcre_includes; with_libpcre_includes="$withval" else with_libpcre_includes=no fi # Check whether --with-libpcre_libraries was given. if test "${with_libpcre_libraries+set}" = set; then : withval=$with_libpcre_libraries; with_libpcre_libraries="$withval" else with_libpcre_libraries="no" fi if test "$with_libpcre_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libpcre_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "pcre.h" "ac_cv_header_pcre_h" "$ac_includes_default" if test "x$ac_cv_header_pcre_h" = xyes; then : else as_fn_error $? "pcre.h not found ..." "$LINENO" 5 fi if test "$with_libpcre_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libpcre_libraries}" fi PCRE="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre_get_substring in -lpcre" >&5 $as_echo_n "checking for pcre_get_substring in -lpcre... " >&6; } if ${ac_cv_lib_pcre_pcre_get_substring+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcre $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcre_get_substring (); int main () { return pcre_get_substring (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcre_pcre_get_substring=yes else ac_cv_lib_pcre_pcre_get_substring=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcre_pcre_get_substring" >&5 $as_echo "$ac_cv_lib_pcre_pcre_get_substring" >&6; } if test "x$ac_cv_lib_pcre_pcre_get_substring" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPCRE 1 _ACEOF LIBS="-lpcre $LIBS" else PCRE="no" fi if test "$PCRE" = "no"; then echo echo " ERROR! pcre library not found, go get it" echo " from www.pcre.org." echo exit 1 fi # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work # see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful PCRE="" TMPLIBS="${LIBS}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre_dfa_exec in -lpcre" >&5 $as_echo_n "checking for pcre_dfa_exec in -lpcre... " >&6; } if ${ac_cv_lib_pcre_pcre_dfa_exec+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcre $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcre_dfa_exec (); int main () { return pcre_dfa_exec (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcre_pcre_dfa_exec=yes else ac_cv_lib_pcre_pcre_dfa_exec=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcre_pcre_dfa_exec" >&5 $as_echo "$ac_cv_lib_pcre_pcre_dfa_exec" >&6; } if test "x$ac_cv_lib_pcre_pcre_dfa_exec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPCRE 1 _ACEOF LIBS="-lpcre $LIBS" else PCRE="no" fi if test "$PCRE" = "no"; then echo echo " ERROR! pcre library was found but version was < 6.0" echo " please upgrade to a newer version of pcre which you can get from" echo " www.pcre.org." echo exit 1 fi LIBS="${TMPLIBS}" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int eo = 0; eo |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : pcre_match_limit_recursion_available=yes else : fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$pcre_match_limit_recursion_available" != "yes"; then CFLAGS="${CFLAGS} -DNO_PCRE_MATCH_RLIMIT" echo echo " Warning! pcre extra opt PCRE_EXTRA_MATCH_LIMIT_RECURSION not found" echo " This could lead to potential DoS please upgrade to pcre >= 6.5" echo " Continuing for now...." echo " from www.pcre.org." echo fi #enable support for PCRE-jit available since pcre-8.20 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PCRE JIT support" >&5 $as_echo_n "checking for PCRE JIT support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int jit = 0; pcre_config(PCRE_CONFIG_JIT, &jit); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : pcre_jit_available=yes else pcre_jit_available=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "x$pcre_jit_available" = "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define PCRE_HAVE_JIT 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PCRE JIT support usability" >&5 $as_echo_n "checking for PCRE JIT support usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { const char* regexstr = "(a|b|c|d)"; pcre *re; const char *error; pcre_extra *extra; int err_offset; re = pcre_compile(regexstr,0, &error, &err_offset,NULL); extra = pcre_study(re, PCRE_STUDY_JIT_COMPILE, &error); if (extra == NULL) exit(EXIT_FAILURE); int jit = 0; int ret = pcre_fullinfo(re, extra, PCRE_INFO_JIT, &jit); if (ret != 0 || jit != 1) exit(EXIT_FAILURE); exit(EXIT_SUCCESS); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : pcre_jit_works=yes else : fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "x$pcre_jit_works" != "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } echo echo " PCRE JIT support detection worked but testing it failed" echo " something odd is going on, please file a bug report." echo exit 1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # libyaml # Check whether --with-libyaml_includes was given. if test "${with_libyaml_includes+set}" = set; then : withval=$with_libyaml_includes; with_libyaml_includes="$withval" else with_libyaml_includes=no fi # Check whether --with-libyaml_libraries was given. if test "${with_libyaml_libraries+set}" = set; then : withval=$with_libyaml_libraries; with_libyaml_libraries="$withval" else with_libyaml_libraries="no" fi if test "$with_libyaml_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libyaml_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "yaml.h" "ac_cv_header_yaml_h" "$ac_includes_default" if test "x$ac_cv_header_yaml_h" = xyes; then : else LIBYAML="no" fi if test "$with_libyaml_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libyaml_libraries}" fi LIBYAML="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for yaml_parser_initialize in -lyaml" >&5 $as_echo_n "checking for yaml_parser_initialize in -lyaml... " >&6; } if ${ac_cv_lib_yaml_yaml_parser_initialize+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lyaml $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char yaml_parser_initialize (); int main () { return yaml_parser_initialize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_yaml_yaml_parser_initialize=yes else ac_cv_lib_yaml_yaml_parser_initialize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_yaml_yaml_parser_initialize" >&5 $as_echo "$ac_cv_lib_yaml_yaml_parser_initialize" >&6; } if test "x$ac_cv_lib_yaml_yaml_parser_initialize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBYAML 1 _ACEOF LIBS="-lyaml $LIBS" else LIBYAML="no" fi if test "$LIBYAML" = "no"; then echo echo " ERROR! libyaml library not found, go get it" echo " from http://pyyaml.org/wiki/LibYAML " echo " or your distribution:" echo echo " Ubuntu: apt-get install libyaml-dev" echo " Fedora: yum install libyaml-devel" echo exit 1 fi # libpthread # Check whether --with-libpthread_includes was given. if test "${with_libpthread_includes+set}" = set; then : withval=$with_libpthread_includes; with_libpthread_includes="$withval" else with_libpthread_includes=no fi # Check whether --with-libpthread_libraries was given. if test "${with_libpthread_libraries+set}" = set; then : withval=$with_libpthread_libraries; with_libpthread_libraries="$withval" else with_libpthread_libraries="no" fi if test "$with_libpthread_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libpthread_includes}" fi if test "$with_libpthread_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libpthread_libraries}" fi PTHREAD="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create=yes else ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" else PTHREAD="no" fi if test "$PTHREAD" = "no"; then echo echo " ERROR! libpthread library not found, glibc problem?" echo exit 1 fi # libjansson enable_jansson="no" # Check whether --with-libjansson_includes was given. if test "${with_libjansson_includes+set}" = set; then : withval=$with_libjansson_includes; with_libjansson_includes="$withval" else with_libjansson_includes=no fi # Check whether --with-libjansson_libraries was given. if test "${with_libjansson_libraries+set}" = set; then : withval=$with_libjansson_libraries; with_libjansson_libraries="$withval" else with_libjansson_libraries="no" fi if test "$with_libjansson_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libjansson_includes}" fi enable_jansson="no" enable_unixsocket="no" # Check whether --enable-unix-socket was given. if test "${enable_unix_socket+set}" = set; then : enableval=$enable_unix_socket; enable_unixsocket="$enableval" else enable_unixsocket=test fi ac_fn_c_check_header_mongrel "$LINENO" "jansson.h" "ac_cv_header_jansson_h" "$ac_includes_default" if test "x$ac_cv_header_jansson_h" = xyes; then : JANSSON="yes" else JANSSON="no" fi if test "$JANSSON" = "yes"; then if test "$with_libjansson_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libjansson_libraries}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_dump_callback in -ljansson" >&5 $as_echo_n "checking for json_dump_callback in -ljansson... " >&6; } if ${ac_cv_lib_jansson_json_dump_callback+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ljansson $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char json_dump_callback (); int main () { return json_dump_callback (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_jansson_json_dump_callback=yes else ac_cv_lib_jansson_json_dump_callback=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jansson_json_dump_callback" >&5 $as_echo "$ac_cv_lib_jansson_json_dump_callback" >&6; } if test "x$ac_cv_lib_jansson_json_dump_callback" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBJANSSON 1 _ACEOF LIBS="-ljansson $LIBS" else JANSSON="no" fi enable_jansson="yes" if test "$JANSSON" = "no"; then echo echo " Jansson >= 2.2 is required for features like unix socket" echo " Go get it from your distribution of from:" echo " http://www.digip.org/jansson/" echo if test "x$enable_unixsocket" = "xyes"; then exit 1 fi enable_unixsocket="no" enable_jansson="no" else case $host in *-*-mingw32*) ;; *-*-cygwin) ;; *) if test "x$enable_unixsocket" = "xtest"; then enable_unixsocket="yes" fi ;; esac fi else if test "x$enable_unixsocket" = "xyes"; then echo echo " Jansson >= 2.2 is required for features like unix socket" echo " Go get it from your distribution of from:" echo " http://www.digip.org/jansson/" echo exit 1 fi enable_unixsocket="no" fi if test "x$enable_unixsocket" = "xyes"; then : $as_echo "#define BUILD_UNIX_SOCKET 1" >>confdefs.h fi #enable support for NFQUEUE # Check whether --enable-nfqueue was given. if test "${enable_nfqueue+set}" = set; then : enableval=$enable_nfqueue; else enable_nfqueue=no fi if test "x$enable_nfqueue" = "xyes"; then : CFLAGS="$CFLAGS -DNFQ" # libnfnetlink case $host in *-*-mingw32*) ;; *) # Check whether --with-libnfnetlink_includes was given. if test "${with_libnfnetlink_includes+set}" = set; then : withval=$with_libnfnetlink_includes; with_libnfnetlink_includes="$withval" else with_libnfnetlink_includes=no fi # Check whether --with-libnfnetlink_libraries was given. if test "${with_libnfnetlink_libraries+set}" = set; then : withval=$with_libnfnetlink_libraries; with_libnfnetlink_libraries="$withval" else with_libnfnetlink_libraries="no" fi if test "$with_libnfnetlink_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libnfnetlink_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "libnfnetlink/libnfnetlink.h" "ac_cv_header_libnfnetlink_libnfnetlink_h" "$ac_includes_default" if test "x$ac_cv_header_libnfnetlink_libnfnetlink_h" = xyes; then : else as_fn_error $? "libnfnetlink.h not found ..." "$LINENO" 5 fi if test "$with_libnfnetlink_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libnfnetlink_libraries}" fi NFNL="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nfnl_fd in -lnfnetlink" >&5 $as_echo_n "checking for nfnl_fd in -lnfnetlink... " >&6; } if ${ac_cv_lib_nfnetlink_nfnl_fd+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnfnetlink $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nfnl_fd (); int main () { return nfnl_fd (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nfnetlink_nfnl_fd=yes else ac_cv_lib_nfnetlink_nfnl_fd=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nfnetlink_nfnl_fd" >&5 $as_echo "$ac_cv_lib_nfnetlink_nfnl_fd" >&6; } if test "x$ac_cv_lib_nfnetlink_nfnl_fd" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNFNETLINK 1 _ACEOF LIBS="-lnfnetlink $LIBS" else NFNL="no" fi if test "$NFNL" = "no"; then echo echo " ERROR! nfnetlink library not found, go get it" echo " from www.netfilter.org." echo " we automatically append libnetfilter_queue/ when searching" echo " for headers etc. when the --with-libnfnetlink-inlcudes directive" echo " is used" echo exit 1 fi ;; esac #libnetfilter_queue # Check whether --with-libnetfilter_queue_includes was given. if test "${with_libnetfilter_queue_includes+set}" = set; then : withval=$with_libnetfilter_queue_includes; with_libnetfilter_queue_includes="$withval" else with_libnetfilter_queue_includes=no fi # Check whether --with-libnetfilter_queue_libraries was given. if test "${with_libnetfilter_queue_libraries+set}" = set; then : withval=$with_libnetfilter_queue_libraries; with_libnetfilter_queue_libraries="$withval" else with_libnetfilter_queue_libraries="no" fi if test "$with_libnetfilter_queue_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libnetfilter_queue_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "libnetfilter_queue/libnetfilter_queue.h" "ac_cv_header_libnetfilter_queue_libnetfilter_queue_h" "$ac_includes_default" if test "x$ac_cv_header_libnetfilter_queue_libnetfilter_queue_h" = xyes; then : else as_fn_error $? "libnetfilter_queue/libnetfilter_queue.h not found ..." "$LINENO" 5 fi if test "$with_libnetfilter_queue_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libnetfilter_queue_libraries}" fi #LDFLAGS="${LDFLAGS} -lnetfilter_queue" NFQ="" case $host in *-*-mingw32*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nfq_open in -lnetfilter_queue" >&5 $as_echo_n "checking for nfq_open in -lnetfilter_queue... " >&6; } if ${ac_cv_lib_netfilter_queue_nfq_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetfilter_queue -lws2_32 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nfq_open (); int main () { return nfq_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_netfilter_queue_nfq_open=yes else ac_cv_lib_netfilter_queue_nfq_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netfilter_queue_nfq_open" >&5 $as_echo "$ac_cv_lib_netfilter_queue_nfq_open" >&6; } if test "x$ac_cv_lib_netfilter_queue_nfq_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNETFILTER_QUEUE 1 _ACEOF LIBS="-lnetfilter_queue $LIBS" else NFQ="no" fi # Check whether --with-netfilterforwin_includes was given. if test "${with_netfilterforwin_includes+set}" = set; then : withval=$with_netfilterforwin_includes; with_netfilterforwin_includes="$withval" else with_netfilterforwin_includes=no fi if test "$with_netfilterforwin_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_netfilterforwin_includes}" else CPPFLAGS="${CPPFLAGS} -I../../netfilterforwin" fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nfq_open in -lnetfilter_queue" >&5 $as_echo_n "checking for nfq_open in -lnetfilter_queue... " >&6; } if ${ac_cv_lib_netfilter_queue_nfq_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetfilter_queue $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nfq_open (); int main () { return nfq_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_netfilter_queue_nfq_open=yes else ac_cv_lib_netfilter_queue_nfq_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netfilter_queue_nfq_open" >&5 $as_echo "$ac_cv_lib_netfilter_queue_nfq_open" >&6; } if test "x$ac_cv_lib_netfilter_queue_nfq_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNETFILTER_QUEUE 1 _ACEOF LIBS="-lnetfilter_queue $LIBS" else NFQ="no" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nfq_set_queue_maxlen in -lnetfilter_queue" >&5 $as_echo_n "checking for nfq_set_queue_maxlen in -lnetfilter_queue... " >&6; } if ${ac_cv_lib_netfilter_queue_nfq_set_queue_maxlen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetfilter_queue -lnfnetlink $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nfq_set_queue_maxlen (); int main () { return nfq_set_queue_maxlen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_netfilter_queue_nfq_set_queue_maxlen=yes else ac_cv_lib_netfilter_queue_nfq_set_queue_maxlen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netfilter_queue_nfq_set_queue_maxlen" >&5 $as_echo "$ac_cv_lib_netfilter_queue_nfq_set_queue_maxlen" >&6; } if test "x$ac_cv_lib_netfilter_queue_nfq_set_queue_maxlen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NFQ_MAXLEN 1 _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nfq_set_verdict2 in -lnetfilter_queue" >&5 $as_echo_n "checking for nfq_set_verdict2 in -lnetfilter_queue... " >&6; } if ${ac_cv_lib_netfilter_queue_nfq_set_verdict2+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetfilter_queue -lnfnetlink $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nfq_set_verdict2 (); int main () { return nfq_set_verdict2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_netfilter_queue_nfq_set_verdict2=yes else ac_cv_lib_netfilter_queue_nfq_set_verdict2=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netfilter_queue_nfq_set_verdict2" >&5 $as_echo "$ac_cv_lib_netfilter_queue_nfq_set_verdict2" >&6; } if test "x$ac_cv_lib_netfilter_queue_nfq_set_verdict2" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NFQ_SET_VERDICT2 1 _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nfq_set_queue_flags in -lnetfilter_queue" >&5 $as_echo_n "checking for nfq_set_queue_flags in -lnetfilter_queue... " >&6; } if ${ac_cv_lib_netfilter_queue_nfq_set_queue_flags+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetfilter_queue -lnfnetlink $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nfq_set_queue_flags (); int main () { return nfq_set_queue_flags (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_netfilter_queue_nfq_set_queue_flags=yes else ac_cv_lib_netfilter_queue_nfq_set_queue_flags=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netfilter_queue_nfq_set_queue_flags" >&5 $as_echo "$ac_cv_lib_netfilter_queue_nfq_set_queue_flags" >&6; } if test "x$ac_cv_lib_netfilter_queue_nfq_set_queue_flags" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NFQ_SET_QUEUE_FLAGS 1 _ACEOF fi # check if the argument to nfq_get_payload is signed or unsigned { $as_echo "$as_me:${as_lineno-$LINENO}: checking for signed nfq_get_payload payload argument" >&5 $as_echo_n "checking for signed nfq_get_payload payload argument... " >&6; } STORECFLAGS="${CFLAGS}" if test `basename $CC` = "clang"; then CFLAGS="${CFLAGS} -Werror=incompatible-pointer-types" else CFLAGS="${CFLAGS} -Werror" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *pktdata; nfq_get_payload(NULL, &pktdata); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : libnetfilter_queue_nfq_get_payload_signed="yes" else libnetfilter_queue_nfq_get_payload_signed="no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libnetfilter_queue_nfq_get_payload_signed" >&5 $as_echo "$libnetfilter_queue_nfq_get_payload_signed" >&6; } if test "x$libnetfilter_queue_nfq_get_payload_signed" = "xyes"; then $as_echo "#define NFQ_GET_PAYLOAD_SIGNED 1" >>confdefs.h fi CFLAGS="${STORECFLAGS}" ;; esac if test "$NFQ" = "no"; then echo echo " ERROR! libnetfilter_queue library not found, go get it" echo " from www.netfilter.org." echo " we automatically append libnetfilter_queue/ when searching" echo " for headers etc. when the --with-libnfq-includes directive" echo " is used" echo exit 1 fi fi # prelude # Check whether --enable-prelude was given. if test "${enable_prelude+set}" = set; then : enableval=$enable_prelude; else enable_prelude=no fi if test "x$enable_prelude" = "xyes"; then : CFLAGS="$CFLAGS -DPRELUDE" # Check whether --with-libprelude-prefix was given. if test "${with_libprelude_prefix+set}" = set; then : withval=$with_libprelude_prefix; libprelude_config_prefix="$withval" else libprelude_config_prefix="" fi if test x$libprelude_config_prefix != x ; then if test x${LIBPRELUDE_CONFIG+set} != xset ; then LIBPRELUDE_CONFIG=$libprelude_config_prefix/bin/libprelude-config fi fi # Extract the first word of "libprelude-config", so it can be a program name with args. set dummy libprelude-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_LIBPRELUDE_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $LIBPRELUDE_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_LIBPRELUDE_CONFIG="$LIBPRELUDE_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_LIBPRELUDE_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_LIBPRELUDE_CONFIG" && ac_cv_path_LIBPRELUDE_CONFIG="no" ;; esac fi LIBPRELUDE_CONFIG=$ac_cv_path_LIBPRELUDE_CONFIG if test -n "$LIBPRELUDE_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBPRELUDE_CONFIG" >&5 $as_echo "$LIBPRELUDE_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$LIBPRELUDE_CONFIG" != "no"; then if $($LIBPRELUDE_CONFIG --thread > /dev/null 2>&1); then LIBPRELUDE_PTHREAD_CFLAGS=`$LIBPRELUDE_CONFIG --thread --cflags` if test xno = xtrue || test xno = xyes; then libprelude_config_args="--thread" else libprelude_config_args="--no-thread" fi else LIBPRELUDE_PTHREAD_CFLAGS=`$LIBPRELUDE_CONFIG --pthread-cflags` fi fi min_libprelude_version=0.9.9 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libprelude - version >= $min_libprelude_version" >&5 $as_echo_n "checking for libprelude - version >= $min_libprelude_version... " >&6; } no_libprelude="" if test "$LIBPRELUDE_CONFIG" = "no" ; then no_libprelude=yes else LIBPRELUDE_CFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --cflags` LIBPRELUDE_LDFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --ldflags` LIBPRELUDE_LIBS=`$LIBPRELUDE_CONFIG $libprelude_config_args --libs` LIBPRELUDE_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --prefix` LIBPRELUDE_CONFIG_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --config-prefix` libprelude_config_version=`$LIBPRELUDE_CONFIG $libprelude_config_args --version` ac_save_CFLAGS="$CFLAGS" ac_save_LDFLAGS="$LDFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS" LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS" LIBS="$LIBS $LIBPRELUDE_LIBS" rm -f conf.libpreludetest if test "$cross_compiling" = yes; then : echo $ac_n "cross compiling; assumed OK... $ac_c" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { system ("touch conf.libpreludetest"); if( strcmp( prelude_check_version(NULL), "$libprelude_config_version" ) ) { printf("\n*** 'libprelude-config --version' returned %s, but LIBPRELUDE (%s)\n", "$libprelude_config_version", prelude_check_version(NULL) ); printf("*** was found! If libprelude-config was correct, then it is best\n"); printf("*** to remove the old version of LIBPRELUDE. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If libprelude-config was wrong, set the environment variable LIBPRELUDE_CONFIG\n"); printf("*** to point to the correct copy of libprelude-config, and remove the file config.cache\n"); printf("*** before re-running configure\n"); } else if ( strcmp(prelude_check_version(NULL), LIBPRELUDE_VERSION ) ) { printf("\n*** LIBPRELUDE header file (version %s) does not match\n", LIBPRELUDE_VERSION); printf("*** library (version %s)\n", prelude_check_version(NULL) ); } else { if ( prelude_check_version( "$min_libprelude_version" ) ) return 0; else { printf("no\n*** An old version of LIBPRELUDE (%s) was found.\n", prelude_check_version(NULL) ); printf("*** You need a version of LIBPRELUDE newer than %s. The latest version of\n", "$min_libprelude_version" ); printf("*** LIBPRELUDE is always available from http://www.prelude-ids.com/development/download/\n"); printf("*** \n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the libprelude-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of LIBPRELUDE, but you can also set the LIBPRELUDE_CONFIG environment to point to the\n"); printf("*** correct copy of libprelude-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else no_libprelude=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" LDFLAGS="$ac_save_LDFLAGS" fi if test "x$no_libprelude" = x ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : else if test -f conf.libpreludetest ; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$LIBPRELUDE_CONFIG" = "no" ; then echo "*** The libprelude-config script installed by LIBPRELUDE could not be found" echo "*** If LIBPRELUDE was installed in PREFIX, make sure PREFIX/bin is in" echo "*** your path, or set the LIBPRELUDE_CONFIG environment variable to the" echo "*** full path to libprelude-config." else if test -f conf.libpreludetest ; then : else echo "*** Could not run libprelude test program, checking why..." CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS" LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS" LIBS="$LIBS $LIBPRELUDE_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { return !!prelude_check_version(NULL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding LIBPRELUDE or finding the wrong" echo "*** version of LIBPRELUDE. If it is not finding LIBPRELUDE, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" echo "***" else echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means LIBPRELUDE was incorrectly installed" echo "*** or that you have moved LIBPRELUDE since it was installed. In the latter case, you" echo "*** may want to edit the libprelude-config script: $LIBPRELUDE_CONFIG" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$ac_save_CFLAGS" LDFLAGS="$ac_save_LDFLAGS" LIBS="$ac_save_LIBS" fi fi LIBPRELUDE_CFLAGS="" LIBPRELUDE_LDFLAGS="" LIBPRELUDE_LIBS="" as_fn_error $? "Cannot find libprelude: Is libprelude-config in the path?" "$LINENO" 5 fi rm -f conf.libpreludetest $as_echo "#define PRELUDE_APPLICATION_USE_LIBTOOL2 /**/" >>confdefs.h if test "x${LIBPRELUDE_CFLAGS}" != "x"; then CPPFLAGS="${CPPFLAGS} ${LIBPRELUDE_CFLAGS}" fi if test "x${LIBPRELUDE_LDFLAGS}" != "x"; then LDFLAGS="${LDFLAGS} ${LIBPRELUDE_LDFLAGS}" fi if test "x${LIBPRELUDE_LIBS}" != "x"; then LDFLAGS="${LDFLAGS} ${LIBPRELUDE_LIBS}" fi fi # libnet # Check whether --with-libnet_includes was given. if test "${with_libnet_includes+set}" = set; then : withval=$with_libnet_includes; with_libnet_includes="$withval" else with_libnet_includes="no" fi # Check whether --with-libnet_libraries was given. if test "${with_libnet_libraries+set}" = set; then : withval=$with_libnet_libraries; with_libnet_libraries="$withval" else with_libnet_libraries="no" fi if test "x$with_libnet_includes" != "xno"; then CPPFLAGS="${CPPFLAGS} -I${with_libnet_includes}" libnet_dir="${with_libnet_includes}" else libnet_dir="/usr/include /usr/local/include /usr/local/include/libnet11 /opt/local/include /usr/local/include/libnet-1.1" fi if test "x$with_libnet_libraries" != "xno"; then LDFLAGS="${LDFLAGS} -L${with_libnet_libraries}" fi LIBNET_DETECT_FAIL="no" LIBNET_INC_DIR="" for i in $libnet_dir; do if test -r "$i/libnet.h"; then LIBNET_INC_DIR="$i" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnet.h version 1.1.x" >&5 $as_echo_n "checking for libnet.h version 1.1.x... " >&6; } if test "$LIBNET_INC_DIR" != ""; then if eval "grep LIBNET_VERSION $LIBNET_INC_DIR/libnet.h | grep -v 1.1 >/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } LIBNET_DETECT_FAIL="yes" echo echo "*************************************************************************" echo " Warning! libnet version 1.1.x could not be found in " $libnet_dir echo " Reject keywords will not be supported." echo " If you require reject support plese install libnet 1.1.x. " echo " If libnet is not installed in a non-standard location please use the" echo " --with-libnet-includes and --with-libnet-libraries configure options" echo "*************************************************************************" echo else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi #CentOS, Fedora, Ubuntu-LTS, Ubuntu all set defines to the same values. libnet-config seems #to have been depreciated but all distro's seem to include it as part of the package. if test "$LIBNET_DETECT_FAIL" = "no"; then LLIBNET="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnet_write in -lnet" >&5 $as_echo_n "checking for libnet_write in -lnet... " >&6; } if ${ac_cv_lib_net_libnet_write+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char libnet_write (); int main () { return libnet_write (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_net_libnet_write=yes else ac_cv_lib_net_libnet_write=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_net_libnet_write" >&5 $as_echo "$ac_cv_lib_net_libnet_write" >&6; } if test "x$ac_cv_lib_net_libnet_write" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNET 1 _ACEOF LIBS="-lnet $LIBS" else LLIBNET="no" fi if test "$LLIBNET" != "no"; then CFLAGS="${CFLAGS} -DHAVE_LIBNET11 -D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H" else #if we displayed a warning already no reason to do it again. if test "$LIBNET_DETECT_FAIL" = "no"; then LIBNET_DETECT_FAIL="yes" echo echo "*************************************************************************" echo " Warning! libnet version 1.1.x could not be found in " $libnet_dir echo " Reject keywords will not be supported." echo " If you require reject support plese install libnet 1.1.x. " echo " If libnet is not installed in a non-standard location please use the" echo " --with-libnet-includes and --with-libnet-libraries configure options" echo "*************************************************************************" echo fi fi # see if we have the patched libnet 1.1 # http://www.inliniac.net/blog/2007/10/16/libnet-11-ipv6-fixes-and-additions.html # # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work # see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful if test "$LIBNET_DETECT_FAIL" = "no"; then LLIBNET="" TMPLIBS="${LIBS}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnet_build_icmpv6_unreach in -lnet" >&5 $as_echo_n "checking for libnet_build_icmpv6_unreach in -lnet... " >&6; } if ${ac_cv_lib_net_libnet_build_icmpv6_unreach+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char libnet_build_icmpv6_unreach (); int main () { return libnet_build_icmpv6_unreach (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_net_libnet_build_icmpv6_unreach=yes else ac_cv_lib_net_libnet_build_icmpv6_unreach=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_net_libnet_build_icmpv6_unreach" >&5 $as_echo "$ac_cv_lib_net_libnet_build_icmpv6_unreach" >&6; } if test "x$ac_cv_lib_net_libnet_build_icmpv6_unreach" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNET 1 _ACEOF LIBS="-lnet $LIBS" else LLIBNET="no" fi if test "$LLIBNET" != "no"; then CFLAGS="$CFLAGS -DHAVE_LIBNET_ICMPV6_UNREACH" fi LIBS="${TMPLIBS}" fi fi else LIBNET_DETECT_FAIL="yes" echo echo "*************************************************************************" echo " Warning! libnet version 1.1.x could not be found in " $libnet_dir echo " Reject keywords will not be supported." echo " If you require reject support plese install libnet 1.1.x. " echo " If libnet is not installed in a non-standard location please use the" echo " --with-libnet-includes and --with-libnet-libraries configure options" echo "*************************************************************************" echo fi # libpfring (currently only supported for libpcap enabled pfring) # Error on the side of caution. If libpfring enabled pcap is being used and we don't link against -lpfring compilation will fail. # Check whether --enable-pfring was given. if test "${enable_pfring+set}" = set; then : enableval=$enable_pfring; else enable_pfring=no fi if test "x$enable_pfring" = "xyes"; then : CFLAGS="$CFLAGS -DHAVE_PFRING" #We have to set CFLAGS for AC_TRY_COMPILE as it doesn't pay attention to CPPFLAGS # Check whether --with-libpfring_includes was given. if test "${with_libpfring_includes+set}" = set; then : withval=$with_libpfring_includes; with_libpfring_includes="$withval" else with_libpfring_includes=no fi # Check whether --with-libpfring_libraries was given. if test "${with_libpfring_libraries+set}" = set; then : withval=$with_libpfring_libraries; with_libpfring_libraries="$withval" else with_libpfring_libraries="no" fi if test "$with_libpfring_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libpfring_includes}" fi if test "$with_libpfring_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libpfring_libraries}" fi LIBPFRING="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pfring_open in -lpfring" >&5 $as_echo_n "checking for pfring_open in -lpfring... " >&6; } if ${ac_cv_lib_pfring_pfring_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpfring -lpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pfring_open (); int main () { return pfring_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pfring_pfring_open=yes else ac_cv_lib_pfring_pfring_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pfring_pfring_open" >&5 $as_echo "$ac_cv_lib_pfring_pfring_open" >&6; } if test "x$ac_cv_lib_pfring_pfring_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPFRING 1 _ACEOF LIBS="-lpfring $LIBS" else LIBPFRING="no" fi if test "$LIBPFRING" = "no"; then LIBPFRING="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pfring_stats in -lpfring" >&5 $as_echo_n "checking for pfring_stats in -lpfring... " >&6; } if ${ac_cv_lib_pfring_pfring_stats+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpfring -lpcap -lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pfring_stats (); int main () { return pfring_stats (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pfring_pfring_stats=yes else ac_cv_lib_pfring_pfring_stats=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pfring_pfring_stats" >&5 $as_echo "$ac_cv_lib_pfring_pfring_stats" >&6; } if test "x$ac_cv_lib_pfring_pfring_stats" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPFRING 1 _ACEOF LIBS="-lpfring $LIBS" else LIBPFRING="no" fi if test "$LIBPFRING" = "no"; then if test "x$enable_pfring" = "xyes"; then echo echo " ERROR! --enable-pfring was passed but the library was not found or version is >4, go get it" echo " from http://www.ntop.org/PF_RING.html" echo exit 1 fi else LIBS="${LIBS} -lrt" fi fi LIBPFRING_ENABLE_RING="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pfring_enable_ring in -lpfring" >&5 $as_echo_n "checking for pfring_enable_ring in -lpfring... " >&6; } if ${ac_cv_lib_pfring_pfring_enable_ring+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpfring -lpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pfring_enable_ring (); int main () { return pfring_enable_ring (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pfring_pfring_enable_ring=yes else ac_cv_lib_pfring_pfring_enable_ring=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pfring_pfring_enable_ring" >&5 $as_echo "$ac_cv_lib_pfring_pfring_enable_ring" >&6; } if test "x$ac_cv_lib_pfring_pfring_enable_ring" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPFRING 1 _ACEOF LIBS="-lpfring $LIBS" else LIBPFRING_ENABLE_RING="no" fi if test "$LIBPFRING_ENABLE_RING" != "no"; then $as_echo "#define HAVE_PFRING_ENABLE 1" >>confdefs.h fi LIBPFRING_CLUSTER_TYPE="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pfring_set_cluster in -lpfring" >&5 $as_echo_n "checking for pfring_set_cluster in -lpfring... " >&6; } if ${ac_cv_lib_pfring_pfring_set_cluster+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpfring -lpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pfring_set_cluster (); int main () { return pfring_set_cluster (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pfring_pfring_set_cluster=yes else ac_cv_lib_pfring_pfring_set_cluster=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pfring_pfring_set_cluster" >&5 $as_echo "$ac_cv_lib_pfring_pfring_set_cluster" >&6; } if test "x$ac_cv_lib_pfring_pfring_set_cluster" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPFRING 1 _ACEOF LIBS="-lpfring $LIBS" else LIBPFRING_CLUSTER_TYPE="no" fi if test "$LIBPFRING_CLUSTER_TYPE" != "no"; then $as_echo "#define HAVE_PFRING_CLUSTER_TYPE 1" >>confdefs.h fi LIBPFRING_BPF_FILTER="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pfring_set_bpf_filter in -lpfring" >&5 $as_echo_n "checking for pfring_set_bpf_filter in -lpfring... " >&6; } if ${ac_cv_lib_pfring_pfring_set_bpf_filter+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpfring -lpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pfring_set_bpf_filter (); int main () { return pfring_set_bpf_filter (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pfring_pfring_set_bpf_filter=yes else ac_cv_lib_pfring_pfring_set_bpf_filter=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pfring_pfring_set_bpf_filter" >&5 $as_echo "$ac_cv_lib_pfring_pfring_set_bpf_filter" >&6; } if test "x$ac_cv_lib_pfring_pfring_set_bpf_filter" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPFRING 1 _ACEOF LIBS="-lpfring $LIBS" else LIBPFRING_BPF_FILTER="no" fi LIBPFRING_REMOVE_BPF_FILTER="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pfring_remove_bpf_filter in -lpfring" >&5 $as_echo_n "checking for pfring_remove_bpf_filter in -lpfring... " >&6; } if ${ac_cv_lib_pfring_pfring_remove_bpf_filter+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpfring -lpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pfring_remove_bpf_filter (); int main () { return pfring_remove_bpf_filter (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pfring_pfring_remove_bpf_filter=yes else ac_cv_lib_pfring_pfring_remove_bpf_filter=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pfring_pfring_remove_bpf_filter" >&5 $as_echo "$ac_cv_lib_pfring_pfring_remove_bpf_filter" >&6; } if test "x$ac_cv_lib_pfring_pfring_remove_bpf_filter" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPFRING 1 _ACEOF LIBS="-lpfring $LIBS" else LIBPFRING_REMOVE_BPF_FILTER="no" fi if test "$LIBPFRING_BPF_FILTER" != "no" -a "$LIBPFRING_REMOVE_BPF_FILTER" != "no"; then $as_echo "#define HAVE_PFRING_SET_BPF_FILTER 1" >>confdefs.h fi STORE_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Werror" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if pfring_recv expects u_char**" >&5 $as_echo_n "checking if pfring_recv expects u_char**... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { u_char *buffer; pfring_recv(NULL, &buffer, 0, NULL, 1); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : pfring_recv_uchar_buff=yes else : fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${STORE_CFLAGS}" if test "$pfring_recv_uchar_buff" = "yes"; then $as_echo "#define HAVE_PFRING_RECV_UCHAR 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # check if the argument to nfq_get_payload is signed or unsigned { $as_echo "$as_me:${as_lineno-$LINENO}: checking for post 5.4.0 pfring_open function" >&5 $as_echo_n "checking for post 5.4.0 pfring_open function... " >&6; } STORECFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pfring_open(NULL, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : pfring_new_open="yes" else pfring_new_open="no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pfring_new_open" >&5 $as_echo "$pfring_new_open" >&6; } if test "x$pfring_new_open" = "xyes"; then $as_echo "#define HAVE_PFRING_OPEN_NEW 1" >>confdefs.h fi CFLAGS="${STORECFLAGS}" fi # libpcap # Check whether --with-libpcap_includes was given. if test "${with_libpcap_includes+set}" = set; then : withval=$with_libpcap_includes; with_libpcap_includes="$withval" else with_libpcap_includes=no fi # Check whether --with-libpcap_libraries was given. if test "${with_libpcap_libraries+set}" = set; then : withval=$with_libpcap_libraries; with_libpcap_libraries="$withval" else with_libpcap_libraries="no" fi if test "$with_libpcap_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libpcap_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "pcap.h" "ac_cv_header_pcap_h" "$ac_includes_default" if test "x$ac_cv_header_pcap_h" = xyes; then : else as_fn_error $? "pcap.h not found ..." "$LINENO" 5 fi if test "$with_libpcap_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libpcap_libraries}" fi for ac_header in pcap.h pcap/pcap.h pcap/bpf.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done LIBPCAP="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_open_live in -lpcap" >&5 $as_echo_n "checking for pcap_open_live in -lpcap... " >&6; } if ${ac_cv_lib_pcap_pcap_open_live+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcap -lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcap_open_live (); int main () { return pcap_open_live (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcap_pcap_open_live=yes else ac_cv_lib_pcap_pcap_open_live=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_open_live" >&5 $as_echo "$ac_cv_lib_pcap_pcap_open_live" >&6; } if test "x$ac_cv_lib_pcap_pcap_open_live" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPCAP 1 _ACEOF LIBS="-lpcap $LIBS" else LIBPCAP="no" fi if test "$LIBPCAP" = "no"; then echo echo " ERROR! libpcap library not found, go get it" echo " from http://www.tcpdump.org or your distribution:" echo echo " Ubuntu: apt-get install libpcap-dev" echo " Fedora: yum install libpcap-devel" echo exit 1 fi # pcap_activate and pcap_create only exists in libpcap >= 1.0 LIBPCAPVTEST="" #To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work #see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful TMPLIBS="${LIBS}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_activate in -lpcap" >&5 $as_echo_n "checking for pcap_activate in -lpcap... " >&6; } if ${ac_cv_lib_pcap_pcap_activate+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcap_activate (); int main () { return pcap_activate (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcap_pcap_activate=yes else ac_cv_lib_pcap_pcap_activate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_activate" >&5 $as_echo "$ac_cv_lib_pcap_pcap_activate" >&6; } if test "x$ac_cv_lib_pcap_pcap_activate" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPCAP 1 _ACEOF LIBS="-lpcap $LIBS" else LPCAPVTEST="no" fi if test "$LPCAPVTEST" != "no"; then # Extract the first word of "pcap-config", so it can be a program name with args. set dummy pcap-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_HAVE_PCAP_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $HAVE_PCAP_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_HAVE_PCAP_CONFIG="$HAVE_PCAP_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_HAVE_PCAP_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_HAVE_PCAP_CONFIG" && ac_cv_path_HAVE_PCAP_CONFIG=""no"" ;; esac fi HAVE_PCAP_CONFIG=$ac_cv_path_HAVE_PCAP_CONFIG if test -n "$HAVE_PCAP_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_PCAP_CONFIG" >&5 $as_echo "$HAVE_PCAP_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$HAVE_PCAP_CONFIG" = "no"; then CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=1" else CFLAGS="${CFLAGS} `pcap-config --defines` `pcap-config --cflags` -DLIBPCAP_VERSION_MAJOR=1" fi else CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=0" fi LIBS="${TMPLIBS}" #Appears as if pcap_set_buffer_size is linux only? LIBPCAPSBUFF="" #To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work #see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful TMPLIBS="${LIBS}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_set_buffer_size in -lpcap" >&5 $as_echo_n "checking for pcap_set_buffer_size in -lpcap... " >&6; } if ${ac_cv_lib_pcap_pcap_set_buffer_size+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcap_set_buffer_size (); int main () { return pcap_set_buffer_size (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcap_pcap_set_buffer_size=yes else ac_cv_lib_pcap_pcap_set_buffer_size=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_set_buffer_size" >&5 $as_echo "$ac_cv_lib_pcap_pcap_set_buffer_size" >&6; } if test "x$ac_cv_lib_pcap_pcap_set_buffer_size" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPCAP 1 _ACEOF LIBS="-lpcap $LIBS" else LPCAPSBUFF="no" fi if test "$LPCAPSBUFF" != "no"; then CFLAGS="${CFLAGS} -DHAVE_PCAP_SET_BUFF" fi LIBS="${TMPLIBS}" # AF_PACKET support # Check whether --enable-af-packet was given. if test "${enable_af_packet+set}" = set; then : enableval=$enable_af_packet; else enable_af_packet=yes fi if test "x$enable_af_packet" = "xyes"; then : ac_fn_c_check_decl "$LINENO" "TPACKET_V2" "ac_cv_have_decl_TPACKET_V2" "#include #include " if test "x$ac_cv_have_decl_TPACKET_V2" = xyes; then : $as_echo "#define HAVE_AF_PACKET 1" >>confdefs.h else enable_af_packet="no" fi ac_fn_c_check_decl "$LINENO" "PACKET_FANOUT" "ac_cv_have_decl_PACKET_FANOUT" "#include " if test "x$ac_cv_have_decl_PACKET_FANOUT" = xyes; then : $as_echo "#define HAVE_PACKET_FANOUT 1" >>confdefs.h fi fi # libhtp # Check whether --enable-non-bundled-htp was given. if test "${enable_non_bundled_htp+set}" = set; then : enableval=$enable_non_bundled_htp; else enable_non_bundled_htp=no fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi if test "x$enable_non_bundled_htp" = "xyes"; then : # Check whether --with-libhtp_includes was given. if test "${with_libhtp_includes+set}" = set; then : withval=$with_libhtp_includes; with_libhtp_includes="$withval" else with_libhtp_includes=no fi # Check whether --with-libhtp_libraries was given. if test "${with_libhtp_libraries+set}" = set; then : withval=$with_libhtp_libraries; with_libhtp_libraries="$withval" else with_libhtp_libraries="no" fi if test "$with_libhtp_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libhtp_includes}" fi if test "$with_libhtp_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libhtp_libraries}" fi ac_fn_c_check_header_mongrel "$LINENO" "htp/htp.h" "ac_cv_header_htp_htp_h" "$ac_includes_default" if test "x$ac_cv_header_htp_htp_h" = xyes; then : else as_fn_error $? "htp/htp.h not found ..." "$LINENO" 5 fi LIBHTP="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for htp_conn_create in -lhtp" >&5 $as_echo_n "checking for htp_conn_create in -lhtp... " >&6; } if ${ac_cv_lib_htp_htp_conn_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lhtp $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char htp_conn_create (); int main () { return htp_conn_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_htp_htp_conn_create=yes else ac_cv_lib_htp_htp_conn_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_htp_htp_conn_create" >&5 $as_echo "$ac_cv_lib_htp_htp_conn_create" >&6; } if test "x$ac_cv_lib_htp_htp_conn_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBHTP 1 _ACEOF LIBS="-lhtp $LIBS" else LIBHTP="no" fi if test "$LIBHTP" = "no"; then echo echo " ERROR! libhtp library not found" echo exit 1 fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBHTPMINVERSION" >&5 $as_echo_n "checking for LIBHTPMINVERSION... " >&6; } if test -n "$LIBHTPMINVERSION_CFLAGS"; then pkg_cv_LIBHTPMINVERSION_CFLAGS="$LIBHTPMINVERSION_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"htp >= 0.2.3\""; } >&5 ($PKG_CONFIG --exists --print-errors "htp >= 0.2.3") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBHTPMINVERSION_CFLAGS=`$PKG_CONFIG --cflags "htp >= 0.2.3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBHTPMINVERSION_LIBS"; then pkg_cv_LIBHTPMINVERSION_LIBS="$LIBHTPMINVERSION_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"htp >= 0.2.3\""; } >&5 ($PKG_CONFIG --exists --print-errors "htp >= 0.2.3") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBHTPMINVERSION_LIBS=`$PKG_CONFIG --libs "htp >= 0.2.3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBHTPMINVERSION_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "htp >= 0.2.3" 2>&1` else LIBHTPMINVERSION_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "htp >= 0.2.3" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBHTPMINVERSION_PKG_ERRORS" >&5 libhtp_minver_found="no" elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } libhtp_minver_found="no" else LIBHTPMINVERSION_CFLAGS=$pkg_cv_LIBHTPMINVERSION_CFLAGS LIBHTPMINVERSION_LIBS=$pkg_cv_LIBHTPMINVERSION_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } libhtp_minver_found="yes" fi if test "$libhtp_minver_found" = "no"; then echo echo " ERROR! libhtp was found but is not the minimum version required >=0.2.3" echo exit 1 fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBHTPMAXVERSION" >&5 $as_echo_n "checking for LIBHTPMAXVERSION... " >&6; } if test -n "$LIBHTPMAXVERSION_CFLAGS"; then pkg_cv_LIBHTPMAXVERSION_CFLAGS="$LIBHTPMAXVERSION_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"htp <= 0.3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "htp <= 0.3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBHTPMAXVERSION_CFLAGS=`$PKG_CONFIG --cflags "htp <= 0.3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBHTPMAXVERSION_LIBS"; then pkg_cv_LIBHTPMAXVERSION_LIBS="$LIBHTPMAXVERSION_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"htp <= 0.3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "htp <= 0.3.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBHTPMAXVERSION_LIBS=`$PKG_CONFIG --libs "htp <= 0.3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBHTPMAXVERSION_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "htp <= 0.3.0" 2>&1` else LIBHTPMAXVERSION_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "htp <= 0.3.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBHTPMAXVERSION_PKG_ERRORS" >&5 libhtp_maxver_found="no" elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } libhtp_maxver_found="no" else LIBHTPMAXVERSION_CFLAGS=$pkg_cv_LIBHTPMAXVERSION_CFLAGS LIBHTPMAXVERSION_LIBS=$pkg_cv_LIBHTPMAXVERSION_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } libhtp_maxver_found="yes" fi if test "$libhtp_maxver_found" = "no"; then echo echo " ERROR! libhtp 0.3.x was found but only 0.2.x is supported" echo exit 1 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for htp_config_register_request_uri_normalize in -lhtp" >&5 $as_echo_n "checking for htp_config_register_request_uri_normalize in -lhtp... " >&6; } if ${ac_cv_lib_htp_htp_config_register_request_uri_normalize+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lhtp -lhtp $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char htp_config_register_request_uri_normalize (); int main () { return htp_config_register_request_uri_normalize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_htp_htp_config_register_request_uri_normalize=yes else ac_cv_lib_htp_htp_config_register_request_uri_normalize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_htp_htp_config_register_request_uri_normalize" >&5 $as_echo "$ac_cv_lib_htp_htp_config_register_request_uri_normalize" >&6; } if test "x$ac_cv_lib_htp_htp_config_register_request_uri_normalize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_HTP_URI_NORMALIZE_HOOK 1 _ACEOF fi # check for htp_tx_get_response_headers_raw { $as_echo "$as_me:${as_lineno-$LINENO}: checking for htp_tx_get_response_headers_raw in -lhtp" >&5 $as_echo_n "checking for htp_tx_get_response_headers_raw in -lhtp... " >&6; } if ${ac_cv_lib_htp_htp_tx_get_response_headers_raw+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lhtp -lhtp $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char htp_tx_get_response_headers_raw (); int main () { return htp_tx_get_response_headers_raw (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_htp_htp_tx_get_response_headers_raw=yes else ac_cv_lib_htp_htp_tx_get_response_headers_raw=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_htp_htp_tx_get_response_headers_raw" >&5 $as_echo "$ac_cv_lib_htp_htp_tx_get_response_headers_raw" >&6; } if test "x$ac_cv_lib_htp_htp_tx_get_response_headers_raw" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW 1 _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for htp_decode_query_inplace in -lhtp" >&5 $as_echo_n "checking for htp_decode_query_inplace in -lhtp... " >&6; } if ${ac_cv_lib_htp_htp_decode_query_inplace+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lhtp -lhtp $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char htp_decode_query_inplace (); int main () { return htp_decode_query_inplace (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_htp_htp_decode_query_inplace=yes else ac_cv_lib_htp_htp_decode_query_inplace=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_htp_htp_decode_query_inplace" >&5 $as_echo "$ac_cv_lib_htp_htp_decode_query_inplace" >&6; } if test "x$ac_cv_lib_htp_htp_decode_query_inplace" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_HTP_DECODE_QUERY_INPLACE 1 _ACEOF fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "htp_config_set_path_decode_u_encoding" >/dev/null 2>&1; then : cat >>confdefs.h <<_ACEOF #define HAVE_HTP_SET_PATH_DECODE_U_ENCODING 1 _ACEOF fi rm -f conftest* fi # even if we are using an installed htp lib we still need to gen Makefiles inside of htp subdirs="$subdirs libhtp" if test "x$enable_non_bundled_htp" = "xno"; then BUILD_LIBHTP_TRUE= BUILD_LIBHTP_FALSE='#' else BUILD_LIBHTP_TRUE='#' BUILD_LIBHTP_FALSE= fi if test "x$enable_non_bundled_htp" = "xno"; then : cat >>confdefs.h <<_ACEOF #define HAVE_HTP_URI_NORMALIZE_HOOK 1 _ACEOF cat >>confdefs.h <<_ACEOF #define HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW 1 _ACEOF cat >>confdefs.h <<_ACEOF #define HAVE_HTP_DECODE_QUERY_INPLACE 1 _ACEOF fi # enable CUDA output # Check whether --enable-cuda was given. if test "${enable_cuda+set}" = set; then : enableval=$enable_cuda; else enable_cuda=no fi if test "x$enable_cuda" = "xyes"; then : # Check whether --with-cuda_includes was given. if test "${with_cuda_includes+set}" = set; then : withval=$with_cuda_includes; with_cuda_includes="$withval" else with_cuda_includes=no fi # Check whether --with-cuda_libraries was given. if test "${with_cuda_libraries+set}" = set; then : withval=$with_cuda_libraries; with_cuda_libraries="$withval" else with_cuda_libraries="no" fi # Check whether --with-cuda_nvcc was given. if test "${with_cuda_nvcc+set}" = set; then : withval=$with_cuda_nvcc; with_cuda_nvcc="$withval" else with_cuda_nvcc=no fi CFLAGS="${CFLAGS} -D__SC_CUDA_SUPPORT__" if test "$with_cuda_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_cuda_includes}" else CPPFLAGS="${CPPFLAGS} -I/usr/local/cuda/include" fi if test "$with_cuda_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_cuda_libraries}" fi if test "$with_cuda_nvcc" != "no"; then NVCC_DIR="${with_cuda_nvcc}" else NVCC_DIR="/usr/local/cuda/bin" fi ac_fn_c_check_header_mongrel "$LINENO" "cuda.h" "ac_cv_header_cuda_h" "$ac_includes_default" if test "x$ac_cv_header_cuda_h" = xyes; then : else as_fn_error $? "cuda.h not found ..." "$LINENO" 5 fi LIBCUDA="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cuArray3DCreate in -lcuda" >&5 $as_echo_n "checking for cuArray3DCreate in -lcuda... " >&6; } if ${ac_cv_lib_cuda_cuArray3DCreate+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcuda $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char cuArray3DCreate (); int main () { return cuArray3DCreate (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_cuda_cuArray3DCreate=yes else ac_cv_lib_cuda_cuArray3DCreate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cuda_cuArray3DCreate" >&5 $as_echo "$ac_cv_lib_cuda_cuArray3DCreate" >&6; } if test "x$ac_cv_lib_cuda_cuArray3DCreate" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCUDA 1 _ACEOF LIBS="-lcuda $LIBS" else LIBCUDA="no" fi if test "$LIBCUDA" = "no"; then echo echo " ERROR! libcuda library not found" echo exit 1 fi # Extract the first word of "nvcc", so it can be a program name with args. set dummy nvcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_NVCC+:} false; then : $as_echo_n "(cached) " >&6 else case $NVCC in [\\/]* | ?:[\\/]*) ac_cv_path_NVCC="$NVCC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$PATH:$NVCC_DIR" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_NVCC="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_NVCC" && ac_cv_path_NVCC="no" ;; esac fi NVCC=$ac_cv_path_NVCC if test -n "$NVCC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NVCC" >&5 $as_echo "$NVCC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$NVCC" = "xno"; then echo echo " ERROR! CUDA nvcc compiler not found: use --with-cuda-nvcc=DIR" echo exit 1 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nvcc version" >&5 $as_echo_n "checking for nvcc version... " >&6; } NVCCVER=`$NVCC --version | grep "release" | sed 's/.*release \([0-9]\)\.\([0-9]\).*/\1\2/'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NVCCVER" >&5 $as_echo "$NVCCVER" >&6; } if test "$NVCCVER" -lt 31; then echo echo " Warning! Your CUDA nvcc version might be outdated." echo " If compilation fails try the latest CUDA toolkit from" echo " www.nvidia.com/object/cuda_develop.html" echo fi # Find any Python interpreter. if test -z "$PYTHON"; then for ac_prog in python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PYTHON+:} false; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$PYTHON" && break done test -n "$PYTHON" || PYTHON=":" fi am_display_PYTHON=python if test "$PYTHON" = :; then no else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5 $as_echo_n "checking for $am_display_PYTHON version... " >&6; } if ${am_cv_python_version+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[:3])"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5 $as_echo "$am_cv_python_version" >&6; } PYTHON_VERSION=$am_cv_python_version PYTHON_PREFIX='${prefix}' PYTHON_EXEC_PREFIX='${exec_prefix}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5 $as_echo_n "checking for $am_display_PYTHON platform... " >&6; } if ${am_cv_python_platform+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5 $as_echo "$am_cv_python_platform" >&6; } PYTHON_PLATFORM=$am_cv_python_platform # Just factor out some code duplication. am_python_setup_sysconfig="\ import sys # Prefer sysconfig over distutils.sysconfig, for better compatibility # with python 3.x. See automake bug#10227. try: import sysconfig except ImportError: can_use_sysconfig = 0 else: can_use_sysconfig = 1 # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: # try: from platform import python_implementation if python_implementation() == 'CPython' and sys.version[:3] == '2.7': can_use_sysconfig = 0 except ImportError: pass" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5 $as_echo_n "checking for $am_display_PYTHON script directory... " >&6; } if ${am_cv_python_pythondir+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5 $as_echo "$am_cv_python_pythondir" >&6; } pythondir=$am_cv_python_pythondir pkgpythondir=\${pythondir}/$PACKAGE { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5 $as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; } if ${am_cv_python_pyexecdir+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5 $as_echo "$am_cv_python_pyexecdir" >&6; } pyexecdir=$am_cv_python_pyexecdir pkgpyexecdir=\${pyexecdir}/$PACKAGE fi if test "x$PYTHON" = "xno"; then echo echo " ERROR! Compiling CUDA kernels requires python." echo exit 1 fi fi if test "x$enable_cuda" = "xyes"; then BUILD_CUDA_TRUE= BUILD_CUDA_FALSE='#' else BUILD_CUDA_TRUE='#' BUILD_CUDA_FALSE= fi # Check for libcap-ng case $host in *-*-linux*) # Check whether --with-libcap_ng_includes was given. if test "${with_libcap_ng_includes+set}" = set; then : withval=$with_libcap_ng_includes; with_libcap-ng_includes="$withval" else with_libcap_ng_includes=no fi # Check whether --with-libcap_ng_libraries was given. if test "${with_libcap_ng_libraries+set}" = set; then : withval=$with_libcap_ng_libraries; with_libcap_ng_libraries="$withval" else with_libcap_ng_libraries="no" fi if test "$with_libcap_ng_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libcap_ng_includes}" fi if test "$with_libcap_ng_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libcap_ng_libraries}" fi ac_fn_c_check_header_mongrel "$LINENO" "cap-ng.h" "ac_cv_header_cap_ng_h" "$ac_includes_default" if test "x$ac_cv_header_cap_ng_h" = xyes; then : else LIBCAP_NG="no" fi if test "$LIBCAP_NG" != "no"; then LIBCAP_NG="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for capng_clear in -lcap-ng" >&5 $as_echo_n "checking for capng_clear in -lcap-ng... " >&6; } if ${ac_cv_lib_cap_ng_capng_clear+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcap-ng $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char capng_clear (); int main () { return capng_clear (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_cap_ng_capng_clear=yes else ac_cv_lib_cap_ng_capng_clear=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_ng_capng_clear" >&5 $as_echo "$ac_cv_lib_cap_ng_capng_clear" >&6; } if test "x$ac_cv_lib_cap_ng_capng_clear" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCAP_NG 1 _ACEOF LIBS="-lcap-ng $LIBS" else LIBCAP_NG="no" fi fi if test "$LIBCAP_NG" != "no"; then CFLAGS="${CFLAGS} -DHAVE_LIBCAP_NG" fi if test "$LIBCAP_NG" = "no"; then echo echo " WARNING! libcap-ng library not found, go get it" echo " from http://people.redhat.com/sgrubb/libcap-ng/" echo " or your distribution:" echo echo " Ubuntu: apt-get install libcap-ng-dev" echo " Fedora: yum install libcap-ng-devel" echo echo " Suricata will be built without support for dropping privs." echo fi ;; esac # Check for DAG support. # Check whether --enable-dag was given. if test "${enable_dag+set}" = set; then : enableval=$enable_dag; enable_dag=yes else enable_dag=no fi # Check whether --with-dag_includes was given. if test "${with_dag_includes+set}" = set; then : withval=$with_dag_includes; with_dag_includes="$withval" else with_dag_includes="no" fi # Check whether --with-dag_libraries was given. if test "${with_dag_libraries+set}" = set; then : withval=$with_dag_libraries; with_dag_libraries="$withval" else with_dag_libraries="no" fi if test "$enable_dag" = "yes"; then if test "$with_dag_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_dag_includes}" fi if test "$with_dag_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_dag_libraries}" fi ac_fn_c_check_header_mongrel "$LINENO" "dagapi.h" "ac_cv_header_dagapi_h" "$ac_includes_default" if test "x$ac_cv_header_dagapi_h" = xyes; then : DAG="yes" else DAG="no" fi if test "$DAG" != "no"; then DAG="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dag_open in -ldag" >&5 $as_echo_n "checking for dag_open in -ldag... " >&6; } if ${ac_cv_lib_dag_dag_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldag $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dag_open (); int main () { return dag_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dag_dag_open=yes else ac_cv_lib_dag_dag_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_open" >&5 $as_echo "$ac_cv_lib_dag_dag_open" >&6; } if test "x$ac_cv_lib_dag_dag_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDAG 1 _ACEOF LIBS="-ldag $LIBS" else DAG="no" fi fi if test "$DAG" != "no"; then CFLAGS="${CFLAGS} -DHAVE_DAG" fi if test "$DAG" = "no"; then echo echo " ERROR! libdag library not found" echo exit 1 fi fi # libnspr enable_nspr="no" # Check whether --with-libnspr_includes was given. if test "${with_libnspr_includes+set}" = set; then : withval=$with_libnspr_includes; with_libnspr_includes="$withval" else with_libnspr_includes=no fi # Check whether --with-libnspr_libraries was given. if test "${with_libnspr_libraries+set}" = set; then : withval=$with_libnspr_libraries; with_libnspr_libraries="$withval" else with_libnspr_libraries="no" fi if test "$with_libnspr_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libnspr_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "nspr.h" "ac_cv_header_nspr_h" "$ac_includes_default" if test "x$ac_cv_header_nspr_h" = xyes; then : NSPR="yes" else NSPR="no" fi if test "$NSPR" = "yes"; then if test "$with_libnspr_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libnspr_libraries}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PR_GetCurrentThread in -lnspr4" >&5 $as_echo_n "checking for PR_GetCurrentThread in -lnspr4... " >&6; } if ${ac_cv_lib_nspr4_PR_GetCurrentThread+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnspr4 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char PR_GetCurrentThread (); int main () { return PR_GetCurrentThread (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nspr4_PR_GetCurrentThread=yes else ac_cv_lib_nspr4_PR_GetCurrentThread=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nspr4_PR_GetCurrentThread" >&5 $as_echo "$ac_cv_lib_nspr4_PR_GetCurrentThread" >&6; } if test "x$ac_cv_lib_nspr4_PR_GetCurrentThread" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSPR4 1 _ACEOF LIBS="-lnspr4 $LIBS" else NSPR="no" fi if test "$NSPR" = "no"; then echo echo " ERROR! libnspr library not found, go get it" echo " from Mozilla or your distribution:" echo echo " Ubuntu: apt-get install libnspr4-dev" echo " Fedora: yum install nspr-devel" echo exit 1 fi enable_nspr="yes" fi # libnss enable_nss="no" # Check whether --with-libnss_includes was given. if test "${with_libnss_includes+set}" = set; then : withval=$with_libnss_includes; with_libnss_includes="$withval" else with_libnss_includes=no fi # Check whether --with-libnss_libraries was given. if test "${with_libnss_libraries+set}" = set; then : withval=$with_libnss_libraries; with_libnss_libraries="$withval" else with_libnss_libraries="no" fi if test "$with_libnss_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libnss_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "sechash.h" "ac_cv_header_sechash_h" "$ac_includes_default" if test "x$ac_cv_header_sechash_h" = xyes; then : NSS="yes" else NSS="no" fi if test "$NSS" = "yes"; then if test "$with_libnss_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libnss_libraries}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for HASH_Begin in -lnss3" >&5 $as_echo_n "checking for HASH_Begin in -lnss3... " >&6; } if ${ac_cv_lib_nss3_HASH_Begin+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnss3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char HASH_Begin (); int main () { return HASH_Begin (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nss3_HASH_Begin=yes else ac_cv_lib_nss3_HASH_Begin=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nss3_HASH_Begin" >&5 $as_echo "$ac_cv_lib_nss3_HASH_Begin" >&6; } if test "x$ac_cv_lib_nss3_HASH_Begin" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSS3 1 _ACEOF LIBS="-lnss3 $LIBS" else NSS="no" fi if test "$NSS" = "no"; then echo echo " ERROR! libnss library not found, go get it" echo " from Mozilla or your distribution:" echo echo " Ubuntu: apt-get install libnss3-dev" echo " Fedora: yum install nss-devel" echo exit 1 fi $as_echo "#define HAVE_NSS 1" >>confdefs.h enable_nss="yes" fi # libmagic # Check whether --with-libmagic_includes was given. if test "${with_libmagic_includes+set}" = set; then : withval=$with_libmagic_includes; with_libmagic_includes="$withval" else with_libmagic_includes=no fi # Check whether --with-libmagic_libraries was given. if test "${with_libmagic_libraries+set}" = set; then : withval=$with_libmagic_libraries; with_libmagic_libraries="$withval" else with_libmagic_libraries="no" fi if test "$with_libmagic_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libmagic_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "magic.h" "ac_cv_header_magic_h" "$ac_includes_default" if test "x$ac_cv_header_magic_h" = xyes; then : else as_fn_error $? "magic.h not found ..." "$LINENO" 5 fi if test "$with_libmagic_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libmagic_libraries}" fi MAGIC="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for magic_open in -lmagic" >&5 $as_echo_n "checking for magic_open in -lmagic... " >&6; } if ${ac_cv_lib_magic_magic_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmagic $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char magic_open (); int main () { return magic_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_magic_magic_open=yes else ac_cv_lib_magic_magic_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_magic_magic_open" >&5 $as_echo "$ac_cv_lib_magic_magic_open" >&6; } if test "x$ac_cv_lib_magic_magic_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBMAGIC 1 _ACEOF LIBS="-lmagic $LIBS" else MAGIC="no" fi if test "$MAGIC" = "no"; then echo echo " ERROR! magic library not found, go get it" echo " from http://www.darwinsys.com/file/ or your distribution:" echo echo " Ubuntu: apt-get install libmagic-dev" echo " Fedora: yum install file-devel" echo exit 1 fi # Napatech - Using the 3GD API # Check whether --enable-napatech was given. if test "${enable_napatech+set}" = set; then : enableval=$enable_napatech; enable_napatech=yes else enable_napatech=no fi # Check whether --with-napatech_includes was given. if test "${with_napatech_includes+set}" = set; then : withval=$with_napatech_includes; with_napatech_includes="$withval" else with_napatech_includes="/opt/napatech3/include" fi # Check whether --with-napatech_libraries was given. if test "${with_napatech_libraries+set}" = set; then : withval=$with_napatech_libraries; with_napatech_libraries="$withval" else with_napatech_libraries="/opt/napatech3/lib" fi if test "$enable_napatech" = "yes"; then CPPFLAGS="${CPPFLAGS} -I${with_napatech_includes}" LDFLAGS="${LDFLAGS} -L${with_napatech_libraries} -lntapi" ac_fn_c_check_header_mongrel "$LINENO" "nt.h" "ac_cv_header_nt_h" "$ac_includes_default" if test "x$ac_cv_header_nt_h" = xyes; then : NAPATECH="yes" else NAPATECH="no" fi if test "$NAPATECH" != "no"; then NAPATECH="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NT_Init in -lntapi" >&5 $as_echo_n "checking for NT_Init in -lntapi... " >&6; } if ${ac_cv_lib_ntapi_NT_Init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lntapi $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char NT_Init (); int main () { return NT_Init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ntapi_NT_Init=yes else ac_cv_lib_ntapi_NT_Init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ntapi_NT_Init" >&5 $as_echo "$ac_cv_lib_ntapi_NT_Init" >&6; } if test "x$ac_cv_lib_ntapi_NT_Init" = xyes; then : NAPATECH="yes" else NAPATECH="no" fi fi if test "$NAPATECH" != "no"; then CFLAGS="${CFLAGS} -DHAVE_NAPATECH" fi if test "$NAPATECH" = "no"; then echo echo " ERROR! libntapi library not found" echo exit 1 fi fi # libluajit # Check whether --enable-luajit was given. if test "${enable_luajit+set}" = set; then : enableval=$enable_luajit; enable_luajit="yes" else enable_luajit="no" fi # Check whether --with-libluajit_includes was given. if test "${with_libluajit_includes+set}" = set; then : withval=$with_libluajit_includes; with_libluajit_includes="$withval" else with_libluajit_includes="no" fi # Check whether --with-libluajit_libraries was given. if test "${with_libluajit_libraries+set}" = set; then : withval=$with_libluajit_libraries; with_libluajit_libraries="$withval" else with_libluajit_libraries="no" fi if test "$enable_luajit" = "yes"; then if test "$with_libluajit_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libluajit_includes}" else pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUAJIT" >&5 $as_echo_n "checking for LUAJIT... " >&6; } if test -n "$LUAJIT_CFLAGS"; then pkg_cv_LUAJIT_CFLAGS="$LUAJIT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit\""; } >&5 ($PKG_CONFIG --exists --print-errors "luajit") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LUAJIT_CFLAGS=`$PKG_CONFIG --cflags "luajit" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LUAJIT_LIBS"; then pkg_cv_LUAJIT_LIBS="$LUAJIT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit\""; } >&5 ($PKG_CONFIG --exists --print-errors "luajit") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LUAJIT_LIBS=`$PKG_CONFIG --libs "luajit" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LUAJIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "luajit" 2>&1` else LUAJIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "luajit" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LUAJIT_PKG_ERRORS" >&5 LUAJIT="no" elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } LUAJIT="no" else LUAJIT_CFLAGS=$pkg_cv_LUAJIT_CFLAGS LUAJIT_LIBS=$pkg_cv_LUAJIT_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi CPPFLAGS="${CPPFLAGS} ${LUAJIT_CFLAGS}" fi ac_fn_c_check_header_mongrel "$LINENO" "lualib.h" "ac_cv_header_lualib_h" "$ac_includes_default" if test "x$ac_cv_header_lualib_h" = xyes; then : LUAJIT="yes" else LUAJIT="no" fi if test "$LUAJIT" = "yes"; then if test "$with_libluajit_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libluajit_libraries}" else pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUAJIT" >&5 $as_echo_n "checking for LUAJIT... " >&6; } if test -n "$LUAJIT_CFLAGS"; then pkg_cv_LUAJIT_CFLAGS="$LUAJIT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit\""; } >&5 ($PKG_CONFIG --exists --print-errors "luajit") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LUAJIT_CFLAGS=`$PKG_CONFIG --cflags "luajit" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LUAJIT_LIBS"; then pkg_cv_LUAJIT_LIBS="$LUAJIT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit\""; } >&5 ($PKG_CONFIG --exists --print-errors "luajit") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LUAJIT_LIBS=`$PKG_CONFIG --libs "luajit" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LUAJIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "luajit" 2>&1` else LUAJIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "luajit" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LUAJIT_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (luajit) were not met: $LUAJIT_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables LUAJIT_CFLAGS and LUAJIT_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables LUAJIT_CFLAGS and LUAJIT_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else LUAJIT_CFLAGS=$pkg_cv_LUAJIT_CFLAGS LUAJIT_LIBS=$pkg_cv_LUAJIT_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi LDFLAGS="${LDFLAGS} ${LUAJIT_LIBS}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for luaL_openlibs in -lluajit-5.1" >&5 $as_echo_n "checking for luaL_openlibs in -lluajit-5.1... " >&6; } if ${ac_cv_lib_luajit_5_1_luaL_openlibs+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lluajit-5.1 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char luaL_openlibs (); int main () { return luaL_openlibs (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_luajit_5_1_luaL_openlibs=yes else ac_cv_lib_luajit_5_1_luaL_openlibs=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_luajit_5_1_luaL_openlibs" >&5 $as_echo "$ac_cv_lib_luajit_5_1_luaL_openlibs" >&6; } if test "x$ac_cv_lib_luajit_5_1_luaL_openlibs" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBLUAJIT_5_1 1 _ACEOF LIBS="-lluajit-5.1 $LIBS" else LUAJIT="no" fi if test "$LUAJIT" = "no"; then echo echo " ERROR! libluajit library not found, go get it" echo " from http://luajit.org/index.html or your distribution:" echo echo " Ubuntu: apt-get install libluajit-5.1-dev" echo echo " If you installed software in a non-standard prefix" echo " consider adjusting the PKG_CONFIG_PATH environment variable" echo " or use --with-libluajit-libraries configure option." echo exit 1 fi $as_echo "#define HAVE_LUAJIT 1" >>confdefs.h enable_luajit="yes" else echo echo " ERROR! libluajit headers not found, go get them" echo " from http://luajit.org/index.html or your distribution:" echo echo " Ubuntu: apt-get install libluajit-5.1-dev" echo echo " If you installed software in a non-standard prefix" echo " consider adjusting the PKG_CONFIG_PATH environment variable" echo " or use --with-libluajit-includes and --with-libluajit-libraries" echo " configure option." echo exit 1 fi fi # libgeoip # Check whether --enable-geoip was given. if test "${enable_geoip+set}" = set; then : enableval=$enable_geoip; enable_geoip="yes" else enable_geoip="no" fi # Check whether --with-libgeoip_includes was given. if test "${with_libgeoip_includes+set}" = set; then : withval=$with_libgeoip_includes; with_libgeoip_includes="$withval" else with_libgeoip_includes="no" fi # Check whether --with-libgeoip_libraries was given. if test "${with_libgeoip_libraries+set}" = set; then : withval=$with_libgeoip_libraries; with_libgeoip_libraries="$withval" else with_libgeoip_libraries="no" fi if test "$enable_geoip" = "yes"; then if test "$with_libgeoip_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_libgeoip_includes}" fi ac_fn_c_check_header_mongrel "$LINENO" "GeoIP.h" "ac_cv_header_GeoIP_h" "$ac_includes_default" if test "x$ac_cv_header_GeoIP_h" = xyes; then : GEOIP="yes" else GEOIP="no" fi if test "$GEOIP" = "yes"; then if test "$with_libgeoip_libraries" != "no"; then LDFLAGS="${LDFLAGS} -L${with_libgeoip_libraries}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GeoIP_country_code_by_ipnum in -lGeoIP" >&5 $as_echo_n "checking for GeoIP_country_code_by_ipnum in -lGeoIP... " >&6; } if ${ac_cv_lib_GeoIP_GeoIP_country_code_by_ipnum+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lGeoIP $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char GeoIP_country_code_by_ipnum (); int main () { return GeoIP_country_code_by_ipnum (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_GeoIP_GeoIP_country_code_by_ipnum=yes else ac_cv_lib_GeoIP_GeoIP_country_code_by_ipnum=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_GeoIP_GeoIP_country_code_by_ipnum" >&5 $as_echo "$ac_cv_lib_GeoIP_GeoIP_country_code_by_ipnum" >&6; } if test "x$ac_cv_lib_GeoIP_GeoIP_country_code_by_ipnum" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGEOIP 1 _ACEOF LIBS="-lGeoIP $LIBS" else GEOIP="no" fi fi if test "$GEOIP" = "no"; then echo echo " ERROR! libgeoip library not found, go get it" echo " from http://www.maxmind.com/en/geolite or your distribution:" echo echo " Ubuntu: apt-get install libgeoip-dev" echo " Fedora: yum install GeoIP-devel" echo exit 1 fi if test "$GEOIP" = "yes"; then $as_echo "#define HAVE_GEOIP 1" >>confdefs.h enable_geoip="yes" fi fi # get revision if test -f ./revision; then REVISION=`cat ./revision` CFLAGS="${CFLAGS} -DREVISION=\"${REVISION}\"" else # Extract the first word of "git", so it can be a program name with args. set dummy git; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_HAVE_GIT_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $HAVE_GIT_CMD in [\\/]* | ?:[\\/]*) ac_cv_path_HAVE_GIT_CMD="$HAVE_GIT_CMD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_HAVE_GIT_CMD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_HAVE_GIT_CMD" && ac_cv_path_HAVE_GIT_CMD=""no"" ;; esac fi HAVE_GIT_CMD=$ac_cv_path_HAVE_GIT_CMD if test -n "$HAVE_GIT_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_GIT_CMD" >&5 $as_echo "$HAVE_GIT_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$HAVE_GIT_CMD" != "no"; then if test -d .git ; then REVISION=`git rev-parse --short HEAD` CFLAGS="${CFLAGS} -DREVISION=\"${REVISION}\"" fi fi fi # suricata log dir if test "$WINDOWS_PATH" = "yes"; then systemtype="`systeminfo | grep \"based PC\"`" case "$systemtype" in *x64*) e_winbase="C:\\\\Program Files (x86)\\\\Suricata" ;; *) e_winbase="C:\\\\Program Files\\\\Suricata" ;; esac e_sysconfdir="$e_winbase\\\\" e_sysconfrulesdir="$e_winbase\\\\rules\\\\" e_magic_file="$e_winbase\\\\magic.mgc" e_logdir="$e_winbase\\\\log" e_logfilesdir="$e_logdir\\\\files" else e_logdir=$localstatedir if test $prefix = 'NONE'; then prefix="/usr/local" fi while true; do case "$e_logdir" in *\$* ) eval "e_logdir=$e_logdir" ;; *) break ;; esac done eval "e_logdir=$e_logdir"/log/suricata/"" e_rundir=$localstatedir if test $prefix = 'NONE'; then prefix="/usr/local" fi while true; do case "$e_rundir" in *\$* ) eval "e_rundir=$e_rundir" ;; *) break ;; esac done eval "e_rundir=$e_rundir"/run/"" e_logfilesdir=$localstatedir if test $prefix = 'NONE'; then prefix="/usr/local" fi while true; do case "$e_logfilesdir" in *\$* ) eval "e_logfilesdir=$e_logfilesdir" ;; *) break ;; esac done eval "e_logfilesdir=$e_logfilesdir"/log/suricata/files"" e_sysconfdir=$sysconfdir if test $prefix = 'NONE'; then prefix="/usr/local" fi while true; do case "$e_sysconfdir" in *\$* ) eval "e_sysconfdir=$e_sysconfdir" ;; *) break ;; esac done eval "e_sysconfdir=$e_sysconfdir"/suricata/"" e_sysconfrulesdir=$sysconfdir if test $prefix = 'NONE'; then prefix="/usr/local" fi while true; do case "$e_sysconfrulesdir" in *\$* ) eval "e_sysconfrulesdir=$e_sysconfrulesdir" ;; *) break ;; esac done eval "e_sysconfrulesdir=$e_sysconfrulesdir"/suricata/rules"" e_localstatedir=$localstatedir if test $prefix = 'NONE'; then prefix="/usr/local" fi while true; do case "$e_localstatedir" in *\$* ) eval "e_localstatedir=$e_localstatedir" ;; *) break ;; esac done eval "e_localstatedir=$e_localstatedir"/run/suricata"" fi cat >>confdefs.h <<_ACEOF #define CONFIG_DIR "$e_sysconfdir" _ACEOF ac_config_files="$ac_config_files Makefile src/Makefile qa/Makefile qa/coccinelle/Makefile rules/Makefile doc/Makefile contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile suricata.yaml scripts/Makefile scripts/suricatasc/Makefile scripts/suricatasc/suricatasc" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_COCCINELLE_TRUE}" && test -z "${HAVE_COCCINELLE_FALSE}"; then as_fn_error $? "conditional \"HAVE_COCCINELLE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PYTHON_TRUE}" && test -z "${HAVE_PYTHON_FALSE}"; then as_fn_error $? "conditional \"HAVE_PYTHON\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_UNITTESTS_TRUE}" && test -z "${BUILD_UNITTESTS_FALSE}"; then as_fn_error $? "conditional \"BUILD_UNITTESTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_LIBHTP_TRUE}" && test -z "${BUILD_LIBHTP_FALSE}"; then as_fn_error $? "conditional \"BUILD_LIBHTP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_CUDA_TRUE}" && test -z "${BUILD_CUDA_FALSE}"; then as_fn_error $? "conditional \"BUILD_CUDA\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "qa/Makefile") CONFIG_FILES="$CONFIG_FILES qa/Makefile" ;; "qa/coccinelle/Makefile") CONFIG_FILES="$CONFIG_FILES qa/coccinelle/Makefile" ;; "rules/Makefile") CONFIG_FILES="$CONFIG_FILES rules/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "contrib/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;; "contrib/file_processor/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/file_processor/Makefile" ;; "contrib/file_processor/Action/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/file_processor/Action/Makefile" ;; "contrib/file_processor/Processor/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/file_processor/Processor/Makefile" ;; "suricata.yaml") CONFIG_FILES="$CONFIG_FILES suricata.yaml" ;; "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;; "scripts/suricatasc/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/suricatasc/Makefile" ;; "scripts/suricatasc/suricatasc") CONFIG_FILES="$CONFIG_FILES scripts/suricatasc/suricatasc" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ | --c=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 $as_echo "$ac_msg" >&6 as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" # Check for guested configure; otherwise get Cygnus style configure. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure elif test -f "$ac_srcdir/configure.in"; then # This should be Cygnus configure. ac_sub_configure=$ac_aux_dir/configure else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 $as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi SURICATA_BUILD_CONF="Suricata Configuration: AF_PACKET support: ${enable_af_packet} PF_RING support: ${enable_pfring} NFQueue support: ${enable_nfqueue} IPFW support: ${enable_ipfw} DAG enabled: ${enable_dag} Napatech enabled: ${enable_napatech} Unix socket enabled: ${enable_unixsocket} libnss support: ${enable_nss} libnspr support: ${enable_nspr} libjansson support: ${enable_jansson} Prelude support: ${enable_prelude} PCRE jit: ${pcre_jit_available} libluajit: ${enable_luajit} libgeoip: ${enable_geoip} Non-bundled htp: ${enable_non_bundled_htp} Old barnyard2 support: ${enable_old_barnyard2} CUDA enabled: ${enable_cuda} Suricatasc install: ${enable_python} Unit tests enabled: ${enable_unittests} Debug output enabled: ${enable_debug} Debug validation enabled: ${enable_debug_validation} Profiling enabled: ${enable_profiling} Profiling locks enabled: ${enable_profiling_locks} Generic build parameters: Installation prefix (--prefix): ${prefix} Configuration directory (--sysconfdir): ${e_sysconfdir} Log directory (--localstatedir) : ${e_logdir} Host: ${host} GCC binary: ${CC} GCC Protect enabled: ${enable_gccprotect} GCC march native enabled: ${enable_gccmarch_native} GCC Profile enabled: ${enable_gccprofile}" echo echo "$SURICATA_BUILD_CONF" echo "printf(" >${ac_builddir}/src/build-info.h echo "$SURICATA_BUILD_CONF" | sed -e 's/^/"/' | sed -e 's/$/\\n"/' >>${ac_builddir}/src/build-info.h echo ");" >>${ac_builddir}/src/build-info.h echo " To build and install run 'make' and 'make install'. You can run 'make install-conf' if you want to install initial configuration files to ${e_sysconfdir}. Running 'make install-full' will install configuration and rules and provide you a ready-to-run suricata." echo echo "To install Suricata into /usr/bin/suricata, have the config in /etc/suricata and use /var/log/suricata as log dir, use: ./configure --prefix=/usr/ --sysconfdir=/etc/ --localstatedir=/var/" echo suricata-1.4.7/suricata.yaml.in0000644000000000000000000011413012253546156013342 00000000000000%YAML 1.1 --- # Suricata configuration file. In addition to the comments describing all # options in this file, full documentation can be found at: # https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricatayaml # Number of packets allowed to be processed simultaneously. Default is a # conservative 1024. A higher number will make sure CPU's/CPU cores will be # more easily kept busy, but may negatively impact caching. # # If you are using the CUDA pattern matcher (b2g_cuda below), different rules # apply. In that case try something like 4000 or more. This is because the CUDA # pattern matcher scans many packets in parallel. #max-pending-packets: 1024 # Runmode the engine should use. Please check --list-runmodes to get the available # runmodes for each packet acquisition method. Defaults to "autofp" (auto flow pinned # load balancing). #runmode: autofp # Specifies the kind of flow load balancer used by the flow pinned autofp mode. # # Supported schedulers are: # # round-robin - Flows assigned to threads in a round robin fashion. # active-packets - Flows assigned to threads that have the lowest number of # unprocessed packets (default). # hash - Flow alloted usihng the address hash. More of a random # technique. Was the default in Suricata 1.2.1 and older. # #autofp-scheduler: active-packets # Run suricata as user and group. #run-as: # user: suri # group: suri # Default pid file. # Will use this file if no --pidfile in command options. #pid-file: /var/run/suricata.pid # Daemon working directory # Suricata will change directory to this one if provided # Default: "/" #daemon-directory: "/" # Preallocated size for packet. Default is 1514 which is the classical # size for pcap on ethernet. You should adjust this value to the highest # packet size (MTU + hardware header) on your system. #default-packet-size: 1514 # The default logging directory. Any log or output file will be # placed here if its not specified with a full path name. This can be # overridden with the -l command line parameter. default-log-dir: @e_logdir@ # Unix command socket can be used to pass commands to suricata. # An external tool can then connect to get information from suricata # or trigger some modifications of the engine. Set enabled to yes # to activate the feature. You can use the filename variable to set # the file name of the socket. unix-command: enabled: no #filename: custom.socket # Configure the type of alert (and other) logging you would like. outputs: # a line based alerts log similar to Snort's fast.log - fast: enabled: yes filename: fast.log append: yes #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' # alert output for use with Barnyard2 - unified2-alert: enabled: yes filename: unified2.alert # File size limit. Can be specified in kb, mb, gb. Just a number # is parsed as bytes. #limit: 32mb # Sensor ID field of unified2 alerts. #sensor-id: 0 # a line based log of HTTP requests (no alerts) - http-log: enabled: yes filename: http.log append: yes #extended: yes # enable this for extended logging information #custom: yes # enabled the custom logging format (defined by customformat) #customformat: "%{%D-%H:%M:%S}t.%z %{X-Forwarded-For}i %H %m %h %u %s %B %a:%p -> %A:%P" #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' # a line based log of TLS handshake parameters (no alerts) - tls-log: enabled: no # Log TLS connections. filename: tls.log # File to store TLS logs. #extended: yes # Log extended information like fingerprint certs-log-dir: certs # directory to store the certificates files # a line based log to used with pcap file study. # this module is dedicated to offline pcap parsing (empty output # if used with another kind of input). It can interoperate with # pcap parser like wireshark via the suriwire plugin. - pcap-info: enabled: no # Packet log... log packets in pcap format. 2 modes of operation: "normal" # and "sguil". # # In normal mode a pcap file "filename" is created in the default-log-dir, # or are as specified by "dir". In Sguil mode "dir" indicates the base directory. # In this base dir the pcaps are created in th directory structure Sguil expects: # # $sguil-base-dir/YYYY-MM-DD/$filename. # # By default all packets are logged except: # - TCP streams beyond stream.reassembly.depth # - encrypted streams after the key exchange # - pcap-log: enabled: no filename: log.pcap # File size limit. Can be specified in kb, mb, gb. Just a number # is parsed as bytes. limit: 1000mb # If set to a value will enable ring buffer mode. Will keep Maximum of "max-files" of size "limit" max-files: 2000 mode: normal # normal or sguil. #sguil-base-dir: /nsm_data/ #ts-format: usec # sec or usec second format (default) is filename.sec usec is filename.sec.usec use-stream-depth: no #If set to "yes" packets seen after reaching stream inspection depth are ignored. "no" logs all packets # a full alerts log containing much information for signature writers # or for investigating suspected false positives. - alert-debug: enabled: no filename: alert-debug.log append: yes #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' # alert output to prelude (http://www.prelude-technologies.com/) only # available if Suricata has been compiled with --enable-prelude - alert-prelude: enabled: no profile: suricata log-packet-content: no log-packet-header: yes # Stats.log contains data from various counters of the suricata engine. # The interval field (in seconds) tells after how long output will be written # on the log file. - stats: enabled: yes filename: stats.log interval: 8 # a line based alerts log similar to fast.log into syslog - syslog: enabled: no # reported identity to syslog. If ommited the program name (usually # suricata) will be used. #identity: "suricata" facility: local5 #level: Info ## possible levels: Emergency, Alert, Critical, ## Error, Warning, Notice, Info, Debug # a line based information for dropped packets in IPS mode - drop: enabled: no filename: drop.log append: yes #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' # output module to store extracted files to disk # # The files are stored to the log-dir in a format "file." where is # an incrementing number starting at 1. For each file "file." a meta # file "file..meta" is created. # # File extraction depends on a lot of things to be fully done: # - stream reassembly depth. For optimal results, set this to 0 (unlimited) # - http request / response body sizes. Again set to 0 for optimal results. # - rules that contain the "filestore" keyword. - file-store: enabled: no # set to yes to enable log-dir: files # directory to store the files force-magic: no # force logging magic on all stored files force-md5: no # force logging of md5 checksums #waldo: file.waldo # waldo file to store the file_id across runs # output module to log files tracked in a easily parsable json format - file-log: enabled: no filename: files-json.log append: yes #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' force-magic: no # force logging magic on all logged files force-md5: no # force logging of md5 checksums # Magic file. The extension .mgc is added to the value here. #magic-file: /usr/share/file/magic magic-file: @e_magic_file@ # When running in NFQ inline mode, it is possible to use a simulated # non-terminal NFQUEUE verdict. # This permit to do send all needed packet to suricata via this a rule: # iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE # And below, you can have your standard filtering ruleset. To activate # this mode, you need to set mode to 'repeat' # If you want packet to be sent to another queue after an ACCEPT decision # set mode to 'route' and set next-queue value. # On linux >= 3.6, you can set the fail-open option to yes to have the kernel # accept the packet if suricata is not able to keep pace. nfq: # mode: accept # repeat-mark: 1 # repeat-mask: 1 # route-queue: 2 # fail-open: yes # af-packet support # Set threads to > 1 to use PACKET_FANOUT support af-packet: - interface: eth0 # Number of receive threads (>1 will enable experimental flow pinned # runmode) threads: 1 # Default clusterid. AF_PACKET will load balance packets based on flow. # All threads/processes that will participate need to have the same # clusterid. cluster-id: 99 # Default AF_PACKET cluster type. AF_PACKET can load balance per flow or per hash. # This is only supported for Linux kernel > 3.1 # possible value are: # * cluster_round_robin: round robin load balancing # * cluster_flow: all packets of a given flow are send to the same socket # * cluster_cpu: all packets treated in kernel by a CPU are send to the same socket cluster-type: cluster_flow # In some fragmentation case, the hash can not be computed. If "defrag" is set # to yes, the kernel will do the needed defragmentation before sending the packets. defrag: yes # To use the ring feature of AF_PACKET, set 'use-mmap' to yes use-mmap: yes # Ring size will be computed with respect to max_pending_packets and number # of threads. You can set manually the ring size in number of packets by setting # the following value. If you are using flow cluster-type and have really network # intensive single-flow you could want to set the ring-size independantly of the number # of threads: #ring-size: 2048 # On busy system, this could help to set it to yes to recover from a packet drop # phase. This will result in some packets (at max a ring flush) being non treated. #use-emergency-flush: yes # recv buffer size, increase value could improve performance # buffer-size: 32768 # Set to yes to disable promiscuous mode # disable-promisc: no # Choose checksum verification mode for the interface. At the moment # of the capture, some packets may be with an invalid checksum due to # offloading to the network card of the checksum computation. # Possible values are: # - kernel: use indication sent by kernel for each packet (default) # - yes: checksum validation is forced # - no: checksum validation is disabled # - auto: suricata uses a statistical approach to detect when # checksum off-loading is used. # Warning: 'checksum-validation' must be set to yes to have any validation #checksum-checks: kernel # BPF filter to apply to this interface. The pcap filter syntax apply here. #bpf-filter: port 80 or udp # You can use the following variables to activate AF_PACKET tap od IPS mode. # If copy-mode is set to ips or tap, the traffic coming to the current # interface will be copied to the copy-iface interface. If 'tap' is set, the # copy is complete. If 'ips' is set, the packet matching a 'drop' action # will not be copied. #copy-mode: ips #copy-iface: eth1 - interface: eth1 threads: 1 cluster-id: 98 cluster-type: cluster_flow defrag: yes # buffer-size: 32768 # disable-promisc: no # Put default values here - interface: default #threads: 2 #use-mmap: yes # You can specify a threshold config file by setting "threshold-file" # to the path of the threshold config file: # threshold-file: /etc/suricata/threshold.config # The detection engine builds internal groups of signatures. The engine # allow us to specify the profile to use for them, to manage memory on an # efficient way keeping a good performance. For the profile keyword you # can use the words "low", "medium", "high" or "custom". If you use custom # make sure to define the values at "- custom-values" as your convenience. # Usually you would prefer medium/high/low. # # "sgh mpm-context", indicates how the staging should allot mpm contexts for # the signature groups. "single" indicates the use of a single context for # all the signature group heads. "full" indicates a mpm-context for each # group head. "auto" lets the engine decide the distribution of contexts # based on the information the engine gathers on the patterns from each # group head. # # The option inspection-recursion-limit is used to limit the recursive calls # in the content inspection code. For certain payload-sig combinations, we # might end up taking too much time in the content inspection code. # If the argument specified is 0, the engine uses an internally defined # default limit. On not specifying a value, we use no limits on the recursion. detect-engine: - profile: medium - custom-values: toclient-src-groups: 2 toclient-dst-groups: 2 toclient-sp-groups: 2 toclient-dp-groups: 3 toserver-src-groups: 2 toserver-dst-groups: 4 toserver-sp-groups: 2 toserver-dp-groups: 25 - sgh-mpm-context: auto - inspection-recursion-limit: 3000 # When rule-reload is enabled, sending a USR2 signal to the Suricata process # will trigger a live rule reload. Experimental feature, use with care. #- rule-reload: true # If set to yes, the loading of signatures will be made after the capture # is started. This will limit the downtime in IPS mode. #- delayed-detect: yes # Suricata is multi-threaded. Here the threading can be influenced. threading: # On some cpu's/architectures it is beneficial to tie individual threads # to specific CPU's/CPU cores. In this case all threads are tied to CPU0, # and each extra CPU/core has one "detect" thread. # # On Intel Core2 and Nehalem CPU's enabling this will degrade performance. # set-cpu-affinity: no # Tune cpu affinity of suricata threads. Each family of threads can be bound # on specific CPUs. cpu-affinity: - management-cpu-set: cpu: [ 0 ] # include only these cpus in affinity settings - receive-cpu-set: cpu: [ 0 ] # include only these cpus in affinity settings - decode-cpu-set: cpu: [ 0, 1 ] mode: "balanced" - stream-cpu-set: cpu: [ "0-1" ] - detect-cpu-set: cpu: [ "all" ] mode: "exclusive" # run detect threads in these cpus # Use explicitely 3 threads and don't compute number by using # detect-thread-ratio variable: # threads: 3 prio: low: [ 0 ] medium: [ "1-2" ] high: [ 3 ] default: "medium" - verdict-cpu-set: cpu: [ 0 ] prio: default: "high" - reject-cpu-set: cpu: [ 0 ] prio: default: "low" - output-cpu-set: cpu: [ "all" ] prio: default: "medium" # # By default Suricata creates one "detect" thread per available CPU/CPU core. # This setting allows controlling this behaviour. A ratio setting of 2 will # create 2 detect threads for each CPU/CPU core. So for a dual core CPU this # will result in 4 detect threads. If values below 1 are used, less threads # are created. So on a dual core CPU a setting of 0.5 results in 1 detect # thread being created. Regardless of the setting at a minimum 1 detect # thread will always be created. # detect-thread-ratio: 1.5 # Cuda configuration. cuda: # The "mpm" profile. On not specifying any of these parameters, the engine's # internal default values are used, which are same as the ones specified here. - mpm: # Threshold limit for no of packets buffered to the GPU. Once we hit this # limit, we pass the buffer to the gpu. packet-buffer-limit: 2400 # The maximum length for a packet that we would buffer to the gpu. # Anything over this is MPM'ed on the CPU. All entries > 0 are valid. # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. packet-size-limit: 1500 # No of packet buffers we initialize. All entries > 0 are valid. packet-buffers: 10 # The timeout limit for batching of packets in secs. If we don't fill the # buffer within this timeout limit, we pass the currently filled buffer to the gpu. # All entries > 0 are valid. batching-timeout: 1 # Specifies whether to use page-locked memory whereever possible. Accepted values # are "enabled" and "disabled". page-locked: enabled # The device to use for the mpm. Currently we don't support load balancing # on multiple gpus. In case you have multiple devices on your system, you # can specify the device to use, using this conf. By default we hold 0, to # specify the first device cuda sees. To find out device-id associated with # the card(s) on the system run "suricata --list-cuda-cards". device-id: 0 # No of Cuda streams used for asynchronous processing. All values > 0 are valid. # For this option you need a device with Compute Capability > 1.0 and # page-locked enabled to have any effect. cuda-streams: 2 # Select the multi pattern algorithm you want to run for scan/search the # in the engine. The supported algorithms are b2g, b2gc, b2gm, b3g, wumanber, # ac and ac-gfbs. # # The mpm you choose also decides the distribution of mpm contexts for # signature groups, specified by the conf - "detect-engine.sgh-mpm-context". # Selecting "ac" as the mpm would require "detect-engine.sgh-mpm-context" # to be set to "single", because of ac's memory requirements, unless the # ruleset is small enough to fit in one's memory, in which case one can # use "full" with "ac". Rest of the mpms can be run in "full" mode. # # There is also a CUDA pattern matcher (only available if Suricata was # compiled with --enable-cuda: b2g_cuda. Make sure to update your # max-pending-packets setting above as well if you use b2g_cuda. mpm-algo: ac # The memory settings for hash size of these algorithms can vary from lowest # (2048) - low (4096) - medium (8192) - high (16384) - higher (32768) - max # (65536). The bloomfilter sizes of these algorithms can vary from low (512) - # medium (1024) - high (2048). # # For B2g/B3g algorithms, there is a support for two different scan/search # algorithms. For B2g the scan algorithms are B2gScan & B2gScanBNDMq, and # search algorithms are B2gSearch & B2gSearchBNDMq. For B3g scan algorithms # are B3gScan & B3gScanBNDMq, and search algorithms are B3gSearch & # B3gSearchBNDMq. # # For B2g the different scan/search algorithms and, hash and bloom # filter size settings. For B3g the different scan/search algorithms and, hash # and bloom filter size settings. For wumanber the hash and bloom filter size # settings. pattern-matcher: - b2gc: search-algo: B2gSearchBNDMq hash-size: low bf-size: medium - b2gm: search-algo: B2gSearchBNDMq hash-size: low bf-size: medium - b2g: search-algo: B2gSearchBNDMq hash-size: low bf-size: medium - b3g: search-algo: B3gSearchBNDMq hash-size: low bf-size: medium - wumanber: hash-size: low bf-size: medium # Defrag settings: defrag: memcap: 32mb hash-size: 65536 trackers: 65535 # number of defragmented flows to follow max-frags: 65535 # number of fragments to keep (higher than trackers) prealloc: yes timeout: 60 # Flow settings: # By default, the reserved memory (memcap) for flows is 32MB. This is the limit # for flow allocation inside the engine. You can change this value to allow # more memory usage for flows. # The hash-size determine the size of the hash used to identify flows inside # the engine, and by default the value is 65536. # At the startup, the engine can preallocate a number of flows, to get a better # performance. The number of flows preallocated is 10000 by default. # emergency-recovery is the percentage of flows that the engine need to # prune before unsetting the emergency state. The emergency state is activated # when the memcap limit is reached, allowing to create new flows, but # prunning them with the emergency timeouts (they are defined below). # If the memcap is reached, the engine will try to prune flows # with the default timeouts. If it doens't find a flow to prune, it will set # the emergency bit and it will try again with more agressive timeouts. # If that doesn't work, then it will try to kill the last time seen flows # not in use. # The memcap can be specified in kb, mb, gb. Just a number indicates it's # in bytes. flow: memcap: 32mb hash-size: 65536 prealloc: 10000 emergency-recovery: 30 # Specific timeouts for flows. Here you can specify the timeouts that the # active flows will wait to transit from the current state to another, on each # protocol. The value of "new" determine the seconds to wait after a hanshake or # stream startup before the engine free the data of that flow it doesn't # change the state to established (usually if we don't receive more packets # of that flow). The value of "established" is the amount of # seconds that the engine will wait to free the flow if it spend that amount # without receiving new packets or closing the connection. "closed" is the # amount of time to wait after a flow is closed (usually zero). # # There's an emergency mode that will become active under attack circumstances, # making the engine to check flow status faster. This configuration variables # use the prefix "emergency-" and work similar as the normal ones. # Some timeouts doesn't apply to all the protocols, like "closed", for udp and # icmp. flow-timeouts: default: new: 30 established: 300 closed: 0 emergency-new: 10 emergency-established: 100 emergency-closed: 0 tcp: new: 60 established: 3600 closed: 120 emergency-new: 10 emergency-established: 300 emergency-closed: 20 udp: new: 30 established: 300 emergency-new: 10 emergency-established: 100 icmp: new: 30 established: 300 emergency-new: 10 emergency-established: 100 # Stream engine settings. Here the TCP stream tracking and reassembly # engine is configured. # # stream: # memcap: 32mb # Can be specified in kb, mb, gb. Just a # # number indicates it's in bytes. # checksum-validation: yes # To validate the checksum of received # # packet. If csum validation is specified as # # "yes", then packet with invalid csum will not # # be processed by the engine stream/app layer. # # Warning: locally generated trafic can be # # generated without checksum due to hardware offload # # of checksum. You can control the handling of checksum # # on a per-interface basis via the 'checksum-checks' # # option # max-sessions: 262144 # 256k concurrent sessions # prealloc-sessions: 32768 # 32k sessions prealloc'd # midstream: false # don't allow midstream session pickups # async-oneside: false # don't enable async stream handling # inline: no # stream inline mode # # reassembly: # memcap: 64mb # Can be specified in kb, mb, gb. Just a number # # indicates it's in bytes. # depth: 1mb # Can be specified in kb, mb, gb. Just a number # # indicates it's in bytes. # toserver-chunk-size: 2560 # inspect raw stream in chunks of at least # # this size. Can be specified in kb, mb, # # gb. Just a number indicates it's in bytes. # toclient-chunk-size: 2560 # inspect raw stream in chunks of at least # # this size. Can be specified in kb, mb, # # gb. Just a number indicates it's in bytes. stream: memcap: 32mb checksum-validation: yes # reject wrong csums inline: auto # auto will use inline mode in IPS mode, yes or no set it statically reassembly: memcap: 64mb depth: 1mb # reassemble 1mb into a stream toserver-chunk-size: 2560 toclient-chunk-size: 2560 # Host table: # # Host table is used by tagging and per host thresholding subsystems. # host: hash-size: 4096 prealloc: 1000 memcap: 16777216 # Logging configuration. This is not about logging IDS alerts, but # IDS output about what its doing, errors, etc. logging: # The default log level, can be overridden in an output section. # Note that debug level logging will only be emitted if Suricata was # compiled with the --enable-debug configure option. # # This value is overriden by the SC_LOG_LEVEL env var. default-log-level: info # The default output format. Optional parameter, should default to # something reasonable if not provided. Can be overriden in an # output section. You can leave this out to get the default. # # This value is overriden by the SC_LOG_FORMAT env var. #default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " # A regex to filter output. Can be overridden in an output section. # Defaults to empty (no filter). # # This value is overriden by the SC_LOG_OP_FILTER env var. default-output-filter: # Define your logging outputs. If none are defined, or they are all # disabled you will get the default - console output. outputs: - console: enabled: yes - file: enabled: no filename: /var/log/suricata.log - syslog: enabled: no facility: local5 format: "[%i] <%d> -- " # PF_RING configuration. for use with native PF_RING support # for more info see http://www.ntop.org/PF_RING.html pfring: - interface: eth0 # Number of receive threads (>1 will enable experimental flow pinned # runmode) threads: 1 # Default clusterid. PF_RING will load balance packets based on flow. # All threads/processes that will participate need to have the same # clusterid. cluster-id: 99 # Default PF_RING cluster type. PF_RING can load balance per flow or per hash. # This is only supported in versions of PF_RING > 4.1.1. cluster-type: cluster_flow # bpf filter for this interface #bpf-filter: tcp # Choose checksum verification mode for the interface. At the moment # of the capture, some packets may be with an invalid checksum due to # offloading to the network card of the checksum computation. # Possible values are: # - rxonly: only compute checksum for packets received by network card. # - yes: checksum validation is forced # - no: checksum validation is disabled # - auto: suricata uses a statistical approach to detect when # checksum off-loading is used. (default) # Warning: 'checksum-validation' must be set to yes to have any validation #checksum-checks: auto # Second interface #- interface: eth1 # threads: 3 # cluster-id: 93 # cluster-type: cluster_flow # Put default values here - interface: default #threads: 2 pcap: - interface: eth0 # On Linux, pcap will try to use mmaped capture and will use buffer-size # as total of memory used by the ring. So set this to something bigger # than 1% of your bandwidth. #buffer-size: 16777216 #bpf-filter: "tcp and port 25" # Choose checksum verification mode for the interface. At the moment # of the capture, some packets may be with an invalid checksum due to # offloading to the network card of the checksum computation. # Possible values are: # - yes: checksum validation is forced # - no: checksum validation is disabled # - auto: suricata uses a statistical approach to detect when # checksum off-loading is used. (default) # Warning: 'checksum-validation' must be set to yes to have any validation #checksum-checks: auto # With some accelerator cards using a modified libpcap (like myricom), you # may want to have the same number of capture threads as the number of capture # rings. In this case, set up the threads variable to N to start N threads # listening on the same interface. #threads: 16 # set to no to disable promiscuous mode: #promisc: no # set snaplen, if not set it defaults to MTU if MTU can be known # via ioctl call and to full capture if not. #snaplen: 1518 # Put default values here - interface: default #checksum-checks: auto # For FreeBSD ipfw(8) divert(4) support. # Please make sure you have ipfw_load="YES" and ipdivert_load="YES" # in /etc/loader.conf or kldload'ing the appropriate kernel modules. # Additionally, you need to have an ipfw rule for the engine to see # the packets from ipfw. For Example: # # ipfw add 100 divert 8000 ip from any to any # # The 8000 above should be the same number you passed on the command # line, i.e. -d 8000 # ipfw: # Reinject packets at the specified ipfw rule number. This config # option is the ipfw rule number AT WHICH rule processing continues # in the ipfw processing system after the engine has finished # inspecting the packet for acceptance. If no rule number is specified, # accepted packets are reinjected at the divert rule which they entered # and IPFW rule processing continues. No check is done to verify # this will rule makes sense so care must be taken to avoid loops in ipfw. # ## The following example tells the engine to reinject packets # back into the ipfw firewall AT rule number 5500: # # ipfw-reinjection-rule-number: 5500 # Set the default rule path here to search for the files. # if not set, it will look at the current working dir default-rule-path: @e_sysconfdir@rules rule-files: - botcc.rules - ciarmy.rules - compromised.rules - drop.rules - dshield.rules - emerging-activex.rules - emerging-attack_response.rules - emerging-chat.rules - emerging-current_events.rules - emerging-dns.rules - emerging-dos.rules - emerging-exploit.rules - emerging-ftp.rules - emerging-games.rules - emerging-icmp_info.rules - emerging-icmp.rules - emerging-imap.rules - emerging-inappropriate.rules - emerging-malware.rules - emerging-misc.rules - emerging-mobile_malware.rules - emerging-netbios.rules - emerging-p2p.rules - emerging-policy.rules - emerging-pop3.rules - emerging-rpc.rules - emerging-scada.rules - emerging-scan.rules - emerging-shellcode.rules - emerging-smtp.rules - emerging-snmp.rules - emerging-sql.rules - emerging-telnet.rules - emerging-tftp.rules - emerging-trojan.rules - emerging-user_agents.rules - emerging-virus.rules - emerging-voip.rules - emerging-web_client.rules - emerging-web_server.rules - emerging-web_specific_apps.rules - emerging-worm.rules - rbn-malvertisers.rules - rbn.rules - tor.rules - decoder-events.rules # available in suricata sources under rules dir - stream-events.rules # available in suricata sources under rules dir - http-events.rules # available in suricata sources under rules dir - smtp-events.rules # available in suricata sources under rules dir classification-file: @e_sysconfdir@classification.config reference-config-file: @e_sysconfdir@reference.config # Holds variables that would be used by the engine. vars: # Holds the address group vars that would be passed in a Signature. # These would be retrieved during the Signature address parsing stage. address-groups: HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" EXTERNAL_NET: "!$HOME_NET" HTTP_SERVERS: "$HOME_NET" SMTP_SERVERS: "$HOME_NET" SQL_SERVERS: "$HOME_NET" DNS_SERVERS: "$HOME_NET" TELNET_SERVERS: "$HOME_NET" AIM_SERVERS: "$EXTERNAL_NET" DNP3_SERVER: "$HOME_NET" DNP3_CLIENT: "$HOME_NET" MODBUS_CLIENT: "$HOME_NET" MODBUS_SERVER: "$HOME_NET" ENIP_CLIENT: "$HOME_NET" ENIP_SERVER: "$HOME_NET" # Holds the port group vars that would be passed in a Signature. # These would be retrieved during the Signature port parsing stage. port-groups: HTTP_PORTS: "80" SHELLCODE_PORTS: "!80" ORACLE_PORTS: 1521 SSH_PORTS: 22 DNP3_PORTS: 20000 # Set the order of alerts bassed on actions # The default order is pass, drop, reject, alert action-order: - pass - drop - reject - alert # IP Reputation #reputation-categories-file: @e_sysconfdir@iprep/categories.txt #default-reputation-path: @e_sysconfdir@iprep #reputation-files: # - reputation.list # Host specific policies for defragmentation and TCP stream # reassembly. The host OS lookup is done using a radix tree, just # like a routing table so the most specific entry matches. host-os-policy: # Make the default policy windows. windows: [0.0.0.0/0] bsd: [] bsd-right: [] old-linux: [] linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"] old-solaris: [] solaris: ["::1"] hpux10: [] hpux11: [] irix: [] macos: [] vista: [] windows2k3: [] # Limit for the maximum number of asn1 frames to decode (default 256) asn1-max-frames: 256 # When run with the option --engine-analysis, the engine will read each of # the parameters below, and print reports for each of the enabled sections # and exit. The reports are printed to a file in the default log dir # given by the parameter "default-log-dir", with engine reporting # subsection below printing reports in its own report file. engine-analysis: # enables printing reports for fast-pattern for every rule. rules-fast-pattern: yes # enables printing reports for each rule rules: yes #recursion and match limits for PCRE where supported pcre: match-limit: 3500 match-limit-recursion: 1500 ########################################################################### # Configure libhtp. # # # default-config: Used when no server-config matches # personality: List of personalities used by default # request-body-limit: Limit reassembly of request body for inspection # by http_client_body & pcre /P option. # response-body-limit: Limit reassembly of response body for inspection # by file_data, http_server_body & pcre /Q option. # double-decode-path: Double decode path section of the URI # double-decode-query: Double decode query section of the URI # # server-config: List of server configurations to use if address matches # address: List of ip addresses or networks for this block # personalitiy: List of personalities used by this block # request-body-limit: Limit reassembly of request body for inspection # by http_client_body & pcre /P option. # response-body-limit: Limit reassembly of response body for inspection # by file_data, http_server_body & pcre /Q option. # double-decode-path: Double decode path section of the URI # double-decode-query: Double decode query section of the URI # # Currently Available Personalities: # Minimal # Generic # IDS (default) # IIS_4_0 # IIS_5_0 # IIS_5_1 # IIS_6_0 # IIS_7_0 # IIS_7_5 # Apache # Apache_2_2 ########################################################################### libhtp: default-config: personality: IDS # Can be specified in kb, mb, gb. Just a number indicates # it's in bytes. request-body-limit: 3072 response-body-limit: 3072 # inspection limits request-body-minimal-inspect-size: 32kb request-body-inspect-window: 4kb response-body-minimal-inspect-size: 32kb response-body-inspect-window: 4kb # decoding double-decode-path: no double-decode-query: no server-config: - apache: address: [192.168.1.0/24, 127.0.0.0/8, "::1"] personality: Apache_2_2 # Can be specified in kb, mb, gb. Just a number indicates # it's in bytes. request-body-limit: 4096 response-body-limit: 4096 double-decode-path: no double-decode-query: no - iis7: address: - 192.168.0.0/24 - 192.168.10.0/24 personality: IIS_7_0 # Can be specified in kb, mb, gb. Just a number indicates # it's in bytes. request-body-limit: 4096 response-body-limit: 4096 double-decode-path: no double-decode-query: no # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. # profiling: # rule profiling rules: # Profiling can be disabled here, but it will still have a # performance impact if compiled in. enabled: yes filename: rule_perf.log append: yes # Sort options: ticks, avgticks, checks, matches, maxticks sort: avgticks # Limit the number of items printed at exit. limit: 100 # packet profiling packets: # Profiling can be disabled here, but it will still have a # performance impact if compiled in. enabled: yes filename: packet_stats.log append: yes # per packet csv output csv: # Output can be disabled here, but it will still have a # performance impact if compiled in. enabled: no filename: packet_stats.csv # profiling of locking. Only available when Suricata was built with # --enable-profiling-locks. locks: enabled: no filename: lock_stats.log append: yes # Suricata core dump configuration. Limits the size of the core dump file to # approximately max-dump. The actual core dump size will be a multiple of the # page size. Core dumps that would be larger than max-dump are truncated. On # Linux, the actual core dump size may be a few pages larger than max-dump. # Setting max-dump to 0 disables core dumping. # Setting max-dump to 'unlimited' will give the full core dump file. # On 32-bit Linux, a max-dump value >= ULONG_MAX may cause the core dump size # to be 'unlimited'. coredump: max-dump: unlimited napatech: # The Host Buffer Allowance for all streams # (-1 = OFF, 1 - 100 = percentage of the host buffer that can be held back) hba: -1 # use_all_streams set to "yes" will query the Napatech service for all configured # streams and listen on all of them. When set to "no" the streams config array # will be used. use-all-streams: yes # The streams to listen on streams: [1, 2, 3] suricata-1.4.7/contrib/0000755000000000000000000000000012253546204011750 500000000000000suricata-1.4.7/contrib/file_processor/0000755000000000000000000000000012253546204014766 500000000000000suricata-1.4.7/contrib/file_processor/file_processor.conf0000644000000000000000000000047112253546156020603 00000000000000{ "logdir": "/var/log/suricata", "debug_level": "INFO", #"virustotal_apikey": "xxx" "actions": { "Action::Log": 1, "Action::Syslog": 1 }, "processors": { "Processor::Anubis": 1, "Processor::Malwr": 1, "Processor::ThreatExpert": 1, "Processor::ShadowServer": 1 #"Processor::VirusTotal": 1 } } suricata-1.4.7/contrib/file_processor/README0000644000000000000000000000304712253546156015600 00000000000000This directory contains what's needed for reading the JSON file /var/log/suricata/files-json.log and processing those entries against plugins. Included are plugins for checking the MD5 of the observed file on the network against already created reports on anubis.iseclab.org, malwr.com, and threatexpert.com. If you have a virustotal.com API key (free, though see the terms of use on virustotal.com/documentation/public-api/), you can enable the virustotal.com plugin and configure your API key so you can check the MD5 against over forty AV vendors' results. To create new plugins, use the existing modules as a guide. Drop a new file with the .pm extension in either the Processor or Action directory, depending on what kind of plugin it is. Processor plugins add information to the data. Action plugins do something with the data once all of the information is available. A simple logging demo has been included, but many different kinds of action plugins could be written to do things like submit full files to a sandbox, send an email, log to a database, send an SNMP trap, etc. INSTALLATION You will need a few Perl modules to get going. I recommend using the excellent cpanm utility which can be installed by typing "cpan App::cpanminus." After cpanm is installed, you can install everything in one command like this: cpanm Moose Module::Pluggable Log::Log4perl Config::JSON File::Tail LWP::UserAgent Sys::Syslog Alternatively, you may wish to install using your operating system's package manager, though that may not use the latest code for these modules. suricata-1.4.7/contrib/file_processor/file_processor.pl0000644000000000000000000001204512253546156020271 00000000000000# Copyright (C) 2012 Martin Holste # # You can copy, redistribute or modify this Program under the terms of # the GNU General Public License version 2 as published by the Free # Software Foundation. # # 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 # version 2 along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # package Processor; use Moose; use Data::Dumper; use Module::Pluggable search_path => qw(Processor), sub_name => 'processors'; use Module::Pluggable search_path => qw(Action), sub_name => 'actions'; use Log::Log4perl; use JSON; has 'conf' => (is => 'rw', isa => 'HashRef', required => 1); has 'log' => (is => 'rw', isa => 'Object', required => 1); has 'json' => (is => 'ro', isa => 'JSON', required => 1, default => sub { return JSON->new->pretty->allow_blessed }); sub BUILD { my $self = shift; foreach my $processor_plugin ($self->processors){ next unless exists $self->conf->{processors}->{$processor_plugin}; eval qq{require $processor_plugin}; $self->log->info('Using processor plugin ' . $processor_plugin->description); } foreach my $action_plugin ($self->actions){ next unless exists $self->conf->{actions}->{$action_plugin}; eval qq{require $action_plugin}; $self->log->info('Using action plugin ' . $action_plugin->description); } } sub process { my $self = shift; my $line = shift; #$self->log->debug('got line ' . $line); eval { my $data = $self->json->decode($line); $data->{processors} = {}; if($data->{md5}){ foreach my $processor_plugin ($self->processors){ next unless exists $self->conf->{processors}->{$processor_plugin}; my $processor = $processor_plugin->new(conf => $self->conf, log => $self->log, md5 => $data->{md5}); $self->log->debug('processing with plugin ' . $processor->description); $data->{processors}->{ $processor->name } = $processor->process(); } } #$self->log->debug('data: ' . Dumper($data)); foreach my $action_plugin ($self->actions){ next unless exists $self->conf->{actions}->{$action_plugin}; my $action = $action_plugin->new(conf => $self->conf, log => $self->log, data => $data); $self->log->debug('performing action with plugin ' . $action->description); $action->perform(); } }; if ($@){ $self->log->error('Error: ' . $@ . ', processing line: ' . $line); } } package main; use strict; use Getopt::Std; use FindBin; use Config::JSON; use File::Tail; # Include the directory this script is in use lib $FindBin::Bin; my %Opts; getopts('c:', \%Opts); my $conf_file = $Opts{c} ? $Opts{c} : '/etc/suricata/file_processor.conf'; my $Conf = { logdir => '/tmp', debug_level => 'TRACE', actions => { 'Action::Log' => 1, 'Action::Syslog' => 1, }, processors => { 'Processor::Anubis' => 1, 'Processor::Malwr' => 1, 'Processor::ThreatExpert' => 1, } }; if (-f $conf_file){ $Conf = Config::JSON->new( $conf_file ); $Conf = $Conf->{config}; # native hash is 10x faster than using Config::JSON->get() } # Setup logger my $logdir = $Conf->{logdir} ? $Conf->{logdir} : '/var/log/suricata'; my $debug_level = $Conf->{debug_level} ? $Conf->{debug_level} : 'TRACE'; my $l4pconf = qq( log4perl.category.App = $debug_level, File, Screen log4perl.appender.File = Log::Log4perl::Appender::File log4perl.appender.File.filename = $logdir/file_processor.log log4perl.appender.File.syswrite = 1 log4perl.appender.File.recreate = 1 log4perl.appender.File.layout = Log::Log4perl::Layout::PatternLayout log4perl.appender.File.layout.ConversionPattern = * %p [%d] %F (%L) %M %P %m%n log4perl.filter.ScreenLevel = Log::Log4perl::Filter::LevelRange log4perl.filter.ScreenLevel.LevelMin = $debug_level log4perl.filter.ScreenLevel.LevelMax = ERROR log4perl.filter.ScreenLevel.AcceptOnMatch = true log4perl.appender.Screen = Log::Log4perl::Appender::Screen log4perl.appender.Screen.Filter = ScreenLevel log4perl.appender.Screen.stderr = 1 log4perl.appender.Screen.layout = Log::Log4perl::Layout::PatternLayout log4perl.appender.Screen.layout.ConversionPattern = * %p [%d] %F (%L) %M %P %m%n ); Log::Log4perl::init( \$l4pconf ) or die("Unable to init logger\n"); my $Log = Log::Log4perl::get_logger('App') or die("Unable to init logger\n"); my $processor = new Processor(conf => $Conf, log => $Log); my $file = $Conf->{file} ? $Conf->{file} : '/var/log/suricata/files-json.log'; my $tail = new File::Tail(name => $file, maxinterval => 1); while (my $line = $tail->read){ $processor->process($line); } __END__ Example config file /etc/suricata/file_processor.conf { "logdir": "/var/log/suricata", "debug_level": "INFO", "virustotal_apikey": "xxx" "actions": { "Action::Log": 1 }, "processors": { "Processor::Anubis": 1, "Processor::Malwr": 1, "Processor::ThreatExpert": 1, "Processor::VirusTotal": 1 } } suricata-1.4.7/contrib/file_processor/Action/0000755000000000000000000000000012253546204016203 500000000000000suricata-1.4.7/contrib/file_processor/Action/Syslog.pm0000644000000000000000000000064712253546156017756 00000000000000package Action::Syslog; use Moose; extends 'Processor'; use Sys::Syslog qw(:standard :macros); our $Program = 'suricata_file'; our $Facility = LOG_LOCAL0; has 'data' => (is => 'rw', isa => 'HashRef', required => 1); sub name { 'syslog' } sub description { 'Log to local syslog' } sub perform { my $self = shift; openlog($Program, undef, $Facility); syslog(LOG_INFO, $self->json->encode($self->data)); closelog; } 1 suricata-1.4.7/contrib/file_processor/Action/Log.pm0000644000000000000000000000040412253546156017206 00000000000000package Action::Log; use Moose; extends 'Processor'; has 'data' => (is => 'rw', isa => 'HashRef', required => 1); sub name { 'log' } sub description { 'Log to file' } sub perform { my $self = shift; $self->log->info($self->json->encode($self->data)); } 1suricata-1.4.7/contrib/file_processor/Action/Makefile.in0000644000000000000000000003163012253546174020201 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = contrib/file_processor/Action DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = Log.pm Syslog.pm all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/file_processor/Action/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu contrib/file_processor/Action/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir 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 \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am 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: suricata-1.4.7/contrib/file_processor/Action/Makefile.am0000644000000000000000000000003412253546156020162 00000000000000EXTRA_DIST=Log.pm Syslog.pm suricata-1.4.7/contrib/file_processor/Makefile.in0000644000000000000000000004626712253546174017000 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = contrib/file_processor DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-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 \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = Action Processor EXTRA_DIST = file_processor.conf file_processor.pl LICENSE README all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/file_processor/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu contrib/file_processor/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ 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; \ ($(am__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" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ 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 || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -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: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-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-am 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: suricata-1.4.7/contrib/file_processor/Processor/0000755000000000000000000000000012253546204016745 500000000000000suricata-1.4.7/contrib/file_processor/Processor/Malwr.pm0000644000000000000000000000200612253546156020311 00000000000000package Processor::Malwr; use Moose; extends 'Processor'; use Data::Dumper; use LWP::UserAgent; has 'md5' => (is => 'ro', isa => 'Str', required => 1); has 'ua' => (is => 'rw', isa => 'LWP::UserAgent', required => 1, default => sub { return LWP::UserAgent->new(agent => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1'); }); has 'url_template' => (is => 'ro', isa => 'Str', required => 1, default => 'http://malwr.com/analysis/%s/'); sub name { 'Malwr' } sub description { 'Processor for Malwr.com' } sub process { my $self = shift; my $url = sprintf($self->url_template, $self->md5); $self->log->debug('Getting url ' . $url); my $response = $self->ua->get($url); if ($response->code eq 200){ if ($response->decoded_content =~ /Cannot find analysis with specified ID or MD5/){ $self->log->debug('No result'); return 0; } $self->log->info('Got malwr.com result'); return $url; } else { $self->log->debug('Communications failure: ' . Dumper($response)); return 0; } } 1suricata-1.4.7/contrib/file_processor/Processor/ThreatExpert.pm0000644000000000000000000000205712253546156021654 00000000000000package Processor::ThreatExpert; use Moose; extends 'Processor'; use Data::Dumper; use LWP::UserAgent; has 'md5' => (is => 'ro', isa => 'Str', required => 1); has 'ua' => (is => 'rw', isa => 'LWP::UserAgent', required => 1, default => sub { return LWP::UserAgent->new(agent => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1'); }); has 'url_template' => (is => 'ro', isa => 'Str', required => 1, default => 'http://www.threatexpert.com/report.aspx?md5=%s'); sub name { 'ThreatExpert' } sub description { 'Processor for threatexpert.com' } sub process { my $self = shift; my $url = sprintf($self->url_template, $self->md5); $self->log->debug('Getting url ' . $url); my $response = $self->ua->get($url); #$self->log->debug(Dumper($response)); if ($response->code eq 200){ if ($response->decoded_content =~ /Search All Reports/){ $self->log->debug('No result'); return 0; } $self->log->info('Got result'); return $url; } else { $self->log->debug('Communications failure: ' . Dumper($response)); return 0; } } 1suricata-1.4.7/contrib/file_processor/Processor/Makefile.in0000644000000000000000000003172512253546174020750 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = contrib/file_processor/Processor DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = Anubis.pm Malwr.pm ShadowServer.pm ThreatExpert.pm VirusTotal.pm all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/file_processor/Processor/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu contrib/file_processor/Processor/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir 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 \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am 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: suricata-1.4.7/contrib/file_processor/Processor/Anubis.pm0000644000000000000000000000204712253546156020455 00000000000000package Processor::Anubis; use Moose; extends 'Processor'; use Data::Dumper; use LWP::UserAgent; has 'md5' => (is => 'ro', isa => 'Str', required => 1); has 'ua' => (is => 'rw', isa => 'LWP::UserAgent', required => 1, default => sub { return LWP::UserAgent->new(agent => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1'); }); has 'url_template' => (is => 'ro', isa => 'Str', required => 1, default => 'http://anubis.iseclab.org/?action=result&task_id=%s'); sub name { 'Anubis' } sub description { 'Processor for anubis.iseclab.org' } sub process { my $self = shift; my $url = sprintf($self->url_template, $self->md5); $self->log->debug('Getting url ' . $url); my $response = $self->ua->get($url); #$self->log->debug(Dumper($response)); if ($response->code eq 200){ if ($response->decoded_content =~ /Invalid Task ID/){ $self->log->debug('No result'); return 0; } $self->log->info('Got result'); return $url; } else { $self->log->debug('Communications failure: ' . Dumper($response)); return 0; } } 1suricata-1.4.7/contrib/file_processor/Processor/ShadowServer.pm0000644000000000000000000000271612253546156021653 00000000000000package Processor::ShadowServer; use Moose; extends 'Processor'; use Data::Dumper; use LWP::UserAgent; use JSON; has 'md5' => (is => 'ro', isa => 'Str', required => 1); has 'ua' => (is => 'rw', isa => 'LWP::UserAgent', required => 1, default => sub { return LWP::UserAgent->new(agent => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1'); }); has 'url_template' => (is => 'ro', isa => 'Str', required => 1, default => 'http://innocuous.shadowserver.org/api/?query=%s'); sub name { 'ShadowServer' } sub description { 'Processor for shadowserver.com' } sub process { my $self = shift; my $url = sprintf($self->url_template, $self->md5); $self->log->debug('Getting url ' . $url); my $response = $self->ua->get($url); if ($response->code eq 200){ if ($response->decoded_content =~ /No match/){ $self->log->debug('No result'); return 0; } elsif ($response->decoded_content =~ /Whitelisted/){ $self->log->info('Whitelisted'); return 0; } $self->log->info('Got shadowserver.com result'); my $ret; eval { my ($meta,$json) = split(/\n/, $response->decoded_content); my @meta_cols = qw(md5 sha1 first_date last_date type ssdeep); my %metas; @metas{@meta_cols} = split(/\,/, $meta); $ret = { meta => \%metas, results => decode_json($json) }; }; if ($@){ $self->log->error($@); return 0; } return $ret; } else { $self->log->debug('Communications failure: ' . Dumper($response)); return 0; } } 1 suricata-1.4.7/contrib/file_processor/Processor/Makefile.am0000644000000000000000000000012112253546156020721 00000000000000EXTRA_DIST=Anubis.pm Malwr.pm ShadowServer.pm ThreatExpert.pm VirusTotal.pm suricata-1.4.7/contrib/file_processor/Processor/VirusTotal.pm0000644000000000000000000000245212253546156021350 00000000000000package Processor::VirusTotal; use Moose; extends 'Processor'; use Data::Dumper; use LWP::UserAgent; has 'md5' => (is => 'ro', isa => 'Str', required => 1); has 'ua' => (is => 'rw', isa => 'LWP::UserAgent', required => 1, default => sub { return LWP::UserAgent->new(agent => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1'); }); has 'url' => (is => 'ro', isa => 'Str', required => 1, default => 'https://www.virustotal.com/vtapi/v2/file/report'); sub name { 'VirusTotal' } sub description { 'Processor for virustotal.com' } sub process { my $self = shift; unless ($self->conf->{virustotal_apikey}){ warn('No VirusTotal apikey configured in config file'); return 0; } $self->log->debug('Getting url ' . $self->url); #$self->log->debug('md5: ' . $self->md5 . ', apikey: ' . $self->conf->{virustotal_apikey}); my $response = $self->ua->post($self->url, { resource => $self->md5, apikey => $self->conf->{virustotal_apikey} }); #$self->log->debug(Dumper($response)); if ($response->code eq 200){ my $data = $self->json->decode($response->decoded_content); $self->log->debug('data: ' . Dumper($data)); if ($data->{positives}){ return $data; } else { return 0; } } else { $self->log->debug('Communications failure: ' . Dumper($response)); return 0; } } 1suricata-1.4.7/contrib/file_processor/LICENSE0000644000000000000000000004310312253546156015722 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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. Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. , 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 Lesser General Public License instead of this License. suricata-1.4.7/contrib/file_processor/Makefile.am0000644000000000000000000000013612253546156016750 00000000000000SUBDIRS = Action Processor EXTRA_DIST = file_processor.conf file_processor.pl LICENSE README suricata-1.4.7/contrib/Makefile.in0000644000000000000000000004607612253546173013757 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@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 = contrib DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-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 \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_COCCINELLE_CONFIG = @HAVE_COCCINELLE_CONFIG@ HAVE_GIT_CMD = @HAVE_GIT_CMD@ HAVE_PCAP_CONFIG = @HAVE_PCAP_CONFIG@ HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@ HAVE_PYTHON_CONFIG = @HAVE_PYTHON_CONFIG@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBHTPMAXVERSION_CFLAGS = @LIBHTPMAXVERSION_CFLAGS@ LIBHTPMAXVERSION_LIBS = @LIBHTPMAXVERSION_LIBS@ LIBHTPMINVERSION_CFLAGS = @LIBHTPMINVERSION_CFLAGS@ LIBHTPMINVERSION_LIBS = @LIBHTPMINVERSION_LIBS@ LIBOBJS = @LIBOBJS@ LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@ LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@ LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@ LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@ LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@ LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@ LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUAJIT_CFLAGS = @LUAJIT_CFLAGS@ LUAJIT_LIBS = @LUAJIT_LIBS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ NVCC = @NVCC@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ 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_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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@ e_localstatedir = @e_localstatedir@ e_logdir = @e_logdir@ e_logfilesdir = @e_logfilesdir@ e_magic_file = @e_magic_file@ e_rundir = @e_rundir@ e_sysconfdir = @e_sysconfdir@ e_sysconfrulesdir = @e_sysconfrulesdir@ 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@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = file_processor all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu contrib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ 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; \ ($(am__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" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ 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 || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ 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 "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -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: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-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-am 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: suricata-1.4.7/contrib/Makefile.am0000644000000000000000000000003112253546156013724 00000000000000SUBDIRS = file_processor